Line data Source code
1 : /*
2 : * Copyright 2011 Sven Verdoolaege
3 : * Copyright 2012-2013 Ecole Normale Superieure
4 : *
5 : * Use of this software is governed by the MIT license
6 : *
7 : * Written by Sven Verdoolaege,
8 : * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
9 : */
10 :
11 : #include <isl/id.h>
12 : #include <isl_space_private.h>
13 : #include <isl_val_private.h>
14 : #include <isl/set.h>
15 : #include <isl_reordering.h>
16 :
17 : #include <isl_multi_macro.h>
18 :
19 : #define MULTI_NAME(BASE) "isl_multi_" #BASE
20 : #define xLIST(EL) EL ## _list
21 : #define LIST(EL) xLIST(EL)
22 :
23 0 : isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi)
24 : {
25 0 : return multi ? isl_space_get_ctx(multi->space) : NULL;
26 : }
27 :
28 : /* Return the space of "multi".
29 : */
30 0 : __isl_keep isl_space *FN(MULTI(BASE),peek_space)(__isl_keep MULTI(BASE) *multi)
31 : {
32 0 : return multi ? multi->space : NULL;
33 : }
34 :
35 0 : __isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi)
36 : {
37 0 : return isl_space_copy(FN(MULTI(BASE),peek_space)(multi));
38 : }
39 :
40 : /* Return the position of the dimension of the given type and name
41 : * in "multi".
42 : * Return -1 if no such dimension can be found.
43 : */
44 0 : int FN(MULTI(BASE),find_dim_by_name)(__isl_keep MULTI(BASE) *multi,
45 : enum isl_dim_type type, const char *name)
46 : {
47 0 : if (!multi)
48 0 : return -1;
49 0 : return isl_space_find_dim_by_name(multi->space, type, name);
50 : }
51 :
52 0 : __isl_give isl_space *FN(MULTI(BASE),get_domain_space)(
53 : __isl_keep MULTI(BASE) *multi)
54 : {
55 0 : return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL;
56 : }
57 :
58 : /* Allocate a multi expression living in "space".
59 : *
60 : * If the number of base expressions is zero, then make sure
61 : * there is enough room in the structure for the explicit domain,
62 : * in case the type supports such an explicit domain.
63 : */
64 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space)
65 : {
66 : isl_ctx *ctx;
67 : int n;
68 : MULTI(BASE) *multi;
69 :
70 0 : if (!space)
71 0 : return NULL;
72 :
73 0 : ctx = isl_space_get_ctx(space);
74 0 : n = isl_space_dim(space, isl_dim_out);
75 0 : if (n > 0)
76 0 : multi = isl_calloc(ctx, MULTI(BASE),
77 : sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *));
78 : else
79 0 : multi = isl_calloc(ctx, MULTI(BASE), sizeof(MULTI(BASE)));
80 0 : if (!multi)
81 0 : goto error;
82 :
83 0 : multi->space = space;
84 0 : multi->n = n;
85 0 : multi->ref = 1;
86 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi))
87 0 : multi = FN(MULTI(BASE),init_explicit_domain)(multi);
88 0 : return multi;
89 : error:
90 0 : isl_space_free(space);
91 0 : return NULL;
92 : }
93 :
94 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
95 : {
96 : int i;
97 : MULTI(BASE) *dup;
98 :
99 0 : if (!multi)
100 0 : return NULL;
101 :
102 0 : dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
103 0 : if (!dup)
104 0 : return NULL;
105 :
106 0 : for (i = 0; i < multi->n; ++i)
107 0 : dup = FN(FN(MULTI(BASE),set),BASE)(dup, i,
108 : FN(EL,copy)(multi->u.p[i]));
109 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi))
110 0 : dup = FN(MULTI(BASE),copy_explicit_domain)(dup, multi);
111 :
112 0 : return dup;
113 : }
114 :
115 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
116 : {
117 0 : if (!multi)
118 0 : return NULL;
119 :
120 0 : if (multi->ref == 1)
121 0 : return multi;
122 :
123 0 : multi->ref--;
124 0 : return FN(MULTI(BASE),dup)(multi);
125 : }
126 :
127 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
128 : {
129 0 : if (!multi)
130 0 : return NULL;
131 :
132 0 : multi->ref++;
133 0 : return multi;
134 : }
135 :
136 0 : __isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
137 : {
138 : int i;
139 :
140 0 : if (!multi)
141 0 : return NULL;
142 :
143 0 : if (--multi->ref > 0)
144 0 : return NULL;
145 :
146 0 : isl_space_free(multi->space);
147 0 : for (i = 0; i < multi->n; ++i)
148 0 : FN(EL,free)(multi->u.p[i]);
149 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi))
150 0 : FN(MULTI(BASE),free_explicit_domain)(multi);
151 0 : free(multi);
152 :
153 0 : return NULL;
154 : }
155 :
156 0 : unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
157 : enum isl_dim_type type)
158 : {
159 0 : return multi ? isl_space_dim(multi->space, type) : 0;
160 : }
161 :
162 : /* Return the position of the first dimension of "type" with id "id".
163 : * Return -1 if there is no such dimension.
164 : */
165 0 : int FN(MULTI(BASE),find_dim_by_id)(__isl_keep MULTI(BASE) *multi,
166 : enum isl_dim_type type, __isl_keep isl_id *id)
167 : {
168 0 : if (!multi)
169 0 : return -1;
170 0 : return isl_space_find_dim_by_id(multi->space, type, id);
171 : }
172 :
173 : /* Return the id of the given dimension.
174 : */
175 0 : __isl_give isl_id *FN(MULTI(BASE),get_dim_id)(__isl_keep MULTI(BASE) *multi,
176 : enum isl_dim_type type, unsigned pos)
177 : {
178 0 : return multi ? isl_space_get_dim_id(multi->space, type, pos) : NULL;
179 : }
180 :
181 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)(
182 : __isl_take MULTI(BASE) *multi,
183 : enum isl_dim_type type, unsigned pos, const char *s)
184 : {
185 : int i;
186 :
187 0 : multi = FN(MULTI(BASE),cow)(multi);
188 0 : if (!multi)
189 0 : return NULL;
190 :
191 0 : multi->space = isl_space_set_dim_name(multi->space, type, pos, s);
192 0 : if (!multi->space)
193 0 : return FN(MULTI(BASE),free)(multi);
194 :
195 0 : if (type == isl_dim_out)
196 0 : return multi;
197 0 : for (i = 0; i < multi->n; ++i) {
198 0 : multi->u.p[i] = FN(EL,set_dim_name)(multi->u.p[i],
199 : type, pos, s);
200 0 : if (!multi->u.p[i])
201 0 : return FN(MULTI(BASE),free)(multi);
202 : }
203 :
204 0 : return multi;
205 : }
206 :
207 0 : const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi,
208 : enum isl_dim_type type)
209 : {
210 0 : return multi ? isl_space_get_tuple_name(multi->space, type) : NULL;
211 : }
212 :
213 : /* Does the specified tuple have an id?
214 : */
215 0 : isl_bool FN(MULTI(BASE),has_tuple_id)(__isl_keep MULTI(BASE) *multi,
216 : enum isl_dim_type type)
217 : {
218 0 : if (!multi)
219 0 : return isl_bool_error;
220 0 : return isl_space_has_tuple_id(multi->space, type);
221 : }
222 :
223 : /* Return the id of the specified tuple.
224 : */
225 0 : __isl_give isl_id *FN(MULTI(BASE),get_tuple_id)(__isl_keep MULTI(BASE) *multi,
226 : enum isl_dim_type type)
227 : {
228 0 : return multi ? isl_space_get_tuple_id(multi->space, type) : NULL;
229 : }
230 :
231 0 : __isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
232 : int pos)
233 : {
234 : isl_ctx *ctx;
235 :
236 0 : if (!multi)
237 0 : return NULL;
238 0 : ctx = FN(MULTI(BASE),get_ctx)(multi);
239 0 : if (pos < 0 || pos >= multi->n)
240 0 : isl_die(ctx, isl_error_invalid,
241 : "index out of bounds", return NULL);
242 0 : return FN(EL,copy)(multi->u.p[pos]);
243 : }
244 :
245 : /* Set the element at position "pos" of "multi" to "el",
246 : * where the position may be empty if "multi" has only a single reference.
247 : */
248 0 : static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore)(
249 : __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
250 : {
251 0 : multi = FN(MULTI(BASE),cow)(multi);
252 0 : if (!multi || !el)
253 : goto error;
254 :
255 0 : if (pos < 0 || pos >= multi->n)
256 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
257 : "index out of bounds", goto error);
258 :
259 0 : FN(EL,free)(multi->u.p[pos]);
260 0 : multi->u.p[pos] = el;
261 :
262 0 : return multi;
263 : error:
264 0 : FN(MULTI(BASE),free)(multi);
265 0 : FN(EL,free)(el);
266 0 : return NULL;
267 : }
268 :
269 : /* Set the element at position "pos" of "multi" to "el",
270 : * where the position may be empty if "multi" has only a single reference.
271 : * However, the space of "multi" is available and is checked
272 : * for compatibility with "el".
273 : */
274 0 : static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore_check_space)(
275 : __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
276 : {
277 : isl_space *space;
278 :
279 0 : space = FN(MULTI(BASE),peek_space)(multi);
280 0 : if (FN(EL,check_match_domain_space)(el, space) < 0)
281 0 : multi = FN(MULTI(BASE),free)(multi);
282 0 : return FN(MULTI(BASE),restore)(multi, pos, el);
283 : }
284 :
285 0 : __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
286 : __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
287 : {
288 0 : isl_space *multi_space = NULL;
289 0 : isl_space *el_space = NULL;
290 : isl_bool match;
291 :
292 0 : multi_space = FN(MULTI(BASE),get_space)(multi);
293 0 : match = FN(EL,matching_params)(el, multi_space);
294 0 : if (match < 0)
295 0 : goto error;
296 0 : if (!match) {
297 0 : multi = FN(MULTI(BASE),align_params)(multi,
298 : FN(EL,get_space)(el));
299 0 : isl_space_free(multi_space);
300 0 : multi_space = FN(MULTI(BASE),get_space)(multi);
301 0 : el = FN(EL,align_params)(el, isl_space_copy(multi_space));
302 : }
303 :
304 0 : multi = FN(MULTI(BASE),restore_check_space)(multi, pos, el);
305 :
306 0 : isl_space_free(multi_space);
307 0 : isl_space_free(el_space);
308 :
309 0 : return multi;
310 : error:
311 0 : FN(MULTI(BASE),free)(multi);
312 0 : FN(EL,free)(el);
313 0 : isl_space_free(multi_space);
314 0 : isl_space_free(el_space);
315 0 : return NULL;
316 : }
317 :
318 : /* Reset the space of "multi". This function is called from isl_pw_templ.c
319 : * and doesn't know if the space of an element object is represented
320 : * directly or through its domain. It therefore passes along both,
321 : * which we pass along to the element function since we don't know how
322 : * that is represented either.
323 : *
324 : * If "multi" has an explicit domain, then the caller is expected
325 : * to make sure that any modification that would change the dimensions
326 : * of the explicit domain has bee applied before this function is called.
327 : */
328 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
329 : __isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
330 : __isl_take isl_space *domain)
331 : {
332 : int i;
333 :
334 0 : multi = FN(MULTI(BASE),cow)(multi);
335 0 : if (!multi || !space || !domain)
336 : goto error;
337 :
338 0 : for (i = 0; i < multi->n; ++i) {
339 0 : multi->u.p[i] = FN(EL,reset_domain_space)(multi->u.p[i],
340 : isl_space_copy(domain));
341 0 : if (!multi->u.p[i])
342 0 : goto error;
343 : }
344 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
345 0 : multi = FN(MULTI(BASE),reset_explicit_domain_space)(multi,
346 : isl_space_copy(domain));
347 0 : if (!multi)
348 0 : goto error;
349 : }
350 0 : isl_space_free(domain);
351 0 : isl_space_free(multi->space);
352 0 : multi->space = space;
353 :
354 0 : return multi;
355 : error:
356 0 : isl_space_free(domain);
357 0 : isl_space_free(space);
358 0 : FN(MULTI(BASE),free)(multi);
359 0 : return NULL;
360 : }
361 :
362 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
363 : __isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
364 : {
365 : isl_space *space;
366 :
367 0 : space = isl_space_extend_domain_with_range(isl_space_copy(domain),
368 : isl_space_copy(multi->space));
369 0 : return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
370 : }
371 :
372 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
373 : __isl_take MULTI(BASE) *multi, __isl_take isl_space *space)
374 : {
375 : isl_space *domain;
376 :
377 0 : domain = isl_space_domain(isl_space_copy(space));
378 0 : return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
379 : }
380 :
381 : /* Set the id of the given dimension of "multi" to "id".
382 : */
383 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_id)(
384 : __isl_take MULTI(BASE) *multi,
385 : enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
386 : {
387 : isl_space *space;
388 :
389 0 : multi = FN(MULTI(BASE),cow)(multi);
390 0 : if (!multi || !id)
391 : goto error;
392 :
393 0 : space = FN(MULTI(BASE),get_space)(multi);
394 0 : space = isl_space_set_dim_id(space, type, pos, id);
395 :
396 0 : return FN(MULTI(BASE),reset_space)(multi, space);
397 : error:
398 0 : isl_id_free(id);
399 0 : FN(MULTI(BASE),free)(multi);
400 0 : return NULL;
401 : }
402 :
403 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)(
404 : __isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
405 : const char *s)
406 : {
407 : isl_space *space;
408 :
409 0 : multi = FN(MULTI(BASE),cow)(multi);
410 0 : if (!multi)
411 0 : return NULL;
412 :
413 0 : space = FN(MULTI(BASE),get_space)(multi);
414 0 : space = isl_space_set_tuple_name(space, type, s);
415 :
416 0 : return FN(MULTI(BASE),reset_space)(multi, space);
417 : }
418 :
419 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_id)(
420 : __isl_take MULTI(BASE) *multi, enum isl_dim_type type,
421 : __isl_take isl_id *id)
422 : {
423 : isl_space *space;
424 :
425 0 : multi = FN(MULTI(BASE),cow)(multi);
426 0 : if (!multi)
427 0 : goto error;
428 :
429 0 : space = FN(MULTI(BASE),get_space)(multi);
430 0 : space = isl_space_set_tuple_id(space, type, id);
431 :
432 0 : return FN(MULTI(BASE),reset_space)(multi, space);
433 : error:
434 0 : isl_id_free(id);
435 0 : return NULL;
436 : }
437 :
438 : /* Drop the id on the specified tuple.
439 : */
440 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_tuple_id)(
441 : __isl_take MULTI(BASE) *multi, enum isl_dim_type type)
442 : {
443 : isl_space *space;
444 :
445 0 : if (!multi)
446 0 : return NULL;
447 0 : if (!FN(MULTI(BASE),has_tuple_id)(multi, type))
448 0 : return multi;
449 :
450 0 : multi = FN(MULTI(BASE),cow)(multi);
451 0 : if (!multi)
452 0 : return NULL;
453 :
454 0 : space = FN(MULTI(BASE),get_space)(multi);
455 0 : space = isl_space_reset_tuple_id(space, type);
456 :
457 0 : return FN(MULTI(BASE),reset_space)(multi, space);
458 : }
459 :
460 : /* Reset the user pointer on all identifiers of parameters and tuples
461 : * of the space of "multi".
462 : */
463 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_user)(
464 : __isl_take MULTI(BASE) *multi)
465 : {
466 : isl_space *space;
467 :
468 0 : space = FN(MULTI(BASE),get_space)(multi);
469 0 : space = isl_space_reset_user(space);
470 :
471 0 : return FN(MULTI(BASE),reset_space)(multi, space);
472 : }
473 :
474 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
475 : __isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp)
476 : {
477 : int i;
478 : isl_space *space;
479 :
480 0 : multi = FN(MULTI(BASE),cow)(multi);
481 0 : if (!multi || !exp)
482 : goto error;
483 :
484 0 : for (i = 0; i < multi->n; ++i) {
485 0 : multi->u.p[i] = FN(EL,realign_domain)(multi->u.p[i],
486 : isl_reordering_copy(exp));
487 0 : if (!multi->u.p[i])
488 0 : goto error;
489 : }
490 :
491 0 : space = isl_reordering_get_space(exp);
492 0 : multi = FN(MULTI(BASE),reset_domain_space)(multi, space);
493 :
494 0 : isl_reordering_free(exp);
495 0 : return multi;
496 : error:
497 0 : isl_reordering_free(exp);
498 0 : FN(MULTI(BASE),free)(multi);
499 0 : return NULL;
500 : }
501 :
502 : /* Align the parameters of "multi" to those of "model".
503 : *
504 : * If "multi" has an explicit domain, then align the parameters
505 : * of the domain first.
506 : */
507 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
508 : __isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
509 : {
510 : isl_ctx *ctx;
511 : isl_bool equal_params;
512 : isl_reordering *exp;
513 :
514 0 : if (!multi || !model)
515 : goto error;
516 :
517 0 : equal_params = isl_space_has_equal_params(multi->space, model);
518 0 : if (equal_params < 0)
519 0 : goto error;
520 0 : if (equal_params) {
521 0 : isl_space_free(model);
522 0 : return multi;
523 : }
524 :
525 0 : ctx = isl_space_get_ctx(model);
526 0 : if (!isl_space_has_named_params(model))
527 0 : isl_die(ctx, isl_error_invalid,
528 : "model has unnamed parameters", goto error);
529 0 : if (!isl_space_has_named_params(multi->space))
530 0 : isl_die(ctx, isl_error_invalid,
531 : "input has unnamed parameters", goto error);
532 :
533 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
534 0 : multi = FN(MULTI(BASE),align_explicit_domain_params)(multi,
535 : isl_space_copy(model));
536 0 : if (!multi)
537 0 : goto error;
538 : }
539 0 : exp = isl_parameter_alignment_reordering(multi->space, model);
540 0 : exp = isl_reordering_extend_space(exp,
541 : FN(MULTI(BASE),get_domain_space)(multi));
542 0 : multi = FN(MULTI(BASE),realign_domain)(multi, exp);
543 :
544 0 : isl_space_free(model);
545 0 : return multi;
546 : error:
547 0 : isl_space_free(model);
548 0 : FN(MULTI(BASE),free)(multi);
549 0 : return NULL;
550 : }
551 :
552 : /* Create a multi expression in the given space with the elements of "list"
553 : * as base expressions.
554 : *
555 : * Since isl_multi_*_restore_* assumes that the element and
556 : * the multi expression have matching spaces, the alignment
557 : * (if any) needs to be performed beforehand.
558 : */
559 0 : __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
560 : __isl_take isl_space *space, __isl_take LIST(EL) *list)
561 : {
562 : int i;
563 : int n;
564 : isl_ctx *ctx;
565 : MULTI(BASE) *multi;
566 :
567 0 : if (!space || !list)
568 : goto error;
569 :
570 0 : ctx = isl_space_get_ctx(space);
571 0 : n = FN(FN(LIST(EL),n),BASE)(list);
572 0 : if (n != isl_space_dim(space, isl_dim_out))
573 0 : isl_die(ctx, isl_error_invalid,
574 : "invalid number of elements in list", goto error);
575 :
576 0 : for (i = 0; i < n; ++i) {
577 0 : EL *el = FN(LIST(EL),peek)(list, i);
578 0 : space = isl_space_align_params(space, FN(EL,get_space)(el));
579 : }
580 0 : multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
581 0 : for (i = 0; i < n; ++i) {
582 0 : EL *el = FN(FN(LIST(EL),get),BASE)(list, i);
583 0 : el = FN(EL,align_params)(el, isl_space_copy(space));
584 0 : multi = FN(MULTI(BASE),restore_check_space)(multi, i, el);
585 : }
586 :
587 0 : isl_space_free(space);
588 0 : FN(LIST(EL),free)(list);
589 0 : return multi;
590 : error:
591 0 : isl_space_free(space);
592 0 : FN(LIST(EL),free)(list);
593 0 : return NULL;
594 : }
595 :
596 : #ifndef NO_IDENTITY
597 : /* Create a multi expression in the given space that maps each
598 : * input dimension to the corresponding output dimension.
599 : */
600 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),identity)(__isl_take isl_space *space)
601 : {
602 : int i, n;
603 : isl_local_space *ls;
604 : MULTI(BASE) *multi;
605 :
606 0 : if (!space)
607 0 : return NULL;
608 :
609 0 : if (isl_space_is_set(space))
610 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
611 : "expecting map space", goto error);
612 :
613 0 : n = isl_space_dim(space, isl_dim_out);
614 0 : if (n != isl_space_dim(space, isl_dim_in))
615 0 : isl_die(isl_space_get_ctx(space), isl_error_invalid,
616 : "number of input and output dimensions needs to be "
617 : "the same", goto error);
618 :
619 0 : multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
620 :
621 0 : if (!n) {
622 0 : isl_space_free(space);
623 0 : return multi;
624 : }
625 :
626 0 : space = isl_space_domain(space);
627 0 : ls = isl_local_space_from_space(space);
628 :
629 0 : for (i = 0; i < n; ++i) {
630 : EL *el;
631 0 : el = FN(EL,var_on_domain)(isl_local_space_copy(ls),
632 : isl_dim_set, i);
633 0 : multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, el);
634 : }
635 :
636 0 : isl_local_space_free(ls);
637 :
638 0 : return multi;
639 : error:
640 0 : isl_space_free(space);
641 0 : return NULL;
642 : }
643 : #endif
644 :
645 : #ifndef NO_ZERO
646 : /* Construct a multi expression in the given space with value zero in
647 : * each of the output dimensions.
648 : */
649 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space)
650 : {
651 : int n;
652 : MULTI(BASE) *multi;
653 :
654 0 : if (!space)
655 0 : return NULL;
656 :
657 0 : n = isl_space_dim(space , isl_dim_out);
658 0 : multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
659 :
660 0 : if (!n)
661 0 : isl_space_free(space);
662 : else {
663 : int i;
664 : isl_local_space *ls;
665 : EL *el;
666 :
667 0 : space = isl_space_domain(space);
668 0 : ls = isl_local_space_from_space(space);
669 0 : el = FN(EL,zero_on_domain)(ls);
670 :
671 0 : for (i = 0; i < n; ++i)
672 0 : multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
673 : FN(EL,copy)(el));
674 :
675 0 : FN(EL,free)(el);
676 : }
677 :
678 0 : return multi;
679 : }
680 : #endif
681 :
682 : #ifndef NO_FROM_BASE
683 : /* Create a multiple expression with a single output/set dimension
684 : * equal to "el".
685 : * For most multiple expression types, the base type has a single
686 : * output/set dimension and the space of the result is therefore
687 : * the same as the space of the input.
688 : * In the case of isl_multi_union_pw_aff, however, the base type
689 : * lives in a parameter space and we therefore need to add
690 : * a single set dimension.
691 : */
692 0 : __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),BASE)(__isl_take EL *el)
693 : {
694 : isl_space *space;
695 : MULTI(BASE) *multi;
696 :
697 0 : space = FN(EL,get_space(el));
698 0 : if (isl_space_is_params(space)) {
699 0 : space = isl_space_set_from_params(space);
700 0 : space = isl_space_add_dims(space, isl_dim_set, 1);
701 : }
702 0 : multi = FN(MULTI(BASE),alloc)(space);
703 0 : multi = FN(FN(MULTI(BASE),set),BASE)(multi, 0, el);
704 :
705 0 : return multi;
706 : }
707 : #endif
708 :
709 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
710 : __isl_take MULTI(BASE) *multi,
711 : enum isl_dim_type type, unsigned first, unsigned n)
712 : {
713 : int i;
714 : unsigned dim;
715 :
716 0 : multi = FN(MULTI(BASE),cow)(multi);
717 0 : if (!multi)
718 0 : return NULL;
719 :
720 0 : dim = FN(MULTI(BASE),dim)(multi, type);
721 0 : if (first + n > dim || first + n < first)
722 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
723 : "index out of bounds",
724 : return FN(MULTI(BASE),free)(multi));
725 :
726 0 : multi->space = isl_space_drop_dims(multi->space, type, first, n);
727 0 : if (!multi->space)
728 0 : return FN(MULTI(BASE),free)(multi);
729 :
730 0 : if (type == isl_dim_out) {
731 0 : for (i = 0; i < n; ++i)
732 0 : FN(EL,free)(multi->u.p[first + i]);
733 0 : for (i = first; i + n < multi->n; ++i)
734 0 : multi->u.p[i] = multi->u.p[i + n];
735 0 : multi->n -= n;
736 0 : if (n > 0 && FN(MULTI(BASE),has_explicit_domain)(multi))
737 0 : multi = FN(MULTI(BASE),init_explicit_domain)(multi);
738 :
739 0 : return multi;
740 : }
741 :
742 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi))
743 0 : multi = FN(MULTI(BASE),drop_explicit_domain_dims)(multi,
744 : type, first, n);
745 0 : if (!multi)
746 0 : return NULL;
747 :
748 0 : for (i = 0; i < multi->n; ++i) {
749 0 : multi->u.p[i] = FN(EL,drop_dims)(multi->u.p[i], type, first, n);
750 0 : if (!multi->u.p[i])
751 0 : return FN(MULTI(BASE),free)(multi);
752 : }
753 :
754 0 : return multi;
755 : }
756 :
757 : /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
758 : */
759 0 : static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
760 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
761 : __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
762 : __isl_take MULTI(BASE) *multi2))
763 : {
764 : isl_ctx *ctx;
765 : isl_bool equal_params;
766 :
767 0 : if (!multi1 || !multi2)
768 : goto error;
769 0 : equal_params = isl_space_has_equal_params(multi1->space, multi2->space);
770 0 : if (equal_params < 0)
771 0 : goto error;
772 0 : if (equal_params)
773 0 : return fn(multi1, multi2);
774 0 : ctx = FN(MULTI(BASE),get_ctx)(multi1);
775 0 : if (!isl_space_has_named_params(multi1->space) ||
776 0 : !isl_space_has_named_params(multi2->space))
777 0 : isl_die(ctx, isl_error_invalid,
778 : "unaligned unnamed parameters", goto error);
779 0 : multi1 = FN(MULTI(BASE),align_params)(multi1,
780 : FN(MULTI(BASE),get_space)(multi2));
781 0 : multi2 = FN(MULTI(BASE),align_params)(multi2,
782 : FN(MULTI(BASE),get_space)(multi1));
783 0 : return fn(multi1, multi2);
784 : error:
785 0 : FN(MULTI(BASE),free)(multi1);
786 0 : FN(MULTI(BASE),free)(multi2);
787 0 : return NULL;
788 : }
789 :
790 : /* Given two MULTI(BASE)s A -> B and C -> D,
791 : * construct a MULTI(BASE) (A * C) -> [B -> D].
792 : *
793 : * The parameters are assumed to have been aligned.
794 : *
795 : * If "multi1" and/or "multi2" has an explicit domain, then
796 : * intersect the domain of the result with these explicit domains.
797 : */
798 0 : static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
799 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
800 : {
801 : int i, n1, n2;
802 : EL *el;
803 : isl_space *space;
804 : MULTI(BASE) *res;
805 :
806 0 : if (!multi1 || !multi2)
807 : goto error;
808 :
809 0 : space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
810 : FN(MULTI(BASE),get_space)(multi2));
811 0 : res = FN(MULTI(BASE),alloc)(space);
812 :
813 0 : n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
814 0 : n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
815 :
816 0 : for (i = 0; i < n1; ++i) {
817 0 : el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
818 0 : res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
819 : }
820 :
821 0 : for (i = 0; i < n2; ++i) {
822 0 : el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
823 0 : res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
824 : }
825 :
826 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi1))
827 0 : res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi1);
828 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi2))
829 0 : res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi2);
830 :
831 0 : FN(MULTI(BASE),free)(multi1);
832 0 : FN(MULTI(BASE),free)(multi2);
833 0 : return res;
834 : error:
835 0 : FN(MULTI(BASE),free)(multi1);
836 0 : FN(MULTI(BASE),free)(multi2);
837 0 : return NULL;
838 : }
839 :
840 : /* Given two MULTI(BASE)s A -> B and C -> D,
841 : * construct a MULTI(BASE) (A * C) -> [B -> D].
842 : */
843 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
844 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
845 : {
846 0 : return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
847 : &FN(MULTI(BASE),range_product_aligned));
848 : }
849 :
850 : /* Is the range of "multi" a wrapped relation?
851 : */
852 0 : isl_bool FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
853 : {
854 0 : if (!multi)
855 0 : return isl_bool_error;
856 0 : return isl_space_range_is_wrapping(multi->space);
857 : }
858 :
859 : /* Given a function A -> [B -> C], extract the function A -> B.
860 : */
861 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
862 : __isl_take MULTI(BASE) *multi)
863 : {
864 : isl_space *space;
865 : int total, keep;
866 :
867 0 : if (!multi)
868 0 : return NULL;
869 0 : if (!isl_space_range_is_wrapping(multi->space))
870 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
871 : "range is not a product",
872 : return FN(MULTI(BASE),free)(multi));
873 :
874 0 : space = FN(MULTI(BASE),get_space)(multi);
875 0 : total = isl_space_dim(space, isl_dim_out);
876 0 : space = isl_space_range_factor_domain(space);
877 0 : keep = isl_space_dim(space, isl_dim_out);
878 0 : multi = FN(MULTI(BASE),drop_dims)(multi,
879 0 : isl_dim_out, keep, total - keep);
880 0 : multi = FN(MULTI(BASE),reset_space)(multi, space);
881 :
882 0 : return multi;
883 : }
884 :
885 : /* Given a function A -> [B -> C], extract the function A -> C.
886 : */
887 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
888 : __isl_take MULTI(BASE) *multi)
889 : {
890 : isl_space *space;
891 : int total, keep;
892 :
893 0 : if (!multi)
894 0 : return NULL;
895 0 : if (!isl_space_range_is_wrapping(multi->space))
896 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
897 : "range is not a product",
898 : return FN(MULTI(BASE),free)(multi));
899 :
900 0 : space = FN(MULTI(BASE),get_space)(multi);
901 0 : total = isl_space_dim(space, isl_dim_out);
902 0 : space = isl_space_range_factor_range(space);
903 0 : keep = isl_space_dim(space, isl_dim_out);
904 0 : multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
905 0 : multi = FN(MULTI(BASE),reset_space)(multi, space);
906 :
907 0 : return multi;
908 : }
909 :
910 : /* Given a function [B -> C], extract the function C.
911 : */
912 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)(
913 : __isl_take MULTI(BASE) *multi)
914 : {
915 : isl_space *space;
916 : int total, keep;
917 :
918 0 : if (!multi)
919 0 : return NULL;
920 0 : if (!isl_space_is_wrapping(multi->space))
921 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
922 : "not a product", return FN(MULTI(BASE),free)(multi));
923 :
924 0 : space = FN(MULTI(BASE),get_space)(multi);
925 0 : total = isl_space_dim(space, isl_dim_out);
926 0 : space = isl_space_factor_range(space);
927 0 : keep = isl_space_dim(space, isl_dim_out);
928 0 : multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
929 0 : multi = FN(MULTI(BASE),reset_space)(multi, space);
930 :
931 0 : return multi;
932 : }
933 :
934 : #ifndef NO_PRODUCT
935 : /* Given two MULTI(BASE)s A -> B and C -> D,
936 : * construct a MULTI(BASE) [A -> C] -> [B -> D].
937 : *
938 : * The parameters are assumed to have been aligned.
939 : *
940 : * If "multi1" and/or "multi2" has an explicit domain, then
941 : * intersect the domain of the result with these explicit domains.
942 : */
943 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),product_aligned)(
944 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
945 : {
946 : int i;
947 : EL *el;
948 : isl_space *space;
949 : MULTI(BASE) *res;
950 : int in1, in2, out1, out2;
951 :
952 0 : in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
953 0 : in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
954 0 : out1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
955 0 : out2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
956 0 : space = isl_space_product(FN(MULTI(BASE),get_space)(multi1),
957 : FN(MULTI(BASE),get_space)(multi2));
958 0 : res = FN(MULTI(BASE),alloc)(isl_space_copy(space));
959 0 : space = isl_space_domain(space);
960 :
961 0 : for (i = 0; i < out1; ++i) {
962 0 : el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
963 0 : el = FN(EL,insert_dims)(el, isl_dim_in, in1, in2);
964 0 : el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
965 0 : res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
966 : }
967 :
968 0 : for (i = 0; i < out2; ++i) {
969 0 : el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
970 0 : el = FN(EL,insert_dims)(el, isl_dim_in, 0, in1);
971 0 : el = FN(EL,reset_domain_space)(el, isl_space_copy(space));
972 0 : res = FN(FN(MULTI(BASE),set),BASE)(res, out1 + i, el);
973 : }
974 :
975 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi1) ||
976 0 : FN(MULTI(BASE),has_explicit_domain)(multi2))
977 0 : res = FN(MULTI(BASE),intersect_explicit_domain_product)(res,
978 : multi1, multi2);
979 :
980 0 : isl_space_free(space);
981 0 : FN(MULTI(BASE),free)(multi1);
982 0 : FN(MULTI(BASE),free)(multi2);
983 0 : return res;
984 : }
985 :
986 : /* Given two MULTI(BASE)s A -> B and C -> D,
987 : * construct a MULTI(BASE) [A -> C] -> [B -> D].
988 : */
989 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),product)(
990 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
991 : {
992 0 : return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
993 : &FN(MULTI(BASE),product_aligned));
994 : }
995 : #endif
996 :
997 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
998 : __isl_take MULTI(BASE) *multi)
999 : {
1000 0 : if (!multi)
1001 0 : return NULL;
1002 :
1003 0 : if (!multi->space->nested[1])
1004 0 : return multi;
1005 :
1006 0 : multi = FN(MULTI(BASE),cow)(multi);
1007 0 : if (!multi)
1008 0 : return NULL;
1009 :
1010 0 : multi->space = isl_space_flatten_range(multi->space);
1011 0 : if (!multi->space)
1012 0 : return FN(MULTI(BASE),free)(multi);
1013 :
1014 0 : return multi;
1015 : }
1016 :
1017 : /* Given two MULTI(BASE)s A -> B and C -> D,
1018 : * construct a MULTI(BASE) (A * C) -> (B, D).
1019 : */
1020 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
1021 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
1022 : {
1023 : MULTI(BASE) *multi;
1024 :
1025 0 : multi = FN(MULTI(BASE),range_product)(multi1, multi2);
1026 0 : multi = FN(MULTI(BASE),flatten_range)(multi);
1027 0 : return multi;
1028 : }
1029 :
1030 : /* Given two multi expressions, "multi1"
1031 : *
1032 : * [A] -> [B1 B2]
1033 : *
1034 : * where B2 starts at position "pos", and "multi2"
1035 : *
1036 : * [A] -> [D]
1037 : *
1038 : * return the multi expression
1039 : *
1040 : * [A] -> [B1 D B2]
1041 : */
1042 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
1043 : __isl_take MULTI(BASE) *multi1, unsigned pos,
1044 : __isl_take MULTI(BASE) *multi2)
1045 : {
1046 : MULTI(BASE) *res;
1047 : unsigned dim;
1048 :
1049 0 : if (!multi1 || !multi2)
1050 : goto error;
1051 :
1052 0 : dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
1053 0 : if (pos > dim)
1054 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
1055 : "index out of bounds", goto error);
1056 :
1057 0 : res = FN(MULTI(BASE),copy)(multi1);
1058 0 : res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
1059 0 : multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
1060 :
1061 0 : res = FN(MULTI(BASE),flat_range_product)(res, multi2);
1062 0 : res = FN(MULTI(BASE),flat_range_product)(res, multi1);
1063 :
1064 0 : return res;
1065 : error:
1066 0 : FN(MULTI(BASE),free)(multi1);
1067 0 : FN(MULTI(BASE),free)(multi2);
1068 0 : return NULL;
1069 : }
1070 :
1071 : #ifndef NO_SPLICE
1072 : /* Given two multi expressions, "multi1"
1073 : *
1074 : * [A1 A2] -> [B1 B2]
1075 : *
1076 : * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
1077 : * and "multi2"
1078 : *
1079 : * [C] -> [D]
1080 : *
1081 : * return the multi expression
1082 : *
1083 : * [A1 C A2] -> [B1 D B2]
1084 : *
1085 : * We first insert input dimensions to obtain
1086 : *
1087 : * [A1 C A2] -> [B1 B2]
1088 : *
1089 : * and
1090 : *
1091 : * [A1 C A2] -> [D]
1092 : *
1093 : * and then apply range_splice.
1094 : */
1095 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),splice)(
1096 : __isl_take MULTI(BASE) *multi1, unsigned in_pos, unsigned out_pos,
1097 : __isl_take MULTI(BASE) *multi2)
1098 : {
1099 : unsigned n_in1;
1100 : unsigned n_in2;
1101 :
1102 0 : if (!multi1 || !multi2)
1103 : goto error;
1104 :
1105 0 : n_in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
1106 0 : if (in_pos > n_in1)
1107 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
1108 : "index out of bounds", goto error);
1109 :
1110 0 : n_in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
1111 :
1112 0 : multi1 = FN(MULTI(BASE),insert_dims)(multi1, isl_dim_in, in_pos, n_in2);
1113 0 : multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, n_in2,
1114 : n_in1 - in_pos);
1115 0 : multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, 0, in_pos);
1116 :
1117 0 : return FN(MULTI(BASE),range_splice)(multi1, out_pos, multi2);
1118 : error:
1119 0 : FN(MULTI(BASE),free)(multi1);
1120 0 : FN(MULTI(BASE),free)(multi2);
1121 0 : return NULL;
1122 : }
1123 : #endif
1124 :
1125 : /* Check that "multi1" and "multi2" live in the same space,
1126 : * reporting an error if they do not.
1127 : */
1128 0 : static isl_stat FN(MULTI(BASE),check_equal_space)(
1129 : __isl_keep MULTI(BASE) *multi1, __isl_keep MULTI(BASE) *multi2)
1130 : {
1131 : isl_bool equal;
1132 :
1133 0 : if (!multi1 || !multi2)
1134 0 : return isl_stat_error;
1135 :
1136 0 : equal = isl_space_is_equal(multi1->space, multi2->space);
1137 0 : if (equal < 0)
1138 0 : return isl_stat_error;
1139 0 : if (!equal)
1140 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
1141 : "spaces don't match", return isl_stat_error);
1142 :
1143 0 : return isl_stat_ok;
1144 : }
1145 :
1146 : /* This function is currently only used from isl_aff.c
1147 : */
1148 : static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
1149 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
1150 : __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
1151 : __attribute__ ((unused));
1152 :
1153 : /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
1154 : * return the result.
1155 : *
1156 : * If "multi2" has an explicit domain, then
1157 : * intersect the domain of the result with this explicit domain.
1158 : */
1159 0 : static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
1160 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
1161 : __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
1162 : {
1163 : int i;
1164 :
1165 0 : multi1 = FN(MULTI(BASE),cow)(multi1);
1166 0 : if (FN(MULTI(BASE),check_equal_space)(multi1, multi2) < 0)
1167 0 : goto error;
1168 :
1169 0 : for (i = 0; i < multi1->n; ++i) {
1170 0 : multi1->u.p[i] = fn(multi1->u.p[i],
1171 : FN(EL,copy)(multi2->u.p[i]));
1172 0 : if (!multi1->u.p[i])
1173 0 : goto error;
1174 : }
1175 :
1176 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi2))
1177 0 : multi1 = FN(MULTI(BASE),intersect_explicit_domain)(multi1,
1178 : multi2);
1179 :
1180 0 : FN(MULTI(BASE),free)(multi2);
1181 0 : return multi1;
1182 : error:
1183 0 : FN(MULTI(BASE),free)(multi1);
1184 0 : FN(MULTI(BASE),free)(multi2);
1185 0 : return NULL;
1186 : }
1187 :
1188 : /* Add "multi2" from "multi1" and return the result.
1189 : *
1190 : * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1191 : */
1192 0 : static __isl_give MULTI(BASE) *FN(MULTI(BASE),add_aligned)(
1193 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
1194 : {
1195 0 : return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,add));
1196 : }
1197 :
1198 : /* Add "multi2" from "multi1" and return the result.
1199 : */
1200 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),add)(__isl_take MULTI(BASE) *multi1,
1201 : __isl_take MULTI(BASE) *multi2)
1202 : {
1203 0 : return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
1204 : &FN(MULTI(BASE),add_aligned));
1205 : }
1206 :
1207 : /* Subtract "multi2" from "multi1" and return the result.
1208 : *
1209 : * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1210 : */
1211 0 : static __isl_give MULTI(BASE) *FN(MULTI(BASE),sub_aligned)(
1212 : __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
1213 : {
1214 0 : return FN(MULTI(BASE),bin_op)(multi1, multi2, &FN(EL,sub));
1215 : }
1216 :
1217 : /* Subtract "multi2" from "multi1" and return the result.
1218 : */
1219 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),sub)(__isl_take MULTI(BASE) *multi1,
1220 : __isl_take MULTI(BASE) *multi2)
1221 : {
1222 0 : return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
1223 : &FN(MULTI(BASE),sub_aligned));
1224 : }
1225 :
1226 : /* Multiply the elements of "multi" by "v" and return the result.
1227 : */
1228 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi,
1229 : __isl_take isl_val *v)
1230 : {
1231 : int i;
1232 :
1233 0 : if (!multi || !v)
1234 : goto error;
1235 :
1236 0 : if (isl_val_is_one(v)) {
1237 0 : isl_val_free(v);
1238 0 : return multi;
1239 : }
1240 :
1241 0 : if (!isl_val_is_rat(v))
1242 0 : isl_die(isl_val_get_ctx(v), isl_error_invalid,
1243 : "expecting rational factor", goto error);
1244 :
1245 0 : multi = FN(MULTI(BASE),cow)(multi);
1246 0 : if (!multi)
1247 0 : return NULL;
1248 :
1249 0 : for (i = 0; i < multi->n; ++i) {
1250 0 : multi->u.p[i] = FN(EL,scale_val)(multi->u.p[i],
1251 : isl_val_copy(v));
1252 0 : if (!multi->u.p[i])
1253 0 : goto error;
1254 : }
1255 :
1256 0 : isl_val_free(v);
1257 0 : return multi;
1258 : error:
1259 0 : isl_val_free(v);
1260 0 : return FN(MULTI(BASE),free)(multi);
1261 : }
1262 :
1263 : /* Divide the elements of "multi" by "v" and return the result.
1264 : */
1265 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_val)(
1266 : __isl_take MULTI(BASE) *multi, __isl_take isl_val *v)
1267 : {
1268 : int i;
1269 :
1270 0 : if (!multi || !v)
1271 : goto error;
1272 :
1273 0 : if (isl_val_is_one(v)) {
1274 0 : isl_val_free(v);
1275 0 : return multi;
1276 : }
1277 :
1278 0 : if (!isl_val_is_rat(v))
1279 0 : isl_die(isl_val_get_ctx(v), isl_error_invalid,
1280 : "expecting rational factor", goto error);
1281 0 : if (isl_val_is_zero(v))
1282 0 : isl_die(isl_val_get_ctx(v), isl_error_invalid,
1283 : "cannot scale down by zero", goto error);
1284 :
1285 0 : multi = FN(MULTI(BASE),cow)(multi);
1286 0 : if (!multi)
1287 0 : return NULL;
1288 :
1289 0 : for (i = 0; i < multi->n; ++i) {
1290 0 : multi->u.p[i] = FN(EL,scale_down_val)(multi->u.p[i],
1291 : isl_val_copy(v));
1292 0 : if (!multi->u.p[i])
1293 0 : goto error;
1294 : }
1295 :
1296 0 : isl_val_free(v);
1297 0 : return multi;
1298 : error:
1299 0 : isl_val_free(v);
1300 0 : return FN(MULTI(BASE),free)(multi);
1301 : }
1302 :
1303 : /* Multiply the elements of "multi" by the corresponding element of "mv"
1304 : * and return the result.
1305 : */
1306 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
1307 : __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1308 : {
1309 : int i;
1310 :
1311 0 : if (!multi || !mv)
1312 : goto error;
1313 :
1314 0 : if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1315 : mv->space, isl_dim_set))
1316 0 : isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1317 : "spaces don't match", goto error);
1318 :
1319 0 : multi = FN(MULTI(BASE),cow)(multi);
1320 0 : if (!multi)
1321 0 : goto error;
1322 :
1323 0 : for (i = 0; i < multi->n; ++i) {
1324 : isl_val *v;
1325 :
1326 0 : v = isl_multi_val_get_val(mv, i);
1327 0 : multi->u.p[i] = FN(EL,scale_val)(multi->u.p[i], v);
1328 0 : if (!multi->u.p[i])
1329 0 : goto error;
1330 : }
1331 :
1332 0 : isl_multi_val_free(mv);
1333 0 : return multi;
1334 : error:
1335 0 : isl_multi_val_free(mv);
1336 0 : return FN(MULTI(BASE),free)(multi);
1337 : }
1338 :
1339 : /* Divide the elements of "multi" by the corresponding element of "mv"
1340 : * and return the result.
1341 : */
1342 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_down_multi_val)(
1343 : __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1344 : {
1345 : int i;
1346 :
1347 0 : if (!multi || !mv)
1348 : goto error;
1349 :
1350 0 : if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1351 : mv->space, isl_dim_set))
1352 0 : isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1353 : "spaces don't match", goto error);
1354 :
1355 0 : multi = FN(MULTI(BASE),cow)(multi);
1356 0 : if (!multi)
1357 0 : return NULL;
1358 :
1359 0 : for (i = 0; i < multi->n; ++i) {
1360 : isl_val *v;
1361 :
1362 0 : v = isl_multi_val_get_val(mv, i);
1363 0 : multi->u.p[i] = FN(EL,scale_down_val)(multi->u.p[i], v);
1364 0 : if (!multi->u.p[i])
1365 0 : goto error;
1366 : }
1367 :
1368 0 : isl_multi_val_free(mv);
1369 0 : return multi;
1370 : error:
1371 0 : isl_multi_val_free(mv);
1372 0 : return FN(MULTI(BASE),free)(multi);
1373 : }
1374 :
1375 : /* Compute the residues of the elements of "multi" modulo
1376 : * the corresponding element of "mv" and return the result.
1377 : */
1378 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),mod_multi_val)(
1379 : __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
1380 : {
1381 : int i;
1382 :
1383 0 : if (!multi || !mv)
1384 : goto error;
1385 :
1386 0 : if (!isl_space_tuple_is_equal(multi->space, isl_dim_out,
1387 : mv->space, isl_dim_set))
1388 0 : isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
1389 : "spaces don't match", goto error);
1390 :
1391 0 : multi = FN(MULTI(BASE),cow)(multi);
1392 0 : if (!multi)
1393 0 : goto error;
1394 :
1395 0 : for (i = 0; i < multi->n; ++i) {
1396 : isl_val *v;
1397 :
1398 0 : v = isl_multi_val_get_val(mv, i);
1399 0 : multi->u.p[i] = FN(EL,mod_val)(multi->u.p[i], v);
1400 0 : if (!multi->u.p[i])
1401 0 : goto error;
1402 : }
1403 :
1404 0 : isl_multi_val_free(mv);
1405 0 : return multi;
1406 : error:
1407 0 : isl_multi_val_free(mv);
1408 0 : return FN(MULTI(BASE),free)(multi);
1409 : }
1410 :
1411 : #ifndef NO_MOVE_DIMS
1412 : /* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
1413 : * to dimensions of "dst_type" at "dst_pos".
1414 : *
1415 : * We only support moving input dimensions to parameters and vice versa.
1416 : */
1417 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi,
1418 : enum isl_dim_type dst_type, unsigned dst_pos,
1419 : enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1420 : {
1421 : int i;
1422 :
1423 0 : if (!multi)
1424 0 : return NULL;
1425 :
1426 0 : if (n == 0 &&
1427 0 : !isl_space_is_named_or_nested(multi->space, src_type) &&
1428 0 : !isl_space_is_named_or_nested(multi->space, dst_type))
1429 0 : return multi;
1430 :
1431 0 : if (dst_type == isl_dim_out || src_type == isl_dim_out)
1432 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1433 : "cannot move output/set dimension",
1434 : return FN(MULTI(BASE),free)(multi));
1435 0 : if (dst_type == isl_dim_div || src_type == isl_dim_div)
1436 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1437 : "cannot move divs",
1438 : return FN(MULTI(BASE),free)(multi));
1439 0 : if (src_pos + n > isl_space_dim(multi->space, src_type))
1440 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1441 : "range out of bounds",
1442 : return FN(MULTI(BASE),free)(multi));
1443 0 : if (dst_type == src_type)
1444 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_unsupported,
1445 : "moving dims within the same type not supported",
1446 : return FN(MULTI(BASE),free)(multi));
1447 :
1448 0 : multi = FN(MULTI(BASE),cow)(multi);
1449 0 : if (!multi)
1450 0 : return NULL;
1451 :
1452 0 : multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos,
1453 : src_type, src_pos, n);
1454 0 : if (!multi->space)
1455 0 : return FN(MULTI(BASE),free)(multi);
1456 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi))
1457 0 : multi = FN(MULTI(BASE),move_explicit_domain_dims)(multi,
1458 : dst_type, dst_pos, src_type, src_pos, n);
1459 0 : if (!multi)
1460 0 : return NULL;
1461 :
1462 0 : for (i = 0; i < multi->n; ++i) {
1463 0 : multi->u.p[i] = FN(EL,move_dims)(multi->u.p[i],
1464 : dst_type, dst_pos,
1465 : src_type, src_pos, n);
1466 0 : if (!multi->u.p[i])
1467 0 : return FN(MULTI(BASE),free)(multi);
1468 : }
1469 :
1470 0 : return multi;
1471 : }
1472 : #endif
1473 :
1474 : /* Convert a multiple expression defined over a parameter domain
1475 : * into one that is defined over a zero-dimensional set.
1476 : */
1477 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
1478 : __isl_take MULTI(BASE) *multi)
1479 : {
1480 : isl_space *space;
1481 :
1482 0 : if (!multi)
1483 0 : return NULL;
1484 0 : if (!isl_space_is_set(multi->space))
1485 0 : isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1486 : "not living in a set space",
1487 : return FN(MULTI(BASE),free)(multi));
1488 :
1489 0 : space = FN(MULTI(BASE),get_space)(multi);
1490 0 : space = isl_space_from_range(space);
1491 0 : multi = FN(MULTI(BASE),reset_space)(multi, space);
1492 :
1493 0 : return multi;
1494 : }
1495 :
1496 : /* Are "multi1" and "multi2" obviously equal?
1497 : */
1498 0 : isl_bool FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
1499 : __isl_keep MULTI(BASE) *multi2)
1500 : {
1501 : int i;
1502 : isl_bool equal;
1503 :
1504 0 : if (!multi1 || !multi2)
1505 0 : return isl_bool_error;
1506 0 : if (multi1->n != multi2->n)
1507 0 : return isl_bool_false;
1508 0 : equal = isl_space_is_equal(multi1->space, multi2->space);
1509 0 : if (equal < 0 || !equal)
1510 0 : return equal;
1511 :
1512 0 : for (i = 0; i < multi1->n; ++i) {
1513 0 : equal = FN(EL,plain_is_equal)(multi1->u.p[i], multi2->u.p[i]);
1514 0 : if (equal < 0 || !equal)
1515 0 : return equal;
1516 : }
1517 :
1518 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi1) ||
1519 0 : FN(MULTI(BASE),has_explicit_domain)(multi2)) {
1520 0 : equal = FN(MULTI(BASE),equal_explicit_domain)(multi1, multi2);
1521 0 : if (equal < 0 || !equal)
1522 0 : return equal;
1523 : }
1524 :
1525 0 : return isl_bool_true;
1526 : }
1527 :
1528 : /* Does "multi" involve any NaNs?
1529 : */
1530 0 : isl_bool FN(MULTI(BASE),involves_nan)(__isl_keep MULTI(BASE) *multi)
1531 : {
1532 : int i;
1533 :
1534 0 : if (!multi)
1535 0 : return isl_bool_error;
1536 0 : if (multi->n == 0)
1537 0 : return isl_bool_false;
1538 :
1539 0 : for (i = 0; i < multi->n; ++i) {
1540 0 : isl_bool has_nan = FN(EL,involves_nan)(multi->u.p[i]);
1541 0 : if (has_nan < 0 || has_nan)
1542 0 : return has_nan;
1543 : }
1544 :
1545 0 : return isl_bool_false;
1546 : }
1547 :
1548 : #ifndef NO_DOMAIN
1549 : /* Return the shared domain of the elements of "multi".
1550 : *
1551 : * If "multi" has an explicit domain, then return this domain.
1552 : */
1553 0 : __isl_give isl_set *FN(MULTI(BASE),domain)(__isl_take MULTI(BASE) *multi)
1554 : {
1555 : int i;
1556 : isl_set *dom;
1557 :
1558 0 : if (!multi)
1559 0 : return NULL;
1560 :
1561 0 : if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
1562 0 : dom = FN(MULTI(BASE),get_explicit_domain)(multi);
1563 0 : FN(MULTI(BASE),free)(multi);
1564 0 : return dom;
1565 : }
1566 :
1567 0 : dom = isl_set_universe(FN(MULTI(BASE),get_domain_space)(multi));
1568 0 : for (i = 0; i < multi->n; ++i) {
1569 : isl_set *dom_i;
1570 :
1571 0 : dom_i = FN(EL,domain)(FN(FN(MULTI(BASE),get),BASE)(multi, i));
1572 0 : dom = isl_set_intersect(dom, dom_i);
1573 : }
1574 :
1575 0 : FN(MULTI(BASE),free)(multi);
1576 0 : return dom;
1577 : }
1578 : #endif
1579 :
1580 : #ifndef NO_NEG
1581 : /* Return the opposite of "multi".
1582 : */
1583 0 : __isl_give MULTI(BASE) *FN(MULTI(BASE),neg)(__isl_take MULTI(BASE) *multi)
1584 : {
1585 : int i;
1586 :
1587 0 : multi = FN(MULTI(BASE),cow)(multi);
1588 0 : if (!multi)
1589 0 : return NULL;
1590 :
1591 0 : for (i = 0; i < multi->n; ++i) {
1592 0 : multi->u.p[i] = FN(EL,neg)(multi->u.p[i]);
1593 0 : if (!multi->u.p[i])
1594 0 : return FN(MULTI(BASE),free)(multi);
1595 : }
1596 :
1597 0 : return multi;
1598 : }
1599 : #endif
|