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
11 #include <isl_space_private.h>
13 #include <isl_reordering.h>
15 #include <isl_multi_macro.h>
17 #define MULTI_NAME(BASE) "isl_multi_" #BASE
18 #define xLIST(EL) EL ## _list
19 #define LIST(EL) xLIST(EL)
21 isl_ctx
*FN(MULTI(BASE
),get_ctx
)(__isl_keep
MULTI(BASE
) *multi
)
23 return multi
? isl_space_get_ctx(multi
->space
) : NULL
;
26 /* Return the space of "multi".
28 static __isl_keep isl_space
*FN(MULTI(BASE
),peek_space
)(
29 __isl_keep
MULTI(BASE
) *multi
)
31 return multi
? multi
->space
: NULL
;
34 __isl_give isl_space
*FN(MULTI(BASE
),get_space
)(__isl_keep
MULTI(BASE
) *multi
)
36 return isl_space_copy(FN(MULTI(BASE
),peek_space
)(multi
));
39 /* Return the position of the dimension of the given type and name
41 * Return -1 if no such dimension can be found.
43 int FN(MULTI(BASE
),find_dim_by_name
)(__isl_keep
MULTI(BASE
) *multi
,
44 enum isl_dim_type type
, const char *name
)
48 return isl_space_find_dim_by_name(multi
->space
, type
, name
);
51 __isl_give isl_space
*FN(MULTI(BASE
),get_domain_space
)(
52 __isl_keep
MULTI(BASE
) *multi
)
54 return multi
? isl_space_domain(isl_space_copy(multi
->space
)) : NULL
;
57 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),alloc
)(__isl_take isl_space
*space
)
66 ctx
= isl_space_get_ctx(space
);
67 n
= isl_space_dim(space
, isl_dim_out
);
68 multi
= isl_calloc(ctx
, MULTI(BASE
),
69 sizeof(MULTI(BASE
)) + (n
- 1) * sizeof(struct EL
*));
78 isl_space_free(space
);
82 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),dup
)(__isl_keep
MULTI(BASE
) *multi
)
90 dup
= FN(MULTI(BASE
),alloc
)(isl_space_copy(multi
->space
));
94 for (i
= 0; i
< multi
->n
; ++i
)
95 dup
= FN(FN(MULTI(BASE
),set
),BASE
)(dup
, i
,
96 FN(EL
,copy
)(multi
->p
[i
]));
101 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),cow
)(__isl_take
MULTI(BASE
) *multi
)
110 return FN(MULTI(BASE
),dup
)(multi
);
113 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),copy
)(__isl_keep
MULTI(BASE
) *multi
)
122 __isl_null
MULTI(BASE
) *FN(MULTI(BASE
),free
)(__isl_take
MULTI(BASE
) *multi
)
129 if (--multi
->ref
> 0)
132 isl_space_free(multi
->space
);
133 for (i
= 0; i
< multi
->n
; ++i
)
134 FN(EL
,free
)(multi
->p
[i
]);
140 unsigned FN(MULTI(BASE
),dim
)(__isl_keep
MULTI(BASE
) *multi
,
141 enum isl_dim_type type
)
143 return multi
? isl_space_dim(multi
->space
, type
) : 0;
146 /* Return the position of the first dimension of "type" with id "id".
147 * Return -1 if there is no such dimension.
149 int FN(MULTI(BASE
),find_dim_by_id
)(__isl_keep
MULTI(BASE
) *multi
,
150 enum isl_dim_type type
, __isl_keep isl_id
*id
)
154 return isl_space_find_dim_by_id(multi
->space
, type
, id
);
157 /* Return the id of the given dimension.
159 __isl_give isl_id
*FN(MULTI(BASE
),get_dim_id
)(__isl_keep
MULTI(BASE
) *multi
,
160 enum isl_dim_type type
, unsigned pos
)
162 return multi
? isl_space_get_dim_id(multi
->space
, type
, pos
) : NULL
;
165 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_dim_name
)(
166 __isl_take
MULTI(BASE
) *multi
,
167 enum isl_dim_type type
, unsigned pos
, const char *s
)
171 multi
= FN(MULTI(BASE
),cow
)(multi
);
175 multi
->space
= isl_space_set_dim_name(multi
->space
, type
, pos
, s
);
177 return FN(MULTI(BASE
),free
)(multi
);
179 if (type
== isl_dim_out
)
181 for (i
= 0; i
< multi
->n
; ++i
) {
182 multi
->p
[i
] = FN(EL
,set_dim_name
)(multi
->p
[i
], type
, pos
, s
);
184 return FN(MULTI(BASE
),free
)(multi
);
190 const char *FN(MULTI(BASE
),get_tuple_name
)(__isl_keep
MULTI(BASE
) *multi
,
191 enum isl_dim_type type
)
193 return multi
? isl_space_get_tuple_name(multi
->space
, type
) : NULL
;
196 /* Does the specified tuple have an id?
198 isl_bool
FN(MULTI(BASE
),has_tuple_id
)(__isl_keep
MULTI(BASE
) *multi
,
199 enum isl_dim_type type
)
202 return isl_bool_error
;
203 return isl_space_has_tuple_id(multi
->space
, type
);
206 /* Return the id of the specified tuple.
208 __isl_give isl_id
*FN(MULTI(BASE
),get_tuple_id
)(__isl_keep
MULTI(BASE
) *multi
,
209 enum isl_dim_type type
)
211 return multi
? isl_space_get_tuple_id(multi
->space
, type
) : NULL
;
214 __isl_give EL
*FN(FN(MULTI(BASE
),get
),BASE
)(__isl_keep
MULTI(BASE
) *multi
,
221 ctx
= FN(MULTI(BASE
),get_ctx
)(multi
);
222 if (pos
< 0 || pos
>= multi
->n
)
223 isl_die(ctx
, isl_error_invalid
,
224 "index out of bounds", return NULL
);
225 return FN(EL
,copy
)(multi
->p
[pos
]);
228 /* Set the element at position "pos" of "multi" to "el",
229 * where the position may be empty if "multi" has only a single reference.
231 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),restore
)(
232 __isl_take
MULTI(BASE
) *multi
, int pos
, __isl_take EL
*el
)
234 multi
= FN(MULTI(BASE
),cow
)(multi
);
238 if (pos
< 0 || pos
>= multi
->n
)
239 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
240 "index out of bounds", goto error
);
242 FN(EL
,free
)(multi
->p
[pos
]);
247 FN(MULTI(BASE
),free
)(multi
);
252 /* Set the element at position "pos" of "multi" to "el",
253 * where the position may be empty if "multi" has only a single reference.
254 * However, the space of "multi" is available and is checked
255 * for compatibility with "el".
257 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),restore_check_space
)(
258 __isl_take
MULTI(BASE
) *multi
, int pos
, __isl_take EL
*el
)
262 space
= FN(MULTI(BASE
),peek_space
)(multi
);
263 if (FN(EL
,check_match_domain_space
)(el
, space
) < 0)
264 multi
= FN(MULTI(BASE
),free
)(multi
);
265 return FN(MULTI(BASE
),restore
)(multi
, pos
, el
);
268 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),set
),BASE
)(
269 __isl_take
MULTI(BASE
) *multi
, int pos
, __isl_take EL
*el
)
271 isl_space
*multi_space
= NULL
;
272 isl_space
*el_space
= NULL
;
275 multi_space
= FN(MULTI(BASE
),get_space
)(multi
);
276 match
= FN(EL
,matching_params
)(el
, multi_space
);
280 multi
= FN(MULTI(BASE
),align_params
)(multi
,
281 FN(EL
,get_space
)(el
));
282 isl_space_free(multi_space
);
283 multi_space
= FN(MULTI(BASE
),get_space
)(multi
);
284 el
= FN(EL
,align_params
)(el
, isl_space_copy(multi_space
));
287 multi
= FN(MULTI(BASE
),restore_check_space
)(multi
, pos
, el
);
289 isl_space_free(multi_space
);
290 isl_space_free(el_space
);
294 FN(MULTI(BASE
),free
)(multi
);
296 isl_space_free(multi_space
);
297 isl_space_free(el_space
);
301 /* Reset the space of "multi". This function is called from isl_pw_templ.c
302 * and doesn't know if the space of an element object is represented
303 * directly or through its domain. It therefore passes along both,
304 * which we pass along to the element function since we don't know how
305 * that is represented either.
307 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_space_and_domain
)(
308 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*space
,
309 __isl_take isl_space
*domain
)
313 multi
= FN(MULTI(BASE
),cow
)(multi
);
314 if (!multi
|| !space
|| !domain
)
317 for (i
= 0; i
< multi
->n
; ++i
) {
318 multi
->p
[i
] = FN(EL
,reset_domain_space
)(multi
->p
[i
],
319 isl_space_copy(domain
));
323 isl_space_free(domain
);
324 isl_space_free(multi
->space
);
325 multi
->space
= space
;
329 isl_space_free(domain
);
330 isl_space_free(space
);
331 FN(MULTI(BASE
),free
)(multi
);
335 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_domain_space
)(
336 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*domain
)
340 space
= isl_space_extend_domain_with_range(isl_space_copy(domain
),
341 isl_space_copy(multi
->space
));
342 return FN(MULTI(BASE
),reset_space_and_domain
)(multi
, space
, domain
);
345 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_space
)(
346 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*space
)
350 domain
= isl_space_domain(isl_space_copy(space
));
351 return FN(MULTI(BASE
),reset_space_and_domain
)(multi
, space
, domain
);
354 /* Set the id of the given dimension of "multi" to "id".
356 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_dim_id
)(
357 __isl_take
MULTI(BASE
) *multi
,
358 enum isl_dim_type type
, unsigned pos
, __isl_take isl_id
*id
)
362 multi
= FN(MULTI(BASE
),cow
)(multi
);
366 space
= FN(MULTI(BASE
),get_space
)(multi
);
367 space
= isl_space_set_dim_id(space
, type
, pos
, id
);
369 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
372 FN(MULTI(BASE
),free
)(multi
);
376 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_tuple_name
)(
377 __isl_keep
MULTI(BASE
) *multi
, enum isl_dim_type type
,
382 multi
= FN(MULTI(BASE
),cow
)(multi
);
386 space
= FN(MULTI(BASE
),get_space
)(multi
);
387 space
= isl_space_set_tuple_name(space
, type
, s
);
389 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
392 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_tuple_id
)(
393 __isl_take
MULTI(BASE
) *multi
, enum isl_dim_type type
,
394 __isl_take isl_id
*id
)
398 multi
= FN(MULTI(BASE
),cow
)(multi
);
402 space
= FN(MULTI(BASE
),get_space
)(multi
);
403 space
= isl_space_set_tuple_id(space
, type
, id
);
405 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
411 /* Drop the id on the specified tuple.
413 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_tuple_id
)(
414 __isl_take
MULTI(BASE
) *multi
, enum isl_dim_type type
)
420 if (!FN(MULTI(BASE
),has_tuple_id
)(multi
, type
))
423 multi
= FN(MULTI(BASE
),cow
)(multi
);
427 space
= FN(MULTI(BASE
),get_space
)(multi
);
428 space
= isl_space_reset_tuple_id(space
, type
);
430 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
433 /* Reset the user pointer on all identifiers of parameters and tuples
434 * of the space of "multi".
436 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_user
)(
437 __isl_take
MULTI(BASE
) *multi
)
441 space
= FN(MULTI(BASE
),get_space
)(multi
);
442 space
= isl_space_reset_user(space
);
444 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
447 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),realign_domain
)(
448 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_reordering
*exp
)
452 multi
= FN(MULTI(BASE
),cow
)(multi
);
456 for (i
= 0; i
< multi
->n
; ++i
) {
457 multi
->p
[i
] = FN(EL
,realign_domain
)(multi
->p
[i
],
458 isl_reordering_copy(exp
));
463 multi
= FN(MULTI(BASE
),reset_domain_space
)(multi
,
464 isl_space_copy(exp
->dim
));
466 isl_reordering_free(exp
);
469 isl_reordering_free(exp
);
470 FN(MULTI(BASE
),free
)(multi
);
474 /* Align the parameters of "multi" to those of "model".
476 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),align_params
)(
477 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*model
)
480 isl_bool equal_params
;
483 if (!multi
|| !model
)
486 equal_params
= isl_space_has_equal_params(multi
->space
, model
);
487 if (equal_params
< 0)
490 isl_space_free(model
);
494 ctx
= isl_space_get_ctx(model
);
495 if (!isl_space_has_named_params(model
))
496 isl_die(ctx
, isl_error_invalid
,
497 "model has unnamed parameters", goto error
);
498 if (!isl_space_has_named_params(multi
->space
))
499 isl_die(ctx
, isl_error_invalid
,
500 "input has unnamed parameters", goto error
);
502 model
= isl_space_params(model
);
503 exp
= isl_parameter_alignment_reordering(multi
->space
, model
);
504 exp
= isl_reordering_extend_space(exp
,
505 FN(MULTI(BASE
),get_domain_space
)(multi
));
506 multi
= FN(MULTI(BASE
),realign_domain
)(multi
, exp
);
508 isl_space_free(model
);
511 isl_space_free(model
);
512 FN(MULTI(BASE
),free
)(multi
);
516 /* Create a multi expression in the given space with the elements of "list"
517 * as base expressions.
519 * Since isl_multi_*_restore_* assumes that the element and
520 * the multi expression have matching spaces, the alignment
521 * (if any) needs to be performed beforehand.
523 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),from
),LIST(BASE
))(
524 __isl_take isl_space
*space
, __isl_take
LIST(EL
) *list
)
534 ctx
= isl_space_get_ctx(space
);
535 n
= FN(FN(LIST(EL
),n
),BASE
)(list
);
536 if (n
!= isl_space_dim(space
, isl_dim_out
))
537 isl_die(ctx
, isl_error_invalid
,
538 "invalid number of elements in list", goto error
);
540 for (i
= 0; i
< n
; ++i
) {
541 EL
*el
= FN(LIST(EL
),peek
)(list
, i
);
542 space
= isl_space_align_params(space
, FN(EL
,get_space
)(el
));
544 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
545 for (i
= 0; i
< n
; ++i
) {
546 EL
*el
= FN(FN(LIST(EL
),get
),BASE
)(list
, i
);
547 el
= FN(EL
,align_params
)(el
, isl_space_copy(space
));
548 multi
= FN(MULTI(BASE
),restore_check_space
)(multi
, i
, el
);
551 isl_space_free(space
);
552 FN(LIST(EL
),free
)(list
);
555 isl_space_free(space
);
556 FN(LIST(EL
),free
)(list
);
561 /* Create a multi expression in the given space that maps each
562 * input dimension to the corresponding output dimension.
564 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),identity
)(__isl_take isl_space
*space
)
573 if (isl_space_is_set(space
))
574 isl_die(isl_space_get_ctx(space
), isl_error_invalid
,
575 "expecting map space", goto error
);
577 n
= isl_space_dim(space
, isl_dim_out
);
578 if (n
!= isl_space_dim(space
, isl_dim_in
))
579 isl_die(isl_space_get_ctx(space
), isl_error_invalid
,
580 "number of input and output dimensions needs to be "
581 "the same", goto error
);
583 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
586 isl_space_free(space
);
590 space
= isl_space_domain(space
);
591 ls
= isl_local_space_from_space(space
);
593 for (i
= 0; i
< n
; ++i
) {
595 el
= FN(EL
,var_on_domain
)(isl_local_space_copy(ls
),
597 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, i
, el
);
600 isl_local_space_free(ls
);
604 isl_space_free(space
);
610 /* Construct a multi expression in the given space with value zero in
611 * each of the output dimensions.
613 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),zero
)(__isl_take isl_space
*space
)
621 n
= isl_space_dim(space
, isl_dim_out
);
622 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
625 isl_space_free(space
);
631 space
= isl_space_domain(space
);
632 ls
= isl_local_space_from_space(space
);
633 el
= FN(EL
,zero_on_domain
)(ls
);
635 for (i
= 0; i
< n
; ++i
)
636 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, i
,
647 /* Create a multiple expression with a single output/set dimension
649 * For most multiple expression types, the base type has a single
650 * output/set dimension and the space of the result is therefore
651 * the same as the space of the input.
652 * In the case of isl_multi_union_pw_aff, however, the base type
653 * lives in a parameter space and we therefore need to add
654 * a single set dimension.
656 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),from
),BASE
)(__isl_take EL
*el
)
661 space
= FN(EL
,get_space(el
));
662 if (isl_space_is_params(space
)) {
663 space
= isl_space_set_from_params(space
);
664 space
= isl_space_add_dims(space
, isl_dim_set
, 1);
666 multi
= FN(MULTI(BASE
),alloc
)(space
);
667 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, 0, el
);
673 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),drop_dims
)(
674 __isl_take
MULTI(BASE
) *multi
,
675 enum isl_dim_type type
, unsigned first
, unsigned n
)
680 multi
= FN(MULTI(BASE
),cow
)(multi
);
684 dim
= FN(MULTI(BASE
),dim
)(multi
, type
);
685 if (first
+ n
> dim
|| first
+ n
< first
)
686 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
687 "index out of bounds",
688 return FN(MULTI(BASE
),free
)(multi
));
690 multi
->space
= isl_space_drop_dims(multi
->space
, type
, first
, n
);
692 return FN(MULTI(BASE
),free
)(multi
);
694 if (type
== isl_dim_out
) {
695 for (i
= 0; i
< n
; ++i
)
696 FN(EL
,free
)(multi
->p
[first
+ i
]);
697 for (i
= first
; i
+ n
< multi
->n
; ++i
)
698 multi
->p
[i
] = multi
->p
[i
+ n
];
704 for (i
= 0; i
< multi
->n
; ++i
) {
705 multi
->p
[i
] = FN(EL
,drop_dims
)(multi
->p
[i
], type
, first
, n
);
707 return FN(MULTI(BASE
),free
)(multi
);
713 /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
715 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),align_params_multi_multi_and
)(
716 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
717 __isl_give
MULTI(BASE
) *(*fn
)(__isl_take
MULTI(BASE
) *multi1
,
718 __isl_take
MULTI(BASE
) *multi2
))
721 isl_bool equal_params
;
723 if (!multi1
|| !multi2
)
725 equal_params
= isl_space_has_equal_params(multi1
->space
, multi2
->space
);
726 if (equal_params
< 0)
729 return fn(multi1
, multi2
);
730 ctx
= FN(MULTI(BASE
),get_ctx
)(multi1
);
731 if (!isl_space_has_named_params(multi1
->space
) ||
732 !isl_space_has_named_params(multi2
->space
))
733 isl_die(ctx
, isl_error_invalid
,
734 "unaligned unnamed parameters", goto error
);
735 multi1
= FN(MULTI(BASE
),align_params
)(multi1
,
736 FN(MULTI(BASE
),get_space
)(multi2
));
737 multi2
= FN(MULTI(BASE
),align_params
)(multi2
,
738 FN(MULTI(BASE
),get_space
)(multi1
));
739 return fn(multi1
, multi2
);
741 FN(MULTI(BASE
),free
)(multi1
);
742 FN(MULTI(BASE
),free
)(multi2
);
746 /* Given two MULTI(BASE)s A -> B and C -> D,
747 * construct a MULTI(BASE) (A * C) -> [B -> D].
749 * The parameters are assumed to have been aligned.
751 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_product_aligned
)(
752 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
759 if (!multi1
|| !multi2
)
762 space
= isl_space_range_product(FN(MULTI(BASE
),get_space
)(multi1
),
763 FN(MULTI(BASE
),get_space
)(multi2
));
764 res
= FN(MULTI(BASE
),alloc
)(space
);
766 n1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
767 n2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_out
);
769 for (i
= 0; i
< n1
; ++i
) {
770 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi1
, i
);
771 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, i
, el
);
774 for (i
= 0; i
< n2
; ++i
) {
775 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi2
, i
);
776 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, n1
+ i
, el
);
779 FN(MULTI(BASE
),free
)(multi1
);
780 FN(MULTI(BASE
),free
)(multi2
);
783 FN(MULTI(BASE
),free
)(multi1
);
784 FN(MULTI(BASE
),free
)(multi2
);
788 /* Given two MULTI(BASE)s A -> B and C -> D,
789 * construct a MULTI(BASE) (A * C) -> [B -> D].
791 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_product
)(
792 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
794 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
795 &FN(MULTI(BASE
),range_product_aligned
));
798 /* Is the range of "multi" a wrapped relation?
800 isl_bool
FN(MULTI(BASE
),range_is_wrapping
)(__isl_keep
MULTI(BASE
) *multi
)
803 return isl_bool_error
;
804 return isl_space_range_is_wrapping(multi
->space
);
807 /* Given a function A -> [B -> C], extract the function A -> B.
809 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_factor_domain
)(
810 __isl_take
MULTI(BASE
) *multi
)
817 if (!isl_space_range_is_wrapping(multi
->space
))
818 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
819 "range is not a product",
820 return FN(MULTI(BASE
),free
)(multi
));
822 space
= FN(MULTI(BASE
),get_space
)(multi
);
823 total
= isl_space_dim(space
, isl_dim_out
);
824 space
= isl_space_range_factor_domain(space
);
825 keep
= isl_space_dim(space
, isl_dim_out
);
826 multi
= FN(MULTI(BASE
),drop_dims
)(multi
,
827 isl_dim_out
, keep
, total
- keep
);
828 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
833 /* Given a function A -> [B -> C], extract the function A -> C.
835 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_factor_range
)(
836 __isl_take
MULTI(BASE
) *multi
)
843 if (!isl_space_range_is_wrapping(multi
->space
))
844 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
845 "range is not a product",
846 return FN(MULTI(BASE
),free
)(multi
));
848 space
= FN(MULTI(BASE
),get_space
)(multi
);
849 total
= isl_space_dim(space
, isl_dim_out
);
850 space
= isl_space_range_factor_range(space
);
851 keep
= isl_space_dim(space
, isl_dim_out
);
852 multi
= FN(MULTI(BASE
),drop_dims
)(multi
, isl_dim_out
, 0, total
- keep
);
853 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
858 /* Given a function [B -> C], extract the function C.
860 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),factor_range
)(
861 __isl_take
MULTI(BASE
) *multi
)
868 if (!isl_space_is_wrapping(multi
->space
))
869 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
870 "not a product", return FN(MULTI(BASE
),free
)(multi
));
872 space
= FN(MULTI(BASE
),get_space
)(multi
);
873 total
= isl_space_dim(space
, isl_dim_out
);
874 space
= isl_space_factor_range(space
);
875 keep
= isl_space_dim(space
, isl_dim_out
);
876 multi
= FN(MULTI(BASE
),drop_dims
)(multi
, isl_dim_out
, 0, total
- keep
);
877 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
883 /* Given two MULTI(BASE)s A -> B and C -> D,
884 * construct a MULTI(BASE) [A -> C] -> [B -> D].
886 * The parameters are assumed to have been aligned.
888 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),product_aligned
)(
889 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
895 int in1
, in2
, out1
, out2
;
897 in1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_in
);
898 in2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_in
);
899 out1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
900 out2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_out
);
901 space
= isl_space_product(FN(MULTI(BASE
),get_space
)(multi1
),
902 FN(MULTI(BASE
),get_space
)(multi2
));
903 res
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
904 space
= isl_space_domain(space
);
906 for (i
= 0; i
< out1
; ++i
) {
907 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi1
, i
);
908 el
= FN(EL
,insert_dims
)(el
, isl_dim_in
, in1
, in2
);
909 el
= FN(EL
,reset_domain_space
)(el
, isl_space_copy(space
));
910 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, i
, el
);
913 for (i
= 0; i
< out2
; ++i
) {
914 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi2
, i
);
915 el
= FN(EL
,insert_dims
)(el
, isl_dim_in
, 0, in1
);
916 el
= FN(EL
,reset_domain_space
)(el
, isl_space_copy(space
));
917 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, out1
+ i
, el
);
920 isl_space_free(space
);
921 FN(MULTI(BASE
),free
)(multi1
);
922 FN(MULTI(BASE
),free
)(multi2
);
926 /* Given two MULTI(BASE)s A -> B and C -> D,
927 * construct a MULTI(BASE) [A -> C] -> [B -> D].
929 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),product
)(
930 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
932 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
933 &FN(MULTI(BASE
),product_aligned
));
937 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),flatten_range
)(
938 __isl_take
MULTI(BASE
) *multi
)
943 if (!multi
->space
->nested
[1])
946 multi
= FN(MULTI(BASE
),cow
)(multi
);
950 multi
->space
= isl_space_flatten_range(multi
->space
);
952 return FN(MULTI(BASE
),free
)(multi
);
957 /* Given two MULTI(BASE)s A -> B and C -> D,
958 * construct a MULTI(BASE) (A * C) -> (B, D).
960 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),flat_range_product
)(
961 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
965 multi
= FN(MULTI(BASE
),range_product
)(multi1
, multi2
);
966 multi
= FN(MULTI(BASE
),flatten_range
)(multi
);
970 /* Given two multi expressions, "multi1"
974 * where B2 starts at position "pos", and "multi2"
978 * return the multi expression
982 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_splice
)(
983 __isl_take
MULTI(BASE
) *multi1
, unsigned pos
,
984 __isl_take
MULTI(BASE
) *multi2
)
989 if (!multi1
|| !multi2
)
992 dim
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
994 isl_die(FN(MULTI(BASE
),get_ctx
)(multi1
), isl_error_invalid
,
995 "index out of bounds", goto error
);
997 res
= FN(MULTI(BASE
),copy
)(multi1
);
998 res
= FN(MULTI(BASE
),drop_dims
)(res
, isl_dim_out
, pos
, dim
- pos
);
999 multi1
= FN(MULTI(BASE
),drop_dims
)(multi1
, isl_dim_out
, 0, pos
);
1001 res
= FN(MULTI(BASE
),flat_range_product
)(res
, multi2
);
1002 res
= FN(MULTI(BASE
),flat_range_product
)(res
, multi1
);
1006 FN(MULTI(BASE
),free
)(multi1
);
1007 FN(MULTI(BASE
),free
)(multi2
);
1012 /* Given two multi expressions, "multi1"
1014 * [A1 A2] -> [B1 B2]
1016 * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
1021 * return the multi expression
1023 * [A1 C A2] -> [B1 D B2]
1025 * We first insert input dimensions to obtain
1027 * [A1 C A2] -> [B1 B2]
1033 * and then apply range_splice.
1035 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),splice
)(
1036 __isl_take
MULTI(BASE
) *multi1
, unsigned in_pos
, unsigned out_pos
,
1037 __isl_take
MULTI(BASE
) *multi2
)
1042 if (!multi1
|| !multi2
)
1045 n_in1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_in
);
1047 isl_die(FN(MULTI(BASE
),get_ctx
)(multi1
), isl_error_invalid
,
1048 "index out of bounds", goto error
);
1050 n_in2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_in
);
1052 multi1
= FN(MULTI(BASE
),insert_dims
)(multi1
, isl_dim_in
, in_pos
, n_in2
);
1053 multi2
= FN(MULTI(BASE
),insert_dims
)(multi2
, isl_dim_in
, n_in2
,
1055 multi2
= FN(MULTI(BASE
),insert_dims
)(multi2
, isl_dim_in
, 0, in_pos
);
1057 return FN(MULTI(BASE
),range_splice
)(multi1
, out_pos
, multi2
);
1059 FN(MULTI(BASE
),free
)(multi1
);
1060 FN(MULTI(BASE
),free
)(multi2
);
1065 /* This function is currently only used from isl_aff.c
1067 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),bin_op
)(
1068 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
1069 __isl_give EL
*(*fn
)(__isl_take EL
*, __isl_take EL
*))
1070 __attribute__ ((unused
));
1072 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
1073 * return the result.
1075 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),bin_op
)(
1076 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
1077 __isl_give EL
*(*fn
)(__isl_take EL
*, __isl_take EL
*))
1082 multi1
= FN(MULTI(BASE
),cow
)(multi1
);
1083 if (!multi1
|| !multi2
)
1086 ctx
= FN(MULTI(BASE
),get_ctx
)(multi1
);
1087 if (!isl_space_is_equal(multi1
->space
, multi2
->space
))
1088 isl_die(ctx
, isl_error_invalid
,
1089 "spaces don't match", goto error
);
1091 for (i
= 0; i
< multi1
->n
; ++i
) {
1092 multi1
->p
[i
] = fn(multi1
->p
[i
], FN(EL
,copy
)(multi2
->p
[i
]));
1097 FN(MULTI(BASE
),free
)(multi2
);
1100 FN(MULTI(BASE
),free
)(multi1
);
1101 FN(MULTI(BASE
),free
)(multi2
);
1105 /* Add "multi2" from "multi1" and return the result.
1107 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1109 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),add_aligned
)(
1110 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
1112 return FN(MULTI(BASE
),bin_op
)(multi1
, multi2
, &FN(EL
,add
));
1115 /* Add "multi2" from "multi1" and return the result.
1117 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),add
)(__isl_take
MULTI(BASE
) *multi1
,
1118 __isl_take
MULTI(BASE
) *multi2
)
1120 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
1121 &FN(MULTI(BASE
),add_aligned
));
1124 /* Subtract "multi2" from "multi1" and return the result.
1126 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1128 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),sub_aligned
)(
1129 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
1131 return FN(MULTI(BASE
),bin_op
)(multi1
, multi2
, &FN(EL
,sub
));
1134 /* Subtract "multi2" from "multi1" and return the result.
1136 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),sub
)(__isl_take
MULTI(BASE
) *multi1
,
1137 __isl_take
MULTI(BASE
) *multi2
)
1139 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
1140 &FN(MULTI(BASE
),sub_aligned
));
1143 /* Multiply the elements of "multi" by "v" and return the result.
1145 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_val
)(__isl_take
MULTI(BASE
) *multi
,
1146 __isl_take isl_val
*v
)
1153 if (isl_val_is_one(v
)) {
1158 if (!isl_val_is_rat(v
))
1159 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1160 "expecting rational factor", goto error
);
1162 multi
= FN(MULTI(BASE
),cow
)(multi
);
1166 for (i
= 0; i
< multi
->n
; ++i
) {
1167 multi
->p
[i
] = FN(EL
,scale_val
)(multi
->p
[i
], isl_val_copy(v
));
1176 return FN(MULTI(BASE
),free
)(multi
);
1179 /* Divide the elements of "multi" by "v" and return the result.
1181 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_down_val
)(
1182 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_val
*v
)
1189 if (isl_val_is_one(v
)) {
1194 if (!isl_val_is_rat(v
))
1195 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1196 "expecting rational factor", goto error
);
1197 if (isl_val_is_zero(v
))
1198 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1199 "cannot scale down by zero", goto error
);
1201 multi
= FN(MULTI(BASE
),cow
)(multi
);
1205 for (i
= 0; i
< multi
->n
; ++i
) {
1206 multi
->p
[i
] = FN(EL
,scale_down_val
)(multi
->p
[i
],
1216 return FN(MULTI(BASE
),free
)(multi
);
1219 /* Multiply the elements of "multi" by the corresponding element of "mv"
1220 * and return the result.
1222 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_multi_val
)(
1223 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1230 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1231 mv
->space
, isl_dim_set
))
1232 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1233 "spaces don't match", goto error
);
1235 multi
= FN(MULTI(BASE
),cow
)(multi
);
1239 for (i
= 0; i
< multi
->n
; ++i
) {
1242 v
= isl_multi_val_get_val(mv
, i
);
1243 multi
->p
[i
] = FN(EL
,scale_val
)(multi
->p
[i
], v
);
1248 isl_multi_val_free(mv
);
1251 isl_multi_val_free(mv
);
1252 return FN(MULTI(BASE
),free
)(multi
);
1255 /* Divide the elements of "multi" by the corresponding element of "mv"
1256 * and return the result.
1258 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_down_multi_val
)(
1259 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1266 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1267 mv
->space
, isl_dim_set
))
1268 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1269 "spaces don't match", goto error
);
1271 multi
= FN(MULTI(BASE
),cow
)(multi
);
1275 for (i
= 0; i
< multi
->n
; ++i
) {
1278 v
= isl_multi_val_get_val(mv
, i
);
1279 multi
->p
[i
] = FN(EL
,scale_down_val
)(multi
->p
[i
], v
);
1284 isl_multi_val_free(mv
);
1287 isl_multi_val_free(mv
);
1288 return FN(MULTI(BASE
),free
)(multi
);
1291 /* Compute the residues of the elements of "multi" modulo
1292 * the corresponding element of "mv" and return the result.
1294 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),mod_multi_val
)(
1295 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1302 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1303 mv
->space
, isl_dim_set
))
1304 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1305 "spaces don't match", goto error
);
1307 multi
= FN(MULTI(BASE
),cow
)(multi
);
1311 for (i
= 0; i
< multi
->n
; ++i
) {
1314 v
= isl_multi_val_get_val(mv
, i
);
1315 multi
->p
[i
] = FN(EL
,mod_val
)(multi
->p
[i
], v
);
1320 isl_multi_val_free(mv
);
1323 isl_multi_val_free(mv
);
1324 return FN(MULTI(BASE
),free
)(multi
);
1327 #ifndef NO_MOVE_DIMS
1328 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
1329 * to dimensions of "dst_type" at "dst_pos".
1331 * We only support moving input dimensions to parameters and vice versa.
1333 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),move_dims
)(__isl_take
MULTI(BASE
) *multi
,
1334 enum isl_dim_type dst_type
, unsigned dst_pos
,
1335 enum isl_dim_type src_type
, unsigned src_pos
, unsigned n
)
1343 !isl_space_is_named_or_nested(multi
->space
, src_type
) &&
1344 !isl_space_is_named_or_nested(multi
->space
, dst_type
))
1347 if (dst_type
== isl_dim_out
|| src_type
== isl_dim_out
)
1348 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1349 "cannot move output/set dimension",
1350 return FN(MULTI(BASE
),free
)(multi
));
1351 if (dst_type
== isl_dim_div
|| src_type
== isl_dim_div
)
1352 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1354 return FN(MULTI(BASE
),free
)(multi
));
1355 if (src_pos
+ n
> isl_space_dim(multi
->space
, src_type
))
1356 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1357 "range out of bounds",
1358 return FN(MULTI(BASE
),free
)(multi
));
1359 if (dst_type
== src_type
)
1360 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_unsupported
,
1361 "moving dims within the same type not supported",
1362 return FN(MULTI(BASE
),free
)(multi
));
1364 multi
= FN(MULTI(BASE
),cow
)(multi
);
1368 multi
->space
= isl_space_move_dims(multi
->space
, dst_type
, dst_pos
,
1369 src_type
, src_pos
, n
);
1371 return FN(MULTI(BASE
),free
)(multi
);
1373 for (i
= 0; i
< multi
->n
; ++i
) {
1374 multi
->p
[i
] = FN(EL
,move_dims
)(multi
->p
[i
], dst_type
, dst_pos
,
1375 src_type
, src_pos
, n
);
1377 return FN(MULTI(BASE
),free
)(multi
);
1384 /* Convert a multiple expression defined over a parameter domain
1385 * into one that is defined over a zero-dimensional set.
1387 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),from_range
)(
1388 __isl_take
MULTI(BASE
) *multi
)
1394 if (!isl_space_is_set(multi
->space
))
1395 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1396 "not living in a set space",
1397 return FN(MULTI(BASE
),free
)(multi
));
1399 space
= FN(MULTI(BASE
),get_space
)(multi
);
1400 space
= isl_space_from_range(space
);
1401 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
1406 /* Are "multi1" and "multi2" obviously equal?
1408 isl_bool
FN(MULTI(BASE
),plain_is_equal
)(__isl_keep
MULTI(BASE
) *multi1
,
1409 __isl_keep
MULTI(BASE
) *multi2
)
1414 if (!multi1
|| !multi2
)
1415 return isl_bool_error
;
1416 if (multi1
->n
!= multi2
->n
)
1417 return isl_bool_false
;
1418 equal
= isl_space_is_equal(multi1
->space
, multi2
->space
);
1419 if (equal
< 0 || !equal
)
1422 for (i
= 0; i
< multi1
->n
; ++i
) {
1423 equal
= FN(EL
,plain_is_equal
)(multi1
->p
[i
], multi2
->p
[i
]);
1424 if (equal
< 0 || !equal
)
1428 return isl_bool_true
;
1431 /* Does "multi" involve any NaNs?
1433 isl_bool
FN(MULTI(BASE
),involves_nan
)(__isl_keep
MULTI(BASE
) *multi
)
1438 return isl_bool_error
;
1440 return isl_bool_false
;
1442 for (i
= 0; i
< multi
->n
; ++i
) {
1443 isl_bool has_nan
= FN(EL
,involves_nan
)(multi
->p
[i
]);
1444 if (has_nan
< 0 || has_nan
)
1448 return isl_bool_false
;
1452 /* Return the shared domain of the elements of "multi".
1454 __isl_give isl_set
*FN(MULTI(BASE
),domain
)(__isl_take
MULTI(BASE
) *multi
)
1462 dom
= isl_set_universe(FN(MULTI(BASE
),get_domain_space
)(multi
));
1463 for (i
= 0; i
< multi
->n
; ++i
) {
1466 dom_i
= FN(EL
,domain
)(FN(FN(MULTI(BASE
),get
),BASE
)(multi
, i
));
1467 dom
= isl_set_intersect(dom
, dom_i
);
1470 FN(MULTI(BASE
),free
)(multi
);
1476 /* Return the opposite of "multi".
1478 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),neg
)(__isl_take
MULTI(BASE
) *multi
)
1482 multi
= FN(MULTI(BASE
),cow
)(multi
);
1486 for (i
= 0; i
< multi
->n
; ++i
) {
1487 multi
->p
[i
] = FN(EL
,neg
)(multi
->p
[i
]);
1489 return FN(MULTI(BASE
),free
)(multi
);