add isl_multi_*_find_dim_by_id
[isl.git] / isl_multi_templ.c
blob6923001f941b0e2bc5504a98a7e678ca1d472f00
1 /*
2 * Copyright 2011 Sven Verdoolaege
3 * Copyright 2012-2013 Ecole Normale Superieure
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege,
8 * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
9 */
11 #include <isl_space_private.h>
12 #include <isl/set.h>
13 #include <isl_reordering.h>
15 #define xCAT(A,B) A ## B
16 #define CAT(A,B) xCAT(A,B)
17 #undef EL
18 #define EL CAT(isl_,BASE)
19 #define xFN(TYPE,NAME) TYPE ## _ ## NAME
20 #define FN(TYPE,NAME) xFN(TYPE,NAME)
21 #define xMULTI(BASE) isl_multi_ ## BASE
22 #define MULTI(BASE) xMULTI(BASE)
23 #define MULTI_NAME(BASE) "isl_multi_" #BASE
24 #define xLIST(EL) EL ## _list
25 #define LIST(EL) xLIST(EL)
27 isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi)
29 return multi ? isl_space_get_ctx(multi->space) : NULL;
32 __isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi)
34 return multi ? isl_space_copy(multi->space) : NULL;
37 __isl_give isl_space *FN(MULTI(BASE),get_domain_space)(
38 __isl_keep MULTI(BASE) *multi)
40 return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL;
43 __isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space)
45 isl_ctx *ctx;
46 int n;
47 MULTI(BASE) *multi;
49 if (!space)
50 return NULL;
52 ctx = isl_space_get_ctx(space);
53 n = isl_space_dim(space, isl_dim_out);
54 multi = isl_calloc(ctx, MULTI(BASE),
55 sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *));
56 if (!multi)
57 goto error;
59 multi->space = space;
60 multi->n = n;
61 multi->ref = 1;
62 return multi;
63 error:
64 isl_space_free(space);
65 return NULL;
68 __isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
70 int i;
71 MULTI(BASE) *dup;
73 if (!multi)
74 return NULL;
76 dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
77 if (!dup)
78 return NULL;
80 for (i = 0; i < multi->n; ++i)
81 dup = FN(FN(MULTI(BASE),set),BASE)(dup, i,
82 FN(EL,copy)(multi->p[i]));
84 return dup;
87 __isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
89 if (!multi)
90 return NULL;
92 if (multi->ref == 1)
93 return multi;
95 multi->ref--;
96 return FN(MULTI(BASE),dup)(multi);
99 __isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
101 if (!multi)
102 return NULL;
104 multi->ref++;
105 return multi;
108 void *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
110 int i;
112 if (!multi)
113 return NULL;
115 if (--multi->ref > 0)
116 return NULL;
118 isl_space_free(multi->space);
119 for (i = 0; i < multi->n; ++i)
120 FN(EL,free)(multi->p[i]);
121 free(multi);
123 return NULL;
126 __isl_give MULTI(BASE) *FN(MULTI(BASE),insert_dims)(
127 __isl_take MULTI(BASE) *multi,
128 enum isl_dim_type type, unsigned first, unsigned n)
130 int i;
132 if (!multi)
133 return NULL;
134 if (type == isl_dim_out)
135 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
136 "cannot insert output/set dimensions",
137 return FN(MULTI(BASE),free)(multi));
138 if (n == 0 && !isl_space_is_named_or_nested(multi->space, type))
139 return multi;
141 multi = FN(MULTI(BASE),cow)(multi);
142 if (!multi)
143 return NULL;
145 multi->space = isl_space_insert_dims(multi->space, type, first, n);
146 if (!multi->space)
147 return FN(MULTI(BASE),free)(multi);
149 for (i = 0; i < multi->n; ++i) {
150 multi->p[i] = FN(EL,insert_dims)(multi->p[i], type, first, n);
151 if (!multi->p[i])
152 return FN(MULTI(BASE),free)(multi);
155 return multi;
158 __isl_give MULTI(BASE) *FN(MULTI(BASE),add_dims)(__isl_take MULTI(BASE) *multi,
159 enum isl_dim_type type, unsigned n)
161 unsigned pos;
163 pos = FN(MULTI(BASE),dim)(multi, type);
165 return FN(MULTI(BASE),insert_dims)(multi, type, pos, n);
168 unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
169 enum isl_dim_type type)
171 return multi ? isl_space_dim(multi->space, type) : 0;
174 /* Return the position of the first dimension of "type" with id "id".
175 * Return -1 if there is no such dimension.
177 int FN(MULTI(BASE),find_dim_by_id)(__isl_keep MULTI(BASE) *multi,
178 enum isl_dim_type type, __isl_keep isl_id *id)
180 if (!multi)
181 return -1;
182 return isl_space_find_dim_by_id(multi->space, type, id);
185 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)(
186 __isl_take MULTI(BASE) *multi,
187 enum isl_dim_type type, unsigned pos, const char *s)
189 int i;
191 multi = FN(MULTI(BASE),cow)(multi);
192 if (!multi)
193 return NULL;
195 multi->space = isl_space_set_dim_name(multi->space, type, pos, s);
196 if (!multi->space)
197 return FN(MULTI(BASE),free)(multi);
199 if (type == isl_dim_out)
200 return multi;
201 for (i = 0; i < multi->n; ++i) {
202 multi->p[i] = FN(EL,set_dim_name)(multi->p[i], type, pos, s);
203 if (!multi->p[i])
204 return FN(MULTI(BASE),free)(multi);
207 return multi;
210 const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi,
211 enum isl_dim_type type)
213 return multi ? isl_space_get_tuple_name(multi->space, type) : NULL;
216 /* Does the specified tuple have an id?
218 int FN(MULTI(BASE),has_tuple_id)(__isl_keep MULTI(BASE) *multi,
219 enum isl_dim_type type)
221 return multi ? isl_space_has_tuple_id(multi->space, type) : -1;
224 /* Return the id of the specified tuple.
226 __isl_give isl_id *FN(MULTI(BASE),get_tuple_id)(__isl_keep MULTI(BASE) *multi,
227 enum isl_dim_type type)
229 return multi ? isl_space_get_tuple_id(multi->space, type) : NULL;
232 __isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
233 int pos)
235 isl_ctx *ctx;
237 if (!multi)
238 return NULL;
239 ctx = FN(MULTI(BASE),get_ctx)(multi);
240 if (pos < 0 || pos >= multi->n)
241 isl_die(ctx, isl_error_invalid,
242 "index out of bounds", return NULL);
243 return FN(EL,copy)(multi->p[pos]);
246 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
247 __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
249 isl_space *multi_space = NULL;
250 isl_space *el_space = NULL;
251 int match;
253 multi = FN(MULTI(BASE),cow)(multi);
254 if (!multi || !el)
255 goto error;
257 multi_space = FN(MULTI(BASE),get_space)(multi);
258 match = FN(EL,matching_params)(el, multi_space);
259 if (match < 0)
260 goto error;
261 if (!match) {
262 multi = FN(MULTI(BASE),align_params)(multi,
263 FN(EL,get_space)(el));
264 isl_space_free(multi_space);
265 multi_space = FN(MULTI(BASE),get_space)(multi);
266 el = FN(EL,align_params)(el, isl_space_copy(multi_space));
268 if (FN(EL,check_match_domain_space)(el, multi_space) < 0)
269 goto error;
271 if (pos < 0 || pos >= multi->n)
272 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
273 "index out of bounds", goto error);
275 FN(EL,free)(multi->p[pos]);
276 multi->p[pos] = el;
278 isl_space_free(multi_space);
279 isl_space_free(el_space);
281 return multi;
282 error:
283 FN(MULTI(BASE),free)(multi);
284 FN(EL,free)(el);
285 isl_space_free(multi_space);
286 isl_space_free(el_space);
287 return NULL;
290 /* Reset the space of "multi". This function is called from isl_pw_templ.c
291 * and doesn't know if the space of an element object is represented
292 * directly or through its domain. It therefore passes along both,
293 * which we pass along to the element function since we don't how
294 * that is represented either.
296 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
297 __isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
298 __isl_take isl_space *domain)
300 int i;
302 multi = FN(MULTI(BASE),cow)(multi);
303 if (!multi || !space || !domain)
304 goto error;
306 for (i = 0; i < multi->n; ++i) {
307 multi->p[i] = FN(EL,reset_domain_space)(multi->p[i],
308 isl_space_copy(domain));
309 if (!multi->p[i])
310 goto error;
312 isl_space_free(domain);
313 isl_space_free(multi->space);
314 multi->space = space;
316 return multi;
317 error:
318 isl_space_free(domain);
319 isl_space_free(space);
320 FN(MULTI(BASE),free)(multi);
321 return NULL;
324 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
325 __isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
327 isl_space *space;
329 space = isl_space_extend_domain_with_range(isl_space_copy(domain),
330 isl_space_copy(multi->space));
331 return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
334 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
335 __isl_take MULTI(BASE) *multi, __isl_take isl_space *space)
337 isl_space *domain;
339 domain = isl_space_domain(isl_space_copy(space));
340 return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
343 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_name)(
344 __isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
345 const char *s)
347 isl_space *space;
349 multi = FN(MULTI(BASE),cow)(multi);
350 if (!multi)
351 return NULL;
353 space = FN(MULTI(BASE),get_space)(multi);
354 space = isl_space_set_tuple_name(space, type, s);
356 return FN(MULTI(BASE),reset_space)(multi, space);
359 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_id)(
360 __isl_take MULTI(BASE) *multi, enum isl_dim_type type,
361 __isl_take isl_id *id)
363 isl_space *space;
365 multi = FN(MULTI(BASE),cow)(multi);
366 if (!multi)
367 return isl_id_free(id);
369 space = FN(MULTI(BASE),get_space)(multi);
370 space = isl_space_set_tuple_id(space, type, id);
372 return FN(MULTI(BASE),reset_space)(multi, space);
375 /* Drop the id on the specified tuple.
377 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_tuple_id)(
378 __isl_take MULTI(BASE) *multi, enum isl_dim_type type)
380 isl_space *space;
382 if (!multi)
383 return NULL;
384 if (!FN(MULTI(BASE),has_tuple_id)(multi, type))
385 return multi;
387 multi = FN(MULTI(BASE),cow)(multi);
388 if (!multi)
389 return NULL;
391 space = FN(MULTI(BASE),get_space)(multi);
392 space = isl_space_reset_tuple_id(space, type);
394 return FN(MULTI(BASE),reset_space)(multi, space);
397 __isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
398 __isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp)
400 int i;
402 multi = FN(MULTI(BASE),cow)(multi);
403 if (!multi || !exp)
404 goto error;
406 for (i = 0; i < multi->n; ++i) {
407 multi->p[i] = FN(EL,realign_domain)(multi->p[i],
408 isl_reordering_copy(exp));
409 if (!multi->p[i])
410 goto error;
413 multi = FN(MULTI(BASE),reset_domain_space)(multi,
414 isl_space_copy(exp->dim));
416 isl_reordering_free(exp);
417 return multi;
418 error:
419 isl_reordering_free(exp);
420 FN(MULTI(BASE),free)(multi);
421 return NULL;
424 /* Align the parameters of "multi" to those of "model".
426 __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
427 __isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
429 isl_ctx *ctx;
431 if (!multi || !model)
432 goto error;
434 ctx = isl_space_get_ctx(model);
435 if (!isl_space_has_named_params(model))
436 isl_die(ctx, isl_error_invalid,
437 "model has unnamed parameters", goto error);
438 if (!isl_space_has_named_params(multi->space))
439 isl_die(ctx, isl_error_invalid,
440 "input has unnamed parameters", goto error);
441 if (!isl_space_match(multi->space, isl_dim_param,
442 model, isl_dim_param)) {
443 isl_reordering *exp;
445 model = isl_space_params(model);
446 exp = isl_parameter_alignment_reordering(multi->space, model);
447 exp = isl_reordering_extend_space(exp,
448 FN(MULTI(BASE),get_domain_space)(multi));
449 multi = FN(MULTI(BASE),realign_domain)(multi, exp);
452 isl_space_free(model);
453 return multi;
454 error:
455 isl_space_free(model);
456 FN(MULTI(BASE),free)(multi);
457 return NULL;
460 #ifndef NO_GIST
461 static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_set_and)(
462 __isl_take MULTI(BASE) *multi, __isl_take isl_set *set,
463 __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi,
464 __isl_take isl_set *set))
466 isl_ctx *ctx;
468 if (!multi || !set)
469 goto error;
470 if (isl_space_match(multi->space, isl_dim_param,
471 set->dim, isl_dim_param))
472 return fn(multi, set);
473 ctx = FN(MULTI(BASE),get_ctx)(multi);
474 if (!isl_space_has_named_params(multi->space) ||
475 !isl_space_has_named_params(set->dim))
476 isl_die(ctx, isl_error_invalid,
477 "unaligned unnamed parameters", goto error);
478 multi = FN(MULTI(BASE),align_params)(multi, isl_set_get_space(set));
479 set = isl_set_align_params(set, FN(MULTI(BASE),get_space)(multi));
480 return fn(multi, set);
481 error:
482 FN(MULTI(BASE),free)(multi);
483 isl_set_free(set);
484 return NULL;
487 __isl_give MULTI(BASE) *FN(MULTI(BASE),gist_aligned)(
488 __isl_take MULTI(BASE) *multi, __isl_take isl_set *context)
490 int i;
492 multi = FN(MULTI(BASE),cow)(multi);
493 if (!multi || !context)
494 goto error;
496 for (i = 0; i < multi->n; ++i) {
497 multi->p[i] = FN(EL,gist)(multi->p[i], isl_set_copy(context));
498 if (!multi->p[i])
499 goto error;
502 isl_set_free(context);
503 return multi;
504 error:
505 isl_set_free(context);
506 FN(MULTI(BASE),free)(multi);
507 return NULL;
510 __isl_give MULTI(BASE) *FN(MULTI(BASE),gist)(__isl_take MULTI(BASE) *multi,
511 __isl_take isl_set *context)
513 return FN(MULTI(BASE),align_params_multi_set_and)(multi, context,
514 &FN(MULTI(BASE),gist_aligned));
517 __isl_give MULTI(BASE) *FN(MULTI(BASE),gist_params)(
518 __isl_take MULTI(BASE) *multi, __isl_take isl_set *context)
520 isl_space *space = FN(MULTI(BASE),get_domain_space)(multi);
521 isl_set *dom_context = isl_set_universe(space);
522 dom_context = isl_set_intersect_params(dom_context, context);
523 return FN(MULTI(BASE),gist)(multi, dom_context);
525 #endif
527 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
528 __isl_take isl_space *space, __isl_take LIST(EL) *list)
530 int i;
531 int n;
532 isl_ctx *ctx;
533 MULTI(BASE) *multi;
535 if (!space || !list)
536 goto error;
538 ctx = isl_space_get_ctx(space);
539 n = FN(FN(LIST(EL),n),BASE)(list);
540 if (n != isl_space_dim(space, isl_dim_out))
541 isl_die(ctx, isl_error_invalid,
542 "invalid number of elements in list", goto error);
544 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
545 for (i = 0; i < n; ++i) {
546 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
547 FN(FN(LIST(EL),get),BASE)(list, i));
550 isl_space_free(space);
551 FN(LIST(EL),free)(list);
552 return multi;
553 error:
554 isl_space_free(space);
555 FN(LIST(EL),free)(list);
556 return NULL;
559 #ifndef NO_IDENTITY
560 /* Create a multi expression in the given space that maps each
561 * input dimension to the corresponding output dimension.
563 __isl_give MULTI(BASE) *FN(MULTI(BASE),identity)(__isl_take isl_space *space)
565 int i, n;
566 isl_local_space *ls;
567 MULTI(BASE) *multi;
569 if (!space)
570 return NULL;
572 if (isl_space_is_set(space))
573 isl_die(isl_space_get_ctx(space), isl_error_invalid,
574 "expecting map space", goto error);
576 n = isl_space_dim(space, isl_dim_out);
577 if (n != isl_space_dim(space, isl_dim_in))
578 isl_die(isl_space_get_ctx(space), isl_error_invalid,
579 "number of input and output dimensions needs to be "
580 "the same", goto error);
582 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
584 if (!n) {
585 isl_space_free(space);
586 return multi;
589 space = isl_space_domain(space);
590 ls = isl_local_space_from_space(space);
592 for (i = 0; i < n; ++i) {
593 EL *el;
594 el = FN(EL,var_on_domain)(isl_local_space_copy(ls),
595 isl_dim_set, i);
596 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, el);
599 isl_local_space_free(ls);
601 return multi;
602 error:
603 isl_space_free(space);
604 return NULL;
606 #endif
608 /* Construct a multi expression in the given space with value zero in
609 * each of the output dimensions.
611 __isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space)
613 int n;
614 MULTI(BASE) *multi;
616 if (!space)
617 return NULL;
619 n = isl_space_dim(space , isl_dim_out);
620 multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
622 if (!n)
623 isl_space_free(space);
624 else {
625 int i;
626 isl_local_space *ls;
627 EL *el;
629 space = isl_space_domain(space);
630 ls = isl_local_space_from_space(space);
631 el = FN(EL,zero_on_domain)(ls);
633 for (i = 0; i < n; ++i)
634 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
635 FN(EL,copy)(el));
637 FN(EL,free)(el);
640 return multi;
643 #ifndef NO_FROM_BASE
644 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),BASE)(__isl_take EL *el)
646 MULTI(BASE) *multi;
648 multi = FN(MULTI(BASE),alloc)(FN(EL,get_space)(el));
649 multi = FN(FN(MULTI(BASE),set),BASE)(multi, 0, el);
651 return multi;
653 #endif
655 __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
656 __isl_take MULTI(BASE) *multi,
657 enum isl_dim_type type, unsigned first, unsigned n)
659 int i;
660 unsigned dim;
662 multi = FN(MULTI(BASE),cow)(multi);
663 if (!multi)
664 return NULL;
666 dim = FN(MULTI(BASE),dim)(multi, type);
667 if (first + n > dim || first + n < first)
668 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
669 "index out of bounds",
670 return FN(MULTI(BASE),cow)(multi));
672 multi->space = isl_space_drop_dims(multi->space, type, first, n);
673 if (!multi->space)
674 return FN(MULTI(BASE),cow)(multi);
676 if (type == isl_dim_out) {
677 for (i = 0; i < n; ++i)
678 FN(EL,free)(multi->p[first + i]);
679 for (i = first; i + n < multi->n; ++i)
680 multi->p[i] = multi->p[i + n];
681 multi->n -= n;
683 return multi;
686 for (i = 0; i < multi->n; ++i) {
687 multi->p[i] = FN(EL,drop_dims)(multi->p[i], type, first, n);
688 if (!multi->p[i])
689 return FN(MULTI(BASE),cow)(multi);
692 return multi;
695 /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
697 static __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params_multi_multi_and)(
698 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
699 __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi1,
700 __isl_take MULTI(BASE) *multi2))
702 isl_ctx *ctx;
704 if (!multi1 || !multi2)
705 goto error;
706 if (isl_space_match(multi1->space, isl_dim_param,
707 multi2->space, isl_dim_param))
708 return fn(multi1, multi2);
709 ctx = FN(MULTI(BASE),get_ctx)(multi1);
710 if (!isl_space_has_named_params(multi1->space) ||
711 !isl_space_has_named_params(multi2->space))
712 isl_die(ctx, isl_error_invalid,
713 "unaligned unnamed parameters", goto error);
714 multi1 = FN(MULTI(BASE),align_params)(multi1,
715 FN(MULTI(BASE),get_space)(multi2));
716 multi2 = FN(MULTI(BASE),align_params)(multi2,
717 FN(MULTI(BASE),get_space)(multi1));
718 return fn(multi1, multi2);
719 error:
720 FN(MULTI(BASE),free)(multi1);
721 FN(MULTI(BASE),free)(multi2);
722 return NULL;
725 /* Given two MULTI(BASE)s A -> B and C -> D,
726 * construct a MULTI(BASE) (A * C) -> (B, D).
728 * The parameters are assumed to have been aligned.
730 static __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product_aligned)(
731 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
733 int i, n1, n2;
734 EL *el;
735 isl_space *space;
736 MULTI(BASE) *res;
738 if (!multi1 || !multi2)
739 goto error;
741 space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
742 FN(MULTI(BASE),get_space)(multi2));
743 res = FN(MULTI(BASE),alloc)(space);
745 n1 = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
746 n2 = FN(MULTI(BASE),dim)(multi2, isl_dim_out);
748 for (i = 0; i < n1; ++i) {
749 el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
750 res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
753 for (i = 0; i < n2; ++i) {
754 el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
755 res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
758 FN(MULTI(BASE),free)(multi1);
759 FN(MULTI(BASE),free)(multi2);
760 return res;
761 error:
762 FN(MULTI(BASE),free)(multi1);
763 FN(MULTI(BASE),free)(multi2);
764 return NULL;
767 /* Given two MULTI(BASE)s A -> B and C -> D,
768 * construct a MULTI(BASE) (A * C) -> (B, D).
770 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
771 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
773 return FN(MULTI(BASE),align_params_multi_multi_and)(multi1, multi2,
774 &FN(MULTI(BASE),range_product_aligned));
777 __isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
778 __isl_take MULTI(BASE) *multi)
780 if (!multi)
781 return NULL;
783 if (!multi->space->nested[1])
784 return multi;
786 multi = FN(MULTI(BASE),cow)(multi);
787 if (!multi)
788 return NULL;
790 multi->space = isl_space_flatten_range(multi->space);
791 if (!multi->space)
792 return FN(MULTI(BASE),free)(multi);
794 return multi;
797 /* Given two MULTI(BASE)s A -> B and C -> D,
798 * construct a MULTI(BASE) (A * C) -> [B -> D].
800 __isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
801 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
803 MULTI(BASE) *multi;
805 multi = FN(MULTI(BASE),range_product)(multi1, multi2);
806 multi = FN(MULTI(BASE),flatten_range)(multi);
807 return multi;
810 /* Given two multi expressions, "multi1"
812 * [A] -> [B1 B2]
814 * where B2 starts at position "pos", and "multi2"
816 * [A] -> [D]
818 * return the multi expression
820 * [A] -> [B1 D B2]
822 __isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
823 __isl_take MULTI(BASE) *multi1, unsigned pos,
824 __isl_take MULTI(BASE) *multi2)
826 MULTI(BASE) *res;
827 unsigned dim;
829 if (!multi1 || !multi2)
830 goto error;
832 dim = FN(MULTI(BASE),dim)(multi1, isl_dim_out);
833 if (pos > dim)
834 isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
835 "index out of bounds", goto error);
837 res = FN(MULTI(BASE),copy)(multi1);
838 res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
839 multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
841 res = FN(MULTI(BASE),flat_range_product)(res, multi2);
842 res = FN(MULTI(BASE),flat_range_product)(res, multi1);
844 return res;
845 error:
846 FN(MULTI(BASE),free)(multi1);
847 FN(MULTI(BASE),free)(multi2);
848 return NULL;
851 /* Given two multi expressions, "multi1"
853 * [A1 A2] -> [B1 B2]
855 * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
856 * and "multi2"
858 * [C] -> [D]
860 * return the multi expression
862 * [A1 C A2] -> [B1 D B2]
864 * We first insert input dimensions to obtain
866 * [A1 C A2] -> [B1 B2]
868 * and
870 * [A1 C A2] -> [D]
872 * and then apply range_splice.
874 __isl_give MULTI(BASE) *FN(MULTI(BASE),splice)(
875 __isl_take MULTI(BASE) *multi1, unsigned in_pos, unsigned out_pos,
876 __isl_take MULTI(BASE) *multi2)
878 unsigned n_in1;
879 unsigned n_in2;
881 if (!multi1 || !multi2)
882 goto error;
884 n_in1 = FN(MULTI(BASE),dim)(multi1, isl_dim_in);
885 if (in_pos > n_in1)
886 isl_die(FN(MULTI(BASE),get_ctx)(multi1), isl_error_invalid,
887 "index out of bounds", goto error);
889 n_in2 = FN(MULTI(BASE),dim)(multi2, isl_dim_in);
891 multi1 = FN(MULTI(BASE),insert_dims)(multi1, isl_dim_in, in_pos, n_in2);
892 multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, n_in2,
893 n_in1 - in_pos);
894 multi2 = FN(MULTI(BASE),insert_dims)(multi2, isl_dim_in, 0, in_pos);
896 return FN(MULTI(BASE),range_splice)(multi1, out_pos, multi2);
897 error:
898 FN(MULTI(BASE),free)(multi1);
899 FN(MULTI(BASE),free)(multi2);
900 return NULL;
903 /* This function is currently only used from isl_aff.c
905 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
906 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
907 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
908 __attribute__ ((unused));
910 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
911 * return the result.
913 static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
914 __isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
915 __isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
917 int i;
918 isl_ctx *ctx;
920 multi1 = FN(MULTI(BASE),cow)(multi1);
921 if (!multi1 || !multi2)
922 goto error;
924 ctx = FN(MULTI(BASE),get_ctx)(multi1);
925 if (!isl_space_is_equal(multi1->space, multi2->space))
926 isl_die(ctx, isl_error_invalid,
927 "spaces don't match", goto error);
929 for (i = 0; i < multi1->n; ++i) {
930 multi1->p[i] = fn(multi1->p[i], FN(EL,copy)(multi2->p[i]));
931 if (!multi1->p[i])
932 goto error;
935 FN(MULTI(BASE),free)(multi2);
936 return multi1;
937 error:
938 FN(MULTI(BASE),free)(multi1);
939 FN(MULTI(BASE),free)(multi2);
940 return NULL;
943 /* Multiply the elements of "multi" by "v" and return the result.
945 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_val)(__isl_take MULTI(BASE) *multi,
946 __isl_take isl_val *v)
948 int i;
950 if (!multi || !v)
951 goto error;
953 if (isl_val_is_one(v)) {
954 isl_val_free(v);
955 return multi;
958 if (!isl_val_is_rat(v))
959 isl_die(isl_val_get_ctx(v), isl_error_invalid,
960 "expecting rational factor", goto error);
962 multi = FN(MULTI(BASE),cow)(multi);
963 if (!multi)
964 return NULL;
966 for (i = 0; i < multi->n; ++i) {
967 multi->p[i] = FN(EL,scale_val)(multi->p[i], isl_val_copy(v));
968 if (!multi->p[i])
969 goto error;
972 isl_val_free(v);
973 return multi;
974 error:
975 isl_val_free(v);
976 return FN(MULTI(BASE),free)(multi);
979 /* Multiply the elements of "multi" by the corresponding element of "mv"
980 * and return the result.
982 __isl_give MULTI(BASE) *FN(MULTI(BASE),scale_multi_val)(
983 __isl_take MULTI(BASE) *multi, __isl_take isl_multi_val *mv)
985 int i;
987 if (!multi || !mv)
988 goto error;
990 if (!isl_space_tuple_match(multi->space, isl_dim_out,
991 mv->space, isl_dim_set))
992 isl_die(isl_multi_val_get_ctx(mv), isl_error_invalid,
993 "spaces don't match", goto error);
995 multi = FN(MULTI(BASE),cow)(multi);
996 if (!multi)
997 return NULL;
999 for (i = 0; i < multi->n; ++i) {
1000 isl_val *v;
1002 v = isl_multi_val_get_val(mv, i);
1003 multi->p[i] = FN(EL,scale_val)(multi->p[i], v);
1004 if (!multi->p[i])
1005 goto error;
1008 isl_multi_val_free(mv);
1009 return multi;
1010 error:
1011 isl_multi_val_free(mv);
1012 return FN(MULTI(BASE),free)(multi);
1015 #ifndef NO_MOVE_DIMS
1016 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
1017 * to dimensions of "dst_type" at "dst_pos".
1019 * We only support moving input dimensions to parameters and vice versa.
1021 __isl_give MULTI(BASE) *FN(MULTI(BASE),move_dims)(__isl_take MULTI(BASE) *multi,
1022 enum isl_dim_type dst_type, unsigned dst_pos,
1023 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1025 int i;
1027 if (!multi)
1028 return NULL;
1030 if (n == 0 &&
1031 !isl_space_is_named_or_nested(multi->space, src_type) &&
1032 !isl_space_is_named_or_nested(multi->space, dst_type))
1033 return multi;
1035 if (dst_type == isl_dim_out || src_type == isl_dim_out)
1036 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1037 "cannot move output/set dimension",
1038 return FN(MULTI(BASE),free)(multi));
1039 if (dst_type == isl_dim_div || src_type == isl_dim_div)
1040 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1041 "cannot move divs",
1042 return FN(MULTI(BASE),free)(multi));
1043 if (src_pos + n > isl_space_dim(multi->space, src_type))
1044 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
1045 "range out of bounds",
1046 return FN(MULTI(BASE),free)(multi));
1047 if (dst_type == src_type)
1048 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_unsupported,
1049 "moving dims within the same type not supported",
1050 return FN(MULTI(BASE),free)(multi));
1052 multi = FN(MULTI(BASE),cow)(multi);
1053 if (!multi)
1054 return NULL;
1056 multi->space = isl_space_move_dims(multi->space, dst_type, dst_pos,
1057 src_type, src_pos, n);
1058 if (!multi->space)
1059 return FN(MULTI(BASE),free)(multi);
1061 for (i = 0; i < multi->n; ++i) {
1062 multi->p[i] = FN(EL,move_dims)(multi->p[i], dst_type, dst_pos,
1063 src_type, src_pos, n);
1064 if (!multi->p[i])
1065 return FN(MULTI(BASE),free)(multi);
1068 return multi;
1070 #endif