isl_map_list.c: directly include required header
[isl.git] / isl_schedule_tree.c
blob09becd3bc8eeef519261b606d2ff3e7d5eeaf666
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_extension:
106 dup->extension = isl_union_map_copy(tree->extension);
107 if (!dup->extension)
108 return isl_schedule_tree_free(dup);
109 break;
110 case isl_schedule_node_filter:
111 dup->filter = isl_union_set_copy(tree->filter);
112 if (!dup->filter)
113 return isl_schedule_tree_free(dup);
114 break;
115 case isl_schedule_node_guard:
116 dup->guard = isl_set_copy(tree->guard);
117 if (!dup->guard)
118 return isl_schedule_tree_free(dup);
119 break;
120 case isl_schedule_node_mark:
121 dup->mark = isl_id_copy(tree->mark);
122 if (!dup->mark)
123 return isl_schedule_tree_free(dup);
124 break;
125 case isl_schedule_node_leaf:
126 case isl_schedule_node_sequence:
127 case isl_schedule_node_set:
128 break;
131 if (tree->children) {
132 dup->children = isl_schedule_tree_list_copy(tree->children);
133 if (!dup->children)
134 return isl_schedule_tree_free(dup);
136 dup->anchored = tree->anchored;
138 return dup;
141 /* Return an isl_schedule_tree that is equal to "tree" and that has only
142 * a single reference.
144 * This function is called before a tree is modified.
145 * A static tree (with negative reference count) should never be modified,
146 * so it is not allowed to call this function on a static tree.
148 __isl_give isl_schedule_tree *isl_schedule_tree_cow(
149 __isl_take isl_schedule_tree *tree)
151 if (!tree)
152 return NULL;
154 if (tree->ref < 0)
155 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
156 "static trees cannot be modified",
157 return isl_schedule_tree_free(tree));
159 if (tree->ref == 1)
160 return tree;
161 tree->ref--;
162 return isl_schedule_tree_dup(tree);
165 /* Return a new reference to "tree".
167 * A static tree (with negative reference count) does not keep track
168 * of the number of references and should not be modified.
170 __isl_give isl_schedule_tree *isl_schedule_tree_copy(
171 __isl_keep isl_schedule_tree *tree)
173 if (!tree)
174 return NULL;
176 if (tree->ref < 0)
177 return tree;
179 tree->ref++;
180 return tree;
183 /* Free "tree" and return NULL.
185 __isl_null isl_schedule_tree *isl_schedule_tree_free(
186 __isl_take isl_schedule_tree *tree)
188 if (!tree)
189 return NULL;
190 if (tree->ref < 0)
191 return NULL;
192 if (--tree->ref > 0)
193 return NULL;
195 switch (tree->type) {
196 case isl_schedule_node_band:
197 isl_schedule_band_free(tree->band);
198 break;
199 case isl_schedule_node_context:
200 isl_set_free(tree->context);
201 break;
202 case isl_schedule_node_domain:
203 isl_union_set_free(tree->domain);
204 break;
205 case isl_schedule_node_expansion:
206 isl_union_pw_multi_aff_free(tree->contraction);
207 isl_union_map_free(tree->expansion);
208 break;
209 case isl_schedule_node_extension:
210 isl_union_map_free(tree->extension);
211 break;
212 case isl_schedule_node_filter:
213 isl_union_set_free(tree->filter);
214 break;
215 case isl_schedule_node_guard:
216 isl_set_free(tree->guard);
217 break;
218 case isl_schedule_node_mark:
219 isl_id_free(tree->mark);
220 break;
221 case isl_schedule_node_sequence:
222 case isl_schedule_node_set:
223 case isl_schedule_node_error:
224 case isl_schedule_node_leaf:
225 break;
227 isl_schedule_tree_list_free(tree->children);
228 isl_ctx_deref(tree->ctx);
229 free(tree);
231 return NULL;
234 /* Create and return a new leaf schedule tree.
236 __isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx)
238 return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf);
241 /* Create a new band schedule tree referring to "band"
242 * with no children.
244 __isl_give isl_schedule_tree *isl_schedule_tree_from_band(
245 __isl_take isl_schedule_band *band)
247 isl_ctx *ctx;
248 isl_schedule_tree *tree;
250 if (!band)
251 return NULL;
253 ctx = isl_schedule_band_get_ctx(band);
254 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band);
255 if (!tree)
256 goto error;
258 tree->band = band;
259 tree->anchored = isl_schedule_band_is_anchored(band);
261 return tree;
262 error:
263 isl_schedule_band_free(band);
264 return NULL;
267 /* Create a new context schedule tree with the given context and no children.
268 * Since the context references the outer schedule dimension,
269 * the tree is anchored.
271 __isl_give isl_schedule_tree *isl_schedule_tree_from_context(
272 __isl_take isl_set *context)
274 isl_ctx *ctx;
275 isl_schedule_tree *tree;
277 if (!context)
278 return NULL;
280 ctx = isl_set_get_ctx(context);
281 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context);
282 if (!tree)
283 goto error;
285 tree->context = context;
286 tree->anchored = 1;
288 return tree;
289 error:
290 isl_set_free(context);
291 return NULL;
294 /* Create a new domain schedule tree with the given domain and no children.
296 __isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
297 __isl_take isl_union_set *domain)
299 isl_ctx *ctx;
300 isl_schedule_tree *tree;
302 if (!domain)
303 return NULL;
305 ctx = isl_union_set_get_ctx(domain);
306 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain);
307 if (!tree)
308 goto error;
310 tree->domain = domain;
312 return tree;
313 error:
314 isl_union_set_free(domain);
315 return NULL;
318 /* Create a new expansion schedule tree with the given contraction and
319 * expansion and no children.
321 __isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
322 __isl_take isl_union_pw_multi_aff *contraction,
323 __isl_take isl_union_map *expansion)
325 isl_ctx *ctx;
326 isl_schedule_tree *tree;
328 if (!contraction || !expansion)
329 goto error;
331 ctx = isl_union_map_get_ctx(expansion);
332 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion);
333 if (!tree)
334 goto error;
336 tree->contraction = contraction;
337 tree->expansion = expansion;
339 return tree;
340 error:
341 isl_union_pw_multi_aff_free(contraction);
342 isl_union_map_free(expansion);
343 return NULL;
346 /* Create a new extension schedule tree with the given extension and
347 * no children.
348 * Since the domain of the extension refers to the outer schedule dimension,
349 * the tree is anchored.
351 __isl_give isl_schedule_tree *isl_schedule_tree_from_extension(
352 __isl_take isl_union_map *extension)
354 isl_ctx *ctx;
355 isl_schedule_tree *tree;
357 if (!extension)
358 return NULL;
360 ctx = isl_union_map_get_ctx(extension);
361 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension);
362 if (!tree)
363 goto error;
365 tree->extension = extension;
366 tree->anchored = 1;
368 return tree;
369 error:
370 isl_union_map_free(extension);
371 return NULL;
374 /* Create a new filter schedule tree with the given filter and no children.
376 __isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
377 __isl_take isl_union_set *filter)
379 isl_ctx *ctx;
380 isl_schedule_tree *tree;
382 if (!filter)
383 return NULL;
385 ctx = isl_union_set_get_ctx(filter);
386 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter);
387 if (!tree)
388 goto error;
390 tree->filter = filter;
392 return tree;
393 error:
394 isl_union_set_free(filter);
395 return NULL;
398 /* Create a new guard schedule tree with the given guard and no children.
399 * Since the guard references the outer schedule dimension,
400 * the tree is anchored.
402 __isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
403 __isl_take isl_set *guard)
405 isl_ctx *ctx;
406 isl_schedule_tree *tree;
408 if (!guard)
409 return NULL;
411 ctx = isl_set_get_ctx(guard);
412 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard);
413 if (!tree)
414 goto error;
416 tree->guard = guard;
417 tree->anchored = 1;
419 return tree;
420 error:
421 isl_set_free(guard);
422 return NULL;
425 /* Create a new mark schedule tree with the given mark identifier and
426 * no children.
428 __isl_give isl_schedule_tree *isl_schedule_tree_from_mark(
429 __isl_take isl_id *mark)
431 isl_ctx *ctx;
432 isl_schedule_tree *tree;
434 if (!mark)
435 return NULL;
437 ctx = isl_id_get_ctx(mark);
438 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark);
439 if (!tree)
440 goto error;
442 tree->mark = mark;
444 return tree;
445 error:
446 isl_id_free(mark);
447 return NULL;
450 /* Does "tree" have any node that depends on its position
451 * in the complete schedule tree?
453 int isl_schedule_tree_is_subtree_anchored(__isl_keep isl_schedule_tree *tree)
455 return tree ? tree->anchored : -1;
458 /* Does the root node of "tree" depend on its position in the complete
459 * schedule tree?
460 * Band nodes may be anchored depending on the associated AST build options.
461 * Context, extension and guard nodes are always anchored.
463 int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
465 if (!tree)
466 return -1;
468 switch (isl_schedule_tree_get_type(tree)) {
469 case isl_schedule_node_error:
470 return -1;
471 case isl_schedule_node_band:
472 return isl_schedule_band_is_anchored(tree->band);
473 case isl_schedule_node_context:
474 case isl_schedule_node_extension:
475 case isl_schedule_node_guard:
476 return 1;
477 case isl_schedule_node_domain:
478 case isl_schedule_node_expansion:
479 case isl_schedule_node_filter:
480 case isl_schedule_node_leaf:
481 case isl_schedule_node_mark:
482 case isl_schedule_node_sequence:
483 case isl_schedule_node_set:
484 return 0;
488 /* Update the anchored field of "tree" based on whether the root node
489 * itself in anchored and the anchored fields of the children.
491 * This function should be called whenever the children of a tree node
492 * are changed or the anchoredness of the tree root itself changes.
494 __isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
495 __isl_take isl_schedule_tree *tree)
497 int i, n;
498 int anchored;
500 if (!tree)
501 return NULL;
503 anchored = isl_schedule_tree_is_anchored(tree);
504 if (anchored < 0)
505 return isl_schedule_tree_free(tree);
507 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
508 for (i = 0; !anchored && i < n; ++i) {
509 isl_schedule_tree *child;
511 child = isl_schedule_tree_get_child(tree, i);
512 if (!child)
513 return isl_schedule_tree_free(tree);
514 anchored = child->anchored;
515 isl_schedule_tree_free(child);
518 if (anchored == tree->anchored)
519 return tree;
520 tree = isl_schedule_tree_cow(tree);
521 if (!tree)
522 return NULL;
523 tree->anchored = anchored;
524 return tree;
527 /* Create a new tree of the given type (isl_schedule_node_sequence or
528 * isl_schedule_node_set) with the given children.
530 __isl_give isl_schedule_tree *isl_schedule_tree_from_children(
531 enum isl_schedule_node_type type,
532 __isl_take isl_schedule_tree_list *list)
534 isl_ctx *ctx;
535 isl_schedule_tree *tree;
537 if (!list)
538 return NULL;
540 ctx = isl_schedule_tree_list_get_ctx(list);
541 tree = isl_schedule_tree_alloc(ctx, type);
542 if (!tree)
543 goto error;
545 tree->children = list;
546 tree = isl_schedule_tree_update_anchored(tree);
548 return tree;
549 error:
550 isl_schedule_tree_list_free(list);
551 return NULL;
554 /* Construct a tree with a root node of type "type" and as children
555 * "tree1" and "tree2".
556 * If the root of one (or both) of the input trees is itself of type "type",
557 * then the tree is replaced by its children.
559 __isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
560 enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
561 __isl_take isl_schedule_tree *tree2)
563 isl_ctx *ctx;
564 isl_schedule_tree_list *list;
566 if (!tree1 || !tree2)
567 goto error;
569 ctx = isl_schedule_tree_get_ctx(tree1);
570 if (isl_schedule_tree_get_type(tree1) == type) {
571 list = isl_schedule_tree_list_copy(tree1->children);
572 isl_schedule_tree_free(tree1);
573 } else {
574 list = isl_schedule_tree_list_alloc(ctx, 2);
575 list = isl_schedule_tree_list_add(list, tree1);
577 if (isl_schedule_tree_get_type(tree2) == type) {
578 isl_schedule_tree_list *children;
580 children = isl_schedule_tree_list_copy(tree2->children);
581 list = isl_schedule_tree_list_concat(list, children);
582 isl_schedule_tree_free(tree2);
583 } else {
584 list = isl_schedule_tree_list_add(list, tree2);
587 return isl_schedule_tree_from_children(type, list);
588 error:
589 isl_schedule_tree_free(tree1);
590 isl_schedule_tree_free(tree2);
591 return NULL;
594 /* Construct a tree with a sequence root node and as children
595 * "tree1" and "tree2".
596 * If the root of one (or both) of the input trees is itself a sequence,
597 * then the tree is replaced by its children.
599 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
600 __isl_take isl_schedule_tree *tree1,
601 __isl_take isl_schedule_tree *tree2)
603 return isl_schedule_tree_from_pair(isl_schedule_node_sequence,
604 tree1, tree2);
607 /* Return the isl_ctx to which "tree" belongs.
609 isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
611 return tree ? tree->ctx : NULL;
614 /* Return the type of the root of the tree or isl_schedule_node_error
615 * on error.
617 enum isl_schedule_node_type isl_schedule_tree_get_type(
618 __isl_keep isl_schedule_tree *tree)
620 return tree ? tree->type : isl_schedule_node_error;
623 /* Are "tree1" and "tree2" obviously equal to each other?
625 int isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
626 __isl_keep isl_schedule_tree *tree2)
628 int equal;
629 int i, n;
631 if (!tree1 || !tree2)
632 return -1;
633 if (tree1 == tree2)
634 return 1;
635 if (tree1->type != tree2->type)
636 return 0;
638 switch (tree1->type) {
639 case isl_schedule_node_band:
640 equal = isl_schedule_band_plain_is_equal(tree1->band,
641 tree2->band);
642 break;
643 case isl_schedule_node_context:
644 equal = isl_set_is_equal(tree1->context, tree2->context);
645 break;
646 case isl_schedule_node_domain:
647 equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
648 break;
649 case isl_schedule_node_expansion:
650 equal = isl_union_map_is_equal(tree1->expansion,
651 tree2->expansion);
652 if (equal >= 0 && equal)
653 equal = isl_union_pw_multi_aff_plain_is_equal(
654 tree1->contraction, tree2->contraction);
655 break;
656 case isl_schedule_node_extension:
657 equal = isl_union_map_is_equal(tree1->extension,
658 tree2->extension);
659 break;
660 case isl_schedule_node_filter:
661 equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
662 break;
663 case isl_schedule_node_guard:
664 equal = isl_set_is_equal(tree1->guard, tree2->guard);
665 break;
666 case isl_schedule_node_mark:
667 equal = tree1->mark == tree2->mark;
668 break;
669 case isl_schedule_node_leaf:
670 case isl_schedule_node_sequence:
671 case isl_schedule_node_set:
672 equal = 1;
673 break;
674 case isl_schedule_node_error:
675 equal = -1;
676 break;
679 if (equal < 0 || !equal)
680 return equal;
682 n = isl_schedule_tree_n_children(tree1);
683 if (n != isl_schedule_tree_n_children(tree2))
684 return 0;
685 for (i = 0; i < n; ++i) {
686 isl_schedule_tree *child1, *child2;
688 child1 = isl_schedule_tree_get_child(tree1, i);
689 child2 = isl_schedule_tree_get_child(tree2, i);
690 equal = isl_schedule_tree_plain_is_equal(child1, child2);
691 isl_schedule_tree_free(child1);
692 isl_schedule_tree_free(child2);
694 if (equal < 0 || !equal)
695 return equal;
698 return 1;
701 /* Does "tree" have any children, other than an implicit leaf.
703 int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
705 if (!tree)
706 return -1;
708 return tree->children != NULL;
711 /* Return the number of children of "tree", excluding implicit leaves.
713 int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
715 if (!tree)
716 return -1;
718 return isl_schedule_tree_list_n_schedule_tree(tree->children);
721 /* Return a copy of the (explicit) child at position "pos" of "tree".
723 __isl_give isl_schedule_tree *isl_schedule_tree_get_child(
724 __isl_keep isl_schedule_tree *tree, int pos)
726 if (!tree)
727 return NULL;
728 if (!tree->children)
729 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
730 "schedule tree has no explicit children", return NULL);
731 return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
734 /* Return a copy of the (explicit) child at position "pos" of "tree" and
735 * free "tree".
737 __isl_give isl_schedule_tree *isl_schedule_tree_child(
738 __isl_take isl_schedule_tree *tree, int pos)
740 isl_schedule_tree *child;
742 child = isl_schedule_tree_get_child(tree, pos);
743 isl_schedule_tree_free(tree);
744 return child;
747 /* Remove all (explicit) children from "tree".
749 __isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
750 __isl_take isl_schedule_tree *tree)
752 tree = isl_schedule_tree_cow(tree);
753 if (!tree)
754 return NULL;
755 tree->children = isl_schedule_tree_list_free(tree->children);
756 return tree;
759 /* Remove the child at position "pos" from the children of "tree".
760 * If there was only one child to begin with, then remove all children.
762 __isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
763 __isl_take isl_schedule_tree *tree, int pos)
765 int n;
767 tree = isl_schedule_tree_cow(tree);
768 if (!tree)
769 return NULL;
771 if (!isl_schedule_tree_has_children(tree))
772 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
773 "tree does not have any explicit children",
774 return isl_schedule_tree_free(tree));
775 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
776 if (pos < 0 || pos >= n)
777 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
778 "position out of bounds",
779 return isl_schedule_tree_free(tree));
780 if (n == 1)
781 return isl_schedule_tree_reset_children(tree);
783 tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
784 if (!tree->children)
785 return isl_schedule_tree_free(tree);
787 return tree;
790 /* Replace the child at position "pos" of "tree" by "child".
792 * If the new child is a leaf, then it is not explicitly
793 * recorded in the list of children. Instead, the list of children
794 * (which is assumed to have only one element) is removed.
795 * Note that the children of set and sequence nodes are always
796 * filters, so they cannot be replaced by empty trees.
798 __isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
799 __isl_take isl_schedule_tree *tree, int pos,
800 __isl_take isl_schedule_tree *child)
802 tree = isl_schedule_tree_cow(tree);
803 if (!tree || !child)
804 goto error;
806 if (isl_schedule_tree_is_leaf(child)) {
807 isl_schedule_tree_free(child);
808 if (!tree->children && pos == 0)
809 return tree;
810 if (isl_schedule_tree_n_children(tree) != 1)
811 isl_die(isl_schedule_tree_get_ctx(tree),
812 isl_error_internal,
813 "can only replace single child by leaf",
814 goto error);
815 return isl_schedule_tree_reset_children(tree);
818 if (!tree->children && pos == 0)
819 tree->children =
820 isl_schedule_tree_list_from_schedule_tree(child);
821 else
822 tree->children = isl_schedule_tree_list_set_schedule_tree(
823 tree->children, pos, child);
825 if (!tree->children)
826 return isl_schedule_tree_free(tree);
827 tree = isl_schedule_tree_update_anchored(tree);
829 return tree;
830 error:
831 isl_schedule_tree_free(tree);
832 isl_schedule_tree_free(child);
833 return NULL;
836 /* Replace the (explicit) children of "tree" by "children"?
838 __isl_give isl_schedule_tree *isl_schedule_tree_set_children(
839 __isl_take isl_schedule_tree *tree,
840 __isl_take isl_schedule_tree_list *children)
842 tree = isl_schedule_tree_cow(tree);
843 if (!tree || !children)
844 goto error;
845 isl_schedule_tree_list_free(tree->children);
846 tree->children = children;
847 return tree;
848 error:
849 isl_schedule_tree_free(tree);
850 isl_schedule_tree_list_free(children);
851 return NULL;
854 /* Create a new band schedule tree referring to "band"
855 * with "tree" as single child.
857 __isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
858 __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
860 isl_schedule_tree *res;
862 res = isl_schedule_tree_from_band(band);
863 return isl_schedule_tree_replace_child(res, 0, tree);
866 /* Create a new context schedule tree with the given context and
867 * with "tree" as single child.
869 __isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
870 __isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
872 isl_schedule_tree *res;
874 res = isl_schedule_tree_from_context(context);
875 return isl_schedule_tree_replace_child(res, 0, tree);
878 /* Create a new domain schedule tree with the given domain and
879 * with "tree" as single child.
881 __isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
882 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
884 isl_schedule_tree *res;
886 res = isl_schedule_tree_from_domain(domain);
887 return isl_schedule_tree_replace_child(res, 0, tree);
890 /* Create a new expansion schedule tree with the given contraction and
891 * expansion and with "tree" as single child.
893 __isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
894 __isl_take isl_schedule_tree *tree,
895 __isl_take isl_union_pw_multi_aff *contraction,
896 __isl_take isl_union_map *expansion)
898 isl_schedule_tree *res;
900 res = isl_schedule_tree_from_expansion(contraction, expansion);
901 return isl_schedule_tree_replace_child(res, 0, tree);
904 /* Create a new extension schedule tree with the given extension and
905 * with "tree" as single child.
907 __isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
908 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
910 isl_schedule_tree *res;
912 res = isl_schedule_tree_from_extension(extension);
913 return isl_schedule_tree_replace_child(res, 0, tree);
916 /* Create a new filter schedule tree with the given filter and single child.
918 * If the root of "tree" is itself a filter node, then the two
919 * filter nodes are merged into one node.
921 __isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
922 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
924 isl_schedule_tree *res;
926 if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
927 isl_union_set *tree_filter;
929 tree_filter = isl_schedule_tree_filter_get_filter(tree);
930 tree_filter = isl_union_set_intersect(tree_filter, filter);
931 tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
932 return tree;
935 res = isl_schedule_tree_from_filter(filter);
936 return isl_schedule_tree_replace_child(res, 0, tree);
939 /* Insert a filter node with filter set "filter"
940 * in each of the children of "tree".
942 __isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
943 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
945 int i, n;
947 if (!tree || !filter)
948 goto error;
950 n = isl_schedule_tree_n_children(tree);
951 for (i = 0; i < n; ++i) {
952 isl_schedule_tree *child;
954 child = isl_schedule_tree_get_child(tree, i);
955 child = isl_schedule_tree_insert_filter(child,
956 isl_union_set_copy(filter));
957 tree = isl_schedule_tree_replace_child(tree, i, child);
960 isl_union_set_free(filter);
961 return tree;
962 error:
963 isl_union_set_free(filter);
964 isl_schedule_tree_free(tree);
965 return NULL;
968 /* Create a new guard schedule tree with the given guard and
969 * with "tree" as single child.
971 __isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
972 __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
974 isl_schedule_tree *res;
976 res = isl_schedule_tree_from_guard(guard);
977 return isl_schedule_tree_replace_child(res, 0, tree);
980 /* Create a new mark schedule tree with the given mark identifier and
981 * single child.
983 __isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
984 __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
986 isl_schedule_tree *res;
988 res = isl_schedule_tree_from_mark(mark);
989 return isl_schedule_tree_replace_child(res, 0, tree);
992 /* Return the number of members in the band tree root.
994 unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
996 if (!tree)
997 return 0;
999 if (tree->type != isl_schedule_node_band)
1000 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1001 "not a band node", return 0);
1003 return isl_schedule_band_n_member(tree->band);
1006 /* Is the band member at position "pos" of the band tree root
1007 * marked coincident?
1009 int isl_schedule_tree_band_member_get_coincident(
1010 __isl_keep isl_schedule_tree *tree, int pos)
1012 if (!tree)
1013 return -1;
1015 if (tree->type != isl_schedule_node_band)
1016 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1017 "not a band node", return -1);
1019 return isl_schedule_band_member_get_coincident(tree->band, pos);
1022 /* Mark the given band member as being coincident or not
1023 * according to "coincident".
1025 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
1026 __isl_take isl_schedule_tree *tree, int pos, int coincident)
1028 if (!tree)
1029 return NULL;
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 isl_schedule_tree_free(tree));
1033 if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
1034 coincident)
1035 return tree;
1036 tree = isl_schedule_tree_cow(tree);
1037 if (!tree)
1038 return NULL;
1040 tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
1041 coincident);
1042 if (!tree->band)
1043 return isl_schedule_tree_free(tree);
1044 return tree;
1047 /* Is the band tree root marked permutable?
1049 int isl_schedule_tree_band_get_permutable(__isl_keep isl_schedule_tree *tree)
1051 if (!tree)
1052 return -1;
1054 if (tree->type != isl_schedule_node_band)
1055 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1056 "not a band node", return -1);
1058 return isl_schedule_band_get_permutable(tree->band);
1061 /* Mark the band tree root permutable or not according to "permutable"?
1063 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
1064 __isl_take isl_schedule_tree *tree, int permutable)
1066 if (!tree)
1067 return NULL;
1068 if (tree->type != isl_schedule_node_band)
1069 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1070 "not a band node", return isl_schedule_tree_free(tree));
1071 if (isl_schedule_tree_band_get_permutable(tree) == permutable)
1072 return tree;
1073 tree = isl_schedule_tree_cow(tree);
1074 if (!tree)
1075 return NULL;
1077 tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
1078 if (!tree->band)
1079 return isl_schedule_tree_free(tree);
1080 return tree;
1083 /* Return the schedule space of the band tree root.
1085 __isl_give isl_space *isl_schedule_tree_band_get_space(
1086 __isl_keep isl_schedule_tree *tree)
1088 if (!tree)
1089 return NULL;
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 NULL);
1095 return isl_schedule_band_get_space(tree->band);
1098 /* Intersect the domain of the band schedule of the band tree root
1099 * with "domain".
1101 __isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
1102 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1104 if (!tree || !domain)
1105 goto error;
1107 if (tree->type != isl_schedule_node_band)
1108 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1109 "not a band node", goto error);
1111 tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
1112 if (!tree->band)
1113 return isl_schedule_tree_free(tree);
1115 return tree;
1116 error:
1117 isl_schedule_tree_free(tree);
1118 isl_union_set_free(domain);
1119 return NULL;
1122 /* Return the schedule of the band tree root in isolation.
1124 __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
1125 __isl_keep isl_schedule_tree *tree)
1127 if (!tree)
1128 return NULL;
1130 if (tree->type != isl_schedule_node_band)
1131 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1132 "not a band node", return NULL);
1134 return isl_schedule_band_get_partial_schedule(tree->band);
1137 /* Replace the schedule of the band tree root by "schedule".
1139 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
1140 __isl_take isl_schedule_tree *tree,
1141 __isl_take isl_multi_union_pw_aff *schedule)
1143 tree = isl_schedule_tree_cow(tree);
1144 if (!tree || !schedule)
1145 goto error;
1147 if (tree->type != isl_schedule_node_band)
1148 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1149 "not a band node", return NULL);
1150 tree->band = isl_schedule_band_set_partial_schedule(tree->band,
1151 schedule);
1153 return tree;
1154 error:
1155 isl_schedule_tree_free(tree);
1156 isl_multi_union_pw_aff_free(schedule);
1157 return NULL;
1160 /* Return the loop AST generation type for the band member
1161 * of the band tree root at position "pos".
1163 enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
1164 __isl_keep isl_schedule_tree *tree, int pos)
1166 if (!tree)
1167 return isl_ast_loop_error;
1169 if (tree->type != isl_schedule_node_band)
1170 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1171 "not a band node", return isl_ast_loop_error);
1173 return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
1176 /* Set the loop AST generation type for the band member of the band tree root
1177 * at position "pos" to "type".
1179 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
1180 __isl_take isl_schedule_tree *tree, int pos,
1181 enum isl_ast_loop_type type)
1183 tree = isl_schedule_tree_cow(tree);
1184 if (!tree)
1185 return NULL;
1187 if (tree->type != isl_schedule_node_band)
1188 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1189 "not a band node", return isl_schedule_tree_free(tree));
1191 tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
1192 pos, type);
1193 if (!tree->band)
1194 return isl_schedule_tree_free(tree);
1196 return tree;
1199 /* Return the loop AST generation type for the band member
1200 * of the band tree root at position "pos" for the isolated part.
1202 enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
1203 __isl_keep isl_schedule_tree *tree, int pos)
1205 if (!tree)
1206 return isl_ast_loop_error;
1208 if (tree->type != isl_schedule_node_band)
1209 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1210 "not a band node", return isl_ast_loop_error);
1212 return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
1213 pos);
1216 /* Set the loop AST generation type for the band member of the band tree root
1217 * at position "pos" for the isolated part to "type".
1219 __isl_give isl_schedule_tree *
1220 isl_schedule_tree_band_member_set_isolate_ast_loop_type(
1221 __isl_take isl_schedule_tree *tree, int pos,
1222 enum isl_ast_loop_type type)
1224 tree = isl_schedule_tree_cow(tree);
1225 if (!tree)
1226 return NULL;
1228 if (tree->type != isl_schedule_node_band)
1229 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1230 "not a band node", return isl_schedule_tree_free(tree));
1232 tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
1233 tree->band, pos, type);
1234 if (!tree->band)
1235 return isl_schedule_tree_free(tree);
1237 return tree;
1240 /* Return the AST build options associated to the band tree root.
1242 __isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
1243 __isl_keep isl_schedule_tree *tree)
1245 if (!tree)
1246 return NULL;
1248 if (tree->type != isl_schedule_node_band)
1249 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1250 "not a band node", return NULL);
1252 return isl_schedule_band_get_ast_build_options(tree->band);
1255 /* Replace the AST build options associated to band tree root by "options".
1256 * Updated the anchored field if the anchoredness of the root node itself
1257 * changes.
1259 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
1260 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
1262 int was_anchored;
1264 tree = isl_schedule_tree_cow(tree);
1265 if (!tree || !options)
1266 goto error;
1268 if (tree->type != isl_schedule_node_band)
1269 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1270 "not a band node", goto error);
1272 was_anchored = isl_schedule_tree_is_anchored(tree);
1273 tree->band = isl_schedule_band_set_ast_build_options(tree->band,
1274 options);
1275 if (!tree->band)
1276 return isl_schedule_tree_free(tree);
1277 if (isl_schedule_tree_is_anchored(tree) != was_anchored)
1278 tree = isl_schedule_tree_update_anchored(tree);
1280 return tree;
1281 error:
1282 isl_schedule_tree_free(tree);
1283 isl_union_set_free(options);
1284 return NULL;
1287 /* Return the context of the context tree root.
1289 __isl_give isl_set *isl_schedule_tree_context_get_context(
1290 __isl_keep isl_schedule_tree *tree)
1292 if (!tree)
1293 return NULL;
1295 if (tree->type != isl_schedule_node_context)
1296 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1297 "not a context node", return NULL);
1299 return isl_set_copy(tree->context);
1302 /* Return the domain of the domain tree root.
1304 __isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
1305 __isl_keep isl_schedule_tree *tree)
1307 if (!tree)
1308 return NULL;
1310 if (tree->type != isl_schedule_node_domain)
1311 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1312 "not a domain node", return NULL);
1314 return isl_union_set_copy(tree->domain);
1317 /* Replace the domain of domain tree root "tree" by "domain".
1319 __isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
1320 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1322 tree = isl_schedule_tree_cow(tree);
1323 if (!tree || !domain)
1324 goto error;
1326 if (tree->type != isl_schedule_node_domain)
1327 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1328 "not a domain node", goto error);
1330 isl_union_set_free(tree->domain);
1331 tree->domain = domain;
1333 return tree;
1334 error:
1335 isl_schedule_tree_free(tree);
1336 isl_union_set_free(domain);
1337 return NULL;
1340 /* Return the contraction of the expansion tree root.
1342 __isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
1343 __isl_keep isl_schedule_tree *tree)
1345 if (!tree)
1346 return NULL;
1348 if (tree->type != isl_schedule_node_expansion)
1349 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1350 "not an expansion node", return NULL);
1352 return isl_union_pw_multi_aff_copy(tree->contraction);
1355 /* Return the expansion of the expansion tree root.
1357 __isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
1358 __isl_keep isl_schedule_tree *tree)
1360 if (!tree)
1361 return NULL;
1363 if (tree->type != isl_schedule_node_expansion)
1364 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1365 "not an expansion node", return NULL);
1367 return isl_union_map_copy(tree->expansion);
1370 /* Replace the contraction and the expansion of the expansion tree root "tree"
1371 * by "contraction" and "expansion".
1373 __isl_give isl_schedule_tree *
1374 isl_schedule_tree_expansion_set_contraction_and_expansion(
1375 __isl_take isl_schedule_tree *tree,
1376 __isl_take isl_union_pw_multi_aff *contraction,
1377 __isl_take isl_union_map *expansion)
1379 tree = isl_schedule_tree_cow(tree);
1380 if (!tree || !contraction || !expansion)
1381 goto error;
1383 if (tree->type != isl_schedule_node_expansion)
1384 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1385 "not an expansion node", return NULL);
1387 isl_union_pw_multi_aff_free(tree->contraction);
1388 tree->contraction = contraction;
1389 isl_union_map_free(tree->expansion);
1390 tree->expansion = expansion;
1392 return tree;
1393 error:
1394 isl_schedule_tree_free(tree);
1395 isl_union_pw_multi_aff_free(contraction);
1396 isl_union_map_free(expansion);
1397 return NULL;
1400 /* Return the extension of the extension tree root.
1402 __isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
1403 __isl_take isl_schedule_tree *tree)
1405 if (!tree)
1406 return NULL;
1408 if (tree->type != isl_schedule_node_extension)
1409 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1410 "not an extension node", return NULL);
1412 return isl_union_map_copy(tree->extension);
1415 /* Replace the extension of extension tree root "tree" by "extension".
1417 __isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
1418 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
1420 tree = isl_schedule_tree_cow(tree);
1421 if (!tree || !extension)
1422 goto error;
1424 if (tree->type != isl_schedule_node_extension)
1425 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1426 "not an extension node", return NULL);
1427 isl_union_map_free(tree->extension);
1428 tree->extension = extension;
1430 return tree;
1431 error:
1432 isl_schedule_tree_free(tree);
1433 isl_union_map_free(extension);
1434 return NULL;
1437 /* Return the filter of the filter tree root.
1439 __isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
1440 __isl_keep isl_schedule_tree *tree)
1442 if (!tree)
1443 return NULL;
1445 if (tree->type != isl_schedule_node_filter)
1446 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1447 "not a filter node", return NULL);
1449 return isl_union_set_copy(tree->filter);
1452 /* Replace the filter of the filter tree root by "filter".
1454 __isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
1455 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
1457 tree = isl_schedule_tree_cow(tree);
1458 if (!tree || !filter)
1459 goto error;
1461 if (tree->type != isl_schedule_node_filter)
1462 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1463 "not a filter node", return NULL);
1465 isl_union_set_free(tree->filter);
1466 tree->filter = filter;
1468 return tree;
1469 error:
1470 isl_schedule_tree_free(tree);
1471 isl_union_set_free(filter);
1472 return NULL;
1475 /* Return the guard of the guard tree root.
1477 __isl_give isl_set *isl_schedule_tree_guard_get_guard(
1478 __isl_take isl_schedule_tree *tree)
1480 if (!tree)
1481 return NULL;
1483 if (tree->type != isl_schedule_node_guard)
1484 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1485 "not a guard node", return NULL);
1487 return isl_set_copy(tree->guard);
1490 /* Return the mark identifier of the mark tree root "tree".
1492 __isl_give isl_id *isl_schedule_tree_mark_get_id(
1493 __isl_keep isl_schedule_tree *tree)
1495 if (!tree)
1496 return NULL;
1498 if (tree->type != isl_schedule_node_mark)
1499 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1500 "not a mark node", return NULL);
1502 return isl_id_copy(tree->mark);
1505 /* Set dim to the range dimension of "map" and abort the search.
1507 static int set_range_dim(__isl_take isl_map *map, void *user)
1509 int *dim = user;
1511 *dim = isl_map_dim(map, isl_dim_out);
1512 isl_map_free(map);
1514 return -1;
1517 /* Return the dimension of the range of "umap".
1518 * "umap" is assumed not to be empty and
1519 * all maps inside "umap" are assumed to have the same range.
1521 * We extract the range dimension from the first map in "umap".
1523 static int range_dim(__isl_keep isl_union_map *umap)
1525 int dim = -1;
1527 if (!umap)
1528 return -1;
1529 if (isl_union_map_n_map(umap) == 0)
1530 isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
1531 "unexpected empty input", return -1);
1533 isl_union_map_foreach_map(umap, &set_range_dim, &dim);
1535 return dim;
1538 /* Append an "extra" number of zeros to the range of "umap" and
1539 * return the result.
1541 static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
1542 int extra)
1544 isl_union_set *dom;
1545 isl_space *space;
1546 isl_multi_val *mv;
1547 isl_union_pw_multi_aff *suffix;
1548 isl_union_map *universe;
1549 isl_union_map *suffix_umap;
1551 universe = isl_union_map_universe(isl_union_map_copy(umap));
1552 dom = isl_union_map_domain(universe);
1553 space = isl_union_set_get_space(dom);
1554 space = isl_space_set_from_params(space);
1555 space = isl_space_add_dims(space, isl_dim_set, extra);
1556 mv = isl_multi_val_zero(space);
1558 suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
1559 suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
1560 umap = isl_union_map_flat_range_product(umap, suffix_umap);
1562 return umap;
1565 /* Should we skip the root of "tree" while looking for the first
1566 * descendant with schedule information?
1567 * That is, is it impossible to derive any information about
1568 * the iteration domain from this node?
1570 * We do not want to skip leaf or error nodes because there is
1571 * no point in looking any deeper from these nodes.
1572 * We can only extract partial iteration domain information
1573 * from an extension node, but extension nodes are not supported
1574 * by the caller and it will error out on them.
1576 static int domain_less(__isl_keep isl_schedule_tree *tree)
1578 enum isl_schedule_node_type type;
1580 type = isl_schedule_tree_get_type(tree);
1581 switch (type) {
1582 case isl_schedule_node_band:
1583 return isl_schedule_tree_band_n_member(tree) == 0;
1584 case isl_schedule_node_context:
1585 case isl_schedule_node_guard:
1586 case isl_schedule_node_mark:
1587 return 1;
1588 case isl_schedule_node_leaf:
1589 case isl_schedule_node_error:
1590 case isl_schedule_node_domain:
1591 case isl_schedule_node_expansion:
1592 case isl_schedule_node_extension:
1593 case isl_schedule_node_filter:
1594 case isl_schedule_node_set:
1595 case isl_schedule_node_sequence:
1596 return 0;
1600 /* Move down to the first descendant of "tree" that contains any schedule
1601 * information or return "leaf" if there is no such descendant.
1603 __isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
1604 __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
1606 while (domain_less(tree)) {
1607 if (!isl_schedule_tree_has_children(tree)) {
1608 isl_schedule_tree_free(tree);
1609 return isl_schedule_tree_copy(leaf);
1611 tree = isl_schedule_tree_child(tree, 0);
1614 return tree;
1617 static __isl_give isl_union_map *subtree_schedule_extend(
1618 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);
1620 /* Extend the schedule map "outer" with the subtree schedule
1621 * of the (single) child of "tree", if any.
1623 * If "tree" does not have any descendants (apart from those that
1624 * do not carry any schedule information), then we simply return "outer".
1625 * Otherwise, we extend the schedule map "outer" with the subtree schedule
1626 * of the single child.
1628 static __isl_give isl_union_map *subtree_schedule_extend_child(
1629 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1631 isl_schedule_tree *child;
1632 isl_union_map *res;
1634 if (!tree)
1635 return isl_union_map_free(outer);
1636 if (!isl_schedule_tree_has_children(tree))
1637 return outer;
1638 child = isl_schedule_tree_get_child(tree, 0);
1639 if (!child)
1640 return isl_union_map_free(outer);
1641 res = subtree_schedule_extend(child, outer);
1642 isl_schedule_tree_free(child);
1643 return res;
1646 /* Extract the parameter space from one of the children of "tree",
1647 * which are assumed to be filters.
1649 static __isl_give isl_space *extract_space_from_filter_child(
1650 __isl_keep isl_schedule_tree *tree)
1652 isl_space *space;
1653 isl_union_set *dom;
1654 isl_schedule_tree *child;
1656 child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
1657 dom = isl_schedule_tree_filter_get_filter(child);
1658 space = isl_union_set_get_space(dom);
1659 isl_union_set_free(dom);
1660 isl_schedule_tree_free(child);
1662 return space;
1665 /* Extend the schedule map "outer" with the subtree schedule
1666 * of a set or sequence node.
1668 * The schedule for the set or sequence node itself is composed of
1669 * pieces of the form
1671 * filter -> []
1673 * or
1675 * filter -> [index]
1677 * The first form is used if there is only a single child or
1678 * if the current node is a set node and the schedule_separate_components
1679 * option is not set.
1681 * Each of the pieces above is extended with the subtree schedule of
1682 * the child of the corresponding filter, if any, padded with zeros
1683 * to ensure that all pieces have the same range dimension.
1685 static __isl_give isl_union_map *subtree_schedule_extend_from_children(
1686 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1688 int i, n;
1689 int dim;
1690 int separate;
1691 isl_ctx *ctx;
1692 isl_val *v = NULL;
1693 isl_multi_val *mv;
1694 isl_space *space;
1695 isl_union_map *umap;
1697 if (!tree)
1698 return NULL;
1700 ctx = isl_schedule_tree_get_ctx(tree);
1701 if (!tree->children)
1702 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1703 "missing children", return NULL);
1704 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
1705 if (n == 0)
1706 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1707 "missing children", return NULL);
1709 separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
1710 isl_options_get_schedule_separate_components(ctx));
1712 space = extract_space_from_filter_child(tree);
1714 umap = isl_union_map_empty(isl_space_copy(space));
1715 space = isl_space_set_from_params(space);
1716 if (separate) {
1717 space = isl_space_add_dims(space, isl_dim_set, 1);
1718 v = isl_val_zero(ctx);
1720 mv = isl_multi_val_zero(space);
1722 dim = isl_multi_val_dim(mv, isl_dim_set);
1723 for (i = 0; i < n; ++i) {
1724 isl_union_pw_multi_aff *upma;
1725 isl_union_map *umap_i;
1726 isl_union_set *dom;
1727 isl_schedule_tree *child;
1728 int dim_i;
1729 int empty;
1731 child = isl_schedule_tree_list_get_schedule_tree(
1732 tree->children, i);
1733 dom = isl_schedule_tree_filter_get_filter(child);
1735 if (separate) {
1736 mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
1737 v = isl_val_add_ui(v, 1);
1739 upma = isl_union_pw_multi_aff_multi_val_on_domain(dom,
1740 isl_multi_val_copy(mv));
1741 umap_i = isl_union_map_from_union_pw_multi_aff(upma);
1742 umap_i = isl_union_map_flat_range_product(
1743 isl_union_map_copy(outer), umap_i);
1744 umap_i = subtree_schedule_extend_child(child, umap_i);
1745 isl_schedule_tree_free(child);
1747 empty = isl_union_map_is_empty(umap_i);
1748 if (empty < 0)
1749 umap_i = isl_union_map_free(umap_i);
1750 else if (empty) {
1751 isl_union_map_free(umap_i);
1752 continue;
1755 dim_i = range_dim(umap_i);
1756 if (dim_i < 0) {
1757 umap = isl_union_map_free(umap);
1758 } else if (dim < dim_i) {
1759 umap = append_range(umap, dim_i - dim);
1760 dim = dim_i;
1761 } else if (dim_i < dim) {
1762 umap_i = append_range(umap_i, dim - dim_i);
1764 umap = isl_union_map_union(umap, umap_i);
1767 isl_val_free(v);
1768 isl_multi_val_free(mv);
1769 isl_union_map_free(outer);
1771 return umap;
1774 /* Extend the schedule map "outer" with the subtree schedule of "tree".
1776 * If the root of the tree is a set or a sequence, then we extend
1777 * the schedule map in subtree_schedule_extend_from_children.
1778 * Otherwise, we extend the schedule map with the partial schedule
1779 * corresponding to the root of the tree and then continue with
1780 * the single child of this root.
1781 * In the special case of an expansion, the schedule map is "extended"
1782 * by applying the expansion to the domain of the schedule map.
1784 static __isl_give isl_union_map *subtree_schedule_extend(
1785 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1787 isl_multi_union_pw_aff *mupa;
1788 isl_union_map *umap;
1789 isl_union_set *domain;
1791 if (!tree)
1792 return NULL;
1794 switch (tree->type) {
1795 case isl_schedule_node_error:
1796 return isl_union_map_free(outer);
1797 case isl_schedule_node_extension:
1798 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1799 "cannot construct subtree schedule of tree "
1800 "with extension nodes",
1801 return isl_union_map_free(outer));
1802 case isl_schedule_node_context:
1803 case isl_schedule_node_guard:
1804 case isl_schedule_node_mark:
1805 return subtree_schedule_extend_child(tree, outer);
1806 case isl_schedule_node_band:
1807 if (isl_schedule_tree_band_n_member(tree) == 0)
1808 return subtree_schedule_extend_child(tree, outer);
1809 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1810 umap = isl_union_map_from_multi_union_pw_aff(mupa);
1811 outer = isl_union_map_flat_range_product(outer, umap);
1812 umap = subtree_schedule_extend_child(tree, outer);
1813 break;
1814 case isl_schedule_node_domain:
1815 domain = isl_schedule_tree_domain_get_domain(tree);
1816 umap = isl_union_map_from_domain(domain);
1817 outer = isl_union_map_flat_range_product(outer, umap);
1818 umap = subtree_schedule_extend_child(tree, outer);
1819 break;
1820 case isl_schedule_node_expansion:
1821 umap = isl_schedule_tree_expansion_get_expansion(tree);
1822 outer = isl_union_map_apply_domain(outer, umap);
1823 umap = subtree_schedule_extend_child(tree, outer);
1824 break;
1825 case isl_schedule_node_filter:
1826 domain = isl_schedule_tree_filter_get_filter(tree);
1827 umap = isl_union_map_from_domain(domain);
1828 outer = isl_union_map_flat_range_product(outer, umap);
1829 umap = subtree_schedule_extend_child(tree, outer);
1830 break;
1831 case isl_schedule_node_leaf:
1832 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1833 "leaf node should be handled by caller", return NULL);
1834 case isl_schedule_node_set:
1835 case isl_schedule_node_sequence:
1836 umap = subtree_schedule_extend_from_children(tree, outer);
1837 break;
1840 return umap;
1843 static __isl_give isl_union_set *initial_domain(
1844 __isl_keep isl_schedule_tree *tree);
1846 /* Extract a universe domain from the children of the tree root "tree",
1847 * which is a set or sequence, meaning that its children are filters.
1848 * In particular, return the union of the universes of the filters.
1850 static __isl_give isl_union_set *initial_domain_from_children(
1851 __isl_keep isl_schedule_tree *tree)
1853 int i, n;
1854 isl_space *space;
1855 isl_union_set *domain;
1857 if (!tree->children)
1858 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1859 "missing children", return NULL);
1860 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
1861 if (n == 0)
1862 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1863 "missing children", return NULL);
1865 space = extract_space_from_filter_child(tree);
1866 domain = isl_union_set_empty(space);
1868 for (i = 0; i < n; ++i) {
1869 isl_schedule_tree *child;
1870 isl_union_set *domain_i;
1872 child = isl_schedule_tree_get_child(tree, i);
1873 domain_i = initial_domain(child);
1874 domain = isl_union_set_union(domain, domain_i);
1875 isl_schedule_tree_free(child);
1878 return domain;
1881 /* Extract a universe domain from the tree root "tree".
1882 * The caller is responsible for making sure that this node
1883 * would not be skipped by isl_schedule_tree_first_schedule_descendant
1884 * and that it is not a leaf node.
1886 static __isl_give isl_union_set *initial_domain(
1887 __isl_keep isl_schedule_tree *tree)
1889 isl_multi_union_pw_aff *mupa;
1890 isl_union_set *domain;
1891 isl_union_map *exp;
1893 if (!tree)
1894 return NULL;
1896 switch (tree->type) {
1897 case isl_schedule_node_error:
1898 return NULL;
1899 case isl_schedule_node_context:
1900 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1901 "context node should be handled by caller",
1902 return NULL);
1903 case isl_schedule_node_guard:
1904 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1905 "guard node should be handled by caller",
1906 return NULL);
1907 case isl_schedule_node_mark:
1908 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1909 "mark node should be handled by caller",
1910 return NULL);
1911 case isl_schedule_node_extension:
1912 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1913 "cannot construct subtree schedule of tree "
1914 "with extension nodes", return NULL);
1915 case isl_schedule_node_band:
1916 if (isl_schedule_tree_band_n_member(tree) == 0)
1917 isl_die(isl_schedule_tree_get_ctx(tree),
1918 isl_error_internal,
1919 "0D band should be handled by caller",
1920 return NULL);
1921 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1922 domain = isl_multi_union_pw_aff_domain(mupa);
1923 domain = isl_union_set_universe(domain);
1924 break;
1925 case isl_schedule_node_domain:
1926 domain = isl_schedule_tree_domain_get_domain(tree);
1927 domain = isl_union_set_universe(domain);
1928 break;
1929 case isl_schedule_node_expansion:
1930 exp = isl_schedule_tree_expansion_get_expansion(tree);
1931 exp = isl_union_map_universe(exp);
1932 domain = isl_union_map_domain(exp);
1933 break;
1934 case isl_schedule_node_filter:
1935 domain = isl_schedule_tree_filter_get_filter(tree);
1936 domain = isl_union_set_universe(domain);
1937 break;
1938 case isl_schedule_node_leaf:
1939 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1940 "leaf node should be handled by caller", return NULL);
1941 case isl_schedule_node_set:
1942 case isl_schedule_node_sequence:
1943 domain = initial_domain_from_children(tree);
1944 break;
1947 return domain;
1950 /* Return the subtree schedule of a node that contains some schedule
1951 * information, i.e., a node that would not be skipped by
1952 * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
1954 * If the tree contains any expansions, then the returned subtree
1955 * schedule is formulated in terms of the expanded domains.
1956 * The tree is not allowed to contain any extension nodes.
1958 * We start with an initial zero-dimensional subtree schedule based
1959 * on the domain information in the root node and then extend it
1960 * based on the schedule information in the root node and its descendants.
1962 __isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
1963 __isl_keep isl_schedule_tree *tree)
1965 isl_union_set *domain;
1966 isl_union_map *umap;
1968 domain = initial_domain(tree);
1969 umap = isl_union_map_from_domain(domain);
1970 return subtree_schedule_extend(tree, umap);
1973 /* Multiply the partial schedule of the band root node of "tree"
1974 * with the factors in "mv".
1976 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
1977 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
1979 if (!tree || !mv)
1980 goto error;
1981 if (tree->type != isl_schedule_node_band)
1982 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1983 "not a band node", goto error);
1985 tree = isl_schedule_tree_cow(tree);
1986 if (!tree)
1987 goto error;
1989 tree->band = isl_schedule_band_scale(tree->band, mv);
1990 if (!tree->band)
1991 return isl_schedule_tree_free(tree);
1993 return tree;
1994 error:
1995 isl_schedule_tree_free(tree);
1996 isl_multi_val_free(mv);
1997 return NULL;
2000 /* Divide the partial schedule of the band root node of "tree"
2001 * by the factors in "mv".
2003 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
2004 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
2006 if (!tree || !mv)
2007 goto error;
2008 if (tree->type != isl_schedule_node_band)
2009 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2010 "not a band node", goto error);
2012 tree = isl_schedule_tree_cow(tree);
2013 if (!tree)
2014 goto error;
2016 tree->band = isl_schedule_band_scale_down(tree->band, mv);
2017 if (!tree->band)
2018 return isl_schedule_tree_free(tree);
2020 return tree;
2021 error:
2022 isl_schedule_tree_free(tree);
2023 isl_multi_val_free(mv);
2024 return NULL;
2027 /* Given two trees with sequence roots, replace the child at position
2028 * "pos" of "tree" with the children of "child".
2030 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
2031 __isl_take isl_schedule_tree *tree, int pos,
2032 __isl_take isl_schedule_tree *child)
2034 int n;
2035 isl_schedule_tree_list *list1, *list2;
2037 tree = isl_schedule_tree_cow(tree);
2038 if (!tree || !child)
2039 goto error;
2040 if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
2041 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2042 "not a sequence node", goto error);
2043 n = isl_schedule_tree_n_children(tree);
2044 if (pos < 0 || pos >= n)
2045 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2046 "position out of bounds", goto error);
2047 if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence)
2048 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2049 "not a sequence node", goto error);
2051 list1 = isl_schedule_tree_list_copy(tree->children);
2052 list1 = isl_schedule_tree_list_drop(list1, pos, n - pos);
2053 list2 = isl_schedule_tree_list_copy(tree->children);
2054 list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1);
2055 list1 = isl_schedule_tree_list_concat(list1,
2056 isl_schedule_tree_list_copy(child->children));
2057 list1 = isl_schedule_tree_list_concat(list1, list2);
2059 isl_schedule_tree_free(tree);
2060 isl_schedule_tree_free(child);
2061 return isl_schedule_tree_from_children(isl_schedule_node_sequence,
2062 list1);
2063 error:
2064 isl_schedule_tree_free(tree);
2065 isl_schedule_tree_free(child);
2066 return NULL;
2069 /* Tile the band root node of "tree" with tile sizes "sizes".
2071 * We duplicate the band node, change the schedule of one of them
2072 * to the tile schedule and the other to the point schedule and then
2073 * attach the point band as a child to the tile band.
2075 __isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
2076 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
2078 isl_schedule_tree *child = NULL;
2080 if (!tree || !sizes)
2081 goto error;
2082 if (tree->type != isl_schedule_node_band)
2083 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2084 "not a band node", goto error);
2086 child = isl_schedule_tree_copy(tree);
2087 tree = isl_schedule_tree_cow(tree);
2088 child = isl_schedule_tree_cow(child);
2089 if (!tree || !child)
2090 goto error;
2092 tree->band = isl_schedule_band_tile(tree->band,
2093 isl_multi_val_copy(sizes));
2094 if (!tree->band)
2095 goto error;
2096 child->band = isl_schedule_band_point(child->band, tree->band, sizes);
2097 if (!child->band)
2098 child = isl_schedule_tree_free(child);
2100 tree = isl_schedule_tree_replace_child(tree, 0, child);
2102 return tree;
2103 error:
2104 isl_schedule_tree_free(child);
2105 isl_schedule_tree_free(tree);
2106 isl_multi_val_free(sizes);
2107 return NULL;
2110 /* Split the band root node of "tree" into two nested band nodes,
2111 * one with the first "pos" dimensions and
2112 * one with the remaining dimensions.
2114 __isl_give isl_schedule_tree *isl_schedule_tree_band_split(
2115 __isl_take isl_schedule_tree *tree, int pos)
2117 int n;
2118 isl_schedule_tree *child;
2120 if (!tree)
2121 return NULL;
2122 if (tree->type != isl_schedule_node_band)
2123 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2124 "not a band node", return isl_schedule_tree_free(tree));
2126 n = isl_schedule_tree_band_n_member(tree);
2127 if (pos < 0 || pos > n)
2128 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2129 "position out of bounds",
2130 return isl_schedule_tree_free(tree));
2132 child = isl_schedule_tree_copy(tree);
2133 tree = isl_schedule_tree_cow(tree);
2134 child = isl_schedule_tree_cow(child);
2135 if (!tree || !child)
2136 goto error;
2138 child->band = isl_schedule_band_drop(child->band, 0, pos);
2139 tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
2140 if (!child->band || !tree->band)
2141 goto error;
2143 tree = isl_schedule_tree_replace_child(tree, 0, child);
2145 return tree;
2146 error:
2147 isl_schedule_tree_free(child);
2148 isl_schedule_tree_free(tree);
2149 return NULL;
2152 /* Attach "tree2" at each of the leaves of "tree1".
2154 * If "tree1" does not have any explicit children, then make "tree2"
2155 * its single child. Otherwise, attach "tree2" to the leaves of
2156 * each of the children of "tree1".
2158 __isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
2159 __isl_take isl_schedule_tree *tree1,
2160 __isl_take isl_schedule_tree *tree2)
2162 int i, n;
2164 if (!tree1 || !tree2)
2165 goto error;
2166 n = isl_schedule_tree_n_children(tree1);
2167 if (n == 0) {
2168 isl_schedule_tree_list *list;
2169 list = isl_schedule_tree_list_from_schedule_tree(tree2);
2170 tree1 = isl_schedule_tree_set_children(tree1, list);
2171 return tree1;
2173 for (i = 0; i < n; ++i) {
2174 isl_schedule_tree *child;
2176 child = isl_schedule_tree_get_child(tree1, i);
2177 child = isl_schedule_tree_append_to_leaves(child,
2178 isl_schedule_tree_copy(tree2));
2179 tree1 = isl_schedule_tree_replace_child(tree1, i, child);
2182 isl_schedule_tree_free(tree2);
2183 return tree1;
2184 error:
2185 isl_schedule_tree_free(tree1);
2186 isl_schedule_tree_free(tree2);
2187 return NULL;
2190 /* Reset the user pointer on all identifiers of parameters and tuples
2191 * in the root of "tree".
2193 __isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
2194 __isl_take isl_schedule_tree *tree)
2196 if (isl_schedule_tree_is_leaf(tree))
2197 return tree;
2199 tree = isl_schedule_tree_cow(tree);
2200 if (!tree)
2201 return NULL;
2203 switch (tree->type) {
2204 case isl_schedule_node_error:
2205 return isl_schedule_tree_free(tree);
2206 case isl_schedule_node_band:
2207 tree->band = isl_schedule_band_reset_user(tree->band);
2208 if (!tree->band)
2209 return isl_schedule_tree_free(tree);
2210 break;
2211 case isl_schedule_node_context:
2212 tree->context = isl_set_reset_user(tree->context);
2213 if (!tree->context)
2214 return isl_schedule_tree_free(tree);
2215 break;
2216 case isl_schedule_node_domain:
2217 tree->domain = isl_union_set_reset_user(tree->domain);
2218 if (!tree->domain)
2219 return isl_schedule_tree_free(tree);
2220 break;
2221 case isl_schedule_node_expansion:
2222 tree->contraction =
2223 isl_union_pw_multi_aff_reset_user(tree->contraction);
2224 tree->expansion = isl_union_map_reset_user(tree->expansion);
2225 if (!tree->contraction || !tree->expansion)
2226 return isl_schedule_tree_free(tree);
2227 break;
2228 case isl_schedule_node_extension:
2229 tree->extension = isl_union_map_reset_user(tree->extension);
2230 if (!tree->extension)
2231 return isl_schedule_tree_free(tree);
2232 break;
2233 case isl_schedule_node_filter:
2234 tree->filter = isl_union_set_reset_user(tree->filter);
2235 if (!tree->filter)
2236 return isl_schedule_tree_free(tree);
2237 break;
2238 case isl_schedule_node_guard:
2239 tree->guard = isl_set_reset_user(tree->guard);
2240 if (!tree->guard)
2241 return isl_schedule_tree_free(tree);
2242 break;
2243 case isl_schedule_node_leaf:
2244 case isl_schedule_node_mark:
2245 case isl_schedule_node_sequence:
2246 case isl_schedule_node_set:
2247 break;
2250 return tree;
2253 /* Align the parameters of the root of "tree" to those of "space".
2255 __isl_give isl_schedule_tree *isl_schedule_tree_align_params(
2256 __isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
2258 if (!space)
2259 goto error;
2261 if (isl_schedule_tree_is_leaf(tree)) {
2262 isl_space_free(space);
2263 return tree;
2266 tree = isl_schedule_tree_cow(tree);
2267 if (!tree)
2268 goto error;
2270 switch (tree->type) {
2271 case isl_schedule_node_error:
2272 goto error;
2273 case isl_schedule_node_band:
2274 tree->band = isl_schedule_band_align_params(tree->band, space);
2275 if (!tree->band)
2276 return isl_schedule_tree_free(tree);
2277 break;
2278 case isl_schedule_node_context:
2279 tree->context = isl_set_align_params(tree->context, space);
2280 if (!tree->context)
2281 return isl_schedule_tree_free(tree);
2282 break;
2283 case isl_schedule_node_domain:
2284 tree->domain = isl_union_set_align_params(tree->domain, space);
2285 if (!tree->domain)
2286 return isl_schedule_tree_free(tree);
2287 break;
2288 case isl_schedule_node_expansion:
2289 tree->contraction =
2290 isl_union_pw_multi_aff_align_params(tree->contraction,
2291 isl_space_copy(space));
2292 tree->expansion = isl_union_map_align_params(tree->expansion,
2293 space);
2294 if (!tree->contraction || !tree->expansion)
2295 return isl_schedule_tree_free(tree);
2296 break;
2297 case isl_schedule_node_extension:
2298 tree->extension = isl_union_map_align_params(tree->extension,
2299 space);
2300 if (!tree->extension)
2301 return isl_schedule_tree_free(tree);
2302 break;
2303 case isl_schedule_node_filter:
2304 tree->filter = isl_union_set_align_params(tree->filter, space);
2305 if (!tree->filter)
2306 return isl_schedule_tree_free(tree);
2307 break;
2308 case isl_schedule_node_guard:
2309 tree->guard = isl_set_align_params(tree->guard, space);
2310 if (!tree->guard)
2311 return isl_schedule_tree_free(tree);
2312 break;
2313 case isl_schedule_node_leaf:
2314 case isl_schedule_node_mark:
2315 case isl_schedule_node_sequence:
2316 case isl_schedule_node_set:
2317 isl_space_free(space);
2318 break;
2321 return tree;
2322 error:
2323 isl_space_free(space);
2324 isl_schedule_tree_free(tree);
2325 return NULL;
2328 /* Does "tree" involve the iteration domain?
2329 * That is, does it need to be modified
2330 * by isl_schedule_tree_pullback_union_pw_multi_aff?
2332 static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
2334 if (!tree)
2335 return -1;
2337 switch (tree->type) {
2338 case isl_schedule_node_error:
2339 return -1;
2340 case isl_schedule_node_band:
2341 case isl_schedule_node_domain:
2342 case isl_schedule_node_expansion:
2343 case isl_schedule_node_extension:
2344 case isl_schedule_node_filter:
2345 return 1;
2346 case isl_schedule_node_context:
2347 case isl_schedule_node_leaf:
2348 case isl_schedule_node_guard:
2349 case isl_schedule_node_mark:
2350 case isl_schedule_node_sequence:
2351 case isl_schedule_node_set:
2352 return 0;
2356 /* Compute the pullback of the root node of "tree" by the function
2357 * represented by "upma".
2358 * In other words, plug in "upma" in the iteration domains of
2359 * the root node of "tree".
2360 * We currently do not handle expansion nodes.
2362 * We first check if the root node involves any iteration domains.
2363 * If so, we handle the specific cases.
2365 __isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
2366 __isl_take isl_schedule_tree *tree,
2367 __isl_take isl_union_pw_multi_aff *upma)
2369 int involves;
2371 if (!tree || !upma)
2372 goto error;
2374 involves = involves_iteration_domain(tree);
2375 if (involves < 0)
2376 goto error;
2377 if (!involves) {
2378 isl_union_pw_multi_aff_free(upma);
2379 return tree;
2382 tree = isl_schedule_tree_cow(tree);
2383 if (!tree)
2384 goto error;
2386 if (tree->type == isl_schedule_node_band) {
2387 tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
2388 tree->band, upma);
2389 if (!tree->band)
2390 return isl_schedule_tree_free(tree);
2391 } else if (tree->type == isl_schedule_node_domain) {
2392 tree->domain =
2393 isl_union_set_preimage_union_pw_multi_aff(tree->domain,
2394 upma);
2395 if (!tree->domain)
2396 return isl_schedule_tree_free(tree);
2397 } else if (tree->type == isl_schedule_node_expansion) {
2398 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
2399 "cannot pullback expansion node", goto error);
2400 } else if (tree->type == isl_schedule_node_extension) {
2401 tree->extension =
2402 isl_union_map_preimage_range_union_pw_multi_aff(
2403 tree->extension, upma);
2404 if (!tree->extension)
2405 return isl_schedule_tree_free(tree);
2406 } else if (tree->type == isl_schedule_node_filter) {
2407 tree->filter =
2408 isl_union_set_preimage_union_pw_multi_aff(tree->filter,
2409 upma);
2410 if (!tree->filter)
2411 return isl_schedule_tree_free(tree);
2414 return tree;
2415 error:
2416 isl_union_pw_multi_aff_free(upma);
2417 isl_schedule_tree_free(tree);
2418 return NULL;
2421 /* Compute the gist of the band tree root with respect to "context".
2423 __isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
2424 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
2426 if (!tree)
2427 return NULL;
2428 if (tree->type != isl_schedule_node_band)
2429 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2430 "not a band node", goto error);
2431 tree = isl_schedule_tree_cow(tree);
2432 if (!tree)
2433 goto error;
2435 tree->band = isl_schedule_band_gist(tree->band, context);
2436 if (!tree->band)
2437 return isl_schedule_tree_free(tree);
2438 return tree;
2439 error:
2440 isl_union_set_free(context);
2441 isl_schedule_tree_free(tree);
2442 return NULL;
2445 /* Are any members in "band" marked coincident?
2447 static int any_coincident(__isl_keep isl_schedule_band *band)
2449 int i, n;
2451 n = isl_schedule_band_n_member(band);
2452 for (i = 0; i < n; ++i)
2453 if (isl_schedule_band_member_get_coincident(band, i))
2454 return 1;
2456 return 0;
2459 /* Print the band node "band" to "p".
2461 * The permutable and coincident properties are only printed if they
2462 * are different from the defaults.
2463 * The coincident property is always printed in YAML flow style.
2465 static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
2466 __isl_keep isl_schedule_band *band)
2468 isl_union_set *options;
2469 int empty;
2471 p = isl_printer_print_str(p, "schedule");
2472 p = isl_printer_yaml_next(p);
2473 p = isl_printer_print_str(p, "\"");
2474 p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
2475 p = isl_printer_print_str(p, "\"");
2476 if (isl_schedule_band_get_permutable(band)) {
2477 p = isl_printer_yaml_next(p);
2478 p = isl_printer_print_str(p, "permutable");
2479 p = isl_printer_yaml_next(p);
2480 p = isl_printer_print_int(p, 1);
2482 if (any_coincident(band)) {
2483 int i, n;
2484 int style;
2486 p = isl_printer_yaml_next(p);
2487 p = isl_printer_print_str(p, "coincident");
2488 p = isl_printer_yaml_next(p);
2489 style = isl_printer_get_yaml_style(p);
2490 p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
2491 p = isl_printer_yaml_start_sequence(p);
2492 n = isl_schedule_band_n_member(band);
2493 for (i = 0; i < n; ++i) {
2494 p = isl_printer_print_int(p,
2495 isl_schedule_band_member_get_coincident(band, i));
2496 p = isl_printer_yaml_next(p);
2498 p = isl_printer_yaml_end_sequence(p);
2499 p = isl_printer_set_yaml_style(p, style);
2501 options = isl_schedule_band_get_ast_build_options(band);
2502 empty = isl_union_set_is_empty(options);
2503 if (empty < 0)
2504 p = isl_printer_free(p);
2505 if (!empty) {
2506 p = isl_printer_yaml_next(p);
2507 p = isl_printer_print_str(p, "options");
2508 p = isl_printer_yaml_next(p);
2509 p = isl_printer_print_str(p, "\"");
2510 p = isl_printer_print_union_set(p, options);
2511 p = isl_printer_print_str(p, "\"");
2513 isl_union_set_free(options);
2515 return p;
2518 /* Print "tree" to "p".
2520 * If "n_ancestor" is non-negative, then "child_pos" contains the child
2521 * positions of a descendant of the current node that should be marked
2522 * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor"
2523 * is zero, then the current node should be marked.
2524 * The marking is only printed in YAML block format.
2526 * Implicit leaf nodes are not printed, except if they correspond
2527 * to the node that should be marked.
2529 __isl_give isl_printer *isl_printer_print_schedule_tree_mark(
2530 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
2531 int n_ancestor, int *child_pos)
2533 int i, n;
2534 int sequence = 0;
2535 int block;
2537 block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;
2539 p = isl_printer_yaml_start_mapping(p);
2540 if (n_ancestor == 0 && block) {
2541 p = isl_printer_print_str(p, "# YOU ARE HERE");
2542 p = isl_printer_end_line(p);
2543 p = isl_printer_start_line(p);
2545 switch (tree->type) {
2546 case isl_schedule_node_error:
2547 p = isl_printer_print_str(p, "ERROR");
2548 break;
2549 case isl_schedule_node_leaf:
2550 p = isl_printer_print_str(p, "leaf");
2551 break;
2552 case isl_schedule_node_sequence:
2553 p = isl_printer_print_str(p, "sequence");
2554 sequence = 1;
2555 break;
2556 case isl_schedule_node_set:
2557 p = isl_printer_print_str(p, "set");
2558 sequence = 1;
2559 break;
2560 case isl_schedule_node_context:
2561 p = isl_printer_print_str(p, "context");
2562 p = isl_printer_yaml_next(p);
2563 p = isl_printer_print_str(p, "\"");
2564 p = isl_printer_print_set(p, tree->context);
2565 p = isl_printer_print_str(p, "\"");
2566 break;
2567 case isl_schedule_node_domain:
2568 p = isl_printer_print_str(p, "domain");
2569 p = isl_printer_yaml_next(p);
2570 p = isl_printer_print_str(p, "\"");
2571 p = isl_printer_print_union_set(p, tree->domain);
2572 p = isl_printer_print_str(p, "\"");
2573 break;
2574 case isl_schedule_node_expansion:
2575 p = isl_printer_print_str(p, "contraction");
2576 p = isl_printer_yaml_next(p);
2577 p = isl_printer_print_str(p, "\"");
2578 p = isl_printer_print_union_pw_multi_aff(p, tree->contraction);
2579 p = isl_printer_print_str(p, "\"");
2580 p = isl_printer_yaml_next(p);
2581 p = isl_printer_print_str(p, "expansion");
2582 p = isl_printer_yaml_next(p);
2583 p = isl_printer_print_str(p, "\"");
2584 p = isl_printer_print_union_map(p, tree->expansion);
2585 p = isl_printer_print_str(p, "\"");
2586 break;
2587 case isl_schedule_node_extension:
2588 p = isl_printer_print_str(p, "extension");
2589 p = isl_printer_yaml_next(p);
2590 p = isl_printer_print_str(p, "\"");
2591 p = isl_printer_print_union_map(p, tree->extension);
2592 p = isl_printer_print_str(p, "\"");
2593 break;
2594 case isl_schedule_node_filter:
2595 p = isl_printer_print_str(p, "filter");
2596 p = isl_printer_yaml_next(p);
2597 p = isl_printer_print_str(p, "\"");
2598 p = isl_printer_print_union_set(p, tree->filter);
2599 p = isl_printer_print_str(p, "\"");
2600 break;
2601 case isl_schedule_node_guard:
2602 p = isl_printer_print_str(p, "guard");
2603 p = isl_printer_yaml_next(p);
2604 p = isl_printer_print_str(p, "\"");
2605 p = isl_printer_print_set(p, tree->guard);
2606 p = isl_printer_print_str(p, "\"");
2607 break;
2608 case isl_schedule_node_mark:
2609 p = isl_printer_print_str(p, "mark");
2610 p = isl_printer_yaml_next(p);
2611 p = isl_printer_print_str(p, "\"");
2612 p = isl_printer_print_str(p, isl_id_get_name(tree->mark));
2613 p = isl_printer_print_str(p, "\"");
2614 break;
2615 case isl_schedule_node_band:
2616 p = print_tree_band(p, tree->band);
2617 break;
2619 p = isl_printer_yaml_next(p);
2621 if (!tree->children) {
2622 if (n_ancestor > 0 && block) {
2623 isl_schedule_tree *leaf;
2625 p = isl_printer_print_str(p, "child");
2626 p = isl_printer_yaml_next(p);
2627 leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
2628 p = isl_printer_print_schedule_tree_mark(p,
2629 leaf, 0, NULL);
2630 isl_schedule_tree_free(leaf);
2631 p = isl_printer_yaml_next(p);
2633 return isl_printer_yaml_end_mapping(p);
2636 if (sequence) {
2637 p = isl_printer_yaml_start_sequence(p);
2638 } else {
2639 p = isl_printer_print_str(p, "child");
2640 p = isl_printer_yaml_next(p);
2643 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
2644 for (i = 0; i < n; ++i) {
2645 isl_schedule_tree *t;
2647 t = isl_schedule_tree_get_child(tree, i);
2648 if (n_ancestor > 0 && child_pos[0] == i)
2649 p = isl_printer_print_schedule_tree_mark(p, t,
2650 n_ancestor - 1, child_pos + 1);
2651 else
2652 p = isl_printer_print_schedule_tree_mark(p, t,
2653 -1, NULL);
2654 isl_schedule_tree_free(t);
2656 p = isl_printer_yaml_next(p);
2659 if (sequence)
2660 p = isl_printer_yaml_end_sequence(p);
2661 p = isl_printer_yaml_end_mapping(p);
2663 return p;
2666 /* Print "tree" to "p".
2668 __isl_give isl_printer *isl_printer_print_schedule_tree(
2669 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
2671 return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
2674 void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
2676 isl_ctx *ctx;
2677 isl_printer *printer;
2679 if (!tree)
2680 return;
2682 ctx = isl_schedule_tree_get_ctx(tree);
2683 printer = isl_printer_to_file(ctx, stderr);
2684 printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
2685 printer = isl_printer_print_schedule_tree(printer, tree);
2687 isl_printer_free(printer);