Line data Source code
1 : /*
2 : * Copyright 2010 INRIA Saclay
3 : * Copyright 2013 Ecole Normale Superieure
4 : *
5 : * Use of this software is governed by the MIT license
6 : *
7 : * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
8 : * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
9 : * 91893 Orsay, France
10 : * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
11 : */
12 :
13 : #undef TYPE
14 : #define TYPE UNION
15 : static
16 : #include "has_single_reference_templ.c"
17 :
18 : __isl_give UNION *FN(UNION,cow)(__isl_take UNION *u);
19 :
20 0 : isl_ctx *FN(UNION,get_ctx)(__isl_keep UNION *u)
21 : {
22 0 : return u ? u->space->ctx : NULL;
23 : }
24 :
25 : /* Return the space of "u".
26 : */
27 0 : static __isl_keep isl_space *FN(UNION,peek_space)(__isl_keep UNION *u)
28 : {
29 0 : if (!u)
30 0 : return NULL;
31 0 : return u->space;
32 : }
33 :
34 : /* Return a copy of the space of "u".
35 : */
36 0 : __isl_give isl_space *FN(UNION,get_space)(__isl_keep UNION *u)
37 : {
38 0 : return isl_space_copy(FN(UNION,peek_space)(u));
39 : }
40 :
41 : /* Return the number of parameters of "u", where "type"
42 : * is required to be set to isl_dim_param.
43 : */
44 0 : unsigned FN(UNION,dim)(__isl_keep UNION *u, enum isl_dim_type type)
45 : {
46 0 : if (!u)
47 0 : return 0;
48 :
49 0 : if (type != isl_dim_param)
50 0 : isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
51 : "can only reference parameters", return 0);
52 :
53 0 : return isl_space_dim(u->space, type);
54 : }
55 :
56 : /* Return the position of the parameter with the given name
57 : * in "u".
58 : * Return -1 if no such dimension can be found.
59 : */
60 0 : int FN(UNION,find_dim_by_name)(__isl_keep UNION *u, enum isl_dim_type type,
61 : const char *name)
62 : {
63 0 : if (!u)
64 0 : return -1;
65 0 : return isl_space_find_dim_by_name(u->space, type, name);
66 : }
67 :
68 : #ifdef HAS_TYPE
69 0 : static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim,
70 : enum isl_fold type, int size)
71 : #else
72 0 : static __isl_give UNION *FN(UNION,alloc)(__isl_take isl_space *dim, int size)
73 : #endif
74 : {
75 : UNION *u;
76 :
77 0 : dim = isl_space_params(dim);
78 0 : if (!dim)
79 0 : return NULL;
80 :
81 0 : u = isl_calloc_type(dim->ctx, UNION);
82 0 : if (!u)
83 0 : goto error;
84 :
85 0 : u->ref = 1;
86 : #ifdef HAS_TYPE
87 0 : u->type = type;
88 : #endif
89 0 : u->space = dim;
90 0 : if (isl_hash_table_init(dim->ctx, &u->table, size) < 0)
91 0 : return FN(UNION,free)(u);
92 :
93 0 : return u;
94 : error:
95 0 : isl_space_free(dim);
96 0 : return NULL;
97 : }
98 :
99 : #ifdef HAS_TYPE
100 0 : __isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
101 : {
102 0 : return FN(UNION,alloc)(dim, type, 16);
103 : }
104 : #else
105 0 : __isl_give UNION *FN(UNION,ZERO)(__isl_take isl_space *dim)
106 : {
107 0 : return FN(UNION,alloc)(dim, 16);
108 : }
109 : #endif
110 :
111 0 : __isl_give UNION *FN(UNION,copy)(__isl_keep UNION *u)
112 : {
113 0 : if (!u)
114 0 : return NULL;
115 :
116 0 : u->ref++;
117 0 : return u;
118 : }
119 :
120 : /* Extract the element of "u" living in "space" (ignoring parameters).
121 : *
122 : * Return the ZERO element if "u" does not contain any element
123 : * living in "space".
124 : */
125 0 : __isl_give PART *FN(FN(UNION,extract),BASE)(__isl_keep UNION *u,
126 : __isl_take isl_space *space)
127 : {
128 : struct isl_hash_table_entry *entry;
129 :
130 0 : space = isl_space_replace_params(space, FN(UNION,peek_space)(u));
131 :
132 0 : entry = FN(UNION,find_part_entry)(u, space, 0);
133 0 : if (!entry)
134 0 : goto error;
135 0 : if (entry == isl_hash_table_entry_none)
136 : #ifdef HAS_TYPE
137 0 : return FN(PART,ZERO)(space, u->type);
138 : #else
139 0 : return FN(PART,ZERO)(space);
140 : #endif
141 0 : isl_space_free(space);
142 0 : return FN(PART,copy)(entry->data);
143 : error:
144 0 : isl_space_free(space);
145 0 : return NULL;
146 : }
147 :
148 : /* Add "part" to "u".
149 : * If "disjoint" is set, then "u" is not allowed to already have
150 : * a part that is defined over a domain that overlaps with the domain
151 : * of "part".
152 : * Otherwise, compute the union sum of "part" and the part in "u"
153 : * defined on the same space.
154 : */
155 0 : static __isl_give UNION *FN(UNION,add_part_generic)(__isl_take UNION *u,
156 : __isl_take PART *part, int disjoint)
157 : {
158 : int empty;
159 : struct isl_hash_table_entry *entry;
160 :
161 0 : if (!part)
162 0 : goto error;
163 :
164 0 : empty = FN(PART,IS_ZERO)(part);
165 0 : if (empty < 0)
166 0 : goto error;
167 0 : if (empty) {
168 0 : FN(PART,free)(part);
169 0 : return u;
170 : }
171 :
172 0 : u = FN(UNION,align_params)(u, FN(PART,get_space)(part));
173 0 : part = FN(PART,align_params)(part, FN(UNION,get_space)(u));
174 :
175 0 : u = FN(UNION,cow)(u);
176 :
177 0 : if (!u)
178 0 : goto error;
179 :
180 0 : if (FN(UNION,check_disjoint_domain_other)(u, part) < 0)
181 0 : goto error;
182 0 : entry = FN(UNION,find_part_entry)(u, part->dim, 1);
183 0 : if (!entry)
184 0 : goto error;
185 :
186 0 : if (!entry->data)
187 0 : entry->data = part;
188 : else {
189 0 : if (disjoint &&
190 0 : FN(UNION,check_disjoint_domain)(entry->data, part) < 0)
191 0 : goto error;
192 0 : entry->data = FN(PART,union_add_)(entry->data,
193 : FN(PART,copy)(part));
194 0 : if (!entry->data)
195 0 : goto error;
196 0 : empty = FN(PART,IS_ZERO)(part);
197 0 : if (empty < 0)
198 0 : goto error;
199 0 : if (empty)
200 0 : u = FN(UNION,remove_part_entry)(u, entry);
201 0 : FN(PART,free)(part);
202 : }
203 :
204 0 : return u;
205 : error:
206 0 : FN(PART,free)(part);
207 0 : FN(UNION,free)(u);
208 0 : return NULL;
209 : }
210 :
211 : /* Add "part" to "u", where "u" is assumed not to already have
212 : * a part that is defined on the same space as "part".
213 : */
214 0 : __isl_give UNION *FN(FN(UNION,add),BASE)(__isl_take UNION *u,
215 : __isl_take PART *part)
216 : {
217 0 : return FN(UNION,add_part_generic)(u, part, 1);
218 : }
219 :
220 : #ifdef HAS_TYPE
221 : /* Allocate a UNION with the same type and the same size as "u" and
222 : * with space "space".
223 : */
224 0 : static __isl_give UNION *FN(UNION,alloc_same_size_on_space)(__isl_keep UNION *u,
225 : __isl_take isl_space *space)
226 : {
227 0 : if (!u)
228 0 : goto error;
229 0 : return FN(UNION,alloc)(space, u->type, u->table.n);
230 : error:
231 0 : isl_space_free(space);
232 0 : return NULL;
233 : }
234 : #else
235 : /* Allocate a UNION with the same size as "u" and with space "space".
236 : */
237 0 : static __isl_give UNION *FN(UNION,alloc_same_size_on_space)(__isl_keep UNION *u,
238 : __isl_take isl_space *space)
239 : {
240 0 : if (!u)
241 0 : goto error;
242 0 : return FN(UNION,alloc)(space, u->table.n);
243 : error:
244 0 : isl_space_free(space);
245 0 : return NULL;
246 : }
247 : #endif
248 :
249 : /* Allocate a UNION with the same space, the same type (if any) and
250 : * the same size as "u".
251 : */
252 0 : static __isl_give UNION *FN(UNION,alloc_same_size)(__isl_keep UNION *u)
253 : {
254 0 : return FN(UNION,alloc_same_size_on_space)(u, FN(UNION,get_space)(u));
255 : }
256 :
257 : /* Internal data structure for isl_union_*_transform_space.
258 : * "fn' is applied to each entry in the input.
259 : * "res" collects the results.
260 : */
261 : S(UNION,transform_data)
262 : {
263 : __isl_give PART *(*fn)(__isl_take PART *part, void *user);
264 : void *user;
265 :
266 : UNION *res;
267 : };
268 :
269 : /* Apply data->fn to "part" and add the result to data->res.
270 : */
271 0 : static isl_stat FN(UNION,transform_entry)(__isl_take PART *part, void *user)
272 : {
273 0 : S(UNION,transform_data) *data = (S(UNION,transform_data) *)user;
274 :
275 0 : part = data->fn(part, data->user);
276 0 : data->res = FN(FN(UNION,add),BASE)(data->res, part);
277 0 : if (!data->res)
278 0 : return isl_stat_error;
279 :
280 0 : return isl_stat_ok;
281 : }
282 :
283 : /* Return a UNION living in "space" that is obtained by applying "fn"
284 : * to each of the entries in "u".
285 : */
286 0 : static __isl_give UNION *FN(UNION,transform_space)(__isl_take UNION *u,
287 : isl_space *space,
288 : __isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user)
289 : {
290 0 : S(UNION,transform_data) data = { fn, user };
291 :
292 0 : data.res = FN(UNION,alloc_same_size_on_space)(u, space);
293 0 : if (FN(FN(UNION,foreach),BASE)(u,
294 : &FN(UNION,transform_entry), &data) < 0)
295 0 : data.res = FN(UNION,free)(data.res);
296 0 : FN(UNION,free)(u);
297 0 : return data.res;
298 : }
299 :
300 : /* Return a UNION that lives in the same space as "u" and that is obtained
301 : * by applying "fn" to each of the entries in "u".
302 : */
303 0 : static __isl_give UNION *FN(UNION,transform)(__isl_take UNION *u,
304 : __isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user)
305 : {
306 0 : return FN(UNION,transform_space)(u, FN(UNION,get_space)(u), fn, user);
307 : }
308 :
309 : /* Apply data->fn to *part and store the result back into *part.
310 : */
311 0 : static isl_stat FN(UNION,transform_inplace_entry)(void **part, void *user)
312 : {
313 0 : S(UNION,transform_data) *data = (S(UNION,transform_data) *) user;
314 :
315 0 : *part = data->fn(*part, data->user);
316 0 : if (!*part)
317 0 : return isl_stat_error;
318 0 : return isl_stat_ok;
319 : }
320 :
321 : /* Update "u" by applying "fn" to each entry.
322 : * This operation is assumed not to change the number of entries nor
323 : * the spaces of the entries.
324 : *
325 : * If there is only one reference to "u", then change "u" inplace.
326 : * Otherwise, create a new UNION from "u" and discard the original.
327 : */
328 0 : static __isl_give UNION *FN(UNION,transform_inplace)(__isl_take UNION *u,
329 : __isl_give PART *(*fn)(__isl_take PART *part, void *user), void *user)
330 : {
331 : isl_bool single_ref;
332 :
333 0 : single_ref = FN(UNION,has_single_reference)(u);
334 0 : if (single_ref < 0)
335 0 : return FN(UNION,free)(u);
336 0 : if (single_ref) {
337 0 : S(UNION,transform_data) data = { fn, user };
338 0 : if (FN(UNION,foreach_inplace)(u,
339 : &FN(UNION,transform_inplace_entry), &data) < 0)
340 0 : return FN(UNION,free)(u);
341 0 : return u;
342 : }
343 0 : return FN(UNION,transform)(u, fn, user);
344 : }
345 :
346 : /* An isl_union_*_transform callback for use in isl_union_*_dup
347 : * that simply returns "part".
348 : */
349 0 : static __isl_give PART *FN(UNION,copy_part)(__isl_take PART *part, void *user)
350 : {
351 0 : return part;
352 : }
353 :
354 0 : __isl_give UNION *FN(UNION,dup)(__isl_keep UNION *u)
355 : {
356 0 : u = FN(UNION,copy)(u);
357 0 : return FN(UNION,transform)(u, &FN(UNION,copy_part), NULL);
358 : }
359 :
360 0 : __isl_give UNION *FN(UNION,cow)(__isl_take UNION *u)
361 : {
362 0 : if (!u)
363 0 : return NULL;
364 :
365 0 : if (u->ref == 1)
366 0 : return u;
367 0 : u->ref--;
368 0 : return FN(UNION,dup)(u);
369 : }
370 :
371 0 : __isl_null UNION *FN(UNION,free)(__isl_take UNION *u)
372 : {
373 0 : if (!u)
374 0 : return NULL;
375 :
376 0 : if (--u->ref > 0)
377 0 : return NULL;
378 :
379 0 : isl_hash_table_foreach(u->space->ctx, &u->table,
380 : &FN(UNION,free_u_entry), NULL);
381 0 : isl_hash_table_clear(&u->table);
382 0 : isl_space_free(u->space);
383 0 : free(u);
384 0 : return NULL;
385 : }
386 :
387 0 : static __isl_give PART *FN(UNION,align_entry)(__isl_take PART *part, void *user)
388 : {
389 0 : isl_reordering *exp = user;
390 :
391 0 : exp = isl_reordering_extend_space(isl_reordering_copy(exp),
392 : FN(PART,get_domain_space)(part));
393 0 : return FN(PART,realign_domain)(part, exp);
394 : }
395 :
396 : /* Reorder the parameters of "u" according to the given reordering.
397 : */
398 0 : static __isl_give UNION *FN(UNION,realign_domain)(__isl_take UNION *u,
399 : __isl_take isl_reordering *r)
400 : {
401 : isl_space *space;
402 :
403 0 : if (!u || !r)
404 : goto error;
405 :
406 0 : space = isl_reordering_get_space(r);
407 0 : u = FN(UNION,transform_space)(u, space, &FN(UNION,align_entry), r);
408 0 : isl_reordering_free(r);
409 0 : return u;
410 : error:
411 0 : FN(UNION,free)(u);
412 0 : isl_reordering_free(r);
413 0 : return NULL;
414 : }
415 :
416 : /* Align the parameters of "u" to those of "model".
417 : */
418 0 : __isl_give UNION *FN(UNION,align_params)(__isl_take UNION *u,
419 : __isl_take isl_space *model)
420 : {
421 : isl_bool equal_params;
422 : isl_reordering *r;
423 :
424 0 : if (!u || !model)
425 : goto error;
426 :
427 0 : equal_params = isl_space_has_equal_params(u->space, model);
428 0 : if (equal_params < 0)
429 0 : goto error;
430 0 : if (equal_params) {
431 0 : isl_space_free(model);
432 0 : return u;
433 : }
434 :
435 0 : r = isl_parameter_alignment_reordering(u->space, model);
436 0 : isl_space_free(model);
437 :
438 0 : return FN(UNION,realign_domain)(u, r);
439 : error:
440 0 : isl_space_free(model);
441 0 : FN(UNION,free)(u);
442 0 : return NULL;
443 : }
444 :
445 : /* Add "part" to *u, taking the union sum if "u" already has
446 : * a part defined on the same space as "part".
447 : */
448 0 : static isl_stat FN(UNION,union_add_part)(__isl_take PART *part, void *user)
449 : {
450 0 : UNION **u = (UNION **)user;
451 :
452 0 : *u = FN(UNION,add_part_generic)(*u, part, 0);
453 :
454 0 : return isl_stat_ok;
455 : }
456 :
457 : /* Compute the sum of "u1" and "u2" on the union of their domains,
458 : * with the actual sum on the shared domain and
459 : * the defined expression on the symmetric difference of the domains.
460 : *
461 : * This is an internal function that is exposed under different
462 : * names depending on whether the base expressions have a zero default
463 : * value.
464 : * If they do, then this function is called "add".
465 : * Otherwise, it is called "union_add".
466 : */
467 0 : static __isl_give UNION *FN(UNION,union_add_)(__isl_take UNION *u1,
468 : __isl_take UNION *u2)
469 : {
470 0 : u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
471 0 : u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
472 :
473 0 : u1 = FN(UNION,cow)(u1);
474 :
475 0 : if (!u1 || !u2)
476 : goto error;
477 :
478 0 : if (FN(FN(UNION,foreach),BASE)(u2, &FN(UNION,union_add_part), &u1) < 0)
479 0 : goto error;
480 :
481 0 : FN(UNION,free)(u2);
482 :
483 0 : return u1;
484 : error:
485 0 : FN(UNION,free)(u1);
486 0 : FN(UNION,free)(u2);
487 0 : return NULL;
488 : }
489 :
490 0 : __isl_give UNION *FN(FN(UNION,from),BASE)(__isl_take PART *part)
491 : {
492 : isl_space *dim;
493 : UNION *u;
494 :
495 0 : if (!part)
496 0 : return NULL;
497 :
498 0 : dim = FN(PART,get_space)(part);
499 0 : dim = isl_space_drop_dims(dim, isl_dim_in, 0, isl_space_dim(dim, isl_dim_in));
500 0 : dim = isl_space_drop_dims(dim, isl_dim_out, 0, isl_space_dim(dim, isl_dim_out));
501 : #ifdef HAS_TYPE
502 0 : u = FN(UNION,ZERO)(dim, part->type);
503 : #else
504 0 : u = FN(UNION,ZERO)(dim);
505 : #endif
506 0 : u = FN(FN(UNION,add),BASE)(u, part);
507 :
508 0 : return u;
509 : }
510 :
511 : S(UNION,match_bin_data) {
512 : UNION *u2;
513 : UNION *res;
514 : __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *);
515 : };
516 :
517 : /* Check if data->u2 has an element living in the same space as "part".
518 : * If so, call data->fn on the two elements and add the result to
519 : * data->res.
520 : */
521 0 : static isl_stat FN(UNION,match_bin_entry)(__isl_take PART *part, void *user)
522 : {
523 0 : S(UNION,match_bin_data) *data = user;
524 : struct isl_hash_table_entry *entry2;
525 : isl_space *space;
526 : PART *part2;
527 :
528 0 : space = FN(PART,get_space)(part);
529 0 : entry2 = FN(UNION,find_part_entry)(data->u2, space, 0);
530 0 : isl_space_free(space);
531 0 : if (!entry2)
532 0 : goto error;
533 0 : if (entry2 == isl_hash_table_entry_none) {
534 0 : FN(PART,free)(part);
535 0 : return isl_stat_ok;
536 : }
537 :
538 0 : part2 = entry2->data;
539 0 : if (!isl_space_tuple_is_equal(part->dim, isl_dim_out,
540 : part2->dim, isl_dim_out))
541 0 : isl_die(FN(UNION,get_ctx)(data->u2), isl_error_invalid,
542 : "entries should have the same range space",
543 : goto error);
544 :
545 0 : part = data->fn(part, FN(PART, copy)(entry2->data));
546 :
547 0 : data->res = FN(FN(UNION,add),BASE)(data->res, part);
548 0 : if (!data->res)
549 0 : return isl_stat_error;
550 :
551 0 : return isl_stat_ok;
552 : error:
553 0 : FN(PART,free)(part);
554 0 : return isl_stat_error;
555 : }
556 :
557 : /* This function is currently only used from isl_polynomial.c
558 : * and not from isl_fold.c.
559 : */
560 : static __isl_give UNION *FN(UNION,match_bin_op)(__isl_take UNION *u1,
561 : __isl_take UNION *u2,
562 : __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *))
563 : __attribute__ ((unused));
564 : /* For each pair of elements in "u1" and "u2" living in the same space,
565 : * call "fn" and collect the results.
566 : */
567 0 : static __isl_give UNION *FN(UNION,match_bin_op)(__isl_take UNION *u1,
568 : __isl_take UNION *u2,
569 : __isl_give PART *(*fn)(__isl_take PART *, __isl_take PART *))
570 : {
571 0 : S(UNION,match_bin_data) data = { NULL, NULL, fn };
572 :
573 0 : u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
574 0 : u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
575 :
576 0 : if (!u1 || !u2)
577 : goto error;
578 :
579 0 : data.u2 = u2;
580 0 : data.res = FN(UNION,alloc_same_size)(u1);
581 0 : if (FN(FN(UNION,foreach),BASE)(u1,
582 : &FN(UNION,match_bin_entry), &data) < 0)
583 0 : goto error;
584 :
585 0 : FN(UNION,free)(u1);
586 0 : FN(UNION,free)(u2);
587 0 : return data.res;
588 : error:
589 0 : FN(UNION,free)(u1);
590 0 : FN(UNION,free)(u2);
591 0 : FN(UNION,free)(data.res);
592 0 : return NULL;
593 : }
594 :
595 : /* Compute the sum of "u1" and "u2".
596 : *
597 : * If the base expressions have a default zero value, then the sum
598 : * is computed on the union of the domains of "u1" and "u2".
599 : * Otherwise, it is computed on their shared domains.
600 : */
601 0 : __isl_give UNION *FN(UNION,add)(__isl_take UNION *u1, __isl_take UNION *u2)
602 : {
603 : #if DEFAULT_IS_ZERO
604 0 : return FN(UNION,union_add_)(u1, u2);
605 : #else
606 0 : return FN(UNION,match_bin_op)(u1, u2, &FN(PART,add));
607 : #endif
608 : }
609 :
610 : #ifndef NO_SUB
611 : /* Subtract "u2" from "u1" and return the result.
612 : */
613 0 : __isl_give UNION *FN(UNION,sub)(__isl_take UNION *u1, __isl_take UNION *u2)
614 : {
615 0 : return FN(UNION,match_bin_op)(u1, u2, &FN(PART,sub));
616 : }
617 : #endif
618 :
619 : S(UNION,any_set_data) {
620 : isl_set *set;
621 : __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
622 : };
623 :
624 0 : static __isl_give PART *FN(UNION,any_set_entry)(__isl_take PART *part,
625 : void *user)
626 : {
627 0 : S(UNION,any_set_data) *data = user;
628 :
629 0 : return data->fn(part, isl_set_copy(data->set));
630 : }
631 :
632 : /* Update each element of "u" by calling "fn" on the element and "set".
633 : */
634 0 : static __isl_give UNION *FN(UNION,any_set_op)(__isl_take UNION *u,
635 : __isl_take isl_set *set,
636 : __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*))
637 : {
638 0 : S(UNION,any_set_data) data = { NULL, fn };
639 :
640 0 : u = FN(UNION,align_params)(u, isl_set_get_space(set));
641 0 : set = isl_set_align_params(set, FN(UNION,get_space)(u));
642 :
643 0 : if (!u || !set)
644 : goto error;
645 :
646 0 : data.set = set;
647 0 : u = FN(UNION,transform)(u, &FN(UNION,any_set_entry), &data);
648 0 : isl_set_free(set);
649 0 : return u;
650 : error:
651 0 : FN(UNION,free)(u);
652 0 : isl_set_free(set);
653 0 : return NULL;
654 : }
655 :
656 : /* Intersect the domain of "u" with the parameter domain "context".
657 : */
658 0 : __isl_give UNION *FN(UNION,intersect_params)(__isl_take UNION *u,
659 : __isl_take isl_set *set)
660 : {
661 0 : return FN(UNION,any_set_op)(u, set, &FN(PW,intersect_params));
662 : }
663 :
664 : /* Compute the gist of the domain of "u" with respect to
665 : * the parameter domain "context".
666 : */
667 0 : __isl_give UNION *FN(UNION,gist_params)(__isl_take UNION *u,
668 : __isl_take isl_set *set)
669 : {
670 0 : return FN(UNION,any_set_op)(u, set, &FN(PW,gist_params));
671 : }
672 :
673 : S(UNION,match_domain_data) {
674 : isl_union_set *uset;
675 : UNION *res;
676 : __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
677 : };
678 :
679 0 : static int FN(UNION,set_has_dim)(const void *entry, const void *val)
680 : {
681 0 : isl_set *set = (isl_set *)entry;
682 0 : isl_space *dim = (isl_space *)val;
683 :
684 0 : return isl_space_is_equal(set->dim, dim);
685 : }
686 :
687 : /* Find the set in data->uset that lives in the same space as the domain
688 : * of "part", apply data->fn to *entry and this set (if any), and add
689 : * the result to data->res.
690 : */
691 0 : static isl_stat FN(UNION,match_domain_entry)(__isl_take PART *part, void *user)
692 : {
693 0 : S(UNION,match_domain_data) *data = user;
694 : uint32_t hash;
695 : struct isl_hash_table_entry *entry2;
696 : isl_space *space;
697 :
698 0 : space = FN(PART,get_domain_space)(part);
699 0 : hash = isl_space_get_hash(space);
700 0 : entry2 = isl_hash_table_find(data->uset->dim->ctx, &data->uset->table,
701 : hash, &FN(UNION,set_has_dim), space, 0);
702 0 : isl_space_free(space);
703 0 : if (!entry2) {
704 0 : FN(PART,free)(part);
705 0 : return isl_stat_ok;
706 : }
707 :
708 0 : part = data->fn(part, isl_set_copy(entry2->data));
709 :
710 0 : data->res = FN(FN(UNION,add),BASE)(data->res, part);
711 0 : if (!data->res)
712 0 : return isl_stat_error;
713 :
714 0 : return isl_stat_ok;
715 : }
716 :
717 : /* Apply fn to each pair of PW in u and set in uset such that
718 : * the set lives in the same space as the domain of PW
719 : * and collect the results.
720 : */
721 0 : static __isl_give UNION *FN(UNION,match_domain_op)(__isl_take UNION *u,
722 : __isl_take isl_union_set *uset,
723 : __isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*))
724 : {
725 0 : S(UNION,match_domain_data) data = { NULL, NULL, fn };
726 :
727 0 : u = FN(UNION,align_params)(u, isl_union_set_get_space(uset));
728 0 : uset = isl_union_set_align_params(uset, FN(UNION,get_space)(u));
729 :
730 0 : if (!u || !uset)
731 : goto error;
732 :
733 0 : data.uset = uset;
734 0 : data.res = FN(UNION,alloc_same_size)(u);
735 0 : if (FN(FN(UNION,foreach),BASE)(u,
736 : &FN(UNION,match_domain_entry), &data) < 0)
737 0 : goto error;
738 :
739 0 : FN(UNION,free)(u);
740 0 : isl_union_set_free(uset);
741 0 : return data.res;
742 : error:
743 0 : FN(UNION,free)(u);
744 0 : isl_union_set_free(uset);
745 0 : FN(UNION,free)(data.res);
746 0 : return NULL;
747 : }
748 :
749 : /* Intersect the domain of "u" with "uset".
750 : * If "uset" is a parameters domain, then intersect the parameter
751 : * domain of "u" with this set.
752 : */
753 0 : __isl_give UNION *FN(UNION,intersect_domain)(__isl_take UNION *u,
754 : __isl_take isl_union_set *uset)
755 : {
756 0 : if (isl_union_set_is_params(uset))
757 0 : return FN(UNION,intersect_params)(u,
758 : isl_set_from_union_set(uset));
759 0 : return FN(UNION,match_domain_op)(u, uset, &FN(PW,intersect_domain));
760 : }
761 :
762 : /* Take the set (which may be empty) in data->uset that lives
763 : * in the same space as the domain of "pw", subtract it from the domain
764 : * of "part" and return the result.
765 : */
766 0 : static __isl_give PART *FN(UNION,subtract_domain_entry)(__isl_take PART *part,
767 : void *user)
768 : {
769 0 : isl_union_set *uset = user;
770 : isl_space *space;
771 : isl_set *set;
772 :
773 0 : space = FN(PART,get_domain_space)(part);
774 0 : set = isl_union_set_extract_set(uset, space);
775 0 : return FN(PART,subtract_domain)(part, set);
776 : }
777 :
778 : /* Subtract "uset' from the domain of "u".
779 : */
780 0 : __isl_give UNION *FN(UNION,subtract_domain)(__isl_take UNION *u,
781 : __isl_take isl_union_set *uset)
782 : {
783 0 : u = FN(UNION,transform)(u, &FN(UNION,subtract_domain_entry), uset);
784 0 : isl_union_set_free(uset);
785 0 : return u;
786 : }
787 :
788 0 : __isl_give UNION *FN(UNION,gist)(__isl_take UNION *u,
789 : __isl_take isl_union_set *uset)
790 : {
791 0 : if (isl_union_set_is_params(uset))
792 0 : return FN(UNION,gist_params)(u, isl_set_from_union_set(uset));
793 0 : return FN(UNION,match_domain_op)(u, uset, &FN(PW,gist));
794 : }
795 :
796 : /* Coalesce an entry in a UNION. Coalescing is performed in-place.
797 : * Since the UNION may have several references, the entry is only
798 : * replaced if the coalescing is successful.
799 : */
800 0 : static isl_stat FN(UNION,coalesce_entry)(void **entry, void *user)
801 : {
802 0 : PART **part_p = (PART **) entry;
803 : PART *part;
804 :
805 0 : part = FN(PART,copy)(*part_p);
806 0 : part = FN(PW,coalesce)(part);
807 0 : if (!part)
808 0 : return isl_stat_error;
809 0 : FN(PART,free)(*part_p);
810 0 : *part_p = part;
811 :
812 0 : return isl_stat_ok;
813 : }
814 :
815 0 : __isl_give UNION *FN(UNION,coalesce)(__isl_take UNION *u)
816 : {
817 0 : if (FN(UNION,foreach_inplace)(u, &FN(UNION,coalesce_entry), NULL) < 0)
818 0 : goto error;
819 :
820 0 : return u;
821 : error:
822 0 : FN(UNION,free)(u);
823 0 : return NULL;
824 : }
825 :
826 0 : static isl_stat FN(UNION,domain_entry)(__isl_take PART *part, void *user)
827 : {
828 0 : isl_union_set **uset = (isl_union_set **)user;
829 :
830 0 : *uset = isl_union_set_add_set(*uset, FN(PART,domain)(part));
831 :
832 0 : return isl_stat_ok;
833 : }
834 :
835 0 : __isl_give isl_union_set *FN(UNION,domain)(__isl_take UNION *u)
836 : {
837 : isl_union_set *uset;
838 :
839 0 : uset = isl_union_set_empty(FN(UNION,get_space)(u));
840 0 : if (FN(FN(UNION,foreach),BASE)(u, &FN(UNION,domain_entry), &uset) < 0)
841 0 : goto error;
842 :
843 0 : FN(UNION,free)(u);
844 :
845 0 : return uset;
846 : error:
847 0 : isl_union_set_free(uset);
848 0 : FN(UNION,free)(u);
849 0 : return NULL;
850 : }
851 :
852 : #ifdef HAS_TYPE
853 : /* Negate the type of "u".
854 : */
855 0 : static __isl_give UNION *FN(UNION,negate_type)(__isl_take UNION *u)
856 : {
857 0 : u = FN(UNION,cow)(u);
858 0 : if (!u)
859 0 : return NULL;
860 0 : u->type = isl_fold_type_negate(u->type);
861 0 : return u;
862 : }
863 : #else
864 : /* Negate the type of "u".
865 : * Since "u" does not have a type, do nothing.
866 : */
867 0 : static __isl_give UNION *FN(UNION,negate_type)(__isl_take UNION *u)
868 : {
869 0 : return u;
870 : }
871 : #endif
872 :
873 : /* Multiply "part" by the isl_val "user" and return the result.
874 : */
875 0 : static __isl_give PART *FN(UNION,scale_val_entry)(__isl_take PART *part,
876 : void *user)
877 : {
878 0 : isl_val *v = user;
879 :
880 0 : return FN(PART,scale_val)(part, isl_val_copy(v));
881 : }
882 :
883 : /* Multiply "u" by "v" and return the result.
884 : */
885 0 : __isl_give UNION *FN(UNION,scale_val)(__isl_take UNION *u,
886 : __isl_take isl_val *v)
887 : {
888 0 : if (!u || !v)
889 : goto error;
890 0 : if (isl_val_is_one(v)) {
891 0 : isl_val_free(v);
892 0 : return u;
893 : }
894 :
895 0 : if (DEFAULT_IS_ZERO && u && isl_val_is_zero(v)) {
896 : UNION *zero;
897 0 : isl_space *space = FN(UNION,get_space)(u);
898 : #ifdef HAS_TYPE
899 0 : zero = FN(UNION,ZERO)(space, u->type);
900 : #else
901 0 : zero = FN(UNION,ZERO)(space);
902 : #endif
903 0 : FN(UNION,free)(u);
904 0 : isl_val_free(v);
905 0 : return zero;
906 : }
907 :
908 0 : if (!isl_val_is_rat(v))
909 0 : isl_die(isl_val_get_ctx(v), isl_error_invalid,
910 : "expecting rational factor", goto error);
911 :
912 0 : u = FN(UNION,transform_inplace)(u, &FN(UNION,scale_val_entry), v);
913 0 : if (isl_val_is_neg(v))
914 0 : u = FN(UNION,negate_type)(u);
915 :
916 0 : isl_val_free(v);
917 0 : return u;
918 : error:
919 0 : isl_val_free(v);
920 0 : FN(UNION,free)(u);
921 0 : return NULL;
922 : }
923 :
924 : /* Divide "part" by the isl_val "user" and return the result.
925 : */
926 0 : static __isl_give PART *FN(UNION,scale_down_val_entry)(__isl_take PART *part,
927 : void *user)
928 : {
929 0 : isl_val *v = user;
930 :
931 0 : return FN(PART,scale_down_val)(part, isl_val_copy(v));
932 : }
933 :
934 : /* Divide "u" by "v" and return the result.
935 : */
936 0 : __isl_give UNION *FN(UNION,scale_down_val)(__isl_take UNION *u,
937 : __isl_take isl_val *v)
938 : {
939 0 : if (!u || !v)
940 : goto error;
941 0 : if (isl_val_is_one(v)) {
942 0 : isl_val_free(v);
943 0 : return u;
944 : }
945 :
946 0 : if (!isl_val_is_rat(v))
947 0 : isl_die(isl_val_get_ctx(v), isl_error_invalid,
948 : "expecting rational factor", goto error);
949 0 : if (isl_val_is_zero(v))
950 0 : isl_die(isl_val_get_ctx(v), isl_error_invalid,
951 : "cannot scale down by zero", goto error);
952 :
953 0 : u = FN(UNION,transform_inplace)(u, &FN(UNION,scale_down_val_entry), v);
954 0 : if (isl_val_is_neg(v))
955 0 : u = FN(UNION,negate_type)(u);
956 :
957 0 : isl_val_free(v);
958 0 : return u;
959 : error:
960 0 : isl_val_free(v);
961 0 : FN(UNION,free)(u);
962 0 : return NULL;
963 : }
964 :
965 : S(UNION,plain_is_equal_data)
966 : {
967 : UNION *u2;
968 : isl_bool is_equal;
969 : };
970 :
971 0 : static isl_stat FN(UNION,plain_is_equal_entry)(void **entry, void *user)
972 : {
973 0 : S(UNION,plain_is_equal_data) *data = user;
974 : struct isl_hash_table_entry *entry2;
975 0 : PW *pw = *entry;
976 :
977 0 : entry2 = FN(UNION,find_part_entry)(data->u2, pw->dim, 0);
978 0 : if (!entry2 || entry2 == isl_hash_table_entry_none) {
979 0 : if (!entry2)
980 0 : data->is_equal = isl_bool_error;
981 : else
982 0 : data->is_equal = isl_bool_false;
983 0 : return isl_stat_error;
984 : }
985 :
986 0 : data->is_equal = FN(PW,plain_is_equal)(pw, entry2->data);
987 0 : if (data->is_equal < 0 || !data->is_equal)
988 0 : return isl_stat_error;
989 :
990 0 : return isl_stat_ok;
991 : }
992 :
993 0 : isl_bool FN(UNION,plain_is_equal)(__isl_keep UNION *u1, __isl_keep UNION *u2)
994 : {
995 0 : S(UNION,plain_is_equal_data) data = { NULL, isl_bool_true };
996 : int n1, n2;
997 :
998 0 : if (!u1 || !u2)
999 0 : return isl_bool_error;
1000 0 : if (u1 == u2)
1001 0 : return isl_bool_true;
1002 0 : if (u1->table.n != u2->table.n)
1003 0 : return isl_bool_false;
1004 0 : n1 = FN(FN(UNION,n),BASE)(u1);
1005 0 : n2 = FN(FN(UNION,n),BASE)(u2);
1006 0 : if (n1 < 0 || n2 < 0)
1007 0 : return isl_bool_error;
1008 0 : if (n1 != n2)
1009 0 : return isl_bool_false;
1010 :
1011 0 : u1 = FN(UNION,copy)(u1);
1012 0 : u2 = FN(UNION,copy)(u2);
1013 0 : u1 = FN(UNION,align_params)(u1, FN(UNION,get_space)(u2));
1014 0 : u2 = FN(UNION,align_params)(u2, FN(UNION,get_space)(u1));
1015 0 : if (!u1 || !u2)
1016 : goto error;
1017 :
1018 0 : data.u2 = u2;
1019 0 : if (FN(UNION,foreach_inplace)(u1,
1020 0 : &FN(UNION,plain_is_equal_entry), &data) < 0 &&
1021 0 : data.is_equal)
1022 0 : goto error;
1023 :
1024 0 : FN(UNION,free)(u1);
1025 0 : FN(UNION,free)(u2);
1026 :
1027 0 : return data.is_equal;
1028 : error:
1029 0 : FN(UNION,free)(u1);
1030 0 : FN(UNION,free)(u2);
1031 0 : return isl_bool_error;
1032 : }
1033 :
1034 : /* Check whether the element that "entry" points to involves any NaNs and
1035 : * store the result in *nan.
1036 : * Abort as soon as one such element has been found.
1037 : */
1038 0 : static isl_stat FN(UNION,involves_nan_entry)(void **entry, void *user)
1039 : {
1040 0 : isl_bool *nan = user;
1041 0 : PW *pw = *entry;
1042 :
1043 0 : *nan = FN(PW,involves_nan)(pw);
1044 0 : if (*nan < 0 || !nan)
1045 0 : return isl_stat_error;
1046 :
1047 0 : return isl_stat_ok;
1048 : }
1049 :
1050 : /* Does "u" involve any NaNs?
1051 : */
1052 0 : isl_bool FN(UNION,involves_nan)(__isl_keep UNION *u)
1053 : {
1054 0 : isl_bool nan = isl_bool_false;
1055 :
1056 0 : if (!u)
1057 0 : return isl_bool_error;
1058 :
1059 0 : if (FN(UNION,foreach_inplace)(u,
1060 0 : &FN(UNION,involves_nan_entry), &nan) < 0 &&
1061 0 : !nan)
1062 0 : return isl_bool_error;
1063 :
1064 0 : return nan;
1065 : }
1066 :
1067 : /* Internal data structure for isl_union_*_drop_dims.
1068 : * type, first and n are passed to isl_*_drop_dims.
1069 : */
1070 : S(UNION,drop_dims_data) {
1071 : enum isl_dim_type type;
1072 : unsigned first;
1073 : unsigned n;
1074 : };
1075 :
1076 : /* Drop the parameters specified by "data" from "part" and return the result.
1077 : */
1078 0 : static __isl_give PART *FN(UNION,drop_dims_entry)(__isl_take PART *part,
1079 : void *user)
1080 : {
1081 0 : S(UNION,drop_dims_data) *data = user;
1082 :
1083 0 : return FN(PART,drop_dims)(part, data->type, data->first, data->n);
1084 : }
1085 :
1086 : /* Drop the specified parameters from "u".
1087 : * That is, type is required to be isl_dim_param.
1088 : */
1089 0 : __isl_give UNION *FN(UNION,drop_dims)( __isl_take UNION *u,
1090 : enum isl_dim_type type, unsigned first, unsigned n)
1091 : {
1092 : isl_space *space;
1093 0 : S(UNION,drop_dims_data) data = { type, first, n };
1094 :
1095 0 : if (!u)
1096 0 : return NULL;
1097 :
1098 0 : if (type != isl_dim_param)
1099 0 : isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
1100 : "can only project out parameters",
1101 : return FN(UNION,free)(u));
1102 :
1103 0 : space = FN(UNION,get_space)(u);
1104 0 : space = isl_space_drop_dims(space, type, first, n);
1105 0 : return FN(UNION,transform_space)(u, space, &FN(UNION,drop_dims_entry),
1106 : &data);
1107 : }
1108 :
1109 : /* Internal data structure for isl_union_*_set_dim_name.
1110 : * pos is the position of the parameter that needs to be renamed.
1111 : * s is the new name.
1112 : */
1113 : S(UNION,set_dim_name_data) {
1114 : unsigned pos;
1115 : const char *s;
1116 : };
1117 :
1118 : /* Change the name of the parameter at position data->pos of "part" to data->s
1119 : * and return the result.
1120 : */
1121 0 : static __isl_give PART *FN(UNION,set_dim_name_entry)(__isl_take PART *part,
1122 : void *user)
1123 : {
1124 0 : S(UNION,set_dim_name_data) *data = user;
1125 :
1126 0 : return FN(PART,set_dim_name)(part, isl_dim_param, data->pos, data->s);
1127 : }
1128 :
1129 : /* Change the name of the parameter at position "pos" to "s".
1130 : * That is, type is required to be isl_dim_param.
1131 : */
1132 0 : __isl_give UNION *FN(UNION,set_dim_name)(__isl_take UNION *u,
1133 : enum isl_dim_type type, unsigned pos, const char *s)
1134 : {
1135 0 : S(UNION,set_dim_name_data) data = { pos, s };
1136 : isl_space *space;
1137 :
1138 0 : if (!u)
1139 0 : return NULL;
1140 :
1141 0 : if (type != isl_dim_param)
1142 0 : isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
1143 : "can only set parameter names",
1144 : return FN(UNION,free)(u));
1145 :
1146 0 : space = FN(UNION,get_space)(u);
1147 0 : space = isl_space_set_dim_name(space, type, pos, s);
1148 0 : return FN(UNION,transform_space)(u, space,
1149 : &FN(UNION,set_dim_name_entry), &data);
1150 : }
1151 :
1152 : /* Reset the user pointer on all identifiers of parameters and tuples
1153 : * of the space of "part" and return the result.
1154 : */
1155 0 : static __isl_give PART *FN(UNION,reset_user_entry)(__isl_take PART *part,
1156 : void *user)
1157 : {
1158 0 : return FN(PART,reset_user)(part);
1159 : }
1160 :
1161 : /* Reset the user pointer on all identifiers of parameters and tuples
1162 : * of the spaces of "u".
1163 : */
1164 0 : __isl_give UNION *FN(UNION,reset_user)(__isl_take UNION *u)
1165 : {
1166 : isl_space *space;
1167 :
1168 0 : space = FN(UNION,get_space)(u);
1169 0 : space = isl_space_reset_user(space);
1170 0 : return FN(UNION,transform_space)(u, space, &FN(UNION,reset_user_entry),
1171 : NULL);
1172 : }
1173 :
1174 : /* Add the base expression held by "entry" to "list".
1175 : */
1176 0 : static isl_stat FN(UNION,add_to_list)(void **entry, void *user)
1177 : {
1178 0 : PW *pw = *entry;
1179 0 : LIST(PART) **list = user;
1180 :
1181 0 : *list = FN(LIST(PART),add)(*list, FN(PART,copy)(pw));
1182 0 : if (!*list)
1183 0 : return isl_stat_error;
1184 :
1185 0 : return isl_stat_ok;
1186 : }
1187 :
1188 : /* Return a list containing all the base expressions in "u".
1189 : *
1190 : * First construct a list of the appropriate size and
1191 : * then add all the elements.
1192 : */
1193 0 : __isl_give LIST(PART) *FN(FN(UNION,get),LIST(BASE))(__isl_keep UNION *u)
1194 : {
1195 : int n;
1196 : LIST(PART) *list;
1197 :
1198 0 : if (!u)
1199 0 : return NULL;
1200 0 : n = FN(FN(UNION,n),BASE)(u);
1201 0 : if (n < 0)
1202 0 : return NULL;
1203 0 : list = FN(LIST(PART),alloc)(FN(UNION,get_ctx(u)), n);
1204 0 : if (FN(UNION,foreach_inplace)(u, &FN(UNION,add_to_list), &list) < 0)
1205 0 : return FN(LIST(PART),free)(list);
1206 :
1207 0 : return list;
1208 : }
|