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 __isl_give isl_space
*FN(MULTI(BASE
),get_space
)(__isl_keep
MULTI(BASE
) *multi
)
28 return multi
? isl_space_copy(multi
->space
) : NULL
;
31 /* Return the position of the dimension of the given type and name
33 * Return -1 if no such dimension can be found.
35 int FN(MULTI(BASE
),find_dim_by_name
)(__isl_keep
MULTI(BASE
) *multi
,
36 enum isl_dim_type type
, const char *name
)
40 return isl_space_find_dim_by_name(multi
->space
, type
, name
);
43 __isl_give isl_space
*FN(MULTI(BASE
),get_domain_space
)(
44 __isl_keep
MULTI(BASE
) *multi
)
46 return multi
? isl_space_domain(isl_space_copy(multi
->space
)) : NULL
;
49 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),alloc
)(__isl_take isl_space
*space
)
58 ctx
= isl_space_get_ctx(space
);
59 n
= isl_space_dim(space
, isl_dim_out
);
60 multi
= isl_calloc(ctx
, MULTI(BASE
),
61 sizeof(MULTI(BASE
)) + (n
- 1) * sizeof(struct EL
*));
70 isl_space_free(space
);
74 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),dup
)(__isl_keep
MULTI(BASE
) *multi
)
82 dup
= FN(MULTI(BASE
),alloc
)(isl_space_copy(multi
->space
));
86 for (i
= 0; i
< multi
->n
; ++i
)
87 dup
= FN(FN(MULTI(BASE
),set
),BASE
)(dup
, i
,
88 FN(EL
,copy
)(multi
->p
[i
]));
93 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),cow
)(__isl_take
MULTI(BASE
) *multi
)
102 return FN(MULTI(BASE
),dup
)(multi
);
105 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),copy
)(__isl_keep
MULTI(BASE
) *multi
)
114 __isl_null
MULTI(BASE
) *FN(MULTI(BASE
),free
)(__isl_take
MULTI(BASE
) *multi
)
121 if (--multi
->ref
> 0)
124 isl_space_free(multi
->space
);
125 for (i
= 0; i
< multi
->n
; ++i
)
126 FN(EL
,free
)(multi
->p
[i
]);
132 /* Check whether "multi" has non-zero coefficients for any dimension
133 * in the given range or if any of these dimensions appear
134 * with non-zero coefficients in any of the integer divisions involved.
136 int FN(MULTI(BASE
),involves_dims
)(__isl_keep
MULTI(BASE
) *multi
,
137 enum isl_dim_type type
, unsigned first
, unsigned n
)
143 if (multi
->n
== 0 || n
== 0)
146 for (i
= 0; i
< multi
->n
; ++i
) {
149 involves
= FN(EL
,involves_dims
)(multi
->p
[i
], type
, first
, n
);
150 if (involves
< 0 || involves
)
157 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),insert_dims
)(
158 __isl_take
MULTI(BASE
) *multi
,
159 enum isl_dim_type type
, unsigned first
, unsigned n
)
165 if (type
== isl_dim_out
)
166 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
167 "cannot insert output/set dimensions",
168 return FN(MULTI(BASE
),free
)(multi
));
169 if (n
== 0 && !isl_space_is_named_or_nested(multi
->space
, type
))
172 multi
= FN(MULTI(BASE
),cow
)(multi
);
176 multi
->space
= isl_space_insert_dims(multi
->space
, type
, first
, n
);
178 return FN(MULTI(BASE
),free
)(multi
);
180 for (i
= 0; i
< multi
->n
; ++i
) {
181 multi
->p
[i
] = FN(EL
,insert_dims
)(multi
->p
[i
], type
, first
, n
);
183 return FN(MULTI(BASE
),free
)(multi
);
189 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),add_dims
)(__isl_take
MULTI(BASE
) *multi
,
190 enum isl_dim_type type
, unsigned n
)
194 pos
= FN(MULTI(BASE
),dim
)(multi
, type
);
196 return FN(MULTI(BASE
),insert_dims
)(multi
, type
, pos
, n
);
199 unsigned FN(MULTI(BASE
),dim
)(__isl_keep
MULTI(BASE
) *multi
,
200 enum isl_dim_type type
)
202 return multi
? isl_space_dim(multi
->space
, type
) : 0;
205 /* Return the position of the first dimension of "type" with id "id".
206 * Return -1 if there is no such dimension.
208 int FN(MULTI(BASE
),find_dim_by_id
)(__isl_keep
MULTI(BASE
) *multi
,
209 enum isl_dim_type type
, __isl_keep isl_id
*id
)
213 return isl_space_find_dim_by_id(multi
->space
, type
, id
);
216 /* Return the id of the given dimension.
218 __isl_give isl_id
*FN(MULTI(BASE
),get_dim_id
)(__isl_keep
MULTI(BASE
) *multi
,
219 enum isl_dim_type type
, unsigned pos
)
221 return multi
? isl_space_get_dim_id(multi
->space
, type
, pos
) : NULL
;
224 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_dim_name
)(
225 __isl_take
MULTI(BASE
) *multi
,
226 enum isl_dim_type type
, unsigned pos
, const char *s
)
230 multi
= FN(MULTI(BASE
),cow
)(multi
);
234 multi
->space
= isl_space_set_dim_name(multi
->space
, type
, pos
, s
);
236 return FN(MULTI(BASE
),free
)(multi
);
238 if (type
== isl_dim_out
)
240 for (i
= 0; i
< multi
->n
; ++i
) {
241 multi
->p
[i
] = FN(EL
,set_dim_name
)(multi
->p
[i
], type
, pos
, s
);
243 return FN(MULTI(BASE
),free
)(multi
);
249 const char *FN(MULTI(BASE
),get_tuple_name
)(__isl_keep
MULTI(BASE
) *multi
,
250 enum isl_dim_type type
)
252 return multi
? isl_space_get_tuple_name(multi
->space
, type
) : NULL
;
255 /* Does the specified tuple have an id?
257 int FN(MULTI(BASE
),has_tuple_id
)(__isl_keep
MULTI(BASE
) *multi
,
258 enum isl_dim_type type
)
260 return multi
? isl_space_has_tuple_id(multi
->space
, type
) : -1;
263 /* Return the id of the specified tuple.
265 __isl_give isl_id
*FN(MULTI(BASE
),get_tuple_id
)(__isl_keep
MULTI(BASE
) *multi
,
266 enum isl_dim_type type
)
268 return multi
? isl_space_get_tuple_id(multi
->space
, type
) : NULL
;
271 __isl_give EL
*FN(FN(MULTI(BASE
),get
),BASE
)(__isl_keep
MULTI(BASE
) *multi
,
278 ctx
= FN(MULTI(BASE
),get_ctx
)(multi
);
279 if (pos
< 0 || pos
>= multi
->n
)
280 isl_die(ctx
, isl_error_invalid
,
281 "index out of bounds", return NULL
);
282 return FN(EL
,copy
)(multi
->p
[pos
]);
285 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),set
),BASE
)(
286 __isl_take
MULTI(BASE
) *multi
, int pos
, __isl_take EL
*el
)
288 isl_space
*multi_space
= NULL
;
289 isl_space
*el_space
= NULL
;
292 multi
= FN(MULTI(BASE
),cow
)(multi
);
296 multi_space
= FN(MULTI(BASE
),get_space
)(multi
);
297 match
= FN(EL
,matching_params
)(el
, multi_space
);
301 multi
= FN(MULTI(BASE
),align_params
)(multi
,
302 FN(EL
,get_space
)(el
));
303 isl_space_free(multi_space
);
304 multi_space
= FN(MULTI(BASE
),get_space
)(multi
);
305 el
= FN(EL
,align_params
)(el
, isl_space_copy(multi_space
));
307 if (FN(EL
,check_match_domain_space
)(el
, multi_space
) < 0)
310 if (pos
< 0 || pos
>= multi
->n
)
311 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
312 "index out of bounds", goto error
);
314 FN(EL
,free
)(multi
->p
[pos
]);
317 isl_space_free(multi_space
);
318 isl_space_free(el_space
);
322 FN(MULTI(BASE
),free
)(multi
);
324 isl_space_free(multi_space
);
325 isl_space_free(el_space
);
329 /* Reset the space of "multi". This function is called from isl_pw_templ.c
330 * and doesn't know if the space of an element object is represented
331 * directly or through its domain. It therefore passes along both,
332 * which we pass along to the element function since we don't how
333 * that is represented either.
335 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_space_and_domain
)(
336 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*space
,
337 __isl_take isl_space
*domain
)
341 multi
= FN(MULTI(BASE
),cow
)(multi
);
342 if (!multi
|| !space
|| !domain
)
345 for (i
= 0; i
< multi
->n
; ++i
) {
346 multi
->p
[i
] = FN(EL
,reset_domain_space
)(multi
->p
[i
],
347 isl_space_copy(domain
));
351 isl_space_free(domain
);
352 isl_space_free(multi
->space
);
353 multi
->space
= space
;
357 isl_space_free(domain
);
358 isl_space_free(space
);
359 FN(MULTI(BASE
),free
)(multi
);
363 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_domain_space
)(
364 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*domain
)
368 space
= isl_space_extend_domain_with_range(isl_space_copy(domain
),
369 isl_space_copy(multi
->space
));
370 return FN(MULTI(BASE
),reset_space_and_domain
)(multi
, space
, domain
);
373 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_space
)(
374 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*space
)
378 domain
= isl_space_domain(isl_space_copy(space
));
379 return FN(MULTI(BASE
),reset_space_and_domain
)(multi
, space
, domain
);
382 /* Set the id of the given dimension of "multi" to "id".
384 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_dim_id
)(
385 __isl_take
MULTI(BASE
) *multi
,
386 enum isl_dim_type type
, unsigned pos
, __isl_take isl_id
*id
)
390 multi
= FN(MULTI(BASE
),cow
)(multi
);
394 space
= FN(MULTI(BASE
),get_space
)(multi
);
395 space
= isl_space_set_dim_id(space
, type
, pos
, id
);
397 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
400 FN(MULTI(BASE
),free
)(multi
);
404 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_tuple_name
)(
405 __isl_keep
MULTI(BASE
) *multi
, enum isl_dim_type type
,
410 multi
= FN(MULTI(BASE
),cow
)(multi
);
414 space
= FN(MULTI(BASE
),get_space
)(multi
);
415 space
= isl_space_set_tuple_name(space
, type
, s
);
417 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
420 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),set_tuple_id
)(
421 __isl_take
MULTI(BASE
) *multi
, enum isl_dim_type type
,
422 __isl_take isl_id
*id
)
426 multi
= FN(MULTI(BASE
),cow
)(multi
);
430 space
= FN(MULTI(BASE
),get_space
)(multi
);
431 space
= isl_space_set_tuple_id(space
, type
, id
);
433 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
439 /* Drop the id on the specified tuple.
441 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_tuple_id
)(
442 __isl_take
MULTI(BASE
) *multi
, enum isl_dim_type type
)
448 if (!FN(MULTI(BASE
),has_tuple_id
)(multi
, type
))
451 multi
= FN(MULTI(BASE
),cow
)(multi
);
455 space
= FN(MULTI(BASE
),get_space
)(multi
);
456 space
= isl_space_reset_tuple_id(space
, type
);
458 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
461 /* Reset the user pointer on all identifiers of parameters and tuples
462 * of the space of "multi".
464 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),reset_user
)(
465 __isl_take
MULTI(BASE
) *multi
)
469 space
= FN(MULTI(BASE
),get_space
)(multi
);
470 space
= isl_space_reset_user(space
);
472 return FN(MULTI(BASE
),reset_space
)(multi
, space
);
475 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),realign_domain
)(
476 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_reordering
*exp
)
480 multi
= FN(MULTI(BASE
),cow
)(multi
);
484 for (i
= 0; i
< multi
->n
; ++i
) {
485 multi
->p
[i
] = FN(EL
,realign_domain
)(multi
->p
[i
],
486 isl_reordering_copy(exp
));
491 multi
= FN(MULTI(BASE
),reset_domain_space
)(multi
,
492 isl_space_copy(exp
->dim
));
494 isl_reordering_free(exp
);
497 isl_reordering_free(exp
);
498 FN(MULTI(BASE
),free
)(multi
);
502 /* Align the parameters of "multi" to those of "model".
504 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),align_params
)(
505 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_space
*model
)
510 if (!multi
|| !model
)
513 if (isl_space_match(multi
->space
, isl_dim_param
,
514 model
, isl_dim_param
)) {
515 isl_space_free(model
);
519 ctx
= isl_space_get_ctx(model
);
520 if (!isl_space_has_named_params(model
))
521 isl_die(ctx
, isl_error_invalid
,
522 "model has unnamed parameters", goto error
);
523 if (!isl_space_has_named_params(multi
->space
))
524 isl_die(ctx
, isl_error_invalid
,
525 "input has unnamed parameters", goto error
);
527 model
= isl_space_params(model
);
528 exp
= isl_parameter_alignment_reordering(multi
->space
, model
);
529 exp
= isl_reordering_extend_space(exp
,
530 FN(MULTI(BASE
),get_domain_space
)(multi
));
531 multi
= FN(MULTI(BASE
),realign_domain
)(multi
, exp
);
533 isl_space_free(model
);
536 isl_space_free(model
);
537 FN(MULTI(BASE
),free
)(multi
);
541 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),from
),LIST(BASE
))(
542 __isl_take isl_space
*space
, __isl_take
LIST(EL
) *list
)
552 ctx
= isl_space_get_ctx(space
);
553 n
= FN(FN(LIST(EL
),n
),BASE
)(list
);
554 if (n
!= isl_space_dim(space
, isl_dim_out
))
555 isl_die(ctx
, isl_error_invalid
,
556 "invalid number of elements in list", goto error
);
558 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
559 for (i
= 0; i
< n
; ++i
) {
560 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, i
,
561 FN(FN(LIST(EL
),get
),BASE
)(list
, i
));
564 isl_space_free(space
);
565 FN(LIST(EL
),free
)(list
);
568 isl_space_free(space
);
569 FN(LIST(EL
),free
)(list
);
574 /* Create a multi expression in the given space that maps each
575 * input dimension to the corresponding output dimension.
577 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),identity
)(__isl_take isl_space
*space
)
586 if (isl_space_is_set(space
))
587 isl_die(isl_space_get_ctx(space
), isl_error_invalid
,
588 "expecting map space", goto error
);
590 n
= isl_space_dim(space
, isl_dim_out
);
591 if (n
!= isl_space_dim(space
, isl_dim_in
))
592 isl_die(isl_space_get_ctx(space
), isl_error_invalid
,
593 "number of input and output dimensions needs to be "
594 "the same", goto error
);
596 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
599 isl_space_free(space
);
603 space
= isl_space_domain(space
);
604 ls
= isl_local_space_from_space(space
);
606 for (i
= 0; i
< n
; ++i
) {
608 el
= FN(EL
,var_on_domain
)(isl_local_space_copy(ls
),
610 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, i
, el
);
613 isl_local_space_free(ls
);
617 isl_space_free(space
);
622 /* Construct a multi expression in the given space with value zero in
623 * each of the output dimensions.
625 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),zero
)(__isl_take isl_space
*space
)
633 n
= isl_space_dim(space
, isl_dim_out
);
634 multi
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
637 isl_space_free(space
);
643 space
= isl_space_domain(space
);
644 ls
= isl_local_space_from_space(space
);
645 el
= FN(EL
,zero_on_domain
)(ls
);
647 for (i
= 0; i
< n
; ++i
)
648 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, i
,
658 __isl_give
MULTI(BASE
) *FN(FN(MULTI(BASE
),from
),BASE
)(__isl_take EL
*el
)
662 multi
= FN(MULTI(BASE
),alloc
)(FN(EL
,get_space
)(el
));
663 multi
= FN(FN(MULTI(BASE
),set
),BASE
)(multi
, 0, el
);
669 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),drop_dims
)(
670 __isl_take
MULTI(BASE
) *multi
,
671 enum isl_dim_type type
, unsigned first
, unsigned n
)
676 multi
= FN(MULTI(BASE
),cow
)(multi
);
680 dim
= FN(MULTI(BASE
),dim
)(multi
, type
);
681 if (first
+ n
> dim
|| first
+ n
< first
)
682 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
683 "index out of bounds",
684 return FN(MULTI(BASE
),cow
)(multi
));
686 multi
->space
= isl_space_drop_dims(multi
->space
, type
, first
, n
);
688 return FN(MULTI(BASE
),cow
)(multi
);
690 if (type
== isl_dim_out
) {
691 for (i
= 0; i
< n
; ++i
)
692 FN(EL
,free
)(multi
->p
[first
+ i
]);
693 for (i
= first
; i
+ n
< multi
->n
; ++i
)
694 multi
->p
[i
] = multi
->p
[i
+ n
];
700 for (i
= 0; i
< multi
->n
; ++i
) {
701 multi
->p
[i
] = FN(EL
,drop_dims
)(multi
->p
[i
], type
, first
, n
);
703 return FN(MULTI(BASE
),cow
)(multi
);
709 /* Align the parameters of "multi1" and "multi2" (if needed) and call "fn".
711 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),align_params_multi_multi_and
)(
712 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
713 __isl_give
MULTI(BASE
) *(*fn
)(__isl_take
MULTI(BASE
) *multi1
,
714 __isl_take
MULTI(BASE
) *multi2
))
718 if (!multi1
|| !multi2
)
720 if (isl_space_match(multi1
->space
, isl_dim_param
,
721 multi2
->space
, isl_dim_param
))
722 return fn(multi1
, multi2
);
723 ctx
= FN(MULTI(BASE
),get_ctx
)(multi1
);
724 if (!isl_space_has_named_params(multi1
->space
) ||
725 !isl_space_has_named_params(multi2
->space
))
726 isl_die(ctx
, isl_error_invalid
,
727 "unaligned unnamed parameters", goto error
);
728 multi1
= FN(MULTI(BASE
),align_params
)(multi1
,
729 FN(MULTI(BASE
),get_space
)(multi2
));
730 multi2
= FN(MULTI(BASE
),align_params
)(multi2
,
731 FN(MULTI(BASE
),get_space
)(multi1
));
732 return fn(multi1
, multi2
);
734 FN(MULTI(BASE
),free
)(multi1
);
735 FN(MULTI(BASE
),free
)(multi2
);
739 /* Given two MULTI(BASE)s A -> B and C -> D,
740 * construct a MULTI(BASE) (A * C) -> [B -> D].
742 * The parameters are assumed to have been aligned.
744 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_product_aligned
)(
745 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
752 if (!multi1
|| !multi2
)
755 space
= isl_space_range_product(FN(MULTI(BASE
),get_space
)(multi1
),
756 FN(MULTI(BASE
),get_space
)(multi2
));
757 res
= FN(MULTI(BASE
),alloc
)(space
);
759 n1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
760 n2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_out
);
762 for (i
= 0; i
< n1
; ++i
) {
763 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi1
, i
);
764 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, i
, el
);
767 for (i
= 0; i
< n2
; ++i
) {
768 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi2
, i
);
769 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, n1
+ i
, el
);
772 FN(MULTI(BASE
),free
)(multi1
);
773 FN(MULTI(BASE
),free
)(multi2
);
776 FN(MULTI(BASE
),free
)(multi1
);
777 FN(MULTI(BASE
),free
)(multi2
);
781 /* Given two MULTI(BASE)s A -> B and C -> D,
782 * construct a MULTI(BASE) (A * C) -> [B -> D].
784 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_product
)(
785 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
787 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
788 &FN(MULTI(BASE
),range_product_aligned
));
791 /* Is the range of "multi" a wrapped relation?
793 int FN(MULTI(BASE
),range_is_wrapping
)(__isl_keep
MULTI(BASE
) *multi
)
797 return isl_space_range_is_wrapping(multi
->space
);
800 /* Given a function A -> [B -> C], extract the function A -> B.
802 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_factor_domain
)(
803 __isl_take
MULTI(BASE
) *multi
)
810 if (!isl_space_range_is_wrapping(multi
->space
))
811 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
812 "range is not a product",
813 return FN(MULTI(BASE
),free
)(multi
));
815 space
= FN(MULTI(BASE
),get_space
)(multi
);
816 total
= isl_space_dim(space
, isl_dim_out
);
817 space
= isl_space_range_factor_domain(space
);
818 keep
= isl_space_dim(space
, isl_dim_out
);
819 multi
= FN(MULTI(BASE
),drop_dims
)(multi
,
820 isl_dim_out
, keep
, total
- keep
);
821 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
826 /* Given a function A -> [B -> C], extract the function A -> C.
828 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_factor_range
)(
829 __isl_take
MULTI(BASE
) *multi
)
836 if (!isl_space_range_is_wrapping(multi
->space
))
837 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
838 "range is not a product",
839 return FN(MULTI(BASE
),free
)(multi
));
841 space
= FN(MULTI(BASE
),get_space
)(multi
);
842 total
= isl_space_dim(space
, isl_dim_out
);
843 space
= isl_space_range_factor_range(space
);
844 keep
= isl_space_dim(space
, isl_dim_out
);
845 multi
= FN(MULTI(BASE
),drop_dims
)(multi
, isl_dim_out
, 0, total
- keep
);
846 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
851 /* Given two MULTI(BASE)s A -> B and C -> D,
852 * construct a MULTI(BASE) [A -> C] -> [B -> D].
854 * The parameters are assumed to have been aligned.
856 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),product_aligned
)(
857 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
863 int in1
, in2
, out1
, out2
;
865 in1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_in
);
866 in2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_in
);
867 out1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
868 out2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_out
);
869 space
= isl_space_product(FN(MULTI(BASE
),get_space
)(multi1
),
870 FN(MULTI(BASE
),get_space
)(multi2
));
871 res
= FN(MULTI(BASE
),alloc
)(isl_space_copy(space
));
872 space
= isl_space_domain(space
);
874 for (i
= 0; i
< out1
; ++i
) {
875 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi1
, i
);
876 el
= FN(EL
,insert_dims
)(el
, isl_dim_in
, in1
, in2
);
877 el
= FN(EL
,reset_domain_space
)(el
, isl_space_copy(space
));
878 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, i
, el
);
881 for (i
= 0; i
< out2
; ++i
) {
882 el
= FN(FN(MULTI(BASE
),get
),BASE
)(multi2
, i
);
883 el
= FN(EL
,insert_dims
)(el
, isl_dim_in
, 0, in1
);
884 el
= FN(EL
,reset_domain_space
)(el
, isl_space_copy(space
));
885 res
= FN(FN(MULTI(BASE
),set
),BASE
)(res
, out1
+ i
, el
);
888 isl_space_free(space
);
889 FN(MULTI(BASE
),free
)(multi1
);
890 FN(MULTI(BASE
),free
)(multi2
);
894 /* Given two MULTI(BASE)s A -> B and C -> D,
895 * construct a MULTI(BASE) [A -> C] -> [B -> D].
897 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),product
)(
898 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
900 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
901 &FN(MULTI(BASE
),product_aligned
));
904 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),flatten_range
)(
905 __isl_take
MULTI(BASE
) *multi
)
910 if (!multi
->space
->nested
[1])
913 multi
= FN(MULTI(BASE
),cow
)(multi
);
917 multi
->space
= isl_space_flatten_range(multi
->space
);
919 return FN(MULTI(BASE
),free
)(multi
);
924 /* Given two MULTI(BASE)s A -> B and C -> D,
925 * construct a MULTI(BASE) (A * C) -> (B, D).
927 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),flat_range_product
)(
928 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
932 multi
= FN(MULTI(BASE
),range_product
)(multi1
, multi2
);
933 multi
= FN(MULTI(BASE
),flatten_range
)(multi
);
937 /* Given two multi expressions, "multi1"
941 * where B2 starts at position "pos", and "multi2"
945 * return the multi expression
949 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),range_splice
)(
950 __isl_take
MULTI(BASE
) *multi1
, unsigned pos
,
951 __isl_take
MULTI(BASE
) *multi2
)
956 if (!multi1
|| !multi2
)
959 dim
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_out
);
961 isl_die(FN(MULTI(BASE
),get_ctx
)(multi1
), isl_error_invalid
,
962 "index out of bounds", goto error
);
964 res
= FN(MULTI(BASE
),copy
)(multi1
);
965 res
= FN(MULTI(BASE
),drop_dims
)(res
, isl_dim_out
, pos
, dim
- pos
);
966 multi1
= FN(MULTI(BASE
),drop_dims
)(multi1
, isl_dim_out
, 0, pos
);
968 res
= FN(MULTI(BASE
),flat_range_product
)(res
, multi2
);
969 res
= FN(MULTI(BASE
),flat_range_product
)(res
, multi1
);
973 FN(MULTI(BASE
),free
)(multi1
);
974 FN(MULTI(BASE
),free
)(multi2
);
978 /* Given two multi expressions, "multi1"
982 * where A2 starts at position "in_pos" and B2 starts at position "out_pos",
987 * return the multi expression
989 * [A1 C A2] -> [B1 D B2]
991 * We first insert input dimensions to obtain
993 * [A1 C A2] -> [B1 B2]
999 * and then apply range_splice.
1001 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),splice
)(
1002 __isl_take
MULTI(BASE
) *multi1
, unsigned in_pos
, unsigned out_pos
,
1003 __isl_take
MULTI(BASE
) *multi2
)
1008 if (!multi1
|| !multi2
)
1011 n_in1
= FN(MULTI(BASE
),dim
)(multi1
, isl_dim_in
);
1013 isl_die(FN(MULTI(BASE
),get_ctx
)(multi1
), isl_error_invalid
,
1014 "index out of bounds", goto error
);
1016 n_in2
= FN(MULTI(BASE
),dim
)(multi2
, isl_dim_in
);
1018 multi1
= FN(MULTI(BASE
),insert_dims
)(multi1
, isl_dim_in
, in_pos
, n_in2
);
1019 multi2
= FN(MULTI(BASE
),insert_dims
)(multi2
, isl_dim_in
, n_in2
,
1021 multi2
= FN(MULTI(BASE
),insert_dims
)(multi2
, isl_dim_in
, 0, in_pos
);
1023 return FN(MULTI(BASE
),range_splice
)(multi1
, out_pos
, multi2
);
1025 FN(MULTI(BASE
),free
)(multi1
);
1026 FN(MULTI(BASE
),free
)(multi2
);
1030 /* This function is currently only used from isl_aff.c
1032 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),bin_op
)(
1033 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
1034 __isl_give EL
*(*fn
)(__isl_take EL
*, __isl_take EL
*))
1035 __attribute__ ((unused
));
1037 /* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
1038 * return the result.
1040 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),bin_op
)(
1041 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
,
1042 __isl_give EL
*(*fn
)(__isl_take EL
*, __isl_take EL
*))
1047 multi1
= FN(MULTI(BASE
),cow
)(multi1
);
1048 if (!multi1
|| !multi2
)
1051 ctx
= FN(MULTI(BASE
),get_ctx
)(multi1
);
1052 if (!isl_space_is_equal(multi1
->space
, multi2
->space
))
1053 isl_die(ctx
, isl_error_invalid
,
1054 "spaces don't match", goto error
);
1056 for (i
= 0; i
< multi1
->n
; ++i
) {
1057 multi1
->p
[i
] = fn(multi1
->p
[i
], FN(EL
,copy
)(multi2
->p
[i
]));
1062 FN(MULTI(BASE
),free
)(multi2
);
1065 FN(MULTI(BASE
),free
)(multi1
);
1066 FN(MULTI(BASE
),free
)(multi2
);
1070 /* Subtract "multi2" from "multi1" and return the result.
1072 * The parameters of "multi1" and "multi2" are assumed to have been aligned.
1074 static __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),sub_aligned
)(
1075 __isl_take
MULTI(BASE
) *multi1
, __isl_take
MULTI(BASE
) *multi2
)
1077 return FN(MULTI(BASE
),bin_op
)(multi1
, multi2
, &FN(EL
,sub
));
1080 /* Subtract "multi2" from "multi1" and return the result.
1082 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),sub
)(__isl_take
MULTI(BASE
) *multi1
,
1083 __isl_take
MULTI(BASE
) *multi2
)
1085 return FN(MULTI(BASE
),align_params_multi_multi_and
)(multi1
, multi2
,
1086 &FN(MULTI(BASE
),sub_aligned
));
1089 /* Multiply the elements of "multi" by "v" and return the result.
1091 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_val
)(__isl_take
MULTI(BASE
) *multi
,
1092 __isl_take isl_val
*v
)
1099 if (isl_val_is_one(v
)) {
1104 if (!isl_val_is_rat(v
))
1105 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1106 "expecting rational factor", goto error
);
1108 multi
= FN(MULTI(BASE
),cow
)(multi
);
1112 for (i
= 0; i
< multi
->n
; ++i
) {
1113 multi
->p
[i
] = FN(EL
,scale_val
)(multi
->p
[i
], isl_val_copy(v
));
1122 return FN(MULTI(BASE
),free
)(multi
);
1125 /* Divide the elements of "multi" by "v" and return the result.
1127 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_down_val
)(
1128 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_val
*v
)
1135 if (isl_val_is_one(v
)) {
1140 if (!isl_val_is_rat(v
))
1141 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1142 "expecting rational factor", goto error
);
1143 if (isl_val_is_zero(v
))
1144 isl_die(isl_val_get_ctx(v
), isl_error_invalid
,
1145 "cannot scale down by zero", goto error
);
1147 multi
= FN(MULTI(BASE
),cow
)(multi
);
1151 for (i
= 0; i
< multi
->n
; ++i
) {
1152 multi
->p
[i
] = FN(EL
,scale_down_val
)(multi
->p
[i
],
1162 return FN(MULTI(BASE
),free
)(multi
);
1165 /* Multiply the elements of "multi" by the corresponding element of "mv"
1166 * and return the result.
1168 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_multi_val
)(
1169 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1176 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1177 mv
->space
, isl_dim_set
))
1178 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1179 "spaces don't match", goto error
);
1181 multi
= FN(MULTI(BASE
),cow
)(multi
);
1185 for (i
= 0; i
< multi
->n
; ++i
) {
1188 v
= isl_multi_val_get_val(mv
, i
);
1189 multi
->p
[i
] = FN(EL
,scale_val
)(multi
->p
[i
], v
);
1194 isl_multi_val_free(mv
);
1197 isl_multi_val_free(mv
);
1198 return FN(MULTI(BASE
),free
)(multi
);
1201 /* Divide the elements of "multi" by the corresponding element of "mv"
1202 * and return the result.
1204 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),scale_down_multi_val
)(
1205 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1212 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1213 mv
->space
, isl_dim_set
))
1214 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1215 "spaces don't match", goto error
);
1217 multi
= FN(MULTI(BASE
),cow
)(multi
);
1221 for (i
= 0; i
< multi
->n
; ++i
) {
1224 v
= isl_multi_val_get_val(mv
, i
);
1225 multi
->p
[i
] = FN(EL
,scale_down_val
)(multi
->p
[i
], v
);
1230 isl_multi_val_free(mv
);
1233 isl_multi_val_free(mv
);
1234 return FN(MULTI(BASE
),free
)(multi
);
1237 /* Compute the residues of the elements of "multi" modulo
1238 * the corresponding element of "mv" and return the result.
1240 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),mod_multi_val
)(
1241 __isl_take
MULTI(BASE
) *multi
, __isl_take isl_multi_val
*mv
)
1248 if (!isl_space_tuple_is_equal(multi
->space
, isl_dim_out
,
1249 mv
->space
, isl_dim_set
))
1250 isl_die(isl_multi_val_get_ctx(mv
), isl_error_invalid
,
1251 "spaces don't match", goto error
);
1253 multi
= FN(MULTI(BASE
),cow
)(multi
);
1257 for (i
= 0; i
< multi
->n
; ++i
) {
1260 v
= isl_multi_val_get_val(mv
, i
);
1261 multi
->p
[i
] = FN(EL
,mod_val
)(multi
->p
[i
], v
);
1266 isl_multi_val_free(mv
);
1269 isl_multi_val_free(mv
);
1270 return FN(MULTI(BASE
),free
)(multi
);
1273 #ifndef NO_MOVE_DIMS
1274 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "multi"
1275 * to dimensions of "dst_type" at "dst_pos".
1277 * We only support moving input dimensions to parameters and vice versa.
1279 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),move_dims
)(__isl_take
MULTI(BASE
) *multi
,
1280 enum isl_dim_type dst_type
, unsigned dst_pos
,
1281 enum isl_dim_type src_type
, unsigned src_pos
, unsigned n
)
1289 !isl_space_is_named_or_nested(multi
->space
, src_type
) &&
1290 !isl_space_is_named_or_nested(multi
->space
, dst_type
))
1293 if (dst_type
== isl_dim_out
|| src_type
== isl_dim_out
)
1294 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1295 "cannot move output/set dimension",
1296 return FN(MULTI(BASE
),free
)(multi
));
1297 if (dst_type
== isl_dim_div
|| src_type
== isl_dim_div
)
1298 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1300 return FN(MULTI(BASE
),free
)(multi
));
1301 if (src_pos
+ n
> isl_space_dim(multi
->space
, src_type
))
1302 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1303 "range out of bounds",
1304 return FN(MULTI(BASE
),free
)(multi
));
1305 if (dst_type
== src_type
)
1306 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_unsupported
,
1307 "moving dims within the same type not supported",
1308 return FN(MULTI(BASE
),free
)(multi
));
1310 multi
= FN(MULTI(BASE
),cow
)(multi
);
1314 multi
->space
= isl_space_move_dims(multi
->space
, dst_type
, dst_pos
,
1315 src_type
, src_pos
, n
);
1317 return FN(MULTI(BASE
),free
)(multi
);
1319 for (i
= 0; i
< multi
->n
; ++i
) {
1320 multi
->p
[i
] = FN(EL
,move_dims
)(multi
->p
[i
], dst_type
, dst_pos
,
1321 src_type
, src_pos
, n
);
1323 return FN(MULTI(BASE
),free
)(multi
);
1330 /* Convert a multiple expression defined over a parameter domain
1331 * into one that is defined over a zero-dimensional set.
1333 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),from_range
)(
1334 __isl_take
MULTI(BASE
) *multi
)
1340 if (!isl_space_is_set(multi
->space
))
1341 isl_die(FN(MULTI(BASE
),get_ctx
)(multi
), isl_error_invalid
,
1342 "not living in a set space",
1343 return FN(MULTI(BASE
),free
)(multi
));
1345 space
= FN(MULTI(BASE
),get_space
)(multi
);
1346 space
= isl_space_from_range(space
);
1347 multi
= FN(MULTI(BASE
),reset_space
)(multi
, space
);
1352 /* Are "multi1" and "multi2" obviously equal?
1354 int FN(MULTI(BASE
),plain_is_equal
)(__isl_keep
MULTI(BASE
) *multi1
,
1355 __isl_keep
MULTI(BASE
) *multi2
)
1360 if (!multi1
|| !multi2
)
1362 if (multi1
->n
!= multi2
->n
)
1364 equal
= isl_space_is_equal(multi1
->space
, multi2
->space
);
1365 if (equal
< 0 || !equal
)
1368 for (i
= 0; i
< multi1
->n
; ++i
) {
1369 equal
= FN(EL
,plain_is_equal
)(multi1
->p
[i
], multi2
->p
[i
]);
1370 if (equal
< 0 || !equal
)
1378 /* Return the shared domain of the elements of "multi".
1380 __isl_give isl_set
*FN(MULTI(BASE
),domain
)(__isl_take
MULTI(BASE
) *multi
)
1388 dom
= isl_set_universe(FN(MULTI(BASE
),get_domain_space
)(multi
));
1389 for (i
= 0; i
< multi
->n
; ++i
) {
1392 dom_i
= FN(EL
,domain
)(FN(FN(MULTI(BASE
),get
),BASE
)(multi
, i
));
1393 dom
= isl_set_intersect(dom
, dom_i
);
1396 FN(MULTI(BASE
),free
)(multi
);
1402 /* Return the opposite of "multi".
1404 __isl_give
MULTI(BASE
) *FN(MULTI(BASE
),neg
)(__isl_take
MULTI(BASE
) *multi
)
1408 multi
= FN(MULTI(BASE
),cow
)(multi
);
1412 for (i
= 0; i
< multi
->n
; ++i
) {
1413 multi
->p
[i
] = FN(EL
,neg
)(multi
->p
[i
]);
1415 return FN(MULTI(BASE
),free
)(multi
);