add isl_local_space_is_params
[isl.git] / isl_union_templ.c
blobf74262dcd7b97d2dbff33401058a908953e6be05
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 #ifdef HAS_TYPE
41 static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim,
42 enum isl_fold type, int size)
43 #else
44 static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim, int size)
45 #endif
47 UNION *u;
49 dim = isl_space_params(dim);
50 if (!dim)
51 return NULL;
53 u = isl_calloc_type(dim->ctx, UNION);
54 if (!u)
55 goto error;
57 u->ref = 1;
58 #ifdef HAS_TYPE
59 u->type = type;
60 #endif
61 u->space = dim;
62 if (isl_hash_table_init(dim->ctx, &u->table, size) < 0)
63 return FN(UNION,free)(u);
65 return u;
66 error:
67 isl_space_free(dim);
68 return NULL;
71 #ifdef HAS_TYPE
72 __isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
74 return FN(UNION,alloc)(dim, type, 16);
76 #else
77 __isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim)
79 return FN(UNION,alloc)(dim, 16);
81 #endif
83 __isl_give UNION *FN(UNION,copy)(__isl_keep UNION *u)
85 if (!u)
86 return NULL;
88 u->ref++;
89 return u;
92 S(UNION,foreach_data)
94 int (*fn)(__isl_take PART *part, void *user);
95 void *user;
98 static int call_on_copy(void **entry, void *user)
100 PART *part = *entry;
101 S(UNION,foreach_data) *data = (S(UNION,foreach_data) *)user;
103 return data->fn(FN(PART,copy)(part), data->user);
106 int FN(FN(UNION,foreach),PARTS)(__isl_keep UNION *u,
107 int (*fn)(__isl_take PART *part, void *user), void *user)
109 S(UNION,foreach_data) data = { fn, user };
111 if (!u)
112 return -1;
114 return isl_hash_table_foreach(u->space->ctx, &u->table,
115 &call_on_copy, &data);
118 /* Is the space of "entry" equal to "space"?
120 static int has_space(const void *entry, const void *val)
122 PART *part = (PART *)entry;
123 isl_space *space = (isl_space *) val;
125 return isl_space_is_equal(part->dim, space);
128 /* This function is not currently used by isl_aff.c.
130 static int has_domain_space(const void *entry, const void *val)
131 __attribute__ ((unused));
133 /* Is the domain space of "entry" equal to "space"?
135 static int has_domain_space(const void *entry, const void *val)
137 PART *part = (PART *)entry;
138 isl_space *space = (isl_space *) val;
140 if (isl_space_is_params(space))
141 return isl_space_is_set(part->dim);
143 return isl_space_tuple_is_equal(part->dim, isl_dim_in,
144 space, isl_dim_set);
147 /* Is the domain space of "entry" equal to the domain of "space"?
149 static int has_same_domain_space(const void *entry, const void *val)
151 PART *part = (PART *)entry;
152 isl_space *space = (isl_space *) val;
154 if (isl_space_is_set(space))
155 return isl_space_is_set(part->dim);
157 return isl_space_tuple_is_equal(part->dim, isl_dim_in,
158 space, isl_dim_in);
161 /* Extract the element of "u" living in "space" (ignoring parameters).
163 * Return the ZERO element if "u" does not contain any element
164 * living in "space".
166 __isl_give PART *FN(FN(UNION,extract),PARTS)(__isl_keep UNION *u,
167 __isl_take isl_space *space)
169 uint32_t hash;
170 struct isl_hash_table_entry *entry;
172 if (!u || !space)
173 goto error;
174 if (!isl_space_match(u->space, isl_dim_param, space, isl_dim_param)) {
175 space = isl_space_drop_dims(space, isl_dim_param,
176 0, isl_space_dim(space, isl_dim_param));
177 space = isl_space_align_params(space,
178 FN(UNION,get_space)(u));
179 if (!space)
180 goto error;
183 hash = isl_space_get_hash(space);
184 entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
185 &has_space, space, 0);
186 if (!entry)
187 #ifdef HAS_TYPE
188 return FN(PART,ZERO)(space, u->type);
189 #else
190 return FN(PART,ZERO)(space);
191 #endif
192 isl_space_free(space);
193 return FN(PART,copy)(entry->data);
194 error:
195 isl_space_free(space);
196 return NULL;
199 /* Add "part" to "u".
200 * If "disjoint" is set, then "u" is not allowed to already have
201 * a part that is defined on the same space as "part".
202 * Otherwise, compute the union sum of "part" and the part in "u"
203 * defined on the same space.
205 static __isl_give UNION *FN(UNION,add_part_generic)(__isl_take UNION *u,
206 __isl_take PART *part, int disjoint)
208 int empty;
209 uint32_t hash;
210 struct isl_hash_table_entry *entry;
212 if (!part)
213 goto error;
215 empty = FN(PART,IS_ZERO)(part);
216 if (empty < 0)
217 goto error;
218 if (empty) {
219 FN(PART,free)(part);
220 return u;
223 u = FN(UNION,align_params)(u, FN(PART,get_space)(part));
224 part = FN(PART,align_params)(part, FN(UNION,get_space)(u));
226 u = FN(UNION,cow)(u);
228 if (!u)
229 goto error;
231 hash = isl_space_get_hash(part->dim);
232 entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
233 &has_same_domain_space, part->dim, 1);
234 if (!entry)
235 goto error;
237 if (!entry->data)
238 entry->data = part;
239 else {
240 PART *entry_part = entry->data;
241 if (disjoint)
242 isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
243 "additional part should live on separate "
244 "space", goto error);
245 if (!isl_space_tuple_is_equal(entry_part->dim, isl_dim_out,
246 part->dim, isl_dim_out))
247 isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
248 "union expression can only contain a single "
249 "expression over a given domain", goto error);
250 entry->data = FN(PART,union_add_)(entry->data,
251 FN(PART,copy)(part));
252 if (!entry->data)
253 goto error;
254 empty = FN(PART,IS_ZERO)(part);
255 if (empty < 0)
256 goto error;
257 if (empty) {
258 FN(PART,free)(entry->data);
259 isl_hash_table_remove(u->space->ctx, &u->table, entry);
261 FN(PART,free)(part);
264 return u;
265 error:
266 FN(PART,free)(part);
267 FN(UNION,free)(u);
268 return NULL;
271 /* Add "part" to "u", where "u" is assumed not to already have
272 * a part that is defined on the same space as "part".
274 __isl_give UNION *FN(FN(UNION,add),PARTS)(__isl_take UNION *u,
275 __isl_take PART *part)
277 return FN(UNION,add_part_generic)(u, part, 1);
280 static int add_part(__isl_take PART *part, void *user)
282 UNION **u = (UNION **)user;
284 *u = FN(FN(UNION,add),PARTS)(*u, part);
286 return 0;
289 __isl_give UNION *FN(UNION,dup)(__isl_keep UNION *u)
291 UNION *dup;
293 if (!u)
294 return NULL;
296 #ifdef HAS_TYPE
297 dup = FN(UNION,ZERO)(isl_space_copy(u->space), u->type);
298 #else
299 dup = FN(UNION,ZERO)(isl_space_copy(u->space));
300 #endif
301 if (FN(FN(UNION,foreach),PARTS)(u, &add_part, &dup) < 0)
302 goto error;
303 return dup;
304 error:
305 FN(UNION,free)(dup);
306 return NULL;
309 __isl_give UNION *FN(UNION,cow)(__isl_take UNION *u)
311 if (!u)
312 return NULL;
314 if (u->ref == 1)
315 return u;
316 u->ref--;
317 return FN(UNION,dup)(u);
320 static int free_u_entry(void **entry, void *user)
322 PART *part = *entry;
323 FN(PART,free)(part);
324 return 0;
327 __isl_null UNION *FN(UNION,free)(__isl_take UNION *u)
329 if (!u)
330 return NULL;
332 if (--u->ref > 0)
333 return NULL;
335 isl_hash_table_foreach(u->space->ctx, &u->table, &free_u_entry, NULL);
336 isl_hash_table_clear(&u->table);
337 isl_space_free(u->space);
338 free(u);
339 return NULL;
342 S(UNION,align) {
343 isl_reordering *exp;
344 UNION *res;
347 #ifdef ALIGN_DOMAIN
348 static int align_entry(__isl_take PART *part, void *user)
350 isl_reordering *exp;
351 S(UNION,align) *data = user;
353 exp = isl_reordering_extend_space(isl_reordering_copy(data->exp),
354 FN(PART,get_domain_space)(part));
356 data->res = FN(FN(UNION,add),PARTS)(data->res,
357 FN(PART,realign_domain)(part, exp));
359 return 0;
361 #else
362 static int align_entry(__isl_take PART *part, void *user)
364 isl_reordering *exp;
365 S(UNION,align) *data = user;
367 exp = isl_reordering_extend_space(isl_reordering_copy(data->exp),
368 FN(PART,get_space)(part));
370 data->res = FN(FN(UNION,add),PARTS)(data->res,
371 FN(PART,realign)(part, exp));
373 return 0;
375 #endif
377 __isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u,
378 __isl_take isl_space *model)
380 S(UNION,align) data = { NULL, NULL };
382 if (!u || !model)
383 goto error;
385 if (isl_space_match(u->space, isl_dim_param, model, isl_dim_param)) {
386 isl_space_free(model);
387 return u;
390 model = isl_space_params(model);
391 data.exp = isl_parameter_alignment_reordering(u->space, model);
392 if (!data.exp)
393 goto error;
395 #ifdef HAS_TYPE
396 data.res = FN(UNION,alloc)(isl_space_copy(data.exp->dim),
397 u->type, u->table.n);
398 #else
399 data.res = FN(UNION,alloc)(isl_space_copy(data.exp->dim), u->table.n);
400 #endif
401 if (FN(FN(UNION,foreach),PARTS)(u, &align_entry, &data) < 0)
402 goto error;
404 isl_reordering_free(data.exp);
405 FN(UNION,free)(u);
406 isl_space_free(model);
407 return data.res;
408 error:
409 isl_reordering_free(data.exp);
410 FN(UNION,free)(u);
411 FN(UNION,free)(data.res);
412 isl_space_free(model);
413 return NULL;
416 /* Add "part" to *u, taking the union sum if "u" already has
417 * a part defined on the same space as "part".
419 static int union_add_part(__isl_take PART *part, void *user)
421 UNION **u = (UNION **)user;
423 *u = FN(UNION,add_part_generic)(*u, part, 0);
425 return 0;
428 /* Compute the sum of "u1" and "u2" on the union of their domains,
429 * with the actual sum on the shared domain and
430 * the defined expression on the symmetric difference of the domains.
432 * This is an internal function that is exposed under different
433 * names depending on whether the base expressions have a zero default
434 * value.
435 * If they do, then this function is called "add".
436 * Otherwise, it is called "union_add".
438 static __isl_give UNION *FN(UNION,union_add_)(__isl_take UNION *u1,
439 __isl_take UNION *u2)
441 u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
442 u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
444 u1 = FN(UNION,cow)(u1);
446 if (!u1 || !u2)
447 goto error;
449 if (FN(FN(UNION,foreach),PARTS)(u2, &union_add_part, &u1) < 0)
450 goto error;
452 FN(UNION,free)(u2);
454 return u1;
455 error:
456 FN(UNION,free)(u1);
457 FN(UNION,free)(u2);
458 return NULL;
461 __isl_give UNION *FN(FN(UNION,from),PARTS)(__isl_take PART *part)
463 isl_space *dim;
464 UNION *u;
466 if (!part)
467 return NULL;
469 dim = FN(PART,get_space)(part);
470 dim = isl_space_drop_dims(dim, isl_dim_in, 0, isl_space_dim(dim, isl_dim_in));
471 dim = isl_space_drop_dims(dim, isl_dim_out, 0, isl_space_dim(dim, isl_dim_out));
472 #ifdef HAS_TYPE
473 u = FN(UNION,ZERO)(dim, part->type);
474 #else
475 u = FN(UNION,ZERO)(dim);
476 #endif
477 u = FN(FN(UNION,add),PARTS)(u, part);
479 return u;
482 S(UNION,match_bin_data) {
483 UNION *u2;
484 UNION *res;
485 __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *);
488 /* Check if data->u2 has an element living in the same space as *entry.
489 * If so, call data->fn on the two elements and add the result to
490 * data->res.
492 static int match_bin_entry(void **entry, void *user)
494 S(UNION,match_bin_data) *data = user;
495 uint32_t hash;
496 struct isl_hash_table_entry *entry2;
497 isl_space *space;
498 PART *part = *entry;
499 PART *part2;
501 space = FN(PART,get_space)(part);
502 hash = isl_space_get_hash(space);
503 entry2 = isl_hash_table_find(data->u2->space->ctx, &data->u2->table,
504 hash, &has_same_domain_space, space, 0);
505 isl_space_free(space);
506 if (!entry2)
507 return 0;
509 part2 = entry2->data;
510 if (!isl_space_tuple_is_equal(part->dim, isl_dim_out,
511 part2->dim, isl_dim_out))
512 isl_die(FN(UNION,get_ctx)(data->u2), isl_error_invalid,
513 "entries should have the same range space",
514 return -1);
516 part = FN(PART, copy)(part);
517 part = data->fn(part, FN(PART, copy)(entry2->data));
519 data->res = FN(FN(UNION,add),PARTS)(data->res, part);
520 if (!data->res)
521 return -1;
523 return 0;
526 /* This function is currently only used from isl_polynomial.c
527 * and not from isl_fold.c.
529 static __isl_give UNION *match_bin_op(__isl_take UNION *u1,
530 __isl_take UNION *u2,
531 __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *))
532 __attribute__ ((unused));
533 /* For each pair of elements in "u1" and "u2" living in the same space,
534 * call "fn" and collect the results.
536 static __isl_give UNION *match_bin_op(__isl_take UNION *u1,
537 __isl_take UNION *u2,
538 __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *))
540 S(UNION,match_bin_data) data = { NULL, NULL, fn };
542 u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
543 u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
545 if (!u1 || !u2)
546 goto error;
548 data.u2 = u2;
549 #ifdef HAS_TYPE
550 data.res = FN(UNION,alloc)(isl_space_copy(u1->space), u1->type,
551 u1->table.n);
552 #else
553 data.res = FN(UNION,alloc)(isl_space_copy(u1->space), u1->table.n);
554 #endif
555 if (isl_hash_table_foreach(u1->space->ctx, &u1->table,
556 &match_bin_entry, &data) < 0)
557 goto error;
559 FN(UNION,free)(u1);
560 FN(UNION,free)(u2);
561 return data.res;
562 error:
563 FN(UNION,free)(u1);
564 FN(UNION,free)(u2);
565 FN(UNION,free)(data.res);
566 return NULL;
569 /* Compute the sum of "u1" and "u2".
571 * If the base expressions have a default zero value, then the sum
572 * is computed on the union of the domains of "u1" and "u2".
573 * Otherwise, it is computed on their shared domains.
575 __isl_give UNION *FN(UNION,add)(__isl_take UNION *u1, __isl_take UNION *u2)
577 #if DEFAULT_IS_ZERO
578 return FN(UNION,union_add_)(u1, u2);
579 #else
580 return match_bin_op(u1, u2, &FN(PART,add));
581 #endif
584 #ifndef NO_SUB
585 /* Subtract "u2" from "u1" and return the result.
587 __isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2)
589 return match_bin_op(u1, u2, &FN(PART,sub));
591 #endif
593 S(UNION,any_set_data) {
594 isl_set *set;
595 UNION *res;
596 __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
599 static int any_set_entry(void **entry, void *user)
601 S(UNION,any_set_data) *data = user;
602 PW *pw = *entry;
604 pw = FN(PW,copy)(pw);
605 pw = data->fn(pw, isl_set_copy(data->set));
607 data->res = FN(FN(UNION,add),PARTS)(data->res, pw);
608 if (!data->res)
609 return -1;
611 return 0;
614 /* Update each element of "u" by calling "fn" on the element and "set".
616 static __isl_give UNION *any_set_op(__isl_take UNION *u,
617 __isl_take isl_set *set,
618 __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*))
620 S(UNION,any_set_data) data = { NULL, NULL, fn };
622 u = FN(UNION,align_params)(u, isl_set_get_space(set));
623 set = isl_set_align_params(set, FN(UNION,get_space)(u));
625 if (!u || !set)
626 goto error;
628 data.set = set;
629 #ifdef HAS_TYPE
630 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type,
631 u->table.n);
632 #else
633 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n);
634 #endif
635 if (isl_hash_table_foreach(u->space->ctx, &u->table,
636 &any_set_entry, &data) < 0)
637 goto error;
639 FN(UNION,free)(u);
640 isl_set_free(set);
641 return data.res;
642 error:
643 FN(UNION,free)(u);
644 isl_set_free(set);
645 FN(UNION,free)(data.res);
646 return NULL;
649 /* Intersect the domain of "u" with the parameter domain "context".
651 __isl_give UNION *FN(UNION,intersect_params)(__isl_take UNION *u,
652 __isl_take isl_set *set)
654 return any_set_op(u, set, &FN(PW,intersect_params));
657 /* Compute the gist of the domain of "u" with respect to
658 * the parameter domain "context".
660 __isl_give UNION *FN(UNION,gist_params)(__isl_take UNION *u,
661 __isl_take isl_set *set)
663 return any_set_op(u, set, &FN(PW,gist_params));
666 S(UNION,match_domain_data) {
667 isl_union_set *uset;
668 UNION *res;
669 __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
672 static int set_has_dim(const void *entry, const void *val)
674 isl_set *set = (isl_set *)entry;
675 isl_space *dim = (isl_space *)val;
677 return isl_space_is_equal(set->dim, dim);
680 /* Find the set in data->uset that lives in the same space as the domain
681 * of *entry, apply data->fn to *entry and this set (if any), and add
682 * the result to data->res.
684 static int match_domain_entry(void **entry, void *user)
686 S(UNION,match_domain_data) *data = user;
687 uint32_t hash;
688 struct isl_hash_table_entry *entry2;
689 PW *pw = *entry;
690 isl_space *space;
692 space = FN(PW,get_domain_space)(pw);
693 hash = isl_space_get_hash(space);
694 entry2 = isl_hash_table_find(data->uset->dim->ctx, &data->uset->table,
695 hash, &set_has_dim, space, 0);
696 isl_space_free(space);
697 if (!entry2)
698 return 0;
700 pw = FN(PW,copy)(pw);
701 pw = data->fn(pw, isl_set_copy(entry2->data));
703 data->res = FN(FN(UNION,add),PARTS)(data->res, pw);
704 if (!data->res)
705 return -1;
707 return 0;
710 /* Apply fn to each pair of PW in u and set in uset such that
711 * the set lives in the same space as the domain of PW
712 * and collect the results.
714 static __isl_give UNION *match_domain_op(__isl_take UNION *u,
715 __isl_take isl_union_set *uset,
716 __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*))
718 S(UNION,match_domain_data) data = { NULL, NULL, fn };
720 u = FN(UNION,align_params)(u, isl_union_set_get_space(uset));
721 uset = isl_union_set_align_params(uset, FN(UNION,get_space)(u));
723 if (!u || !uset)
724 goto error;
726 data.uset = uset;
727 #ifdef HAS_TYPE
728 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type,
729 u->table.n);
730 #else
731 data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n);
732 #endif
733 if (isl_hash_table_foreach(u->space->ctx, &u->table,
734 &match_domain_entry, &data) < 0)
735 goto error;
737 FN(UNION,free)(u);
738 isl_union_set_free(uset);
739 return data.res;
740 error:
741 FN(UNION,free)(u);
742 isl_union_set_free(uset);
743 FN(UNION,free)(data.res);
744 return NULL;
747 /* Intersect the domain of "u" with "uset".
748 * If "uset" is a parameters domain, then intersect the parameter
749 * domain of "u" with this set.
751 __isl_give UNION *FN(UNION,intersect_domain)(__isl_take UNION *u,
752 __isl_take isl_union_set *uset)
754 if (isl_union_set_is_params(uset))
755 return FN(UNION,intersect_params)(u,
756 isl_set_from_union_set(uset));
757 return match_domain_op(u, uset, &FN(PW,intersect_domain));
760 __isl_give UNION *FN(UNION,gist)(__isl_take UNION *u,
761 __isl_take isl_union_set *uset)
763 if (isl_union_set_is_params(uset))
764 return FN(UNION,gist_params)(u, isl_set_from_union_set(uset));
765 return match_domain_op(u, uset, &FN(PW,gist));
768 #ifndef NO_EVAL
769 __isl_give isl_val *FN(UNION,eval)(__isl_take UNION *u,
770 __isl_take isl_point *pnt)
772 uint32_t hash;
773 struct isl_hash_table_entry *entry;
774 isl_space *space;
775 isl_val *v;
777 if (!u || !pnt)
778 goto error;
780 space = isl_space_copy(pnt->dim);
781 if (!space)
782 goto error;
783 hash = isl_space_get_hash(space);
784 entry = isl_hash_table_find(u->space->ctx, &u->table,
785 hash, &has_domain_space, space, 0);
786 isl_space_free(space);
787 if (!entry) {
788 v = isl_val_zero(isl_point_get_ctx(pnt));
789 isl_point_free(pnt);
790 } else {
791 v = FN(PART,eval)(FN(PART,copy)(entry->data), pnt);
793 FN(UNION,free)(u);
794 return v;
795 error:
796 FN(UNION,free)(u);
797 isl_point_free(pnt);
798 return NULL;
800 #endif
802 static int coalesce_entry(void **entry, void *user)
804 PW **pw = (PW **)entry;
806 *pw = FN(PW,coalesce)(*pw);
807 if (!*pw)
808 return -1;
810 return 0;
813 __isl_give UNION *FN(UNION,coalesce)(__isl_take UNION *u)
815 if (!u)
816 return NULL;
818 if (isl_hash_table_foreach(u->space->ctx, &u->table,
819 &coalesce_entry, NULL) < 0)
820 goto error;
822 return u;
823 error:
824 FN(UNION,free)(u);
825 return NULL;
828 static int domain(__isl_take PART *part, void *user)
830 isl_union_set **uset = (isl_union_set **)user;
832 *uset = isl_union_set_add_set(*uset, FN(PART,domain)(part));
834 return 0;
837 __isl_give isl_union_set *FN(UNION,domain)(__isl_take UNION *u)
839 isl_union_set *uset;
841 uset = isl_union_set_empty(FN(UNION,get_space)(u));
842 if (FN(FN(UNION,foreach),PARTS)(u, &domain, &uset) < 0)
843 goto error;
845 FN(UNION,free)(u);
847 return uset;
848 error:
849 isl_union_set_free(uset);
850 FN(UNION,free)(u);
851 return NULL;
854 static int mul_isl_int(void **entry, void *user)
856 PW **pw = (PW **)entry;
857 isl_int *v = user;
859 *pw = FN(PW,mul_isl_int)(*pw, *v);
860 if (!*pw)
861 return -1;
863 return 0;
866 __isl_give UNION *FN(UNION,mul_isl_int)(__isl_take UNION *u, isl_int v)
868 if (isl_int_is_one(v))
869 return u;
871 if (DEFAULT_IS_ZERO && u && isl_int_is_zero(v)) {
872 UNION *zero;
873 isl_space *dim = FN(UNION,get_space)(u);
874 #ifdef HAS_TYPE
875 zero = FN(UNION,ZERO)(dim, u->type);
876 #else
877 zero = FN(UNION,ZERO)(dim);
878 #endif
879 FN(UNION,free)(u);
880 return zero;
883 u = FN(UNION,cow)(u);
884 if (!u)
885 return NULL;
887 #ifdef HAS_TYPE
888 if (isl_int_is_neg(v))
889 u->type = isl_fold_type_negate(u->type);
890 #endif
891 if (isl_hash_table_foreach(u->space->ctx, &u->table,
892 &mul_isl_int, &v) < 0)
893 goto error;
895 return u;
896 error:
897 FN(UNION,free)(u);
898 return NULL;
901 /* Multiply *entry by the isl_val "user".
903 * Return 0 on success and -1 on error.
905 static int scale_val(void **entry, void *user)
907 PW **pw = (PW **)entry;
908 isl_val *v = user;
910 *pw = FN(PW,scale_val)(*pw, isl_val_copy(v));
911 if (!*pw)
912 return -1;
914 return 0;
917 /* Multiply "u" by "v" and return the result.
919 __isl_give UNION *FN(UNION,scale_val)(__isl_take UNION *u,
920 __isl_take isl_val *v)
922 if (!u || !v)
923 goto error;
924 if (isl_val_is_one(v)) {
925 isl_val_free(v);
926 return u;
929 if (DEFAULT_IS_ZERO && u && isl_val_is_zero(v)) {
930 UNION *zero;
931 isl_space *space = FN(UNION,get_space)(u);
932 #ifdef HAS_TYPE
933 zero = FN(UNION,ZERO)(space, u->type);
934 #else
935 zero = FN(UNION,ZERO)(space);
936 #endif
937 FN(UNION,free)(u);
938 isl_val_free(v);
939 return zero;
942 if (!isl_val_is_rat(v))
943 isl_die(isl_val_get_ctx(v), isl_error_invalid,
944 "expecting rational factor", goto error);
946 u = FN(UNION,cow)(u);
947 if (!u)
948 return NULL;
950 #ifdef HAS_TYPE
951 if (isl_val_is_neg(v))
952 u->type = isl_fold_type_negate(u->type);
953 #endif
954 if (isl_hash_table_foreach(u->space->ctx, &u->table, &scale_val, v) < 0)
955 goto error;
957 isl_val_free(v);
958 return u;
959 error:
960 isl_val_free(v);
961 FN(UNION,free)(u);
962 return NULL;
965 S(UNION,plain_is_equal_data)
967 UNION *u2;
968 int is_equal;
971 static int plain_is_equal_entry(void **entry, void *user)
973 S(UNION,plain_is_equal_data) *data = user;
974 uint32_t hash;
975 struct isl_hash_table_entry *entry2;
976 PW *pw = *entry;
978 hash = isl_space_get_hash(pw->dim);
979 entry2 = isl_hash_table_find(data->u2->space->ctx, &data->u2->table,
980 hash, &has_same_domain_space, pw->dim, 0);
981 if (!entry2) {
982 data->is_equal = 0;
983 return -1;
986 data->is_equal = FN(PW,plain_is_equal)(pw, entry2->data);
987 if (data->is_equal < 0 || !data->is_equal)
988 return -1;
990 return 0;
993 int FN(UNION,plain_is_equal)(__isl_keep UNION *u1, __isl_keep UNION *u2)
995 S(UNION,plain_is_equal_data) data = { NULL, 1 };
997 if (!u1 || !u2)
998 return -1;
999 if (u1 == u2)
1000 return 1;
1001 if (u1->table.n != u2->table.n)
1002 return 0;
1004 u1 = FN(UNION,copy)(u1);
1005 u2 = FN(UNION,copy)(u2);
1006 u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
1007 u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
1008 if (!u1 || !u2)
1009 goto error;
1011 data.u2 = u2;
1012 if (isl_hash_table_foreach(u1->space->ctx, &u1->table,
1013 &plain_is_equal_entry, &data) < 0 &&
1014 data.is_equal)
1015 goto error;
1017 FN(UNION,free)(u1);
1018 FN(UNION,free)(u2);
1020 return data.is_equal;
1021 error:
1022 FN(UNION,free)(u1);
1023 FN(UNION,free)(u2);
1024 return -1;