add isl_schedule_node_get_prefix_schedule_relation
[isl.git] / isl_schedule_tree.c
blob8f5475560f0e7e4b4f5a61785f29406e47e7fba1
1 /*
2 * Copyright 2013-2014 Ecole Normale Superieure
3 * Copyright 2014 INRIA Rocquencourt
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege,
8 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
9 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
10 * B.P. 105 - 78153 Le Chesnay, France
13 #include <isl/map.h>
14 #include <isl_schedule_band.h>
15 #include <isl_schedule_private.h>
17 #undef EL
18 #define EL isl_schedule_tree
20 #include <isl_list_templ.h>
22 #undef BASE
23 #define BASE schedule_tree
25 #include <isl_list_templ.c>
27 /* Is "tree" the leaf of a schedule tree?
29 int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree)
31 return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf;
34 /* Create a new schedule tree of type "type".
35 * The caller is responsible for filling in the type specific fields and
36 * the children.
38 * By default, the single node tree does not have any anchored nodes.
39 * The caller is responsible for updating the anchored field if needed.
41 static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx,
42 enum isl_schedule_node_type type)
44 isl_schedule_tree *tree;
46 if (type == isl_schedule_node_error)
47 return NULL;
49 tree = isl_calloc_type(ctx, isl_schedule_tree);
50 if (!tree)
51 return NULL;
53 tree->ref = 1;
54 tree->ctx = ctx;
55 isl_ctx_ref(ctx);
56 tree->type = type;
57 tree->anchored = 0;
59 return tree;
62 /* Return a fresh copy of "tree".
64 __isl_take isl_schedule_tree *isl_schedule_tree_dup(
65 __isl_keep isl_schedule_tree *tree)
67 isl_ctx *ctx;
68 isl_schedule_tree *dup;
70 if (!tree)
71 return NULL;
73 ctx = isl_schedule_tree_get_ctx(tree);
74 dup = isl_schedule_tree_alloc(ctx, tree->type);
75 if (!dup)
76 return NULL;
78 switch (tree->type) {
79 case isl_schedule_node_error:
80 isl_die(ctx, isl_error_internal,
81 "allocation should have failed",
82 isl_schedule_tree_free(dup));
83 case isl_schedule_node_band:
84 dup->band = isl_schedule_band_copy(tree->band);
85 if (!dup->band)
86 return isl_schedule_tree_free(dup);
87 break;
88 case isl_schedule_node_context:
89 dup->context = isl_set_copy(tree->context);
90 if (!dup->context)
91 return isl_schedule_tree_free(dup);
92 break;
93 case isl_schedule_node_domain:
94 dup->domain = isl_union_set_copy(tree->domain);
95 if (!dup->domain)
96 return isl_schedule_tree_free(dup);
97 break;
98 case isl_schedule_node_expansion:
99 dup->contraction =
100 isl_union_pw_multi_aff_copy(tree->contraction);
101 dup->expansion = isl_union_map_copy(tree->expansion);
102 if (!dup->contraction || !dup->expansion)
103 return isl_schedule_tree_free(dup);
104 break;
105 case isl_schedule_node_filter:
106 dup->filter = isl_union_set_copy(tree->filter);
107 if (!dup->filter)
108 return isl_schedule_tree_free(dup);
109 break;
110 case isl_schedule_node_mark:
111 dup->mark = isl_id_copy(tree->mark);
112 if (!dup->mark)
113 return isl_schedule_tree_free(dup);
114 break;
115 case isl_schedule_node_leaf:
116 case isl_schedule_node_sequence:
117 case isl_schedule_node_set:
118 break;
121 if (tree->children) {
122 dup->children = isl_schedule_tree_list_copy(tree->children);
123 if (!dup->children)
124 return isl_schedule_tree_free(dup);
126 dup->anchored = tree->anchored;
128 return dup;
131 /* Return an isl_schedule_tree that is equal to "tree" and that has only
132 * a single reference.
134 * This function is called before a tree is modified.
135 * A static tree (with negative reference count) should never be modified,
136 * so it is not allowed to call this function on a static tree.
138 __isl_give isl_schedule_tree *isl_schedule_tree_cow(
139 __isl_take isl_schedule_tree *tree)
141 if (!tree)
142 return NULL;
144 if (tree->ref < 0)
145 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
146 "static trees cannot be modified",
147 return isl_schedule_tree_free(tree));
149 if (tree->ref == 1)
150 return tree;
151 tree->ref--;
152 return isl_schedule_tree_dup(tree);
155 /* Return a new reference to "tree".
157 * A static tree (with negative reference count) does not keep track
158 * of the number of references and should not be modified.
160 __isl_give isl_schedule_tree *isl_schedule_tree_copy(
161 __isl_keep isl_schedule_tree *tree)
163 if (!tree)
164 return NULL;
166 if (tree->ref < 0)
167 return tree;
169 tree->ref++;
170 return tree;
173 /* Free "tree" and return NULL.
175 __isl_null isl_schedule_tree *isl_schedule_tree_free(
176 __isl_take isl_schedule_tree *tree)
178 if (!tree)
179 return NULL;
180 if (tree->ref < 0)
181 return NULL;
182 if (--tree->ref > 0)
183 return NULL;
185 switch (tree->type) {
186 case isl_schedule_node_band:
187 isl_schedule_band_free(tree->band);
188 break;
189 case isl_schedule_node_context:
190 isl_set_free(tree->context);
191 break;
192 case isl_schedule_node_domain:
193 isl_union_set_free(tree->domain);
194 break;
195 case isl_schedule_node_expansion:
196 isl_union_pw_multi_aff_free(tree->contraction);
197 isl_union_map_free(tree->expansion);
198 break;
199 case isl_schedule_node_filter:
200 isl_union_set_free(tree->filter);
201 break;
202 case isl_schedule_node_mark:
203 isl_id_free(tree->mark);
204 break;
205 case isl_schedule_node_sequence:
206 case isl_schedule_node_set:
207 case isl_schedule_node_error:
208 case isl_schedule_node_leaf:
209 break;
211 isl_schedule_tree_list_free(tree->children);
212 isl_ctx_deref(tree->ctx);
213 free(tree);
215 return NULL;
218 /* Create and return a new leaf schedule tree.
220 __isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx)
222 return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf);
225 /* Create a new band schedule tree referring to "band"
226 * with no children.
228 __isl_give isl_schedule_tree *isl_schedule_tree_from_band(
229 __isl_take isl_schedule_band *band)
231 isl_ctx *ctx;
232 isl_schedule_tree *tree;
234 if (!band)
235 return NULL;
237 ctx = isl_schedule_band_get_ctx(band);
238 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band);
239 if (!tree)
240 goto error;
242 tree->band = band;
243 tree->anchored = isl_schedule_band_is_anchored(band);
245 return tree;
246 error:
247 isl_schedule_band_free(band);
248 return NULL;
251 /* Create a new context schedule tree with the given context and no children.
252 * Since the context references the outer schedule dimension,
253 * the tree is anchored.
255 __isl_give isl_schedule_tree *isl_schedule_tree_from_context(
256 __isl_take isl_set *context)
258 isl_ctx *ctx;
259 isl_schedule_tree *tree;
261 if (!context)
262 return NULL;
264 ctx = isl_set_get_ctx(context);
265 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context);
266 if (!tree)
267 goto error;
269 tree->context = context;
270 tree->anchored = 1;
272 return tree;
273 error:
274 isl_set_free(context);
275 return NULL;
278 /* Create a new domain schedule tree with the given domain and no children.
280 __isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
281 __isl_take isl_union_set *domain)
283 isl_ctx *ctx;
284 isl_schedule_tree *tree;
286 if (!domain)
287 return NULL;
289 ctx = isl_union_set_get_ctx(domain);
290 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain);
291 if (!tree)
292 goto error;
294 tree->domain = domain;
296 return tree;
297 error:
298 isl_union_set_free(domain);
299 return NULL;
302 /* Create a new expansion schedule tree with the given contraction and
303 * expansion and no children.
305 __isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
306 __isl_take isl_union_pw_multi_aff *contraction,
307 __isl_take isl_union_map *expansion)
309 isl_ctx *ctx;
310 isl_schedule_tree *tree;
312 if (!contraction || !expansion)
313 goto error;
315 ctx = isl_union_map_get_ctx(expansion);
316 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion);
317 if (!tree)
318 goto error;
320 tree->contraction = contraction;
321 tree->expansion = expansion;
323 return tree;
324 error:
325 isl_union_pw_multi_aff_free(contraction);
326 isl_union_map_free(expansion);
327 return NULL;
330 /* Create a new filter schedule tree with the given filter and no children.
332 __isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
333 __isl_take isl_union_set *filter)
335 isl_ctx *ctx;
336 isl_schedule_tree *tree;
338 if (!filter)
339 return NULL;
341 ctx = isl_union_set_get_ctx(filter);
342 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter);
343 if (!tree)
344 goto error;
346 tree->filter = filter;
348 return tree;
349 error:
350 isl_union_set_free(filter);
351 return NULL;
354 /* Create a new mark schedule tree with the given mark identifier and
355 * no children.
357 __isl_give isl_schedule_tree *isl_schedule_tree_from_mark(
358 __isl_take isl_id *mark)
360 isl_ctx *ctx;
361 isl_schedule_tree *tree;
363 if (!mark)
364 return NULL;
366 ctx = isl_id_get_ctx(mark);
367 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark);
368 if (!tree)
369 goto error;
371 tree->mark = mark;
373 return tree;
374 error:
375 isl_id_free(mark);
376 return NULL;
379 /* Does "tree" have any node that depends on its position
380 * in the complete schedule tree?
382 int isl_schedule_tree_is_subtree_anchored(__isl_keep isl_schedule_tree *tree)
384 return tree ? tree->anchored : -1;
387 /* Does the root node of "tree" depend on its position in the complete
388 * schedule tree?
389 * Band nodes may be anchored depending on the associated AST build options.
390 * Context nodes are always anchored.
392 int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
394 if (!tree)
395 return -1;
397 switch (isl_schedule_tree_get_type(tree)) {
398 case isl_schedule_node_error:
399 return -1;
400 case isl_schedule_node_band:
401 return isl_schedule_band_is_anchored(tree->band);
402 case isl_schedule_node_context:
403 return 1;
404 case isl_schedule_node_domain:
405 case isl_schedule_node_expansion:
406 case isl_schedule_node_filter:
407 case isl_schedule_node_leaf:
408 case isl_schedule_node_mark:
409 case isl_schedule_node_sequence:
410 case isl_schedule_node_set:
411 return 0;
415 /* Update the anchored field of "tree" based on whether the root node
416 * itself in anchored and the anchored fields of the children.
418 * This function should be called whenever the children of a tree node
419 * are changed or the anchoredness of the tree root itself changes.
421 __isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
422 __isl_take isl_schedule_tree *tree)
424 int i, n;
425 int anchored;
427 if (!tree)
428 return NULL;
430 anchored = isl_schedule_tree_is_anchored(tree);
431 if (anchored < 0)
432 return isl_schedule_tree_free(tree);
434 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
435 for (i = 0; !anchored && i < n; ++i) {
436 isl_schedule_tree *child;
438 child = isl_schedule_tree_get_child(tree, i);
439 if (!child)
440 return isl_schedule_tree_free(tree);
441 anchored = child->anchored;
442 isl_schedule_tree_free(child);
445 if (anchored == tree->anchored)
446 return tree;
447 tree = isl_schedule_tree_cow(tree);
448 if (!tree)
449 return NULL;
450 tree->anchored = anchored;
451 return tree;
454 /* Create a new tree of the given type (isl_schedule_node_sequence or
455 * isl_schedule_node_set) with the given children.
457 __isl_give isl_schedule_tree *isl_schedule_tree_from_children(
458 enum isl_schedule_node_type type,
459 __isl_take isl_schedule_tree_list *list)
461 isl_ctx *ctx;
462 isl_schedule_tree *tree;
464 if (!list)
465 return NULL;
467 ctx = isl_schedule_tree_list_get_ctx(list);
468 tree = isl_schedule_tree_alloc(ctx, type);
469 if (!tree)
470 goto error;
472 tree->children = list;
473 tree = isl_schedule_tree_update_anchored(tree);
475 return tree;
476 error:
477 isl_schedule_tree_list_free(list);
478 return NULL;
481 /* Construct a tree with a root node of type "type" and as children
482 * "tree1" and "tree2".
483 * If the root of one (or both) of the input trees is itself of type "type",
484 * then the tree is replaced by its children.
486 __isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
487 enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
488 __isl_take isl_schedule_tree *tree2)
490 isl_ctx *ctx;
491 isl_schedule_tree_list *list;
493 if (!tree1 || !tree2)
494 goto error;
496 ctx = isl_schedule_tree_get_ctx(tree1);
497 if (isl_schedule_tree_get_type(tree1) == type) {
498 list = isl_schedule_tree_list_copy(tree1->children);
499 isl_schedule_tree_free(tree1);
500 } else {
501 list = isl_schedule_tree_list_alloc(ctx, 2);
502 list = isl_schedule_tree_list_add(list, tree1);
504 if (isl_schedule_tree_get_type(tree2) == type) {
505 isl_schedule_tree_list *children;
507 children = isl_schedule_tree_list_copy(tree2->children);
508 list = isl_schedule_tree_list_concat(list, children);
509 isl_schedule_tree_free(tree2);
510 } else {
511 list = isl_schedule_tree_list_add(list, tree2);
514 return isl_schedule_tree_from_children(type, list);
515 error:
516 isl_schedule_tree_free(tree1);
517 isl_schedule_tree_free(tree2);
518 return NULL;
521 /* Return the isl_ctx to which "tree" belongs.
523 isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
525 return tree ? tree->ctx : NULL;
528 /* Return the type of the root of the tree or isl_schedule_node_error
529 * on error.
531 enum isl_schedule_node_type isl_schedule_tree_get_type(
532 __isl_keep isl_schedule_tree *tree)
534 return tree ? tree->type : isl_schedule_node_error;
537 /* Are "tree1" and "tree2" obviously equal to each other?
539 int isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
540 __isl_keep isl_schedule_tree *tree2)
542 int equal;
543 int i, n;
545 if (!tree1 || !tree2)
546 return -1;
547 if (tree1 == tree2)
548 return 1;
549 if (tree1->type != tree2->type)
550 return 0;
552 switch (tree1->type) {
553 case isl_schedule_node_band:
554 equal = isl_schedule_band_plain_is_equal(tree1->band,
555 tree2->band);
556 break;
557 case isl_schedule_node_context:
558 equal = isl_set_is_equal(tree1->context, tree2->context);
559 break;
560 case isl_schedule_node_domain:
561 equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
562 break;
563 case isl_schedule_node_expansion:
564 equal = isl_union_map_is_equal(tree1->expansion,
565 tree2->expansion);
566 if (equal >= 0 && equal)
567 equal = isl_union_pw_multi_aff_plain_is_equal(
568 tree1->contraction, tree2->contraction);
569 break;
570 case isl_schedule_node_filter:
571 equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
572 break;
573 case isl_schedule_node_mark:
574 equal = tree1->mark == tree2->mark;
575 break;
576 case isl_schedule_node_leaf:
577 case isl_schedule_node_sequence:
578 case isl_schedule_node_set:
579 equal = 1;
580 break;
581 case isl_schedule_node_error:
582 equal = -1;
583 break;
586 if (equal < 0 || !equal)
587 return equal;
589 n = isl_schedule_tree_n_children(tree1);
590 if (n != isl_schedule_tree_n_children(tree2))
591 return 0;
592 for (i = 0; i < n; ++i) {
593 isl_schedule_tree *child1, *child2;
595 child1 = isl_schedule_tree_get_child(tree1, i);
596 child2 = isl_schedule_tree_get_child(tree2, i);
597 equal = isl_schedule_tree_plain_is_equal(child1, child2);
598 isl_schedule_tree_free(child1);
599 isl_schedule_tree_free(child2);
601 if (equal < 0 || !equal)
602 return equal;
605 return 1;
608 /* Does "tree" have any children, other than an implicit leaf.
610 int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
612 if (!tree)
613 return -1;
615 return tree->children != NULL;
618 /* Return the number of children of "tree", excluding implicit leaves.
620 int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
622 if (!tree)
623 return -1;
625 return isl_schedule_tree_list_n_schedule_tree(tree->children);
628 /* Return a copy of the (explicit) child at position "pos" of "tree".
630 __isl_give isl_schedule_tree *isl_schedule_tree_get_child(
631 __isl_keep isl_schedule_tree *tree, int pos)
633 if (!tree)
634 return NULL;
635 if (!tree->children)
636 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
637 "schedule tree has no explicit children", return NULL);
638 return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
641 /* Return a copy of the (explicit) child at position "pos" of "tree" and
642 * free "tree".
644 __isl_give isl_schedule_tree *isl_schedule_tree_child(
645 __isl_take isl_schedule_tree *tree, int pos)
647 isl_schedule_tree *child;
649 child = isl_schedule_tree_get_child(tree, pos);
650 isl_schedule_tree_free(tree);
651 return child;
654 /* Remove all (explicit) children from "tree".
656 __isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
657 __isl_take isl_schedule_tree *tree)
659 tree = isl_schedule_tree_cow(tree);
660 if (!tree)
661 return NULL;
662 tree->children = isl_schedule_tree_list_free(tree->children);
663 return tree;
666 /* Remove the child at position "pos" from the children of "tree".
667 * If there was only one child to begin with, then remove all children.
669 __isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
670 __isl_take isl_schedule_tree *tree, int pos)
672 int n;
674 tree = isl_schedule_tree_cow(tree);
675 if (!tree)
676 return NULL;
678 if (!isl_schedule_tree_has_children(tree))
679 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
680 "tree does not have any explicit children",
681 return isl_schedule_tree_free(tree));
682 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
683 if (pos < 0 || pos >= n)
684 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
685 "position out of bounds",
686 return isl_schedule_tree_free(tree));
687 if (n == 1)
688 return isl_schedule_tree_reset_children(tree);
690 tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
691 if (!tree->children)
692 return isl_schedule_tree_free(tree);
694 return tree;
697 /* Replace the child at position "pos" of "tree" by "child".
699 * If the new child is a leaf, then it is not explicitly
700 * recorded in the list of children. Instead, the list of children
701 * (which is assumed to have only one element) is removed.
702 * Note that the children of set and sequence nodes are always
703 * filters, so they cannot be replaced by empty trees.
705 __isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
706 __isl_take isl_schedule_tree *tree, int pos,
707 __isl_take isl_schedule_tree *child)
709 tree = isl_schedule_tree_cow(tree);
710 if (!tree || !child)
711 goto error;
713 if (isl_schedule_tree_is_leaf(child)) {
714 isl_schedule_tree_free(child);
715 if (!tree->children && pos == 0)
716 return tree;
717 if (isl_schedule_tree_n_children(tree) != 1)
718 isl_die(isl_schedule_tree_get_ctx(tree),
719 isl_error_internal,
720 "can only replace single child by leaf",
721 goto error);
722 return isl_schedule_tree_reset_children(tree);
725 if (!tree->children && pos == 0)
726 tree->children =
727 isl_schedule_tree_list_from_schedule_tree(child);
728 else
729 tree->children = isl_schedule_tree_list_set_schedule_tree(
730 tree->children, pos, child);
732 if (!tree->children)
733 return isl_schedule_tree_free(tree);
734 tree = isl_schedule_tree_update_anchored(tree);
736 return tree;
737 error:
738 isl_schedule_tree_free(tree);
739 isl_schedule_tree_free(child);
740 return NULL;
743 /* Replace the (explicit) children of "tree" by "children"?
745 __isl_give isl_schedule_tree *isl_schedule_tree_set_children(
746 __isl_take isl_schedule_tree *tree,
747 __isl_take isl_schedule_tree_list *children)
749 tree = isl_schedule_tree_cow(tree);
750 if (!tree || !children)
751 goto error;
752 isl_schedule_tree_list_free(tree->children);
753 tree->children = children;
754 return tree;
755 error:
756 isl_schedule_tree_free(tree);
757 isl_schedule_tree_list_free(children);
758 return NULL;
761 /* Create a new band schedule tree referring to "band"
762 * with "tree" as single child.
764 __isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
765 __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
767 isl_schedule_tree *res;
769 res = isl_schedule_tree_from_band(band);
770 return isl_schedule_tree_replace_child(res, 0, tree);
773 /* Create a new context schedule tree with the given context and
774 * with "tree" as single child.
776 __isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
777 __isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
779 isl_schedule_tree *res;
781 res = isl_schedule_tree_from_context(context);
782 return isl_schedule_tree_replace_child(res, 0, tree);
785 /* Create a new domain schedule tree with the given domain and
786 * with "tree" as single child.
788 __isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
789 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
791 isl_schedule_tree *res;
793 res = isl_schedule_tree_from_domain(domain);
794 return isl_schedule_tree_replace_child(res, 0, tree);
797 /* Create a new expansion schedule tree with the given contraction and
798 * expansion and with "tree" as single child.
800 __isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
801 __isl_take isl_schedule_tree *tree,
802 __isl_take isl_union_pw_multi_aff *contraction,
803 __isl_take isl_union_map *expansion)
805 isl_schedule_tree *res;
807 res = isl_schedule_tree_from_expansion(contraction, expansion);
808 return isl_schedule_tree_replace_child(res, 0, tree);
811 /* Create a new filter schedule tree with the given filter and single child.
813 * If the root of "tree" is itself a filter node, then the two
814 * filter nodes are merged into one node.
816 __isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
817 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
819 isl_schedule_tree *res;
821 if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
822 isl_union_set *tree_filter;
824 tree_filter = isl_schedule_tree_filter_get_filter(tree);
825 tree_filter = isl_union_set_intersect(tree_filter, filter);
826 tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
827 return tree;
830 res = isl_schedule_tree_from_filter(filter);
831 return isl_schedule_tree_replace_child(res, 0, tree);
834 /* Insert a filter node with filter set "filter"
835 * in each of the children of "tree".
837 __isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
838 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
840 int i, n;
842 if (!tree || !filter)
843 goto error;
845 n = isl_schedule_tree_n_children(tree);
846 for (i = 0; i < n; ++i) {
847 isl_schedule_tree *child;
849 child = isl_schedule_tree_get_child(tree, i);
850 child = isl_schedule_tree_insert_filter(child,
851 isl_union_set_copy(filter));
852 tree = isl_schedule_tree_replace_child(tree, i, child);
855 isl_union_set_free(filter);
856 return tree;
857 error:
858 isl_union_set_free(filter);
859 isl_schedule_tree_free(tree);
860 return NULL;
863 /* Create a new mark schedule tree with the given mark identifier and
864 * single child.
866 __isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
867 __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
869 isl_schedule_tree *res;
871 res = isl_schedule_tree_from_mark(mark);
872 return isl_schedule_tree_replace_child(res, 0, tree);
875 /* Return the number of members in the band tree root.
877 unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
879 if (!tree)
880 return 0;
882 if (tree->type != isl_schedule_node_band)
883 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
884 "not a band node", return 0);
886 return isl_schedule_band_n_member(tree->band);
889 /* Is the band member at position "pos" of the band tree root
890 * marked coincident?
892 int isl_schedule_tree_band_member_get_coincident(
893 __isl_keep isl_schedule_tree *tree, int pos)
895 if (!tree)
896 return -1;
898 if (tree->type != isl_schedule_node_band)
899 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
900 "not a band node", return -1);
902 return isl_schedule_band_member_get_coincident(tree->band, pos);
905 /* Mark the given band member as being coincident or not
906 * according to "coincident".
908 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
909 __isl_take isl_schedule_tree *tree, int pos, int coincident)
911 if (!tree)
912 return NULL;
913 if (tree->type != isl_schedule_node_band)
914 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
915 "not a band node", return isl_schedule_tree_free(tree));
916 if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
917 coincident)
918 return tree;
919 tree = isl_schedule_tree_cow(tree);
920 if (!tree)
921 return NULL;
923 tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
924 coincident);
925 if (!tree->band)
926 return isl_schedule_tree_free(tree);
927 return tree;
930 /* Is the band tree root marked permutable?
932 int isl_schedule_tree_band_get_permutable(__isl_keep isl_schedule_tree *tree)
934 if (!tree)
935 return -1;
937 if (tree->type != isl_schedule_node_band)
938 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
939 "not a band node", return -1);
941 return isl_schedule_band_get_permutable(tree->band);
944 /* Mark the band tree root permutable or not according to "permutable"?
946 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
947 __isl_take isl_schedule_tree *tree, int permutable)
949 if (!tree)
950 return NULL;
951 if (tree->type != isl_schedule_node_band)
952 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
953 "not a band node", return isl_schedule_tree_free(tree));
954 if (isl_schedule_tree_band_get_permutable(tree) == permutable)
955 return tree;
956 tree = isl_schedule_tree_cow(tree);
957 if (!tree)
958 return NULL;
960 tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
961 if (!tree->band)
962 return isl_schedule_tree_free(tree);
963 return tree;
966 /* Return the schedule space of the band tree root.
968 __isl_give isl_space *isl_schedule_tree_band_get_space(
969 __isl_keep isl_schedule_tree *tree)
971 if (!tree)
972 return NULL;
974 if (tree->type != isl_schedule_node_band)
975 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
976 "not a band node", return NULL);
978 return isl_schedule_band_get_space(tree->band);
981 /* Intersect the domain of the band schedule of the band tree root
982 * with "domain".
984 __isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
985 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
987 if (!tree || !domain)
988 goto error;
990 if (tree->type != isl_schedule_node_band)
991 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
992 "not a band node", goto error);
994 tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
995 if (!tree->band)
996 return isl_schedule_tree_free(tree);
998 return tree;
999 error:
1000 isl_schedule_tree_free(tree);
1001 isl_union_set_free(domain);
1002 return NULL;
1005 /* Return the schedule of the band tree root in isolation.
1007 __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
1008 __isl_keep isl_schedule_tree *tree)
1010 if (!tree)
1011 return NULL;
1013 if (tree->type != isl_schedule_node_band)
1014 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1015 "not a band node", return NULL);
1017 return isl_schedule_band_get_partial_schedule(tree->band);
1020 /* Replace the schedule of the band tree root by "schedule".
1022 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
1023 __isl_take isl_schedule_tree *tree,
1024 __isl_take isl_multi_union_pw_aff *schedule)
1026 tree = isl_schedule_tree_cow(tree);
1027 if (!tree || !schedule)
1028 goto error;
1030 if (tree->type != isl_schedule_node_band)
1031 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1032 "not a band node", return NULL);
1033 tree->band = isl_schedule_band_set_partial_schedule(tree->band,
1034 schedule);
1036 return tree;
1037 error:
1038 isl_schedule_tree_free(tree);
1039 isl_multi_union_pw_aff_free(schedule);
1040 return NULL;
1043 /* Return the loop AST generation type for the band member
1044 * of the band tree root at position "pos".
1046 enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
1047 __isl_keep isl_schedule_tree *tree, int pos)
1049 if (!tree)
1050 return isl_ast_loop_error;
1052 if (tree->type != isl_schedule_node_band)
1053 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1054 "not a band node", return isl_ast_loop_error);
1056 return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
1059 /* Set the loop AST generation type for the band member of the band tree root
1060 * at position "pos" to "type".
1062 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
1063 __isl_take isl_schedule_tree *tree, int pos,
1064 enum isl_ast_loop_type type)
1066 tree = isl_schedule_tree_cow(tree);
1067 if (!tree)
1068 return NULL;
1070 if (tree->type != isl_schedule_node_band)
1071 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1072 "not a band node", return isl_schedule_tree_free(tree));
1074 tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
1075 pos, type);
1076 if (!tree->band)
1077 return isl_schedule_tree_free(tree);
1079 return tree;
1082 /* Return the loop AST generation type for the band member
1083 * of the band tree root at position "pos" for the isolated part.
1085 enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
1086 __isl_keep isl_schedule_tree *tree, int pos)
1088 if (!tree)
1089 return isl_ast_loop_error;
1091 if (tree->type != isl_schedule_node_band)
1092 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1093 "not a band node", return isl_ast_loop_error);
1095 return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
1096 pos);
1099 /* Set the loop AST generation type for the band member of the band tree root
1100 * at position "pos" for the isolated part to "type".
1102 __isl_give isl_schedule_tree *
1103 isl_schedule_tree_band_member_set_isolate_ast_loop_type(
1104 __isl_take isl_schedule_tree *tree, int pos,
1105 enum isl_ast_loop_type type)
1107 tree = isl_schedule_tree_cow(tree);
1108 if (!tree)
1109 return NULL;
1111 if (tree->type != isl_schedule_node_band)
1112 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1113 "not a band node", return isl_schedule_tree_free(tree));
1115 tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
1116 tree->band, pos, type);
1117 if (!tree->band)
1118 return isl_schedule_tree_free(tree);
1120 return tree;
1123 /* Return the AST build options associated to the band tree root.
1125 __isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
1126 __isl_keep isl_schedule_tree *tree)
1128 if (!tree)
1129 return NULL;
1131 if (tree->type != isl_schedule_node_band)
1132 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1133 "not a band node", return NULL);
1135 return isl_schedule_band_get_ast_build_options(tree->band);
1138 /* Replace the AST build options associated to band tree root by "options".
1139 * Updated the anchored field if the anchoredness of the root node itself
1140 * changes.
1142 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
1143 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
1145 int was_anchored;
1147 tree = isl_schedule_tree_cow(tree);
1148 if (!tree || !options)
1149 goto error;
1151 if (tree->type != isl_schedule_node_band)
1152 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1153 "not a band node", goto error);
1155 was_anchored = isl_schedule_tree_is_anchored(tree);
1156 tree->band = isl_schedule_band_set_ast_build_options(tree->band,
1157 options);
1158 if (!tree->band)
1159 return isl_schedule_tree_free(tree);
1160 if (isl_schedule_tree_is_anchored(tree) != was_anchored)
1161 tree = isl_schedule_tree_update_anchored(tree);
1163 return tree;
1164 error:
1165 isl_schedule_tree_free(tree);
1166 isl_union_set_free(options);
1167 return NULL;
1170 /* Return the context of the context tree root.
1172 __isl_give isl_set *isl_schedule_tree_context_get_context(
1173 __isl_keep isl_schedule_tree *tree)
1175 if (!tree)
1176 return NULL;
1178 if (tree->type != isl_schedule_node_context)
1179 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1180 "not a context node", return NULL);
1182 return isl_set_copy(tree->context);
1185 /* Return the domain of the domain tree root.
1187 __isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
1188 __isl_keep isl_schedule_tree *tree)
1190 if (!tree)
1191 return NULL;
1193 if (tree->type != isl_schedule_node_domain)
1194 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1195 "not a domain node", return NULL);
1197 return isl_union_set_copy(tree->domain);
1200 /* Replace the domain of domain tree root "tree" by "domain".
1202 __isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
1203 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1205 tree = isl_schedule_tree_cow(tree);
1206 if (!tree || !domain)
1207 goto error;
1209 if (tree->type != isl_schedule_node_domain)
1210 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1211 "not a domain node", goto error);
1213 isl_union_set_free(tree->domain);
1214 tree->domain = domain;
1216 return tree;
1217 error:
1218 isl_schedule_tree_free(tree);
1219 isl_union_set_free(domain);
1220 return NULL;
1223 /* Return the contraction of the expansion tree root.
1225 __isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
1226 __isl_keep isl_schedule_tree *tree)
1228 if (!tree)
1229 return NULL;
1231 if (tree->type != isl_schedule_node_expansion)
1232 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1233 "not an expansion node", return NULL);
1235 return isl_union_pw_multi_aff_copy(tree->contraction);
1238 /* Return the expansion of the expansion tree root.
1240 __isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
1241 __isl_keep isl_schedule_tree *tree)
1243 if (!tree)
1244 return NULL;
1246 if (tree->type != isl_schedule_node_expansion)
1247 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1248 "not an expansion node", return NULL);
1250 return isl_union_map_copy(tree->expansion);
1253 /* Replace the contraction and the expansion of the expansion tree root "tree"
1254 * by "contraction" and "expansion".
1256 __isl_give isl_schedule_tree *
1257 isl_schedule_tree_expansion_set_contraction_and_expansion(
1258 __isl_take isl_schedule_tree *tree,
1259 __isl_take isl_union_pw_multi_aff *contraction,
1260 __isl_take isl_union_map *expansion)
1262 tree = isl_schedule_tree_cow(tree);
1263 if (!tree || !contraction || !expansion)
1264 goto error;
1266 if (tree->type != isl_schedule_node_expansion)
1267 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1268 "not an expansion node", return NULL);
1270 isl_union_pw_multi_aff_free(tree->contraction);
1271 tree->contraction = contraction;
1272 isl_union_map_free(tree->expansion);
1273 tree->expansion = expansion;
1275 return tree;
1276 error:
1277 isl_schedule_tree_free(tree);
1278 isl_union_pw_multi_aff_free(contraction);
1279 isl_union_map_free(expansion);
1280 return NULL;
1283 /* Return the filter of the filter tree root.
1285 __isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
1286 __isl_keep isl_schedule_tree *tree)
1288 if (!tree)
1289 return NULL;
1291 if (tree->type != isl_schedule_node_filter)
1292 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1293 "not a filter node", return NULL);
1295 return isl_union_set_copy(tree->filter);
1298 /* Replace the filter of the filter tree root by "filter".
1300 __isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
1301 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
1303 tree = isl_schedule_tree_cow(tree);
1304 if (!tree || !filter)
1305 goto error;
1307 if (tree->type != isl_schedule_node_filter)
1308 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1309 "not a filter node", return NULL);
1311 isl_union_set_free(tree->filter);
1312 tree->filter = filter;
1314 return tree;
1315 error:
1316 isl_schedule_tree_free(tree);
1317 isl_union_set_free(filter);
1318 return NULL;
1321 /* Return the mark identifier of the mark tree root "tree".
1323 __isl_give isl_id *isl_schedule_tree_mark_get_id(
1324 __isl_keep isl_schedule_tree *tree)
1326 if (!tree)
1327 return NULL;
1329 if (tree->type != isl_schedule_node_mark)
1330 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1331 "not a mark node", return NULL);
1333 return isl_id_copy(tree->mark);
1336 /* Set dim to the range dimension of "map" and abort the search.
1338 static int set_range_dim(__isl_take isl_map *map, void *user)
1340 int *dim = user;
1342 *dim = isl_map_dim(map, isl_dim_out);
1343 isl_map_free(map);
1345 return -1;
1348 /* Return the dimension of the range of "umap".
1349 * "umap" is assumed not to be empty and
1350 * all maps inside "umap" are assumed to have the same range.
1352 * We extract the range dimension from the first map in "umap".
1354 static int range_dim(__isl_keep isl_union_map *umap)
1356 int dim = -1;
1358 if (!umap)
1359 return -1;
1360 if (isl_union_map_n_map(umap) == 0)
1361 isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
1362 "unexpected empty input", return -1);
1364 isl_union_map_foreach_map(umap, &set_range_dim, &dim);
1366 return dim;
1369 /* Append an "extra" number of zeros to the range of "umap" and
1370 * return the result.
1372 static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
1373 int extra)
1375 isl_union_set *dom;
1376 isl_space *space;
1377 isl_multi_val *mv;
1378 isl_union_pw_multi_aff *suffix;
1379 isl_union_map *universe;
1380 isl_union_map *suffix_umap;
1382 universe = isl_union_map_universe(isl_union_map_copy(umap));
1383 dom = isl_union_map_domain(universe);
1384 space = isl_union_set_get_space(dom);
1385 space = isl_space_set_from_params(space);
1386 space = isl_space_add_dims(space, isl_dim_set, extra);
1387 mv = isl_multi_val_zero(space);
1389 suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
1390 suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
1391 umap = isl_union_map_flat_range_product(umap, suffix_umap);
1393 return umap;
1396 /* Should we skip the root of "tree" while looking for the first
1397 * descendant with schedule information?
1398 * That is, is it impossible to derive any information about
1399 * the iteration domain from this node?
1401 * We do not want to skip leaf or error nodes because there is
1402 * no point in looking any deeper from these nodes.
1404 static int domain_less(__isl_keep isl_schedule_tree *tree)
1406 enum isl_schedule_node_type type;
1408 type = isl_schedule_tree_get_type(tree);
1409 switch (type) {
1410 case isl_schedule_node_band:
1411 return isl_schedule_tree_band_n_member(tree) == 0;
1412 case isl_schedule_node_context:
1413 case isl_schedule_node_mark:
1414 return 1;
1415 case isl_schedule_node_leaf:
1416 case isl_schedule_node_error:
1417 case isl_schedule_node_domain:
1418 case isl_schedule_node_expansion:
1419 case isl_schedule_node_filter:
1420 case isl_schedule_node_set:
1421 case isl_schedule_node_sequence:
1422 return 0;
1426 /* Move down to the first descendant of "tree" that contains any schedule
1427 * information or return "leaf" if there is no such descendant.
1429 __isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
1430 __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
1432 while (domain_less(tree)) {
1433 if (!isl_schedule_tree_has_children(tree)) {
1434 isl_schedule_tree_free(tree);
1435 return isl_schedule_tree_copy(leaf);
1437 tree = isl_schedule_tree_child(tree, 0);
1440 return tree;
1443 static __isl_give isl_union_map *subtree_schedule_extend(
1444 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);
1446 /* Extend the schedule map "outer" with the subtree schedule
1447 * of the (single) child of "tree", if any.
1449 * If "tree" does not have any descendants (apart from those that
1450 * do not carry any schedule information), then we simply return "outer".
1451 * Otherwise, we extend the schedule map "outer" with the subtree schedule
1452 * of the single child.
1454 static __isl_give isl_union_map *subtree_schedule_extend_child(
1455 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1457 isl_schedule_tree *child;
1458 isl_union_map *res;
1460 if (!tree)
1461 return isl_union_map_free(outer);
1462 if (!isl_schedule_tree_has_children(tree))
1463 return outer;
1464 child = isl_schedule_tree_get_child(tree, 0);
1465 if (!child)
1466 return isl_union_map_free(outer);
1467 res = subtree_schedule_extend(child, outer);
1468 isl_schedule_tree_free(child);
1469 return res;
1472 /* Extract the parameter space from one of the children of "tree",
1473 * which are assumed to be filters.
1475 static __isl_give isl_space *extract_space_from_filter_child(
1476 __isl_keep isl_schedule_tree *tree)
1478 isl_space *space;
1479 isl_union_set *dom;
1480 isl_schedule_tree *child;
1482 child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
1483 dom = isl_schedule_tree_filter_get_filter(child);
1484 space = isl_union_set_get_space(dom);
1485 isl_union_set_free(dom);
1486 isl_schedule_tree_free(child);
1488 return space;
1491 /* Extend the schedule map "outer" with the subtree schedule
1492 * of a set or sequence node.
1494 * The schedule for the set or sequence node itself is composed of
1495 * pieces of the form
1497 * filter -> []
1499 * or
1501 * filter -> [index]
1503 * The first form is used if there is only a single child or
1504 * if the current node is a set node and the schedule_separate_components
1505 * option is not set.
1507 * Each of the pieces above is extended with the subtree schedule of
1508 * the child of the corresponding filter, if any, padded with zeros
1509 * to ensure that all pieces have the same range dimension.
1511 static __isl_give isl_union_map *subtree_schedule_extend_from_children(
1512 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1514 int i, n;
1515 int dim;
1516 int separate;
1517 isl_ctx *ctx;
1518 isl_val *v = NULL;
1519 isl_multi_val *mv;
1520 isl_space *space;
1521 isl_union_map *umap;
1523 if (!tree)
1524 return NULL;
1526 ctx = isl_schedule_tree_get_ctx(tree);
1527 if (!tree->children)
1528 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1529 "missing children", return NULL);
1530 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
1531 if (n == 0)
1532 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1533 "missing children", return NULL);
1535 separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
1536 isl_options_get_schedule_separate_components(ctx));
1538 space = extract_space_from_filter_child(tree);
1540 umap = isl_union_map_empty(isl_space_copy(space));
1541 space = isl_space_set_from_params(space);
1542 if (separate) {
1543 space = isl_space_add_dims(space, isl_dim_set, 1);
1544 v = isl_val_zero(ctx);
1546 mv = isl_multi_val_zero(space);
1548 dim = isl_multi_val_dim(mv, isl_dim_set);
1549 for (i = 0; i < n; ++i) {
1550 isl_union_pw_multi_aff *upma;
1551 isl_union_map *umap_i;
1552 isl_union_set *dom;
1553 isl_schedule_tree *child;
1554 int dim_i;
1555 int empty;
1557 child = isl_schedule_tree_list_get_schedule_tree(
1558 tree->children, i);
1559 dom = isl_schedule_tree_filter_get_filter(child);
1561 if (separate) {
1562 mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
1563 v = isl_val_add_ui(v, 1);
1565 upma = isl_union_pw_multi_aff_multi_val_on_domain(dom,
1566 isl_multi_val_copy(mv));
1567 umap_i = isl_union_map_from_union_pw_multi_aff(upma);
1568 umap_i = isl_union_map_flat_range_product(
1569 isl_union_map_copy(outer), umap_i);
1570 umap_i = subtree_schedule_extend_child(child, umap_i);
1571 isl_schedule_tree_free(child);
1573 empty = isl_union_map_is_empty(umap_i);
1574 if (empty < 0)
1575 umap_i = isl_union_map_free(umap_i);
1576 else if (empty) {
1577 isl_union_map_free(umap_i);
1578 continue;
1581 dim_i = range_dim(umap_i);
1582 if (dim_i < 0) {
1583 umap = isl_union_map_free(umap);
1584 } else if (dim < dim_i) {
1585 umap = append_range(umap, dim_i - dim);
1586 dim = dim_i;
1587 } else if (dim_i < dim) {
1588 umap_i = append_range(umap_i, dim - dim_i);
1590 umap = isl_union_map_union(umap, umap_i);
1593 isl_val_free(v);
1594 isl_multi_val_free(mv);
1595 isl_union_map_free(outer);
1597 return umap;
1600 /* Extend the schedule map "outer" with the subtree schedule of "tree".
1602 * If the root of the tree is a set or a sequence, then we extend
1603 * the schedule map in subtree_schedule_extend_from_children.
1604 * Otherwise, we extend the schedule map with the partial schedule
1605 * corresponding to the root of the tree and then continue with
1606 * the single child of this root.
1607 * In the special case of an expansion, the schedule map is "extended"
1608 * by applying the expansion to the domain of the schedule map.
1610 static __isl_give isl_union_map *subtree_schedule_extend(
1611 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1613 isl_multi_union_pw_aff *mupa;
1614 isl_union_map *umap;
1615 isl_union_set *domain;
1617 if (!tree)
1618 return NULL;
1620 switch (tree->type) {
1621 case isl_schedule_node_error:
1622 return isl_union_map_free(outer);
1623 case isl_schedule_node_context:
1624 case isl_schedule_node_mark:
1625 return subtree_schedule_extend_child(tree, outer);
1626 case isl_schedule_node_band:
1627 if (isl_schedule_tree_band_n_member(tree) == 0)
1628 return subtree_schedule_extend_child(tree, outer);
1629 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1630 umap = isl_union_map_from_multi_union_pw_aff(mupa);
1631 outer = isl_union_map_flat_range_product(outer, umap);
1632 umap = subtree_schedule_extend_child(tree, outer);
1633 break;
1634 case isl_schedule_node_domain:
1635 domain = isl_schedule_tree_domain_get_domain(tree);
1636 umap = isl_union_map_from_domain(domain);
1637 outer = isl_union_map_flat_range_product(outer, umap);
1638 umap = subtree_schedule_extend_child(tree, outer);
1639 break;
1640 case isl_schedule_node_expansion:
1641 umap = isl_schedule_tree_expansion_get_expansion(tree);
1642 outer = isl_union_map_apply_domain(outer, umap);
1643 umap = subtree_schedule_extend_child(tree, outer);
1644 break;
1645 case isl_schedule_node_filter:
1646 domain = isl_schedule_tree_filter_get_filter(tree);
1647 umap = isl_union_map_from_domain(domain);
1648 outer = isl_union_map_flat_range_product(outer, umap);
1649 umap = subtree_schedule_extend_child(tree, outer);
1650 break;
1651 case isl_schedule_node_leaf:
1652 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1653 "leaf node should be handled by caller", return NULL);
1654 case isl_schedule_node_set:
1655 case isl_schedule_node_sequence:
1656 umap = subtree_schedule_extend_from_children(tree, outer);
1657 break;
1660 return umap;
1663 static __isl_give isl_union_set *initial_domain(
1664 __isl_keep isl_schedule_tree *tree);
1666 /* Extract a universe domain from the children of the tree root "tree",
1667 * which is a set or sequence, meaning that its children are filters.
1668 * In particular, return the union of the universes of the filters.
1670 static __isl_give isl_union_set *initial_domain_from_children(
1671 __isl_keep isl_schedule_tree *tree)
1673 int i, n;
1674 isl_space *space;
1675 isl_union_set *domain;
1677 if (!tree->children)
1678 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1679 "missing children", return NULL);
1680 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
1681 if (n == 0)
1682 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1683 "missing children", return NULL);
1685 space = extract_space_from_filter_child(tree);
1686 domain = isl_union_set_empty(space);
1688 for (i = 0; i < n; ++i) {
1689 isl_schedule_tree *child;
1690 isl_union_set *domain_i;
1692 child = isl_schedule_tree_get_child(tree, i);
1693 domain_i = initial_domain(child);
1694 domain = isl_union_set_union(domain, domain_i);
1695 isl_schedule_tree_free(child);
1698 return domain;
1701 /* Extract a universe domain from the tree root "tree".
1702 * The caller is responsible for making sure that this node
1703 * would not be skipped by isl_schedule_tree_first_schedule_descendant
1704 * and that it is not a leaf node.
1706 static __isl_give isl_union_set *initial_domain(
1707 __isl_keep isl_schedule_tree *tree)
1709 isl_multi_union_pw_aff *mupa;
1710 isl_union_set *domain;
1711 isl_union_map *exp;
1713 if (!tree)
1714 return NULL;
1716 switch (tree->type) {
1717 case isl_schedule_node_error:
1718 return NULL;
1719 case isl_schedule_node_context:
1720 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1721 "context node should be handled by caller",
1722 return NULL);
1723 case isl_schedule_node_mark:
1724 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1725 "mark node should be handled by caller",
1726 return NULL);
1727 case isl_schedule_node_band:
1728 if (isl_schedule_tree_band_n_member(tree) == 0)
1729 isl_die(isl_schedule_tree_get_ctx(tree),
1730 isl_error_internal,
1731 "0D band should be handled by caller",
1732 return NULL);
1733 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1734 domain = isl_multi_union_pw_aff_domain(mupa);
1735 domain = isl_union_set_universe(domain);
1736 break;
1737 case isl_schedule_node_domain:
1738 domain = isl_schedule_tree_domain_get_domain(tree);
1739 domain = isl_union_set_universe(domain);
1740 break;
1741 case isl_schedule_node_expansion:
1742 exp = isl_schedule_tree_expansion_get_expansion(tree);
1743 exp = isl_union_map_universe(exp);
1744 domain = isl_union_map_domain(exp);
1745 break;
1746 case isl_schedule_node_filter:
1747 domain = isl_schedule_tree_filter_get_filter(tree);
1748 domain = isl_union_set_universe(domain);
1749 break;
1750 case isl_schedule_node_leaf:
1751 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1752 "leaf node should be handled by caller", return NULL);
1753 case isl_schedule_node_set:
1754 case isl_schedule_node_sequence:
1755 domain = initial_domain_from_children(tree);
1756 break;
1759 return domain;
1762 /* Return the subtree schedule of a node that contains some schedule
1763 * information, i.e., a node that would not be skipped by
1764 * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
1766 * If the tree contains any expansions, then the returned subtree
1767 * schedule is formulated in terms of the expanded domains.
1769 * We start with an initial zero-dimensional subtree schedule based
1770 * on the domain information in the root node and then extend it
1771 * based on the schedule information in the root node and its descendants.
1773 __isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
1774 __isl_keep isl_schedule_tree *tree)
1776 isl_union_set *domain;
1777 isl_union_map *umap;
1779 domain = initial_domain(tree);
1780 umap = isl_union_map_from_domain(domain);
1781 return subtree_schedule_extend(tree, umap);
1784 /* Multiply the partial schedule of the band root node of "tree"
1785 * with the factors in "mv".
1787 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
1788 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
1790 if (!tree || !mv)
1791 goto error;
1792 if (tree->type != isl_schedule_node_band)
1793 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1794 "not a band node", goto error);
1796 tree = isl_schedule_tree_cow(tree);
1797 if (!tree)
1798 goto error;
1800 tree->band = isl_schedule_band_scale(tree->band, mv);
1801 if (!tree->band)
1802 return isl_schedule_tree_free(tree);
1804 return tree;
1805 error:
1806 isl_schedule_tree_free(tree);
1807 isl_multi_val_free(mv);
1808 return NULL;
1811 /* Divide the partial schedule of the band root node of "tree"
1812 * by the factors in "mv".
1814 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
1815 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
1817 if (!tree || !mv)
1818 goto error;
1819 if (tree->type != isl_schedule_node_band)
1820 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1821 "not a band node", goto error);
1823 tree = isl_schedule_tree_cow(tree);
1824 if (!tree)
1825 goto error;
1827 tree->band = isl_schedule_band_scale_down(tree->band, mv);
1828 if (!tree->band)
1829 return isl_schedule_tree_free(tree);
1831 return tree;
1832 error:
1833 isl_schedule_tree_free(tree);
1834 isl_multi_val_free(mv);
1835 return NULL;
1838 /* Tile the band root node of "tree" with tile sizes "sizes".
1840 * We duplicate the band node, change the schedule of one of them
1841 * to the tile schedule and the other to the point schedule and then
1842 * attach the point band as a child to the tile band.
1844 __isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
1845 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
1847 isl_schedule_tree *child = NULL;
1849 if (!tree || !sizes)
1850 goto error;
1851 if (tree->type != isl_schedule_node_band)
1852 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1853 "not a band node", goto error);
1855 child = isl_schedule_tree_copy(tree);
1856 tree = isl_schedule_tree_cow(tree);
1857 child = isl_schedule_tree_cow(child);
1858 if (!tree || !child)
1859 goto error;
1861 tree->band = isl_schedule_band_tile(tree->band,
1862 isl_multi_val_copy(sizes));
1863 if (!tree->band)
1864 goto error;
1865 child->band = isl_schedule_band_point(child->band, tree->band, sizes);
1866 if (!child->band)
1867 child = isl_schedule_tree_free(child);
1869 tree = isl_schedule_tree_replace_child(tree, 0, child);
1871 return tree;
1872 error:
1873 isl_schedule_tree_free(child);
1874 isl_schedule_tree_free(tree);
1875 isl_multi_val_free(sizes);
1876 return NULL;
1879 /* Split the band root node of "tree" into two nested band nodes,
1880 * one with the first "pos" dimensions and
1881 * one with the remaining dimensions.
1883 __isl_give isl_schedule_tree *isl_schedule_tree_band_split(
1884 __isl_take isl_schedule_tree *tree, int pos)
1886 int n;
1887 isl_schedule_tree *child;
1889 if (!tree)
1890 return NULL;
1891 if (tree->type != isl_schedule_node_band)
1892 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1893 "not a band node", return isl_schedule_tree_free(tree));
1895 n = isl_schedule_tree_band_n_member(tree);
1896 if (pos < 0 || pos > n)
1897 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1898 "position out of bounds",
1899 return isl_schedule_tree_free(tree));
1901 child = isl_schedule_tree_copy(tree);
1902 tree = isl_schedule_tree_cow(tree);
1903 child = isl_schedule_tree_cow(child);
1904 if (!tree || !child)
1905 goto error;
1907 child->band = isl_schedule_band_drop(child->band, 0, pos);
1908 tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
1909 if (!child->band || !tree->band)
1910 goto error;
1912 tree = isl_schedule_tree_replace_child(tree, 0, child);
1914 return tree;
1915 error:
1916 isl_schedule_tree_free(child);
1917 isl_schedule_tree_free(tree);
1918 return NULL;
1921 /* Attach "tree2" at each of the leaves of "tree1".
1923 * If "tree1" does not have any explicit children, then make "tree2"
1924 * its single child. Otherwise, attach "tree2" to the leaves of
1925 * each of the children of "tree1".
1927 __isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
1928 __isl_take isl_schedule_tree *tree1,
1929 __isl_take isl_schedule_tree *tree2)
1931 int i, n;
1933 if (!tree1 || !tree2)
1934 goto error;
1935 n = isl_schedule_tree_n_children(tree1);
1936 if (n == 0) {
1937 isl_schedule_tree_list *list;
1938 list = isl_schedule_tree_list_from_schedule_tree(tree2);
1939 tree1 = isl_schedule_tree_set_children(tree1, list);
1940 return tree1;
1942 for (i = 0; i < n; ++i) {
1943 isl_schedule_tree *child;
1945 child = isl_schedule_tree_get_child(tree1, i);
1946 child = isl_schedule_tree_append_to_leaves(child,
1947 isl_schedule_tree_copy(tree2));
1948 tree1 = isl_schedule_tree_replace_child(tree1, i, child);
1951 isl_schedule_tree_free(tree2);
1952 return tree1;
1953 error:
1954 isl_schedule_tree_free(tree1);
1955 isl_schedule_tree_free(tree2);
1956 return NULL;
1959 /* Reset the user pointer on all identifiers of parameters and tuples
1960 * in the root of "tree".
1962 __isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
1963 __isl_take isl_schedule_tree *tree)
1965 if (isl_schedule_tree_is_leaf(tree))
1966 return tree;
1968 tree = isl_schedule_tree_cow(tree);
1969 if (!tree)
1970 return NULL;
1972 switch (tree->type) {
1973 case isl_schedule_node_error:
1974 return isl_schedule_tree_free(tree);
1975 case isl_schedule_node_band:
1976 tree->band = isl_schedule_band_reset_user(tree->band);
1977 if (!tree->band)
1978 return isl_schedule_tree_free(tree);
1979 break;
1980 case isl_schedule_node_context:
1981 tree->context = isl_set_reset_user(tree->context);
1982 if (!tree->context)
1983 return isl_schedule_tree_free(tree);
1984 break;
1985 case isl_schedule_node_domain:
1986 tree->domain = isl_union_set_reset_user(tree->domain);
1987 if (!tree->domain)
1988 return isl_schedule_tree_free(tree);
1989 break;
1990 case isl_schedule_node_expansion:
1991 tree->contraction =
1992 isl_union_pw_multi_aff_reset_user(tree->contraction);
1993 tree->expansion = isl_union_map_reset_user(tree->expansion);
1994 if (!tree->contraction || !tree->expansion)
1995 return isl_schedule_tree_free(tree);
1996 break;
1997 case isl_schedule_node_filter:
1998 tree->filter = isl_union_set_reset_user(tree->filter);
1999 if (!tree->filter)
2000 return isl_schedule_tree_free(tree);
2001 break;
2002 case isl_schedule_node_leaf:
2003 case isl_schedule_node_mark:
2004 case isl_schedule_node_sequence:
2005 case isl_schedule_node_set:
2006 break;
2009 return tree;
2012 /* Align the parameters of the root of "tree" to those of "space".
2014 __isl_give isl_schedule_tree *isl_schedule_tree_align_params(
2015 __isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
2017 if (!space)
2018 goto error;
2020 if (isl_schedule_tree_is_leaf(tree)) {
2021 isl_space_free(space);
2022 return tree;
2025 tree = isl_schedule_tree_cow(tree);
2026 if (!tree)
2027 goto error;
2029 switch (tree->type) {
2030 case isl_schedule_node_error:
2031 goto error;
2032 case isl_schedule_node_band:
2033 tree->band = isl_schedule_band_align_params(tree->band, space);
2034 if (!tree->band)
2035 return isl_schedule_tree_free(tree);
2036 break;
2037 case isl_schedule_node_context:
2038 tree->context = isl_set_align_params(tree->context, space);
2039 if (!tree->context)
2040 return isl_schedule_tree_free(tree);
2041 break;
2042 case isl_schedule_node_domain:
2043 tree->domain = isl_union_set_align_params(tree->domain, space);
2044 if (!tree->domain)
2045 return isl_schedule_tree_free(tree);
2046 break;
2047 case isl_schedule_node_expansion:
2048 tree->contraction =
2049 isl_union_pw_multi_aff_align_params(tree->contraction,
2050 isl_space_copy(space));
2051 tree->expansion = isl_union_map_align_params(tree->expansion,
2052 space);
2053 if (!tree->contraction || !tree->expansion)
2054 return isl_schedule_tree_free(tree);
2055 break;
2056 case isl_schedule_node_filter:
2057 tree->filter = isl_union_set_align_params(tree->filter, space);
2058 if (!tree->filter)
2059 return isl_schedule_tree_free(tree);
2060 break;
2061 case isl_schedule_node_leaf:
2062 case isl_schedule_node_mark:
2063 case isl_schedule_node_sequence:
2064 case isl_schedule_node_set:
2065 isl_space_free(space);
2066 break;
2069 return tree;
2070 error:
2071 isl_space_free(space);
2072 isl_schedule_tree_free(tree);
2073 return NULL;
2076 /* Does "tree" involve the iteration domain?
2077 * That is, does it need to be modified
2078 * by isl_schedule_tree_pullback_union_pw_multi_aff?
2080 static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
2082 if (!tree)
2083 return -1;
2085 switch (tree->type) {
2086 case isl_schedule_node_error:
2087 return -1;
2088 case isl_schedule_node_band:
2089 case isl_schedule_node_domain:
2090 case isl_schedule_node_expansion:
2091 case isl_schedule_node_filter:
2092 return 1;
2093 case isl_schedule_node_context:
2094 case isl_schedule_node_leaf:
2095 case isl_schedule_node_mark:
2096 case isl_schedule_node_sequence:
2097 case isl_schedule_node_set:
2098 return 0;
2102 /* Compute the pullback of the root node of "tree" by the function
2103 * represented by "upma".
2104 * In other words, plug in "upma" in the iteration domains of
2105 * the root node of "tree".
2106 * We currently do not handle expansion nodes.
2108 * We first check if the root node involves any iteration domains.
2109 * If so, we handle the specific cases.
2111 __isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
2112 __isl_take isl_schedule_tree *tree,
2113 __isl_take isl_union_pw_multi_aff *upma)
2115 int involves;
2117 if (!tree || !upma)
2118 goto error;
2120 involves = involves_iteration_domain(tree);
2121 if (involves < 0)
2122 goto error;
2123 if (!involves) {
2124 isl_union_pw_multi_aff_free(upma);
2125 return tree;
2128 tree = isl_schedule_tree_cow(tree);
2129 if (!tree)
2130 goto error;
2132 if (tree->type == isl_schedule_node_band) {
2133 tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
2134 tree->band, upma);
2135 if (!tree->band)
2136 return isl_schedule_tree_free(tree);
2137 } else if (tree->type == isl_schedule_node_domain) {
2138 tree->domain =
2139 isl_union_set_preimage_union_pw_multi_aff(tree->domain,
2140 upma);
2141 if (!tree->domain)
2142 return isl_schedule_tree_free(tree);
2143 } else if (tree->type == isl_schedule_node_expansion) {
2144 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
2145 "cannot pullback expansion node", goto error);
2146 } else if (tree->type == isl_schedule_node_filter) {
2147 tree->filter =
2148 isl_union_set_preimage_union_pw_multi_aff(tree->filter,
2149 upma);
2150 if (!tree->filter)
2151 return isl_schedule_tree_free(tree);
2154 return tree;
2155 error:
2156 isl_union_pw_multi_aff_free(upma);
2157 isl_schedule_tree_free(tree);
2158 return NULL;
2161 /* Compute the gist of the band tree root with respect to "context".
2163 __isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
2164 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
2166 if (!tree)
2167 return NULL;
2168 if (tree->type != isl_schedule_node_band)
2169 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2170 "not a band node", goto error);
2171 tree = isl_schedule_tree_cow(tree);
2172 if (!tree)
2173 goto error;
2175 tree->band = isl_schedule_band_gist(tree->band, context);
2176 if (!tree->band)
2177 return isl_schedule_tree_free(tree);
2178 return tree;
2179 error:
2180 isl_union_set_free(context);
2181 isl_schedule_tree_free(tree);
2182 return NULL;
2185 /* Are any members in "band" marked coincident?
2187 static int any_coincident(__isl_keep isl_schedule_band *band)
2189 int i, n;
2191 n = isl_schedule_band_n_member(band);
2192 for (i = 0; i < n; ++i)
2193 if (isl_schedule_band_member_get_coincident(band, i))
2194 return 1;
2196 return 0;
2199 /* Print the band node "band" to "p".
2201 * The permutable and coincident properties are only printed if they
2202 * are different from the defaults.
2203 * The coincident property is always printed in YAML flow style.
2205 static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
2206 __isl_keep isl_schedule_band *band)
2208 isl_union_set *options;
2209 int empty;
2211 p = isl_printer_print_str(p, "schedule");
2212 p = isl_printer_yaml_next(p);
2213 p = isl_printer_print_str(p, "\"");
2214 p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
2215 p = isl_printer_print_str(p, "\"");
2216 if (isl_schedule_band_get_permutable(band)) {
2217 p = isl_printer_yaml_next(p);
2218 p = isl_printer_print_str(p, "permutable");
2219 p = isl_printer_yaml_next(p);
2220 p = isl_printer_print_int(p, 1);
2222 if (any_coincident(band)) {
2223 int i, n;
2224 int style;
2226 p = isl_printer_yaml_next(p);
2227 p = isl_printer_print_str(p, "coincident");
2228 p = isl_printer_yaml_next(p);
2229 style = isl_printer_get_yaml_style(p);
2230 p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
2231 p = isl_printer_yaml_start_sequence(p);
2232 n = isl_schedule_band_n_member(band);
2233 for (i = 0; i < n; ++i) {
2234 p = isl_printer_print_int(p,
2235 isl_schedule_band_member_get_coincident(band, i));
2236 p = isl_printer_yaml_next(p);
2238 p = isl_printer_yaml_end_sequence(p);
2239 p = isl_printer_set_yaml_style(p, style);
2241 options = isl_schedule_band_get_ast_build_options(band);
2242 empty = isl_union_set_is_empty(options);
2243 if (empty < 0)
2244 p = isl_printer_free(p);
2245 if (!empty) {
2246 p = isl_printer_yaml_next(p);
2247 p = isl_printer_print_str(p, "options");
2248 p = isl_printer_yaml_next(p);
2249 p = isl_printer_print_str(p, "\"");
2250 p = isl_printer_print_union_set(p, options);
2251 p = isl_printer_print_str(p, "\"");
2253 isl_union_set_free(options);
2255 return p;
2258 /* Print "tree" to "p".
2260 * If "n_ancestor" is non-negative, then "child_pos" contains the child
2261 * positions of a descendant of the current node that should be marked
2262 * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor"
2263 * is zero, then the current node should be marked.
2264 * The marking is only printed in YAML block format.
2266 * Implicit leaf nodes are not printed, except if they correspond
2267 * to the node that should be marked.
2269 __isl_give isl_printer *isl_printer_print_schedule_tree_mark(
2270 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
2271 int n_ancestor, int *child_pos)
2273 int i, n;
2274 int sequence = 0;
2275 int block;
2277 block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;
2279 p = isl_printer_yaml_start_mapping(p);
2280 if (n_ancestor == 0 && block) {
2281 p = isl_printer_print_str(p, "# YOU ARE HERE");
2282 p = isl_printer_end_line(p);
2283 p = isl_printer_start_line(p);
2285 switch (tree->type) {
2286 case isl_schedule_node_error:
2287 p = isl_printer_print_str(p, "ERROR");
2288 break;
2289 case isl_schedule_node_leaf:
2290 p = isl_printer_print_str(p, "leaf");
2291 break;
2292 case isl_schedule_node_sequence:
2293 p = isl_printer_print_str(p, "sequence");
2294 sequence = 1;
2295 break;
2296 case isl_schedule_node_set:
2297 p = isl_printer_print_str(p, "set");
2298 sequence = 1;
2299 break;
2300 case isl_schedule_node_context:
2301 p = isl_printer_print_str(p, "context");
2302 p = isl_printer_yaml_next(p);
2303 p = isl_printer_print_str(p, "\"");
2304 p = isl_printer_print_set(p, tree->context);
2305 p = isl_printer_print_str(p, "\"");
2306 break;
2307 case isl_schedule_node_domain:
2308 p = isl_printer_print_str(p, "domain");
2309 p = isl_printer_yaml_next(p);
2310 p = isl_printer_print_str(p, "\"");
2311 p = isl_printer_print_union_set(p, tree->domain);
2312 p = isl_printer_print_str(p, "\"");
2313 break;
2314 case isl_schedule_node_expansion:
2315 p = isl_printer_print_str(p, "contraction");
2316 p = isl_printer_yaml_next(p);
2317 p = isl_printer_print_str(p, "\"");
2318 p = isl_printer_print_union_pw_multi_aff(p, tree->contraction);
2319 p = isl_printer_print_str(p, "\"");
2320 p = isl_printer_yaml_next(p);
2321 p = isl_printer_print_str(p, "expansion");
2322 p = isl_printer_yaml_next(p);
2323 p = isl_printer_print_str(p, "\"");
2324 p = isl_printer_print_union_map(p, tree->expansion);
2325 p = isl_printer_print_str(p, "\"");
2326 break;
2327 case isl_schedule_node_filter:
2328 p = isl_printer_print_str(p, "filter");
2329 p = isl_printer_yaml_next(p);
2330 p = isl_printer_print_str(p, "\"");
2331 p = isl_printer_print_union_set(p, tree->filter);
2332 p = isl_printer_print_str(p, "\"");
2333 break;
2334 case isl_schedule_node_mark:
2335 p = isl_printer_print_str(p, "mark");
2336 p = isl_printer_yaml_next(p);
2337 p = isl_printer_print_str(p, "\"");
2338 p = isl_printer_print_str(p, isl_id_get_name(tree->mark));
2339 p = isl_printer_print_str(p, "\"");
2340 break;
2341 case isl_schedule_node_band:
2342 p = print_tree_band(p, tree->band);
2343 break;
2345 p = isl_printer_yaml_next(p);
2347 if (!tree->children) {
2348 if (n_ancestor > 0 && block) {
2349 isl_schedule_tree *leaf;
2351 p = isl_printer_print_str(p, "child");
2352 p = isl_printer_yaml_next(p);
2353 leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
2354 p = isl_printer_print_schedule_tree_mark(p,
2355 leaf, 0, NULL);
2356 isl_schedule_tree_free(leaf);
2357 p = isl_printer_yaml_next(p);
2359 return isl_printer_yaml_end_mapping(p);
2362 if (sequence) {
2363 p = isl_printer_yaml_start_sequence(p);
2364 } else {
2365 p = isl_printer_print_str(p, "child");
2366 p = isl_printer_yaml_next(p);
2369 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
2370 for (i = 0; i < n; ++i) {
2371 isl_schedule_tree *t;
2373 t = isl_schedule_tree_get_child(tree, i);
2374 if (n_ancestor > 0 && child_pos[0] == i)
2375 p = isl_printer_print_schedule_tree_mark(p, t,
2376 n_ancestor - 1, child_pos + 1);
2377 else
2378 p = isl_printer_print_schedule_tree_mark(p, t,
2379 -1, NULL);
2380 isl_schedule_tree_free(t);
2382 p = isl_printer_yaml_next(p);
2385 if (sequence)
2386 p = isl_printer_yaml_end_sequence(p);
2387 p = isl_printer_yaml_end_mapping(p);
2389 return p;
2392 /* Print "tree" to "p".
2394 __isl_give isl_printer *isl_printer_print_schedule_tree(
2395 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
2397 return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
2400 void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
2402 isl_ctx *ctx;
2403 isl_printer *printer;
2405 if (!tree)
2406 return;
2408 ctx = isl_schedule_tree_get_ctx(tree);
2409 printer = isl_printer_to_file(ctx, stderr);
2410 printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
2411 printer = isl_printer_print_schedule_tree(printer, tree);
2413 isl_printer_free(printer);