2 * Copyright 2013 Ecole Normale Superieure
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege,
7 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
11 #include <isl_schedule_band.h>
12 #include <isl_schedule_private.h>
15 #define EL isl_schedule_tree
17 #include <isl_list_templ.h>
20 #define BASE schedule_tree
22 #include <isl_list_templ.c>
24 /* Is "tree" the leaf of a schedule tree?
26 int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree
*tree
)
28 return isl_schedule_tree_get_type(tree
) == isl_schedule_node_leaf
;
31 /* Create a new schedule tree of type "type".
32 * The caller is responsible for filling in the type specific fields and
35 static __isl_give isl_schedule_tree
*isl_schedule_tree_alloc(isl_ctx
*ctx
,
36 enum isl_schedule_node_type type
)
38 isl_schedule_tree
*tree
;
40 if (type
== isl_schedule_node_error
)
43 tree
= isl_calloc_type(ctx
, isl_schedule_tree
);
55 /* Return a fresh copy of "tree".
57 __isl_take isl_schedule_tree
*isl_schedule_tree_dup(
58 __isl_keep isl_schedule_tree
*tree
)
61 isl_schedule_tree
*dup
;
66 ctx
= isl_schedule_tree_get_ctx(tree
);
67 dup
= isl_schedule_tree_alloc(ctx
, tree
->type
);
72 case isl_schedule_node_error
:
73 isl_die(ctx
, isl_error_internal
,
74 "allocation should have failed",
75 isl_schedule_tree_free(dup
));
76 case isl_schedule_node_band
:
77 dup
->band
= isl_schedule_band_copy(tree
->band
);
79 return isl_schedule_tree_free(dup
);
81 case isl_schedule_node_domain
:
82 dup
->domain
= isl_union_set_copy(tree
->domain
);
84 return isl_schedule_tree_free(dup
);
86 case isl_schedule_node_filter
:
87 dup
->filter
= isl_union_set_copy(tree
->filter
);
89 return isl_schedule_tree_free(dup
);
91 case isl_schedule_node_leaf
:
92 case isl_schedule_node_sequence
:
93 case isl_schedule_node_set
:
98 dup
->children
= isl_schedule_tree_list_copy(tree
->children
);
100 return isl_schedule_tree_free(dup
);
106 /* Return an isl_schedule_tree that is equal to "tree" and that has only
107 * a single reference.
109 * This function is called before a tree is modified.
110 * A static tree (with negative reference count) should never be modified,
111 * so it is not allowed to call this function on a static tree.
113 __isl_give isl_schedule_tree
*isl_schedule_tree_cow(
114 __isl_take isl_schedule_tree
*tree
)
120 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_internal
,
121 "static trees cannot be modified",
122 return isl_schedule_tree_free(tree
));
127 return isl_schedule_tree_dup(tree
);
130 /* Return a new reference to "tree".
132 * A static tree (with negative reference count) does not keep track
133 * of the number of references and should not be modified.
135 __isl_give isl_schedule_tree
*isl_schedule_tree_copy(
136 __isl_keep isl_schedule_tree
*tree
)
148 /* Free "tree" and return NULL.
150 __isl_null isl_schedule_tree
*isl_schedule_tree_free(
151 __isl_take isl_schedule_tree
*tree
)
160 switch (tree
->type
) {
161 case isl_schedule_node_band
:
162 isl_schedule_band_free(tree
->band
);
164 case isl_schedule_node_domain
:
165 isl_union_set_free(tree
->domain
);
167 case isl_schedule_node_filter
:
168 isl_union_set_free(tree
->filter
);
170 case isl_schedule_node_sequence
:
171 case isl_schedule_node_set
:
172 case isl_schedule_node_error
:
173 case isl_schedule_node_leaf
:
176 isl_schedule_tree_list_free(tree
->children
);
177 isl_ctx_deref(tree
->ctx
);
183 /* Create and return a new leaf schedule tree.
185 __isl_give isl_schedule_tree
*isl_schedule_tree_leaf(isl_ctx
*ctx
)
187 return isl_schedule_tree_alloc(ctx
, isl_schedule_node_leaf
);
190 /* Create a new band schedule tree referring to "band"
193 __isl_give isl_schedule_tree
*isl_schedule_tree_from_band(
194 __isl_take isl_schedule_band
*band
)
197 isl_schedule_tree
*tree
;
202 ctx
= isl_schedule_band_get_ctx(band
);
203 tree
= isl_schedule_tree_alloc(ctx
, isl_schedule_node_band
);
211 isl_schedule_band_free(band
);
215 /* Create a new domain schedule tree with the given domain and no children.
217 __isl_give isl_schedule_tree
*isl_schedule_tree_from_domain(
218 __isl_take isl_union_set
*domain
)
221 isl_schedule_tree
*tree
;
226 ctx
= isl_union_set_get_ctx(domain
);
227 tree
= isl_schedule_tree_alloc(ctx
, isl_schedule_node_domain
);
231 tree
->domain
= domain
;
235 isl_union_set_free(domain
);
239 /* Create a new filter schedule tree with the given filter and no children.
241 __isl_give isl_schedule_tree
*isl_schedule_tree_from_filter(
242 __isl_take isl_union_set
*filter
)
245 isl_schedule_tree
*tree
;
250 ctx
= isl_union_set_get_ctx(filter
);
251 tree
= isl_schedule_tree_alloc(ctx
, isl_schedule_node_filter
);
255 tree
->filter
= filter
;
259 isl_union_set_free(filter
);
263 /* Create a new tree of the given type (isl_schedule_node_sequence or
264 * isl_schedule_node_set) with the given children.
266 __isl_give isl_schedule_tree
*isl_schedule_tree_from_children(
267 enum isl_schedule_node_type type
,
268 __isl_take isl_schedule_tree_list
*list
)
271 isl_schedule_tree
*tree
;
276 ctx
= isl_schedule_tree_list_get_ctx(list
);
277 tree
= isl_schedule_tree_alloc(ctx
, type
);
281 tree
->children
= list
;
285 isl_schedule_tree_list_free(list
);
289 /* Construct a tree with a root node of type "type" and as children
290 * "tree1" and "tree2".
291 * If the root of one (or both) of the input trees is itself of type "type",
292 * then the tree is replaced by its children.
294 __isl_give isl_schedule_tree
*isl_schedule_tree_from_pair(
295 enum isl_schedule_node_type type
, __isl_take isl_schedule_tree
*tree1
,
296 __isl_take isl_schedule_tree
*tree2
)
299 isl_schedule_tree_list
*list
;
301 if (!tree1
|| !tree2
)
304 ctx
= isl_schedule_tree_get_ctx(tree1
);
305 if (isl_schedule_tree_get_type(tree1
) == type
) {
306 list
= isl_schedule_tree_list_copy(tree1
->children
);
307 isl_schedule_tree_free(tree1
);
309 list
= isl_schedule_tree_list_alloc(ctx
, 2);
310 list
= isl_schedule_tree_list_add(list
, tree1
);
312 if (isl_schedule_tree_get_type(tree2
) == type
) {
313 isl_schedule_tree_list
*children
;
315 children
= isl_schedule_tree_list_copy(tree2
->children
);
316 list
= isl_schedule_tree_list_concat(list
, children
);
317 isl_schedule_tree_free(tree2
);
319 list
= isl_schedule_tree_list_add(list
, tree2
);
322 return isl_schedule_tree_from_children(type
, list
);
324 isl_schedule_tree_free(tree1
);
325 isl_schedule_tree_free(tree2
);
329 /* Return the isl_ctx to which "tree" belongs.
331 isl_ctx
*isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree
*tree
)
333 return tree
? tree
->ctx
: NULL
;
336 /* Return the type of the root of the tree or isl_schedule_node_error
339 enum isl_schedule_node_type
isl_schedule_tree_get_type(
340 __isl_keep isl_schedule_tree
*tree
)
342 return tree
? tree
->type
: isl_schedule_node_error
;
345 /* Are "tree1" and "tree2" obviously equal to each other?
347 int isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree
*tree1
,
348 __isl_keep isl_schedule_tree
*tree2
)
353 if (!tree1
|| !tree2
)
357 if (tree1
->type
!= tree2
->type
)
360 switch (tree1
->type
) {
361 case isl_schedule_node_band
:
362 equal
= isl_schedule_band_plain_is_equal(tree1
->band
,
365 case isl_schedule_node_domain
:
366 equal
= isl_union_set_is_equal(tree1
->domain
, tree2
->domain
);
368 case isl_schedule_node_filter
:
369 equal
= isl_union_set_is_equal(tree1
->filter
, tree2
->filter
);
371 case isl_schedule_node_leaf
:
372 case isl_schedule_node_sequence
:
373 case isl_schedule_node_set
:
376 case isl_schedule_node_error
:
381 if (equal
< 0 || !equal
)
384 n
= isl_schedule_tree_n_children(tree1
);
385 if (n
!= isl_schedule_tree_n_children(tree2
))
387 for (i
= 0; i
< n
; ++i
) {
388 isl_schedule_tree
*child1
, *child2
;
390 child1
= isl_schedule_tree_get_child(tree1
, i
);
391 child2
= isl_schedule_tree_get_child(tree2
, i
);
392 equal
= isl_schedule_tree_plain_is_equal(child1
, child2
);
393 isl_schedule_tree_free(child1
);
394 isl_schedule_tree_free(child2
);
396 if (equal
< 0 || !equal
)
403 /* Does "tree" have any children, other than an implicit leaf.
405 int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree
*tree
)
410 return tree
->children
!= NULL
;
413 /* Return the number of children of "tree", excluding implicit leaves.
415 int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree
*tree
)
420 return isl_schedule_tree_list_n_schedule_tree(tree
->children
);
423 /* Return a copy of the (explicit) child at position "pos" of "tree".
425 __isl_give isl_schedule_tree
*isl_schedule_tree_get_child(
426 __isl_keep isl_schedule_tree
*tree
, int pos
)
431 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_internal
,
432 "schedule tree has no explicit children", return NULL
);
433 return isl_schedule_tree_list_get_schedule_tree(tree
->children
, pos
);
436 /* Return a copy of the (explicit) child at position "pos" of "tree" and
439 __isl_give isl_schedule_tree
*isl_schedule_tree_child(
440 __isl_take isl_schedule_tree
*tree
, int pos
)
442 isl_schedule_tree
*child
;
444 child
= isl_schedule_tree_get_child(tree
, pos
);
445 isl_schedule_tree_free(tree
);
449 /* Remove all (explicit) children from "tree".
451 __isl_give isl_schedule_tree
*isl_schedule_tree_reset_children(
452 __isl_take isl_schedule_tree
*tree
)
454 tree
= isl_schedule_tree_cow(tree
);
457 tree
->children
= isl_schedule_tree_list_free(tree
->children
);
461 /* Replace the child at position "pos" of "tree" by "child".
463 * If the new child is a leaf, then it is not explicitly
464 * recorded in the list of children. Instead, the list of children
465 * (which is assumed to have only one element) is removed.
466 * Note that the children of set and sequence nodes are always
467 * filters, so they cannot be replaced by empty trees.
469 __isl_give isl_schedule_tree
*isl_schedule_tree_replace_child(
470 __isl_take isl_schedule_tree
*tree
, int pos
,
471 __isl_take isl_schedule_tree
*child
)
473 tree
= isl_schedule_tree_cow(tree
);
477 if (isl_schedule_tree_is_leaf(child
)) {
478 isl_schedule_tree_free(child
);
479 if (!tree
->children
&& pos
== 0)
481 if (isl_schedule_tree_n_children(tree
) != 1)
482 isl_die(isl_schedule_tree_get_ctx(tree
),
484 "can only replace single child by leaf",
486 return isl_schedule_tree_reset_children(tree
);
489 if (!tree
->children
&& pos
== 0)
491 isl_schedule_tree_list_from_schedule_tree(child
);
493 tree
->children
= isl_schedule_tree_list_set_schedule_tree(
494 tree
->children
, pos
, child
);
497 return isl_schedule_tree_free(tree
);
501 isl_schedule_tree_free(tree
);
502 isl_schedule_tree_free(child
);
506 /* Replace the (explicit) children of "tree" by "children"?
508 __isl_give isl_schedule_tree
*isl_schedule_tree_set_children(
509 __isl_take isl_schedule_tree
*tree
,
510 __isl_take isl_schedule_tree_list
*children
)
512 tree
= isl_schedule_tree_cow(tree
);
513 if (!tree
|| !children
)
515 isl_schedule_tree_list_free(tree
->children
);
516 tree
->children
= children
;
519 isl_schedule_tree_free(tree
);
520 isl_schedule_tree_list_free(children
);
524 /* Create a new band schedule tree referring to "band"
525 * with "tree" as single child.
527 __isl_give isl_schedule_tree
*isl_schedule_tree_insert_band(
528 __isl_take isl_schedule_tree
*tree
, __isl_take isl_schedule_band
*band
)
530 isl_schedule_tree
*res
;
532 res
= isl_schedule_tree_from_band(band
);
533 return isl_schedule_tree_replace_child(res
, 0, tree
);
536 /* Create a new domain schedule tree with the given domain and
537 * with "tree" as single child.
539 __isl_give isl_schedule_tree
*isl_schedule_tree_insert_domain(
540 __isl_take isl_schedule_tree
*tree
, __isl_take isl_union_set
*domain
)
542 isl_schedule_tree
*res
;
544 res
= isl_schedule_tree_from_domain(domain
);
545 return isl_schedule_tree_replace_child(res
, 0, tree
);
548 /* Create a new filter schedule tree with the given filter and single child.
550 * If the root of "tree" is itself a filter node, then the two
551 * filter nodes are merged into one node.
553 __isl_give isl_schedule_tree
*isl_schedule_tree_insert_filter(
554 __isl_take isl_schedule_tree
*tree
, __isl_take isl_union_set
*filter
)
556 isl_schedule_tree
*res
;
558 if (isl_schedule_tree_get_type(tree
) == isl_schedule_node_filter
) {
559 isl_union_set
*tree_filter
;
561 tree_filter
= isl_schedule_tree_filter_get_filter(tree
);
562 tree_filter
= isl_union_set_intersect(tree_filter
, filter
);
563 tree
= isl_schedule_tree_filter_set_filter(tree
, tree_filter
);
567 res
= isl_schedule_tree_from_filter(filter
);
568 return isl_schedule_tree_replace_child(res
, 0, tree
);
571 /* Insert a filter node with filter set "filter"
572 * in each of the children of "tree".
574 __isl_give isl_schedule_tree
*isl_schedule_tree_children_insert_filter(
575 __isl_take isl_schedule_tree
*tree
, __isl_take isl_union_set
*filter
)
579 if (!tree
|| !filter
)
582 n
= isl_schedule_tree_n_children(tree
);
583 for (i
= 0; i
< n
; ++i
) {
584 isl_schedule_tree
*child
;
586 child
= isl_schedule_tree_get_child(tree
, i
);
587 child
= isl_schedule_tree_insert_filter(child
,
588 isl_union_set_copy(filter
));
589 tree
= isl_schedule_tree_replace_child(tree
, i
, child
);
592 isl_union_set_free(filter
);
595 isl_union_set_free(filter
);
596 isl_schedule_tree_free(tree
);
600 /* Return the number of members in the band tree root.
602 unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree
*tree
)
607 if (tree
->type
!= isl_schedule_node_band
)
608 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
609 "not a band node", return 0);
611 return isl_schedule_band_n_member(tree
->band
);
614 /* Is the band member at position "pos" of the band tree root
617 int isl_schedule_tree_band_member_get_coincident(
618 __isl_keep isl_schedule_tree
*tree
, int pos
)
623 if (tree
->type
!= isl_schedule_node_band
)
624 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
625 "not a band node", return -1);
627 return isl_schedule_band_member_get_coincident(tree
->band
, pos
);
630 /* Mark the given band member as being coincident or not
631 * according to "coincident".
633 __isl_give isl_schedule_tree
*isl_schedule_tree_band_member_set_coincident(
634 __isl_take isl_schedule_tree
*tree
, int pos
, int coincident
)
638 if (tree
->type
!= isl_schedule_node_band
)
639 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
640 "not a band node", return isl_schedule_tree_free(tree
));
641 if (isl_schedule_tree_band_member_get_coincident(tree
, pos
) ==
644 tree
= isl_schedule_tree_cow(tree
);
648 tree
->band
= isl_schedule_band_member_set_coincident(tree
->band
, pos
,
651 return isl_schedule_tree_free(tree
);
655 /* Is the band tree root marked permutable?
657 int isl_schedule_tree_band_get_permutable(__isl_keep isl_schedule_tree
*tree
)
662 if (tree
->type
!= isl_schedule_node_band
)
663 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
664 "not a band node", return -1);
666 return isl_schedule_band_get_permutable(tree
->band
);
669 /* Mark the band tree root permutable or not according to "permutable"?
671 __isl_give isl_schedule_tree
*isl_schedule_tree_band_set_permutable(
672 __isl_take isl_schedule_tree
*tree
, int permutable
)
676 if (tree
->type
!= isl_schedule_node_band
)
677 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
678 "not a band node", return isl_schedule_tree_free(tree
));
679 if (isl_schedule_tree_band_get_permutable(tree
) == permutable
)
681 tree
= isl_schedule_tree_cow(tree
);
685 tree
->band
= isl_schedule_band_set_permutable(tree
->band
, permutable
);
687 return isl_schedule_tree_free(tree
);
691 /* Return the schedule space of the band tree root.
693 __isl_give isl_space
*isl_schedule_tree_band_get_space(
694 __isl_keep isl_schedule_tree
*tree
)
699 if (tree
->type
!= isl_schedule_node_band
)
700 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
701 "not a band node", return NULL
);
703 return isl_schedule_band_get_space(tree
->band
);
706 /* Return the schedule of the band tree root in isolation.
708 __isl_give isl_multi_union_pw_aff
*isl_schedule_tree_band_get_partial_schedule(
709 __isl_keep isl_schedule_tree
*tree
)
714 if (tree
->type
!= isl_schedule_node_band
)
715 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
716 "not a band node", return NULL
);
718 return isl_schedule_band_get_partial_schedule(tree
->band
);
721 /* Return the domain of the domain tree root.
723 __isl_give isl_union_set
*isl_schedule_tree_domain_get_domain(
724 __isl_keep isl_schedule_tree
*tree
)
729 if (tree
->type
!= isl_schedule_node_domain
)
730 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
731 "not a domain node", return NULL
);
733 return isl_union_set_copy(tree
->domain
);
736 /* Replace the domain of domain tree root "tree" by "domain".
738 __isl_give isl_schedule_tree
*isl_schedule_tree_domain_set_domain(
739 __isl_take isl_schedule_tree
*tree
, __isl_take isl_union_set
*domain
)
741 tree
= isl_schedule_tree_cow(tree
);
742 if (!tree
|| !domain
)
745 if (tree
->type
!= isl_schedule_node_domain
)
746 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
747 "not a domain node", goto error
);
749 isl_union_set_free(tree
->domain
);
750 tree
->domain
= domain
;
754 isl_schedule_tree_free(tree
);
755 isl_union_set_free(domain
);
759 /* Return the filter of the filter tree root.
761 __isl_give isl_union_set
*isl_schedule_tree_filter_get_filter(
762 __isl_keep isl_schedule_tree
*tree
)
767 if (tree
->type
!= isl_schedule_node_filter
)
768 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
769 "not a filter node", return NULL
);
771 return isl_union_set_copy(tree
->filter
);
774 /* Replace the filter of the filter tree root by "filter".
776 __isl_give isl_schedule_tree
*isl_schedule_tree_filter_set_filter(
777 __isl_take isl_schedule_tree
*tree
, __isl_take isl_union_set
*filter
)
779 tree
= isl_schedule_tree_cow(tree
);
780 if (!tree
|| !filter
)
783 if (tree
->type
!= isl_schedule_node_filter
)
784 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
785 "not a filter node", return NULL
);
787 isl_union_set_free(tree
->filter
);
788 tree
->filter
= filter
;
792 isl_schedule_tree_free(tree
);
793 isl_union_set_free(filter
);
797 /* Set dim to the range dimension of "map" and abort the search.
799 static int set_range_dim(__isl_take isl_map
*map
, void *user
)
803 *dim
= isl_map_dim(map
, isl_dim_out
);
809 /* Return the dimension of the range of "umap".
810 * "umap" is assumed not to be empty and
811 * all maps inside "umap" are assumed to have the same range.
813 * We extract the range dimension from the first map in "umap".
815 static int range_dim(__isl_keep isl_union_map
*umap
)
821 if (isl_union_map_n_map(umap
) == 0)
822 isl_die(isl_union_map_get_ctx(umap
), isl_error_internal
,
823 "unexpected empty input", return -1);
825 isl_union_map_foreach_map(umap
, &set_range_dim
, &dim
);
830 /* Append an "extra" number of zeros to the range of "umap" and
833 static __isl_give isl_union_map
*append_range(__isl_take isl_union_map
*umap
,
839 isl_union_pw_multi_aff
*suffix
;
840 isl_union_map
*universe
;
841 isl_union_map
*suffix_umap
;
843 universe
= isl_union_map_universe(isl_union_map_copy(umap
));
844 dom
= isl_union_map_domain(universe
);
845 space
= isl_union_set_get_space(dom
);
846 space
= isl_space_set_from_params(space
);
847 space
= isl_space_add_dims(space
, isl_dim_set
, extra
);
848 mv
= isl_multi_val_zero(space
);
850 suffix
= isl_union_pw_multi_aff_multi_val_on_domain(dom
, mv
);
851 suffix_umap
= isl_union_map_from_union_pw_multi_aff(suffix
);
852 umap
= isl_union_map_flat_range_product(umap
, suffix_umap
);
857 /* Move down to the first descendant of "tree" that contains any schedule
858 * information or return "leaf" if there is no such descendant.
860 __isl_give isl_schedule_tree
*isl_schedule_tree_first_schedule_descendant(
861 __isl_take isl_schedule_tree
*tree
, __isl_keep isl_schedule_tree
*leaf
)
863 while (isl_schedule_tree_get_type(tree
) == isl_schedule_node_band
&&
864 isl_schedule_tree_band_n_member(tree
) == 0) {
865 if (!isl_schedule_tree_has_children(tree
)) {
866 isl_schedule_tree_free(tree
);
867 return isl_schedule_tree_copy(leaf
);
869 tree
= isl_schedule_tree_child(tree
, 0);
875 static __isl_give isl_union_map
*subtree_schedule_extend(
876 __isl_keep isl_schedule_tree
*tree
, __isl_take isl_union_map
*outer
);
878 /* Extend the schedule map "outer" with the subtree schedule
879 * of the (single) child of "tree", if any.
881 * If "tree" does not have any descendants (apart from those that
882 * do not carry any schedule information), then we simply return "outer".
883 * Otherwise, we extend the schedule map "outer" with the subtree schedule
884 * of the single child.
886 static __isl_give isl_union_map
*subtree_schedule_extend_child(
887 __isl_keep isl_schedule_tree
*tree
, __isl_take isl_union_map
*outer
)
889 isl_schedule_tree
*child
;
893 return isl_union_map_free(outer
);
894 if (!isl_schedule_tree_has_children(tree
))
896 child
= isl_schedule_tree_get_child(tree
, 0);
898 return isl_union_map_free(outer
);
899 res
= subtree_schedule_extend(child
, outer
);
900 isl_schedule_tree_free(child
);
904 /* Extract the parameter space from one of the children of "tree",
905 * which are assumed to be filters.
907 static __isl_give isl_space
*extract_space_from_filter_child(
908 __isl_keep isl_schedule_tree
*tree
)
912 isl_schedule_tree
*child
;
914 child
= isl_schedule_tree_list_get_schedule_tree(tree
->children
, 0);
915 dom
= isl_schedule_tree_filter_get_filter(child
);
916 space
= isl_union_set_get_space(dom
);
917 isl_union_set_free(dom
);
918 isl_schedule_tree_free(child
);
923 /* Extend the schedule map "outer" with the subtree schedule
924 * of a set or sequence node.
926 * The schedule for the set or sequence node itself is composed of
935 * The first form is used if there is only a single child or
936 * if the current node is a set node and the schedule_separate_components
939 * Each of the pieces above is extended with the subtree schedule of
940 * the child of the corresponding filter, if any, padded with zeros
941 * to ensure that all pieces have the same range dimension.
943 static __isl_give isl_union_map
*subtree_schedule_extend_from_children(
944 __isl_keep isl_schedule_tree
*tree
, __isl_take isl_union_map
*outer
)
958 ctx
= isl_schedule_tree_get_ctx(tree
);
960 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_internal
,
961 "missing children", return NULL
);
962 n
= isl_schedule_tree_list_n_schedule_tree(tree
->children
);
964 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_internal
,
965 "missing children", return NULL
);
967 separate
= n
> 1 && (tree
->type
== isl_schedule_node_sequence
||
968 isl_options_get_schedule_separate_components(ctx
));
970 space
= extract_space_from_filter_child(tree
);
972 umap
= isl_union_map_empty(isl_space_copy(space
));
973 space
= isl_space_set_from_params(space
);
975 space
= isl_space_add_dims(space
, isl_dim_set
, 1);
976 v
= isl_val_zero(ctx
);
978 mv
= isl_multi_val_zero(space
);
980 dim
= isl_multi_val_dim(mv
, isl_dim_set
);
981 for (i
= 0; i
< n
; ++i
) {
982 isl_union_pw_multi_aff
*upma
;
983 isl_union_map
*umap_i
;
985 isl_schedule_tree
*child
;
989 child
= isl_schedule_tree_list_get_schedule_tree(
991 dom
= isl_schedule_tree_filter_get_filter(child
);
994 mv
= isl_multi_val_set_val(mv
, 0, isl_val_copy(v
));
995 v
= isl_val_add_ui(v
, 1);
997 upma
= isl_union_pw_multi_aff_multi_val_on_domain(dom
,
998 isl_multi_val_copy(mv
));
999 umap_i
= isl_union_map_from_union_pw_multi_aff(upma
);
1000 umap_i
= isl_union_map_flat_range_product(
1001 isl_union_map_copy(outer
), umap_i
);
1002 umap_i
= subtree_schedule_extend_child(child
, umap_i
);
1003 isl_schedule_tree_free(child
);
1005 empty
= isl_union_map_is_empty(umap_i
);
1007 umap_i
= isl_union_map_free(umap_i
);
1009 isl_union_map_free(umap_i
);
1013 dim_i
= range_dim(umap_i
);
1015 umap
= isl_union_map_free(umap
);
1016 } else if (dim
< dim_i
) {
1017 umap
= append_range(umap
, dim_i
- dim
);
1019 } else if (dim_i
< dim
) {
1020 umap_i
= append_range(umap_i
, dim
- dim_i
);
1022 umap
= isl_union_map_union(umap
, umap_i
);
1026 isl_multi_val_free(mv
);
1027 isl_union_map_free(outer
);
1032 /* Extend the schedule map "outer" with the subtree schedule of "tree".
1034 * If the root of the tree is a set or a sequence, then we extend
1035 * the schedule map in subtree_schedule_extend_from_children.
1036 * Otherwise, we extend the schedule map with the partial schedule
1037 * corresponding to the root of the tree and then continue with
1038 * the single child of this root.
1040 static __isl_give isl_union_map
*subtree_schedule_extend(
1041 __isl_keep isl_schedule_tree
*tree
, __isl_take isl_union_map
*outer
)
1043 isl_multi_union_pw_aff
*mupa
;
1044 isl_union_map
*umap
;
1045 isl_union_set
*domain
;
1050 switch (tree
->type
) {
1051 case isl_schedule_node_error
:
1052 return isl_union_map_free(outer
);
1053 case isl_schedule_node_band
:
1054 if (isl_schedule_tree_band_n_member(tree
) == 0)
1055 return subtree_schedule_extend_child(tree
, outer
);
1056 mupa
= isl_schedule_band_get_partial_schedule(tree
->band
);
1057 umap
= isl_union_map_from_multi_union_pw_aff(mupa
);
1058 outer
= isl_union_map_flat_range_product(outer
, umap
);
1059 umap
= subtree_schedule_extend_child(tree
, outer
);
1061 case isl_schedule_node_domain
:
1062 domain
= isl_schedule_tree_domain_get_domain(tree
);
1063 umap
= isl_union_map_from_domain(domain
);
1064 outer
= isl_union_map_flat_range_product(outer
, umap
);
1065 umap
= subtree_schedule_extend_child(tree
, outer
);
1067 case isl_schedule_node_filter
:
1068 domain
= isl_schedule_tree_filter_get_filter(tree
);
1069 umap
= isl_union_map_from_domain(domain
);
1070 outer
= isl_union_map_flat_range_product(outer
, umap
);
1071 umap
= subtree_schedule_extend_child(tree
, outer
);
1073 case isl_schedule_node_leaf
:
1074 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_internal
,
1075 "leaf node should be handled by caller", return NULL
);
1076 case isl_schedule_node_set
:
1077 case isl_schedule_node_sequence
:
1078 umap
= subtree_schedule_extend_from_children(tree
, outer
);
1085 static __isl_give isl_union_set
*initial_domain(
1086 __isl_keep isl_schedule_tree
*tree
);
1088 /* Extract a universe domain from the children of the tree root "tree",
1089 * which is a set or sequence, meaning that its children are filters.
1090 * In particular, return the union of the universes of the filters.
1092 static __isl_give isl_union_set
*initial_domain_from_children(
1093 __isl_keep isl_schedule_tree
*tree
)
1097 isl_union_set
*domain
;
1099 if (!tree
->children
)
1100 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_internal
,
1101 "missing children", return NULL
);
1102 n
= isl_schedule_tree_list_n_schedule_tree(tree
->children
);
1104 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_internal
,
1105 "missing children", return NULL
);
1107 space
= extract_space_from_filter_child(tree
);
1108 domain
= isl_union_set_empty(space
);
1110 for (i
= 0; i
< n
; ++i
) {
1111 isl_schedule_tree
*child
;
1112 isl_union_set
*domain_i
;
1114 child
= isl_schedule_tree_get_child(tree
, i
);
1115 domain_i
= initial_domain(child
);
1116 domain
= isl_union_set_union(domain
, domain_i
);
1117 isl_schedule_tree_free(child
);
1123 /* Extract a universe domain from the tree root "tree".
1124 * The caller is responsible for making sure that this node
1125 * would not be skipped by isl_schedule_tree_first_schedule_descendant
1126 * and that it is not a leaf node.
1128 static __isl_give isl_union_set
*initial_domain(
1129 __isl_keep isl_schedule_tree
*tree
)
1131 isl_multi_union_pw_aff
*mupa
;
1132 isl_union_set
*domain
;
1137 switch (tree
->type
) {
1138 case isl_schedule_node_error
:
1140 case isl_schedule_node_band
:
1141 if (isl_schedule_tree_band_n_member(tree
) == 0)
1142 isl_die(isl_schedule_tree_get_ctx(tree
),
1144 "0D band should be handled by caller",
1146 mupa
= isl_schedule_band_get_partial_schedule(tree
->band
);
1147 domain
= isl_multi_union_pw_aff_domain(mupa
);
1148 domain
= isl_union_set_universe(domain
);
1150 case isl_schedule_node_domain
:
1151 domain
= isl_schedule_tree_domain_get_domain(tree
);
1152 domain
= isl_union_set_universe(domain
);
1154 case isl_schedule_node_filter
:
1155 domain
= isl_schedule_tree_filter_get_filter(tree
);
1156 domain
= isl_union_set_universe(domain
);
1158 case isl_schedule_node_leaf
:
1159 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_internal
,
1160 "leaf node should be handled by caller", return NULL
);
1161 case isl_schedule_node_set
:
1162 case isl_schedule_node_sequence
:
1163 domain
= initial_domain_from_children(tree
);
1170 /* Return the subtree schedule of a node that contains some schedule
1171 * information, i.e., a node that would not be skipped by
1172 * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
1174 * We start with an initial zero-dimensional subtree schedule based
1175 * on the domain information in the root node and then extend it
1176 * based on the schedule information in the root node and its descendants.
1178 __isl_give isl_union_map
*isl_schedule_tree_get_subtree_schedule_union_map(
1179 __isl_keep isl_schedule_tree
*tree
)
1181 isl_union_set
*domain
;
1182 isl_union_map
*umap
;
1184 domain
= initial_domain(tree
);
1185 umap
= isl_union_map_from_domain(domain
);
1186 return subtree_schedule_extend(tree
, umap
);
1189 /* Multiply the partial schedule of the band root node of "tree"
1190 * with the factors in "mv".
1192 __isl_give isl_schedule_tree
*isl_schedule_tree_band_scale(
1193 __isl_take isl_schedule_tree
*tree
, __isl_take isl_multi_val
*mv
)
1197 if (tree
->type
!= isl_schedule_node_band
)
1198 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
1199 "not a band node", goto error
);
1201 tree
= isl_schedule_tree_cow(tree
);
1205 tree
->band
= isl_schedule_band_scale(tree
->band
, mv
);
1207 return isl_schedule_tree_free(tree
);
1211 isl_schedule_tree_free(tree
);
1212 isl_multi_val_free(mv
);
1216 /* Divide the partial schedule of the band root node of "tree"
1217 * by the factors in "mv".
1219 __isl_give isl_schedule_tree
*isl_schedule_tree_band_scale_down(
1220 __isl_take isl_schedule_tree
*tree
, __isl_take isl_multi_val
*mv
)
1224 if (tree
->type
!= isl_schedule_node_band
)
1225 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
1226 "not a band node", goto error
);
1228 tree
= isl_schedule_tree_cow(tree
);
1232 tree
->band
= isl_schedule_band_scale_down(tree
->band
, mv
);
1234 return isl_schedule_tree_free(tree
);
1238 isl_schedule_tree_free(tree
);
1239 isl_multi_val_free(mv
);
1243 /* Tile the band root node of "tree" with tile sizes "sizes".
1245 * We duplicate the band node, change the schedule of one of them
1246 * to the tile schedule and the other to the point schedule and then
1247 * attach the point band as a child to the tile band.
1249 __isl_give isl_schedule_tree
*isl_schedule_tree_band_tile(
1250 __isl_take isl_schedule_tree
*tree
, __isl_take isl_multi_val
*sizes
)
1252 isl_schedule_tree
*child
= NULL
;
1254 if (!tree
|| !sizes
)
1256 if (tree
->type
!= isl_schedule_node_band
)
1257 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
1258 "not a band node", goto error
);
1260 child
= isl_schedule_tree_copy(tree
);
1261 tree
= isl_schedule_tree_cow(tree
);
1262 child
= isl_schedule_tree_cow(child
);
1263 if (!tree
|| !child
)
1266 tree
->band
= isl_schedule_band_tile(tree
->band
,
1267 isl_multi_val_copy(sizes
));
1270 child
->band
= isl_schedule_band_point(child
->band
, tree
->band
, sizes
);
1272 child
= isl_schedule_tree_free(child
);
1274 tree
= isl_schedule_tree_replace_child(tree
, 0, child
);
1278 isl_schedule_tree_free(child
);
1279 isl_schedule_tree_free(tree
);
1280 isl_multi_val_free(sizes
);
1284 /* Split the band root node of "tree" into two nested band nodes,
1285 * one with the first "pos" dimensions and
1286 * one with the remaining dimensions.
1288 __isl_give isl_schedule_tree
*isl_schedule_tree_band_split(
1289 __isl_take isl_schedule_tree
*tree
, int pos
)
1292 isl_schedule_tree
*child
;
1296 if (tree
->type
!= isl_schedule_node_band
)
1297 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
1298 "not a band node", return isl_schedule_tree_free(tree
));
1300 n
= isl_schedule_tree_band_n_member(tree
);
1301 if (pos
< 0 || pos
> n
)
1302 isl_die(isl_schedule_tree_get_ctx(tree
), isl_error_invalid
,
1303 "position out of bounds",
1304 return isl_schedule_tree_free(tree
));
1306 child
= isl_schedule_tree_copy(tree
);
1307 tree
= isl_schedule_tree_cow(tree
);
1308 child
= isl_schedule_tree_cow(child
);
1309 if (!tree
|| !child
)
1312 child
->band
= isl_schedule_band_drop(child
->band
, 0, pos
);
1313 tree
->band
= isl_schedule_band_drop(tree
->band
, pos
, n
- pos
);
1314 if (!child
->band
|| !tree
->band
)
1317 tree
= isl_schedule_tree_replace_child(tree
, 0, child
);
1321 isl_schedule_tree_free(child
);
1322 isl_schedule_tree_free(tree
);
1326 /* Attach "tree2" at each of the leaves of "tree1".
1328 * If "tree1" does not have any explicit children, then make "tree2"
1329 * its single child. Otherwise, attach "tree2" to the leaves of
1330 * each of the children of "tree1".
1332 __isl_give isl_schedule_tree
*isl_schedule_tree_append_to_leaves(
1333 __isl_take isl_schedule_tree
*tree1
,
1334 __isl_take isl_schedule_tree
*tree2
)
1338 if (!tree1
|| !tree2
)
1340 n
= isl_schedule_tree_n_children(tree1
);
1342 isl_schedule_tree_list
*list
;
1343 list
= isl_schedule_tree_list_from_schedule_tree(tree2
);
1344 tree1
= isl_schedule_tree_set_children(tree1
, list
);
1347 for (i
= 0; i
< n
; ++i
) {
1348 isl_schedule_tree
*child
;
1350 child
= isl_schedule_tree_get_child(tree1
, i
);
1351 child
= isl_schedule_tree_append_to_leaves(child
,
1352 isl_schedule_tree_copy(tree2
));
1353 tree1
= isl_schedule_tree_replace_child(tree1
, i
, child
);
1356 isl_schedule_tree_free(tree2
);
1359 isl_schedule_tree_free(tree1
);
1360 isl_schedule_tree_free(tree2
);
1364 /* Reset the user pointer on all identifiers of parameters and tuples
1365 * in the root of "tree".
1367 __isl_give isl_schedule_tree
*isl_schedule_tree_reset_user(
1368 __isl_take isl_schedule_tree
*tree
)
1370 if (isl_schedule_tree_is_leaf(tree
))
1373 tree
= isl_schedule_tree_cow(tree
);
1377 switch (tree
->type
) {
1378 case isl_schedule_node_error
:
1379 return isl_schedule_tree_free(tree
);
1380 case isl_schedule_node_band
:
1381 tree
->band
= isl_schedule_band_reset_user(tree
->band
);
1383 return isl_schedule_tree_free(tree
);
1385 case isl_schedule_node_domain
:
1386 tree
->domain
= isl_union_set_reset_user(tree
->domain
);
1388 return isl_schedule_tree_free(tree
);
1390 case isl_schedule_node_filter
:
1391 tree
->filter
= isl_union_set_reset_user(tree
->filter
);
1393 return isl_schedule_tree_free(tree
);
1395 case isl_schedule_node_leaf
:
1396 case isl_schedule_node_sequence
:
1397 case isl_schedule_node_set
:
1404 /* Are any members in "band" marked coincident?
1406 static int any_coincident(__isl_keep isl_schedule_band
*band
)
1410 n
= isl_schedule_band_n_member(band
);
1411 for (i
= 0; i
< n
; ++i
)
1412 if (isl_schedule_band_member_get_coincident(band
, i
))
1418 /* Print the band node "band" to "p".
1420 * The permutable and coincident properties are only printed if they
1421 * are different from the defaults.
1422 * The coincident property is always printed in YAML flow style.
1424 static __isl_give isl_printer
*print_tree_band(__isl_take isl_printer
*p
,
1425 __isl_keep isl_schedule_band
*band
)
1427 p
= isl_printer_print_str(p
, "schedule");
1428 p
= isl_printer_yaml_next(p
);
1429 p
= isl_printer_print_str(p
, "\"");
1430 p
= isl_printer_print_multi_union_pw_aff(p
, band
->mupa
);
1431 p
= isl_printer_print_str(p
, "\"");
1432 if (isl_schedule_band_get_permutable(band
)) {
1433 p
= isl_printer_yaml_next(p
);
1434 p
= isl_printer_print_str(p
, "permutable");
1435 p
= isl_printer_yaml_next(p
);
1436 p
= isl_printer_print_int(p
, 1);
1438 if (any_coincident(band
)) {
1442 p
= isl_printer_yaml_next(p
);
1443 p
= isl_printer_print_str(p
, "coincident");
1444 p
= isl_printer_yaml_next(p
);
1445 style
= isl_printer_get_yaml_style(p
);
1446 p
= isl_printer_set_yaml_style(p
, ISL_YAML_STYLE_FLOW
);
1447 p
= isl_printer_yaml_start_sequence(p
);
1448 n
= isl_schedule_band_n_member(band
);
1449 for (i
= 0; i
< n
; ++i
) {
1450 p
= isl_printer_print_int(p
,
1451 isl_schedule_band_member_get_coincident(band
, i
));
1452 p
= isl_printer_yaml_next(p
);
1454 p
= isl_printer_yaml_end_sequence(p
);
1455 p
= isl_printer_set_yaml_style(p
, style
);
1461 /* Print "tree" to "p".
1463 * If "n_ancestor" is non-negative, then "child_pos" contains the child
1464 * positions of a descendant of the current node that should be marked
1465 * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor"
1466 * is zero, then the current node should be marked.
1467 * The marking is only printed in YAML block format.
1469 * Implicit leaf nodes are not printed, except if they correspond
1470 * to the node that should be marked.
1472 __isl_give isl_printer
*isl_printer_print_schedule_tree_mark(
1473 __isl_take isl_printer
*p
, __isl_keep isl_schedule_tree
*tree
,
1474 int n_ancestor
, int *child_pos
)
1480 block
= isl_printer_get_yaml_style(p
) == ISL_YAML_STYLE_BLOCK
;
1482 p
= isl_printer_yaml_start_mapping(p
);
1483 if (n_ancestor
== 0 && block
) {
1484 p
= isl_printer_print_str(p
, "# YOU ARE HERE");
1485 p
= isl_printer_end_line(p
);
1486 p
= isl_printer_start_line(p
);
1488 switch (tree
->type
) {
1489 case isl_schedule_node_error
:
1490 p
= isl_printer_print_str(p
, "ERROR");
1492 case isl_schedule_node_leaf
:
1493 p
= isl_printer_print_str(p
, "leaf");
1495 case isl_schedule_node_sequence
:
1496 p
= isl_printer_print_str(p
, "sequence");
1499 case isl_schedule_node_set
:
1500 p
= isl_printer_print_str(p
, "set");
1503 case isl_schedule_node_domain
:
1504 p
= isl_printer_print_str(p
, "domain");
1505 p
= isl_printer_yaml_next(p
);
1506 p
= isl_printer_print_str(p
, "\"");
1507 p
= isl_printer_print_union_set(p
, tree
->domain
);
1508 p
= isl_printer_print_str(p
, "\"");
1510 case isl_schedule_node_filter
:
1511 p
= isl_printer_print_str(p
, "filter");
1512 p
= isl_printer_yaml_next(p
);
1513 p
= isl_printer_print_str(p
, "\"");
1514 p
= isl_printer_print_union_set(p
, tree
->filter
);
1515 p
= isl_printer_print_str(p
, "\"");
1517 case isl_schedule_node_band
:
1518 p
= print_tree_band(p
, tree
->band
);
1521 p
= isl_printer_yaml_next(p
);
1523 if (!tree
->children
) {
1524 if (n_ancestor
> 0 && block
) {
1525 isl_schedule_tree
*leaf
;
1527 p
= isl_printer_print_str(p
, "child");
1528 p
= isl_printer_yaml_next(p
);
1529 leaf
= isl_schedule_tree_leaf(isl_printer_get_ctx(p
));
1530 p
= isl_printer_print_schedule_tree_mark(p
,
1532 isl_schedule_tree_free(leaf
);
1533 p
= isl_printer_yaml_next(p
);
1535 return isl_printer_yaml_end_mapping(p
);
1539 p
= isl_printer_yaml_start_sequence(p
);
1541 p
= isl_printer_print_str(p
, "child");
1542 p
= isl_printer_yaml_next(p
);
1545 n
= isl_schedule_tree_list_n_schedule_tree(tree
->children
);
1546 for (i
= 0; i
< n
; ++i
) {
1547 isl_schedule_tree
*t
;
1549 t
= isl_schedule_tree_get_child(tree
, i
);
1550 if (n_ancestor
> 0 && child_pos
[0] == i
)
1551 p
= isl_printer_print_schedule_tree_mark(p
, t
,
1552 n_ancestor
- 1, child_pos
+ 1);
1554 p
= isl_printer_print_schedule_tree_mark(p
, t
,
1556 isl_schedule_tree_free(t
);
1558 p
= isl_printer_yaml_next(p
);
1562 p
= isl_printer_yaml_end_sequence(p
);
1563 p
= isl_printer_yaml_end_mapping(p
);
1568 /* Print "tree" to "p".
1570 __isl_give isl_printer
*isl_printer_print_schedule_tree(
1571 __isl_take isl_printer
*p
, __isl_keep isl_schedule_tree
*tree
)
1573 return isl_printer_print_schedule_tree_mark(p
, tree
, -1, NULL
);
1576 void isl_schedule_tree_dump(__isl_keep isl_schedule_tree
*tree
)
1579 isl_printer
*printer
;
1584 ctx
= isl_schedule_tree_get_ctx(tree
);
1585 printer
= isl_printer_to_file(ctx
, stderr
);
1586 printer
= isl_printer_set_yaml_style(printer
, ISL_YAML_STYLE_BLOCK
);
1587 printer
= isl_printer_print_schedule_tree(printer
, tree
);
1589 isl_printer_free(printer
);