isl_map_coalesce: check for subsets with smaller number of divs
[isl.git] / isl_union_templ.c
blobed7404e7a9d869c7555ce2e1bdc0cd779ea8d1c9
1 /*
2 * Copyright 2010 INRIA Saclay
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8 * 91893 Orsay, France
9 */
11 #define xFN(TYPE,NAME) TYPE ## _ ## NAME
12 #define FN(TYPE,NAME) xFN(TYPE,NAME)
13 #define xS(TYPE,NAME) struct TYPE ## _ ## NAME
14 #define S(TYPE,NAME) xS(TYPE,NAME)
16 struct UNION {
17 int ref;
18 #ifdef HAS_TYPE
19 enum isl_fold type;
20 #endif
21 isl_space *space;
23 struct isl_hash_table table;
26 __isl_give UNION *FN(UNION,cow)(__isl_take UNION *u);
28 isl_ctx *FN(UNION,get_ctx)(__isl_keep UNION *u)
30 return u ? u->space->ctx : NULL;
33 __isl_give isl_space *FN(UNION,get_space)(__isl_keep UNION *u)
35 if (!u)
36 return NULL;
37 return isl_space_copy(u->space);
40 /* Return the number of parameters of "u", where "type"
41 * is required to be set to isl_dim_param.
43 unsigned FN(UNION,dim)(__isl_keep UNION *u, enum isl_dim_type type)
45 if (!u)
46 return 0;
48 if (type != isl_dim_param)
49 isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
50 "can only reference parameters", return 0);
52 return isl_space_dim(u->space, type);
55 /* Return the position of the parameter with the given name
56 * in "u".
57 * Return -1 if no such dimension can be found.
59 int FN(UNION,find_dim_by_name)(__isl_keep UNION *u, enum isl_dim_type type,
60 const char *name)
62 if (!u)
63 return -1;
64 return isl_space_find_dim_by_name(u->space, type, name);
67 #ifdef HAS_TYPE
68 static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim,
69 enum isl_fold type, int size)
70 #else
71 static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim, int size)
72 #endif
74 UNION *u;
76 dim = isl_space_params(dim);
77 if (!dim)
78 return NULL;
80 u = isl_calloc_type(dim->ctx, UNION);
81 if (!u)
82 goto error;
84 u->ref = 1;
85 #ifdef HAS_TYPE
86 u->type = type;
87 #endif
88 u->space = dim;
89 if (isl_hash_table_init(dim->ctx, &u->table, size) < 0)
90 return FN(UNION,free)(u);
92 return u;
93 error:
94 isl_space_free(dim);
95 return NULL;
98 #ifdef HAS_TYPE
99 __isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
101 return FN(UNION,alloc)(dim, type, 16);
103 #else
104 __isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim)
106 return FN(UNION,alloc)(dim, 16);
108 #endif
110 __isl_give UNION *FN(UNION,copy)(__isl_keep UNION *u)
112 if (!u)
113 return NULL;
115 u->ref++;
116 return u;
119 S(UNION,foreach_data)
121 int (*fn)(__isl_take PART *part, void *user);
122 void *user;
125 static int call_on_copy(void **entry, void *user)
127 PART *part = *entry;
128 S(UNION,foreach_data) *data = (S(UNION,foreach_data) *)user;
130 return data->fn(FN(PART,copy)(part), data->user);
133 int FN(FN(UNION,foreach),PARTS)(__isl_keep UNION *u,
134 int (*fn)(__isl_take PART *part, void *user), void *user)
136 S(UNION,foreach_data) data = { fn, user };
138 if (!u)
139 return -1;
141 return isl_hash_table_foreach(u->space->ctx, &u->table,
142 &call_on_copy, &data);
145 /* Is the space of "entry" equal to "space"?
147 static int has_space(const void *entry, const void *val)
149 PART *part = (PART *)entry;
150 isl_space *space = (isl_space *) val;
152 return isl_space_is_equal(part->dim, space);
155 /* This function is not currently used by isl_aff.c.
157 static int has_domain_space(const void *entry, const void *val)
158 __attribute__ ((unused));
160 /* Is the domain space of "entry" equal to "space"?
162 static int has_domain_space(const void *entry, const void *val)
164 PART *part = (PART *)entry;
165 isl_space *space = (isl_space *) val;
167 if (isl_space_is_params(space))
168 return isl_space_is_set(part->dim);
170 return isl_space_tuple_is_equal(part->dim, isl_dim_in,
171 space, isl_dim_set);
174 /* Is the domain space of "entry" equal to the domain of "space"?
176 static int has_same_domain_space(const void *entry, const void *val)
178 PART *part = (PART *)entry;
179 isl_space *space = (isl_space *) val;
181 if (isl_space_is_set(space))
182 return isl_space_is_set(part->dim);
184 return isl_space_tuple_is_equal(part->dim, isl_dim_in,
185 space, isl_dim_in);
188 /* Extract the element of "u" living in "space" (ignoring parameters).
190 * Return the ZERO element if "u" does not contain any element
191 * living in "space".
193 __isl_give PART *FN(FN(UNION,extract),PARTS)(__isl_keep UNION *u,
194 __isl_take isl_space *space)
196 uint32_t hash;
197 struct isl_hash_table_entry *entry;
199 if (!u || !space)
200 goto error;
201 if (!isl_space_match(u->space, isl_dim_param, space, isl_dim_param)) {
202 space = isl_space_drop_dims(space, isl_dim_param,
203 0, isl_space_dim(space, isl_dim_param));
204 space = isl_space_align_params(space,
205 FN(UNION,get_space)(u));
206 if (!space)
207 goto error;
210 hash = isl_space_get_hash(space);
211 entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
212 &has_space, space, 0);
213 if (!entry)
214 #ifdef HAS_TYPE
215 return FN(PART,ZERO)(space, u->type);
216 #else
217 return FN(PART,ZERO)(space);
218 #endif
219 isl_space_free(space);
220 return FN(PART,copy)(entry->data);
221 error:
222 isl_space_free(space);
223 return NULL;
226 /* Add "part" to "u".
227 * If "disjoint" is set, then "u" is not allowed to already have
228 * a part that is defined on the same space as "part".
229 * Otherwise, compute the union sum of "part" and the part in "u"
230 * defined on the same space.
232 static __isl_give UNION *FN(UNION,add_part_generic)(__isl_take UNION *u,
233 __isl_take PART *part, int disjoint)
235 int empty;
236 uint32_t hash;
237 struct isl_hash_table_entry *entry;
239 if (!part)
240 goto error;
242 empty = FN(PART,IS_ZERO)(part);
243 if (empty < 0)
244 goto error;
245 if (empty) {
246 FN(PART,free)(part);
247 return u;
250 u = FN(UNION,align_params)(u, FN(PART,get_space)(part));
251 part = FN(PART,align_params)(part, FN(UNION,get_space)(u));
253 u = FN(UNION,cow)(u);
255 if (!u)
256 goto error;
258 hash = isl_space_get_hash(part->dim);
259 entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
260 &has_same_domain_space, part->dim, 1);
261 if (!entry)
262 goto error;
264 if (!entry->data)
265 entry->data = part;
266 else {
267 PART *entry_part = entry->data;
268 if (disjoint)
269 isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
270 "additional part should live on separate "
271 "space", goto error);
272 if (!isl_space_tuple_is_equal(entry_part->dim, isl_dim_out,
273 part->dim, isl_dim_out))
274 isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
275 "union expression can only contain a single "
276 "expression over a given domain", goto error);
277 entry->data = FN(PART,union_add_)(entry->data,
278 FN(PART,copy)(part));
279 if (!entry->data)
280 goto error;
281 empty = FN(PART,IS_ZERO)(part);
282 if (empty < 0)
283 goto error;
284 if (empty) {
285 FN(PART,free)(entry->data);
286 isl_hash_table_remove(u->space->ctx, &u->table, entry);
288 FN(PART,free)(part);
291 return u;
292 error:
293 FN(PART,free)(part);
294 FN(UNION,free)(u);
295 return NULL;
298 /* Add "part" to "u", where "u" is assumed not to already have
299 * a part that is defined on the same space as "part".
301 __isl_give UNION *FN(FN(UNION,add),PARTS)(__isl_take UNION *u,
302 __isl_take PART *part)
304 return FN(UNION,add_part_generic)(u, part, 1);
307 static int add_part(__isl_take PART *part, void *user)
309 UNION **u = (UNION **)user;
311 *u = FN(FN(UNION,add),PARTS)(*u, part);
313 return 0;
316 __isl_give UNION *FN(UNION,dup)(__isl_keep UNION *u)
318 UNION *dup;
320 if (!u)
321 return NULL;
323 #ifdef HAS_TYPE
324 dup = FN(UNION,ZERO)(isl_space_copy(u->space), u->type);
325 #else
326 dup = FN(UNION,ZERO)(isl_space_copy(u->space));
327 #endif
328 if (FN(FN(UNION,foreach),PARTS)(u, &add_part, &dup) < 0)
329 goto error;
330 return dup;
331 error:
332 FN(UNION,free)(dup);
333 return NULL;
336 __isl_give UNION *FN(UNION,cow)(__isl_take UNION *u)
338 if (!u)
339 return NULL;
341 if (u->ref == 1)
342 return u;
343 u->ref--;
344 return FN(UNION,dup)(u);
347 static int free_u_entry(void **entry, void *user)
349 PART *part = *entry;
350 FN(PART,free)(part);
351 return 0;
354 __isl_null UNION *FN(UNION,free)(__isl_take UNION *u)
356 if (!u)
357 return NULL;
359 if (--u->ref > 0)
360 return NULL;
362 isl_hash_table_foreach(u->space->ctx, &u->table, &free_u_entry, NULL);
363 isl_hash_table_clear(&u->table);
364 isl_space_free(u->space);
365 free(u);
366 return NULL;
369 S(UNION,align) {
370 isl_reordering *exp;
371 UNION *res;
374 #ifdef ALIGN_DOMAIN
375 static int align_entry(__isl_take PART *part, void *user)
377 isl_reordering *exp;
378 S(UNION,align) *data = user;
380 exp = isl_reordering_extend_space(isl_reordering_copy(data->exp),
381 FN(PART,get_domain_space)(part));
383 data->res = FN(FN(UNION,add),PARTS)(data->res,
384 FN(PART,realign_domain)(part, exp));
386 return 0;
388 #else
389 static int align_entry(__isl_take PART *part, void *user)
391 isl_reordering *exp;
392 S(UNION,align) *data = user;
394 exp = isl_reordering_extend_space(isl_reordering_copy(data->exp),
395 FN(PART,get_space)(part));
397 data->res = FN(FN(UNION,add),PARTS)(data->res,
398 FN(PART,realign)(part, exp));
400 return 0;
402 #endif
404 __isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u,
405 __isl_take isl_space *model)
407 S(UNION,align) data = { NULL, NULL };
409 if (!u || !model)
410 goto error;
412 if (isl_space_match(u->space, isl_dim_param, model, isl_dim_param)) {
413 isl_space_free(model);
414 return u;
417 model = isl_space_params(model);
418 data.exp = isl_parameter_alignment_reordering(u->space, model);
419 if (!data.exp)
420 goto error;
422 #ifdef HAS_TYPE
423 data.res = FN(UNION,alloc)(isl_space_copy(data.exp->dim),
424 u->type, u->table.n);
425 #else
426 data.res = FN(UNION,alloc)(isl_space_copy(data.exp->dim), u->table.n);
427 #endif
428 if (FN(FN(UNION,foreach),PARTS)(u, &align_entry, &data) < 0)
429 goto error;
431 isl_reordering_free(data.exp);
432 FN(UNION,free)(u);
433 isl_space_free(model);
434 return data.res;
435 error:
436 isl_reordering_free(data.exp);
437 FN(UNION,free)(u);
438 FN(UNION,free)(data.res);
439 isl_space_free(model);
440 return NULL;
443 /* Add "part" to *u, taking the union sum if "u" already has
444 * a part defined on the same space as "part".
446 static int union_add_part(__isl_take PART *part, void *user)
448 UNION **u = (UNION **)user;
450 *u = FN(UNION,add_part_generic)(*u, part, 0);
452 return 0;
455 /* Compute the sum of "u1" and "u2" on the union of their domains,
456 * with the actual sum on the shared domain and
457 * the defined expression on the symmetric difference of the domains.
459 * This is an internal function that is exposed under different
460 * names depending on whether the base expressions have a zero default
461 * value.
462 * If they do, then this function is called "add".
463 * Otherwise, it is called "union_add".
465 static __isl_give UNION *FN(UNION,union_add_)(__isl_take UNION *u1,
466 __isl_take UNION *u2)
468 u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
469 u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
471 u1 = FN(UNION,cow)(u1);
473 if (!u1 || !u2)
474 goto error;
476 if (FN(FN(UNION,foreach),PARTS)(u2, &union_add_part, &u1) < 0)
477 goto error;
479 FN(UNION,free)(u2);
481 return u1;
482 error:
483 FN(UNION,free)(u1);
484 FN(UNION,free)(u2);
485 return NULL;
488 __isl_give UNION *FN(FN(UNION,from),PARTS)(__isl_take PART *part)
490 isl_space *dim;
491 UNION *u;
493 if (!part)
494 return NULL;
496 dim = FN(PART,get_space)(part);
497 dim = isl_space_drop_dims(dim, isl_dim_in, 0, isl_space_dim(dim, isl_dim_in));
498 dim = isl_space_drop_dims(dim, isl_dim_out, 0, isl_space_dim(dim, isl_dim_out));
499 #ifdef HAS_TYPE
500 u = FN(UNION,ZERO)(dim, part->type);
501 #else
502 u = FN(UNION,ZERO)(dim);
503 #endif
504 u = FN(FN(UNION,add),PARTS)(u, part);
506 return u;
509 S(UNION,match_bin_data) {
510 UNION *u2;
511 UNION *res;
512 __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *);
515 /* Check if data->u2 has an element living in the same space as *entry.
516 * If so, call data->fn on the two elements and add the result to
517 * data->res.
519 static int match_bin_entry(void **entry, void *user)
521 S(UNION,match_bin_data) *data = user;
522 uint32_t hash;
523 struct isl_hash_table_entry *entry2;
524 isl_space *space;
525 PART *part = *entry;
526 PART *part2;
528 space = FN(PART,get_space)(part);
529 hash = isl_space_get_hash(space);
530 entry2 = isl_hash_table_find(data->u2->space->ctx, &data->u2->table,
531 hash, &has_same_domain_space, space, 0);
532 isl_space_free(space);
533 if (!entry2)
534 return 0;
536 part2 = entry2->data;
537 if (!isl_space_tuple_is_equal(part->dim, isl_dim_out,
538 part2->dim, isl_dim_out))
539 isl_die(FN(UNION,get_ctx)(data->u2), isl_error_invalid,
540 "entries should have the same range space",
541 return -1);
543 part = FN(PART, copy)(part);
544 part = data->fn(part, FN(PART, copy)(entry2->data));
546 data->res = FN(FN(UNION,add),PARTS)(data->res, part);
547 if (!data->res)
548 return -1;
550 return 0;
553 /* This function is currently only used from isl_polynomial.c
554 * and not from isl_fold.c.
556 static __isl_give UNION *match_bin_op(__isl_take UNION *u1,
557 __isl_take UNION *u2,
558 __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *))
559 __attribute__ ((unused));
560 /* For each pair of elements in "u1" and "u2" living in the same space,
561 * call "fn" and collect the results.
563 static __isl_give UNION *match_bin_op(__isl_take UNION *u1,
564 __isl_take UNION *u2,
565 __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *))
567 S(UNION,match_bin_data) data = { NULL, NULL, fn };
569 u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
570 u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
572 if (!u1 || !u2)
573 goto error;
575 data.u2 = u2;
576 #ifdef HAS_TYPE
577 data.res = FN(UNION,alloc)(isl_space_copy(u1->space), u1->type,
578 u1->table.n);
579 #else
580 data.res = FN(UNION,alloc)(isl_space_copy(u1->space), u1->table.n);
581 #endif
582 if (isl_hash_table_foreach(u1->space->ctx, &u1->table,
583 &match_bin_entry, &data) < 0)
584 goto error;
586 FN(UNION,free)(u1);
587 FN(UNION,free)(u2);
588 return data.res;
589 error:
590 FN(UNION,free)(u1);
591 FN(UNION,free)(u2);
592 FN(UNION,free)(data.res);
593 return NULL;
596 /* Compute the sum of "u1" and "u2".
598 * If the base expressions have a default zero value, then the sum
599 * is computed on the union of the domains of "u1" and "u2".
600 * Otherwise, it is computed on their shared domains.
602 __isl_give UNION *FN(UNION,add)(__isl_take UNION *u1, __isl_take UNION *u2)
604 #if DEFAULT_IS_ZERO
605 return FN(UNION,union_add_)(u1, u2);
606 #else
607 return match_bin_op(u1, u2, &FN(PART,add));
608 #endif
611 #ifndef NO_SUB
612 /* Subtract "u2" from "u1" and return the result.
614 __isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2)
616 return match_bin_op(u1, u2, &FN(PART,sub));
618 #endif
620 S(UNION,any_set_data) {
621 isl_set *set;
622 UNION *res;
623 __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
626 static int any_set_entry(void **entry, void *user)
628 S(UNION,any_set_data) *data = user;
629 PW *pw = *entry;
631 pw = FN(PW,copy)(pw);
632 pw = data->fn(pw, isl_set_copy(data->set));
634 data->res = FN(FN(UNION,add),PARTS)(data->res, pw);
635 if (!data->res)
636 return -1;
638 return 0;
641 /* Update each element of "u" by calling "fn" on the element and "set".
643 static __isl_give UNION *any_set_op(__isl_take UNION *u,
644 __isl_take isl_set *set,
645 __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*))
647 S(UNION,any_set_data) data = { NULL, NULL, fn };
649 u = FN(UNION,align_params)(u, isl_set_get_space(set));
650 set = isl_set_align_params(set, FN(UNION,get_space)(u));
652 if (!u || !set)
653 goto error;
655 data.set = set;
656 #ifdef HAS_TYPE
657 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type,
658 u->table.n);
659 #else
660 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n);
661 #endif
662 if (isl_hash_table_foreach(u->space->ctx, &u->table,
663 &any_set_entry, &data) < 0)
664 goto error;
666 FN(UNION,free)(u);
667 isl_set_free(set);
668 return data.res;
669 error:
670 FN(UNION,free)(u);
671 isl_set_free(set);
672 FN(UNION,free)(data.res);
673 return NULL;
676 /* Intersect the domain of "u" with the parameter domain "context".
678 __isl_give UNION *FN(UNION,intersect_params)(__isl_take UNION *u,
679 __isl_take isl_set *set)
681 return any_set_op(u, set, &FN(PW,intersect_params));
684 /* Compute the gist of the domain of "u" with respect to
685 * the parameter domain "context".
687 __isl_give UNION *FN(UNION,gist_params)(__isl_take UNION *u,
688 __isl_take isl_set *set)
690 return any_set_op(u, set, &FN(PW,gist_params));
693 S(UNION,match_domain_data) {
694 isl_union_set *uset;
695 UNION *res;
696 __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
699 static int set_has_dim(const void *entry, const void *val)
701 isl_set *set = (isl_set *)entry;
702 isl_space *dim = (isl_space *)val;
704 return isl_space_is_equal(set->dim, dim);
707 /* Find the set in data->uset that lives in the same space as the domain
708 * of *entry, apply data->fn to *entry and this set (if any), and add
709 * the result to data->res.
711 static int match_domain_entry(void **entry, void *user)
713 S(UNION,match_domain_data) *data = user;
714 uint32_t hash;
715 struct isl_hash_table_entry *entry2;
716 PW *pw = *entry;
717 isl_space *space;
719 space = FN(PW,get_domain_space)(pw);
720 hash = isl_space_get_hash(space);
721 entry2 = isl_hash_table_find(data->uset->dim->ctx, &data->uset->table,
722 hash, &set_has_dim, space, 0);
723 isl_space_free(space);
724 if (!entry2)
725 return 0;
727 pw = FN(PW,copy)(pw);
728 pw = data->fn(pw, isl_set_copy(entry2->data));
730 data->res = FN(FN(UNION,add),PARTS)(data->res, pw);
731 if (!data->res)
732 return -1;
734 return 0;
737 /* Apply fn to each pair of PW in u and set in uset such that
738 * the set lives in the same space as the domain of PW
739 * and collect the results.
741 static __isl_give UNION *match_domain_op(__isl_take UNION *u,
742 __isl_take isl_union_set *uset,
743 __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*))
745 S(UNION,match_domain_data) data = { NULL, NULL, fn };
747 u = FN(UNION,align_params)(u, isl_union_set_get_space(uset));
748 uset = isl_union_set_align_params(uset, FN(UNION,get_space)(u));
750 if (!u || !uset)
751 goto error;
753 data.uset = uset;
754 #ifdef HAS_TYPE
755 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type,
756 u->table.n);
757 #else
758 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n);
759 #endif
760 if (isl_hash_table_foreach(u->space->ctx, &u->table,
761 &match_domain_entry, &data) < 0)
762 goto error;
764 FN(UNION,free)(u);
765 isl_union_set_free(uset);
766 return data.res;
767 error:
768 FN(UNION,free)(u);
769 isl_union_set_free(uset);
770 FN(UNION,free)(data.res);
771 return NULL;
774 /* Intersect the domain of "u" with "uset".
775 * If "uset" is a parameters domain, then intersect the parameter
776 * domain of "u" with this set.
778 __isl_give UNION *FN(UNION,intersect_domain)(__isl_take UNION *u,
779 __isl_take isl_union_set *uset)
781 if (isl_union_set_is_params(uset))
782 return FN(UNION,intersect_params)(u,
783 isl_set_from_union_set(uset));
784 return match_domain_op(u, uset, &FN(PW,intersect_domain));
787 /* Internal data structure for isl_union_*_subtract_domain.
788 * uset is the set that needs to be removed from the domain.
789 * res collects the results.
791 S(UNION,subtract_domain_data) {
792 isl_union_set *uset;
793 UNION *res;
796 /* Take the set (which may be empty) in data->uset that lives
797 * in the same space as the domain of "pw", subtract it from the domain
798 * of "pw" and add the result to data->res.
800 static int FN(UNION,subtract_domain_entry)(__isl_take PW *pw, void *user)
802 S(UNION,subtract_domain_data) *data = user;
803 isl_space *space;
804 isl_set *set;
806 space = FN(PW,get_domain_space)(pw);
807 set = isl_union_set_extract_set(data->uset, space);
808 pw = FN(PW,subtract_domain)(pw, set);
809 data->res = FN(FN(UNION,add),PARTS)(data->res, pw);
811 return 0;
814 /* Subtract "uset' from the domain of "u".
816 __isl_give UNION *FN(UNION,subtract_domain)(__isl_take UNION *u,
817 __isl_take isl_union_set *uset)
819 S(UNION,subtract_domain_data) data;
821 if (!u || !uset)
822 goto error;
824 data.uset = uset;
825 #ifdef HAS_TYPE
826 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type,
827 u->table.n);
828 #else
829 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n);
830 #endif
831 if (FN(FN(UNION,foreach),PARTS)(u,
832 &FN(UNION,subtract_domain_entry), &data) < 0)
833 data.res = FN(UNION,free)(data.res);
835 FN(UNION,free)(u);
836 isl_union_set_free(uset);
837 return data.res;
838 error:
839 FN(UNION,free)(u);
840 isl_union_set_free(uset);
841 return NULL;
844 __isl_give UNION *FN(UNION,gist)(__isl_take UNION *u,
845 __isl_take isl_union_set *uset)
847 if (isl_union_set_is_params(uset))
848 return FN(UNION,gist_params)(u, isl_set_from_union_set(uset));
849 return match_domain_op(u, uset, &FN(PW,gist));
852 #ifndef NO_EVAL
853 __isl_give isl_val *FN(UNION,eval)(__isl_take UNION *u,
854 __isl_take isl_point *pnt)
856 uint32_t hash;
857 struct isl_hash_table_entry *entry;
858 isl_space *space;
859 isl_val *v;
861 if (!u || !pnt)
862 goto error;
864 space = isl_space_copy(pnt->dim);
865 if (!space)
866 goto error;
867 hash = isl_space_get_hash(space);
868 entry = isl_hash_table_find(u->space->ctx, &u->table,
869 hash, &has_domain_space, space, 0);
870 isl_space_free(space);
871 if (!entry) {
872 v = isl_val_zero(isl_point_get_ctx(pnt));
873 isl_point_free(pnt);
874 } else {
875 v = FN(PART,eval)(FN(PART,copy)(entry->data), pnt);
877 FN(UNION,free)(u);
878 return v;
879 error:
880 FN(UNION,free)(u);
881 isl_point_free(pnt);
882 return NULL;
884 #endif
886 static int coalesce_entry(void **entry, void *user)
888 PW **pw = (PW **)entry;
890 *pw = FN(PW,coalesce)(*pw);
891 if (!*pw)
892 return -1;
894 return 0;
897 __isl_give UNION *FN(UNION,coalesce)(__isl_take UNION *u)
899 if (!u)
900 return NULL;
902 if (isl_hash_table_foreach(u->space->ctx, &u->table,
903 &coalesce_entry, NULL) < 0)
904 goto error;
906 return u;
907 error:
908 FN(UNION,free)(u);
909 return NULL;
912 static int domain(__isl_take PART *part, void *user)
914 isl_union_set **uset = (isl_union_set **)user;
916 *uset = isl_union_set_add_set(*uset, FN(PART,domain)(part));
918 return 0;
921 __isl_give isl_union_set *FN(UNION,domain)(__isl_take UNION *u)
923 isl_union_set *uset;
925 uset = isl_union_set_empty(FN(UNION,get_space)(u));
926 if (FN(FN(UNION,foreach),PARTS)(u, &domain, &uset) < 0)
927 goto error;
929 FN(UNION,free)(u);
931 return uset;
932 error:
933 isl_union_set_free(uset);
934 FN(UNION,free)(u);
935 return NULL;
938 static int mul_isl_int(void **entry, void *user)
940 PW **pw = (PW **)entry;
941 isl_int *v = user;
943 *pw = FN(PW,mul_isl_int)(*pw, *v);
944 if (!*pw)
945 return -1;
947 return 0;
950 __isl_give UNION *FN(UNION,mul_isl_int)(__isl_take UNION *u, isl_int v)
952 if (isl_int_is_one(v))
953 return u;
955 if (DEFAULT_IS_ZERO && u && isl_int_is_zero(v)) {
956 UNION *zero;
957 isl_space *dim = FN(UNION,get_space)(u);
958 #ifdef HAS_TYPE
959 zero = FN(UNION,ZERO)(dim, u->type);
960 #else
961 zero = FN(UNION,ZERO)(dim);
962 #endif
963 FN(UNION,free)(u);
964 return zero;
967 u = FN(UNION,cow)(u);
968 if (!u)
969 return NULL;
971 #ifdef HAS_TYPE
972 if (isl_int_is_neg(v))
973 u->type = isl_fold_type_negate(u->type);
974 #endif
975 if (isl_hash_table_foreach(u->space->ctx, &u->table,
976 &mul_isl_int, &v) < 0)
977 goto error;
979 return u;
980 error:
981 FN(UNION,free)(u);
982 return NULL;
985 /* Multiply *entry by the isl_val "user".
987 * Return 0 on success and -1 on error.
989 static int scale_val(void **entry, void *user)
991 PW **pw = (PW **)entry;
992 isl_val *v = user;
994 *pw = FN(PW,scale_val)(*pw, isl_val_copy(v));
995 if (!*pw)
996 return -1;
998 return 0;
1001 /* Multiply "u" by "v" and return the result.
1003 __isl_give UNION *FN(UNION,scale_val)(__isl_take UNION *u,
1004 __isl_take isl_val *v)
1006 if (!u || !v)
1007 goto error;
1008 if (isl_val_is_one(v)) {
1009 isl_val_free(v);
1010 return u;
1013 if (DEFAULT_IS_ZERO && u && isl_val_is_zero(v)) {
1014 UNION *zero;
1015 isl_space *space = FN(UNION,get_space)(u);
1016 #ifdef HAS_TYPE
1017 zero = FN(UNION,ZERO)(space, u->type);
1018 #else
1019 zero = FN(UNION,ZERO)(space);
1020 #endif
1021 FN(UNION,free)(u);
1022 isl_val_free(v);
1023 return zero;
1026 if (!isl_val_is_rat(v))
1027 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1028 "expecting rational factor", goto error);
1030 u = FN(UNION,cow)(u);
1031 if (!u)
1032 return NULL;
1034 #ifdef HAS_TYPE
1035 if (isl_val_is_neg(v))
1036 u->type = isl_fold_type_negate(u->type);
1037 #endif
1038 if (isl_hash_table_foreach(u->space->ctx, &u->table, &scale_val, v) < 0)
1039 goto error;
1041 isl_val_free(v);
1042 return u;
1043 error:
1044 isl_val_free(v);
1045 FN(UNION,free)(u);
1046 return NULL;
1049 /* Divide *entry by the isl_val "user".
1051 * Return 0 on success and -1 on error.
1053 static int FN(UNION,scale_down_val_entry)(void **entry, void *user)
1055 PW **pw = (PW **)entry;
1056 isl_val *v = user;
1058 *pw = FN(PW,scale_down_val)(*pw, isl_val_copy(v));
1059 if (!*pw)
1060 return -1;
1062 return 0;
1065 /* Divide "u" by "v" and return the result.
1067 __isl_give UNION *FN(UNION,scale_down_val)(__isl_take UNION *u,
1068 __isl_take isl_val *v)
1070 if (!u || !v)
1071 goto error;
1072 if (isl_val_is_one(v)) {
1073 isl_val_free(v);
1074 return u;
1077 if (!isl_val_is_rat(v))
1078 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1079 "expecting rational factor", goto error);
1080 if (isl_val_is_zero(v))
1081 isl_die(isl_val_get_ctx(v), isl_error_invalid,
1082 "cannot scale down by zero", goto error);
1084 u = FN(UNION,cow)(u);
1085 if (!u)
1086 return NULL;
1088 #ifdef HAS_TYPE
1089 if (isl_val_is_neg(v))
1090 u->type = isl_fold_type_negate(u->type);
1091 #endif
1092 if (isl_hash_table_foreach(FN(UNION,get_ctx)(u), &u->table,
1093 &FN(UNION,scale_down_val_entry), v) < 0)
1094 goto error;
1096 isl_val_free(v);
1097 return u;
1098 error:
1099 isl_val_free(v);
1100 FN(UNION,free)(u);
1101 return NULL;
1104 S(UNION,plain_is_equal_data)
1106 UNION *u2;
1107 int is_equal;
1110 static int plain_is_equal_entry(void **entry, void *user)
1112 S(UNION,plain_is_equal_data) *data = user;
1113 uint32_t hash;
1114 struct isl_hash_table_entry *entry2;
1115 PW *pw = *entry;
1117 hash = isl_space_get_hash(pw->dim);
1118 entry2 = isl_hash_table_find(data->u2->space->ctx, &data->u2->table,
1119 hash, &has_same_domain_space, pw->dim, 0);
1120 if (!entry2) {
1121 data->is_equal = 0;
1122 return -1;
1125 data->is_equal = FN(PW,plain_is_equal)(pw, entry2->data);
1126 if (data->is_equal < 0 || !data->is_equal)
1127 return -1;
1129 return 0;
1132 int FN(UNION,plain_is_equal)(__isl_keep UNION *u1, __isl_keep UNION *u2)
1134 S(UNION,plain_is_equal_data) data = { NULL, 1 };
1136 if (!u1 || !u2)
1137 return -1;
1138 if (u1 == u2)
1139 return 1;
1140 if (u1->table.n != u2->table.n)
1141 return 0;
1143 u1 = FN(UNION,copy)(u1);
1144 u2 = FN(UNION,copy)(u2);
1145 u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
1146 u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
1147 if (!u1 || !u2)
1148 goto error;
1150 data.u2 = u2;
1151 if (isl_hash_table_foreach(u1->space->ctx, &u1->table,
1152 &plain_is_equal_entry, &data) < 0 &&
1153 data.is_equal)
1154 goto error;
1156 FN(UNION,free)(u1);
1157 FN(UNION,free)(u2);
1159 return data.is_equal;
1160 error:
1161 FN(UNION,free)(u1);
1162 FN(UNION,free)(u2);
1163 return -1;