Fix typo in isl_test.c
[isl.git] / isl_schedule_tree.c
blob78fcf49ddb1a17384f8622b6a376724f2de1902d
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 isl_bool isl_schedule_tree_is_subtree_anchored(
454 __isl_keep isl_schedule_tree *tree)
456 return tree ? tree->anchored : isl_bool_error;
459 /* Does the root node of "tree" depend on its position in the complete
460 * schedule tree?
461 * Band nodes may be anchored depending on the associated AST build options.
462 * Context, extension and guard nodes are always anchored.
464 int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
466 if (!tree)
467 return -1;
469 switch (isl_schedule_tree_get_type(tree)) {
470 case isl_schedule_node_error:
471 return -1;
472 case isl_schedule_node_band:
473 return isl_schedule_band_is_anchored(tree->band);
474 case isl_schedule_node_context:
475 case isl_schedule_node_extension:
476 case isl_schedule_node_guard:
477 return 1;
478 case isl_schedule_node_domain:
479 case isl_schedule_node_expansion:
480 case isl_schedule_node_filter:
481 case isl_schedule_node_leaf:
482 case isl_schedule_node_mark:
483 case isl_schedule_node_sequence:
484 case isl_schedule_node_set:
485 return 0;
489 /* Update the anchored field of "tree" based on whether the root node
490 * itself in anchored and the anchored fields of the children.
492 * This function should be called whenever the children of a tree node
493 * are changed or the anchoredness of the tree root itself changes.
495 __isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
496 __isl_take isl_schedule_tree *tree)
498 int i, n;
499 int anchored;
501 if (!tree)
502 return NULL;
504 anchored = isl_schedule_tree_is_anchored(tree);
505 if (anchored < 0)
506 return isl_schedule_tree_free(tree);
508 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
509 for (i = 0; !anchored && i < n; ++i) {
510 isl_schedule_tree *child;
512 child = isl_schedule_tree_get_child(tree, i);
513 if (!child)
514 return isl_schedule_tree_free(tree);
515 anchored = child->anchored;
516 isl_schedule_tree_free(child);
519 if (anchored == tree->anchored)
520 return tree;
521 tree = isl_schedule_tree_cow(tree);
522 if (!tree)
523 return NULL;
524 tree->anchored = anchored;
525 return tree;
528 /* Create a new tree of the given type (isl_schedule_node_sequence or
529 * isl_schedule_node_set) with the given children.
531 __isl_give isl_schedule_tree *isl_schedule_tree_from_children(
532 enum isl_schedule_node_type type,
533 __isl_take isl_schedule_tree_list *list)
535 isl_ctx *ctx;
536 isl_schedule_tree *tree;
538 if (!list)
539 return NULL;
541 ctx = isl_schedule_tree_list_get_ctx(list);
542 tree = isl_schedule_tree_alloc(ctx, type);
543 if (!tree)
544 goto error;
546 tree->children = list;
547 tree = isl_schedule_tree_update_anchored(tree);
549 return tree;
550 error:
551 isl_schedule_tree_list_free(list);
552 return NULL;
555 /* Construct a tree with a root node of type "type" and as children
556 * "tree1" and "tree2".
557 * If the root of one (or both) of the input trees is itself of type "type",
558 * then the tree is replaced by its children.
560 __isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
561 enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
562 __isl_take isl_schedule_tree *tree2)
564 isl_ctx *ctx;
565 isl_schedule_tree_list *list;
567 if (!tree1 || !tree2)
568 goto error;
570 ctx = isl_schedule_tree_get_ctx(tree1);
571 if (isl_schedule_tree_get_type(tree1) == type) {
572 list = isl_schedule_tree_list_copy(tree1->children);
573 isl_schedule_tree_free(tree1);
574 } else {
575 list = isl_schedule_tree_list_alloc(ctx, 2);
576 list = isl_schedule_tree_list_add(list, tree1);
578 if (isl_schedule_tree_get_type(tree2) == type) {
579 isl_schedule_tree_list *children;
581 children = isl_schedule_tree_list_copy(tree2->children);
582 list = isl_schedule_tree_list_concat(list, children);
583 isl_schedule_tree_free(tree2);
584 } else {
585 list = isl_schedule_tree_list_add(list, tree2);
588 return isl_schedule_tree_from_children(type, list);
589 error:
590 isl_schedule_tree_free(tree1);
591 isl_schedule_tree_free(tree2);
592 return NULL;
595 /* Construct a tree with a sequence root node and as children
596 * "tree1" and "tree2".
597 * If the root of one (or both) of the input trees is itself a sequence,
598 * then the tree is replaced by its children.
600 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
601 __isl_take isl_schedule_tree *tree1,
602 __isl_take isl_schedule_tree *tree2)
604 return isl_schedule_tree_from_pair(isl_schedule_node_sequence,
605 tree1, tree2);
608 /* Return the isl_ctx to which "tree" belongs.
610 isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
612 return tree ? tree->ctx : NULL;
615 /* Return the type of the root of the tree or isl_schedule_node_error
616 * on error.
618 enum isl_schedule_node_type isl_schedule_tree_get_type(
619 __isl_keep isl_schedule_tree *tree)
621 return tree ? tree->type : isl_schedule_node_error;
624 /* Are "tree1" and "tree2" obviously equal to each other?
626 isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
627 __isl_keep isl_schedule_tree *tree2)
629 isl_bool equal;
630 int i, n;
632 if (!tree1 || !tree2)
633 return isl_bool_error;
634 if (tree1 == tree2)
635 return isl_bool_true;
636 if (tree1->type != tree2->type)
637 return isl_bool_false;
639 switch (tree1->type) {
640 case isl_schedule_node_band:
641 equal = isl_schedule_band_plain_is_equal(tree1->band,
642 tree2->band);
643 break;
644 case isl_schedule_node_context:
645 equal = isl_set_is_equal(tree1->context, tree2->context);
646 break;
647 case isl_schedule_node_domain:
648 equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
649 break;
650 case isl_schedule_node_expansion:
651 equal = isl_union_map_is_equal(tree1->expansion,
652 tree2->expansion);
653 if (equal >= 0 && equal)
654 equal = isl_union_pw_multi_aff_plain_is_equal(
655 tree1->contraction, tree2->contraction);
656 break;
657 case isl_schedule_node_extension:
658 equal = isl_union_map_is_equal(tree1->extension,
659 tree2->extension);
660 break;
661 case isl_schedule_node_filter:
662 equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
663 break;
664 case isl_schedule_node_guard:
665 equal = isl_set_is_equal(tree1->guard, tree2->guard);
666 break;
667 case isl_schedule_node_mark:
668 equal = tree1->mark == tree2->mark;
669 break;
670 case isl_schedule_node_leaf:
671 case isl_schedule_node_sequence:
672 case isl_schedule_node_set:
673 equal = isl_bool_true;
674 break;
675 case isl_schedule_node_error:
676 equal = isl_bool_error;
677 break;
680 if (equal < 0 || !equal)
681 return equal;
683 n = isl_schedule_tree_n_children(tree1);
684 if (n != isl_schedule_tree_n_children(tree2))
685 return isl_bool_false;
686 for (i = 0; i < n; ++i) {
687 isl_schedule_tree *child1, *child2;
689 child1 = isl_schedule_tree_get_child(tree1, i);
690 child2 = isl_schedule_tree_get_child(tree2, i);
691 equal = isl_schedule_tree_plain_is_equal(child1, child2);
692 isl_schedule_tree_free(child1);
693 isl_schedule_tree_free(child2);
695 if (equal < 0 || !equal)
696 return equal;
699 return isl_bool_true;
702 /* Does "tree" have any children, other than an implicit leaf.
704 int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
706 if (!tree)
707 return -1;
709 return tree->children != NULL;
712 /* Return the number of children of "tree", excluding implicit leaves.
714 int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
716 if (!tree)
717 return -1;
719 return isl_schedule_tree_list_n_schedule_tree(tree->children);
722 /* Return a copy of the (explicit) child at position "pos" of "tree".
724 __isl_give isl_schedule_tree *isl_schedule_tree_get_child(
725 __isl_keep isl_schedule_tree *tree, int pos)
727 if (!tree)
728 return NULL;
729 if (!tree->children)
730 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
731 "schedule tree has no explicit children", return NULL);
732 return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
735 /* Return a copy of the (explicit) child at position "pos" of "tree" and
736 * free "tree".
738 __isl_give isl_schedule_tree *isl_schedule_tree_child(
739 __isl_take isl_schedule_tree *tree, int pos)
741 isl_schedule_tree *child;
743 child = isl_schedule_tree_get_child(tree, pos);
744 isl_schedule_tree_free(tree);
745 return child;
748 /* Remove all (explicit) children from "tree".
750 __isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
751 __isl_take isl_schedule_tree *tree)
753 tree = isl_schedule_tree_cow(tree);
754 if (!tree)
755 return NULL;
756 tree->children = isl_schedule_tree_list_free(tree->children);
757 return tree;
760 /* Remove the child at position "pos" from the children of "tree".
761 * If there was only one child to begin with, then remove all children.
763 __isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
764 __isl_take isl_schedule_tree *tree, int pos)
766 int n;
768 tree = isl_schedule_tree_cow(tree);
769 if (!tree)
770 return NULL;
772 if (!isl_schedule_tree_has_children(tree))
773 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
774 "tree does not have any explicit children",
775 return isl_schedule_tree_free(tree));
776 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
777 if (pos < 0 || pos >= n)
778 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
779 "position out of bounds",
780 return isl_schedule_tree_free(tree));
781 if (n == 1)
782 return isl_schedule_tree_reset_children(tree);
784 tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
785 if (!tree->children)
786 return isl_schedule_tree_free(tree);
788 return tree;
791 /* Replace the child at position "pos" of "tree" by "child".
793 * If the new child is a leaf, then it is not explicitly
794 * recorded in the list of children. Instead, the list of children
795 * (which is assumed to have only one element) is removed.
796 * Note that the children of set and sequence nodes are always
797 * filters, so they cannot be replaced by empty trees.
799 __isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
800 __isl_take isl_schedule_tree *tree, int pos,
801 __isl_take isl_schedule_tree *child)
803 tree = isl_schedule_tree_cow(tree);
804 if (!tree || !child)
805 goto error;
807 if (isl_schedule_tree_is_leaf(child)) {
808 isl_schedule_tree_free(child);
809 if (!tree->children && pos == 0)
810 return tree;
811 if (isl_schedule_tree_n_children(tree) != 1)
812 isl_die(isl_schedule_tree_get_ctx(tree),
813 isl_error_internal,
814 "can only replace single child by leaf",
815 goto error);
816 return isl_schedule_tree_reset_children(tree);
819 if (!tree->children && pos == 0)
820 tree->children =
821 isl_schedule_tree_list_from_schedule_tree(child);
822 else
823 tree->children = isl_schedule_tree_list_set_schedule_tree(
824 tree->children, pos, child);
826 if (!tree->children)
827 return isl_schedule_tree_free(tree);
828 tree = isl_schedule_tree_update_anchored(tree);
830 return tree;
831 error:
832 isl_schedule_tree_free(tree);
833 isl_schedule_tree_free(child);
834 return NULL;
837 /* Replace the (explicit) children of "tree" by "children"?
839 __isl_give isl_schedule_tree *isl_schedule_tree_set_children(
840 __isl_take isl_schedule_tree *tree,
841 __isl_take isl_schedule_tree_list *children)
843 tree = isl_schedule_tree_cow(tree);
844 if (!tree || !children)
845 goto error;
846 isl_schedule_tree_list_free(tree->children);
847 tree->children = children;
848 return tree;
849 error:
850 isl_schedule_tree_free(tree);
851 isl_schedule_tree_list_free(children);
852 return NULL;
855 /* Create a new band schedule tree referring to "band"
856 * with "tree" as single child.
858 __isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
859 __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
861 isl_schedule_tree *res;
863 res = isl_schedule_tree_from_band(band);
864 return isl_schedule_tree_replace_child(res, 0, tree);
867 /* Create a new context schedule tree with the given context and
868 * with "tree" as single child.
870 __isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
871 __isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
873 isl_schedule_tree *res;
875 res = isl_schedule_tree_from_context(context);
876 return isl_schedule_tree_replace_child(res, 0, tree);
879 /* Create a new domain schedule tree with the given domain and
880 * with "tree" as single child.
882 __isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
883 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
885 isl_schedule_tree *res;
887 res = isl_schedule_tree_from_domain(domain);
888 return isl_schedule_tree_replace_child(res, 0, tree);
891 /* Create a new expansion schedule tree with the given contraction and
892 * expansion and with "tree" as single child.
894 __isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
895 __isl_take isl_schedule_tree *tree,
896 __isl_take isl_union_pw_multi_aff *contraction,
897 __isl_take isl_union_map *expansion)
899 isl_schedule_tree *res;
901 res = isl_schedule_tree_from_expansion(contraction, expansion);
902 return isl_schedule_tree_replace_child(res, 0, tree);
905 /* Create a new extension schedule tree with the given extension and
906 * with "tree" as single child.
908 __isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
909 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
911 isl_schedule_tree *res;
913 res = isl_schedule_tree_from_extension(extension);
914 return isl_schedule_tree_replace_child(res, 0, tree);
917 /* Create a new filter schedule tree with the given filter and single child.
919 * If the root of "tree" is itself a filter node, then the two
920 * filter nodes are merged into one node.
922 __isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
923 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
925 isl_schedule_tree *res;
927 if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
928 isl_union_set *tree_filter;
930 tree_filter = isl_schedule_tree_filter_get_filter(tree);
931 tree_filter = isl_union_set_intersect(tree_filter, filter);
932 tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
933 return tree;
936 res = isl_schedule_tree_from_filter(filter);
937 return isl_schedule_tree_replace_child(res, 0, tree);
940 /* Insert a filter node with filter set "filter"
941 * in each of the children of "tree".
943 __isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
944 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
946 int i, n;
948 if (!tree || !filter)
949 goto error;
951 n = isl_schedule_tree_n_children(tree);
952 for (i = 0; i < n; ++i) {
953 isl_schedule_tree *child;
955 child = isl_schedule_tree_get_child(tree, i);
956 child = isl_schedule_tree_insert_filter(child,
957 isl_union_set_copy(filter));
958 tree = isl_schedule_tree_replace_child(tree, i, child);
961 isl_union_set_free(filter);
962 return tree;
963 error:
964 isl_union_set_free(filter);
965 isl_schedule_tree_free(tree);
966 return NULL;
969 /* Create a new guard schedule tree with the given guard and
970 * with "tree" as single child.
972 __isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
973 __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
975 isl_schedule_tree *res;
977 res = isl_schedule_tree_from_guard(guard);
978 return isl_schedule_tree_replace_child(res, 0, tree);
981 /* Create a new mark schedule tree with the given mark identifier and
982 * single child.
984 __isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
985 __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
987 isl_schedule_tree *res;
989 res = isl_schedule_tree_from_mark(mark);
990 return isl_schedule_tree_replace_child(res, 0, tree);
993 /* Return the number of members in the band tree root.
995 unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
997 if (!tree)
998 return 0;
1000 if (tree->type != isl_schedule_node_band)
1001 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1002 "not a band node", return 0);
1004 return isl_schedule_band_n_member(tree->band);
1007 /* Is the band member at position "pos" of the band tree root
1008 * marked coincident?
1010 isl_bool isl_schedule_tree_band_member_get_coincident(
1011 __isl_keep isl_schedule_tree *tree, int pos)
1013 if (!tree)
1014 return isl_bool_error;
1016 if (tree->type != isl_schedule_node_band)
1017 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1018 "not a band node", return isl_bool_error);
1020 return isl_schedule_band_member_get_coincident(tree->band, pos);
1023 /* Mark the given band member as being coincident or not
1024 * according to "coincident".
1026 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
1027 __isl_take isl_schedule_tree *tree, int pos, int coincident)
1029 if (!tree)
1030 return NULL;
1031 if (tree->type != isl_schedule_node_band)
1032 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1033 "not a band node", return isl_schedule_tree_free(tree));
1034 if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
1035 coincident)
1036 return tree;
1037 tree = isl_schedule_tree_cow(tree);
1038 if (!tree)
1039 return NULL;
1041 tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
1042 coincident);
1043 if (!tree->band)
1044 return isl_schedule_tree_free(tree);
1045 return tree;
1048 /* Is the band tree root marked permutable?
1050 isl_bool isl_schedule_tree_band_get_permutable(
1051 __isl_keep isl_schedule_tree *tree)
1053 if (!tree)
1054 return isl_bool_error;
1056 if (tree->type != isl_schedule_node_band)
1057 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1058 "not a band node", return isl_bool_error);
1060 return isl_schedule_band_get_permutable(tree->band);
1063 /* Mark the band tree root permutable or not according to "permutable"?
1065 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
1066 __isl_take isl_schedule_tree *tree, int permutable)
1068 if (!tree)
1069 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));
1073 if (isl_schedule_tree_band_get_permutable(tree) == permutable)
1074 return tree;
1075 tree = isl_schedule_tree_cow(tree);
1076 if (!tree)
1077 return NULL;
1079 tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
1080 if (!tree->band)
1081 return isl_schedule_tree_free(tree);
1082 return tree;
1085 /* Return the schedule space of the band tree root.
1087 __isl_give isl_space *isl_schedule_tree_band_get_space(
1088 __isl_keep isl_schedule_tree *tree)
1090 if (!tree)
1091 return NULL;
1093 if (tree->type != isl_schedule_node_band)
1094 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1095 "not a band node", return NULL);
1097 return isl_schedule_band_get_space(tree->band);
1100 /* Intersect the domain of the band schedule of the band tree root
1101 * with "domain".
1103 __isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
1104 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1106 if (!tree || !domain)
1107 goto error;
1109 if (tree->type != isl_schedule_node_band)
1110 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1111 "not a band node", goto error);
1113 tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
1114 if (!tree->band)
1115 return isl_schedule_tree_free(tree);
1117 return tree;
1118 error:
1119 isl_schedule_tree_free(tree);
1120 isl_union_set_free(domain);
1121 return NULL;
1124 /* Return the schedule of the band tree root in isolation.
1126 __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
1127 __isl_keep isl_schedule_tree *tree)
1129 if (!tree)
1130 return NULL;
1132 if (tree->type != isl_schedule_node_band)
1133 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1134 "not a band node", return NULL);
1136 return isl_schedule_band_get_partial_schedule(tree->band);
1139 /* Replace the schedule of the band tree root by "schedule".
1141 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
1142 __isl_take isl_schedule_tree *tree,
1143 __isl_take isl_multi_union_pw_aff *schedule)
1145 tree = isl_schedule_tree_cow(tree);
1146 if (!tree || !schedule)
1147 goto error;
1149 if (tree->type != isl_schedule_node_band)
1150 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1151 "not a band node", return NULL);
1152 tree->band = isl_schedule_band_set_partial_schedule(tree->band,
1153 schedule);
1155 return tree;
1156 error:
1157 isl_schedule_tree_free(tree);
1158 isl_multi_union_pw_aff_free(schedule);
1159 return NULL;
1162 /* Return the loop AST generation type for the band member
1163 * of the band tree root at position "pos".
1165 enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
1166 __isl_keep isl_schedule_tree *tree, int pos)
1168 if (!tree)
1169 return isl_ast_loop_error;
1171 if (tree->type != isl_schedule_node_band)
1172 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1173 "not a band node", return isl_ast_loop_error);
1175 return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
1178 /* Set the loop AST generation type for the band member of the band tree root
1179 * at position "pos" to "type".
1181 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
1182 __isl_take isl_schedule_tree *tree, int pos,
1183 enum isl_ast_loop_type type)
1185 tree = isl_schedule_tree_cow(tree);
1186 if (!tree)
1187 return NULL;
1189 if (tree->type != isl_schedule_node_band)
1190 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1191 "not a band node", return isl_schedule_tree_free(tree));
1193 tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
1194 pos, type);
1195 if (!tree->band)
1196 return isl_schedule_tree_free(tree);
1198 return tree;
1201 /* Return the loop AST generation type for the band member
1202 * of the band tree root at position "pos" for the isolated part.
1204 enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
1205 __isl_keep isl_schedule_tree *tree, int pos)
1207 if (!tree)
1208 return isl_ast_loop_error;
1210 if (tree->type != isl_schedule_node_band)
1211 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1212 "not a band node", return isl_ast_loop_error);
1214 return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
1215 pos);
1218 /* Set the loop AST generation type for the band member of the band tree root
1219 * at position "pos" for the isolated part to "type".
1221 __isl_give isl_schedule_tree *
1222 isl_schedule_tree_band_member_set_isolate_ast_loop_type(
1223 __isl_take isl_schedule_tree *tree, int pos,
1224 enum isl_ast_loop_type type)
1226 tree = isl_schedule_tree_cow(tree);
1227 if (!tree)
1228 return NULL;
1230 if (tree->type != isl_schedule_node_band)
1231 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1232 "not a band node", return isl_schedule_tree_free(tree));
1234 tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
1235 tree->band, pos, type);
1236 if (!tree->band)
1237 return isl_schedule_tree_free(tree);
1239 return tree;
1242 /* Return the AST build options associated to the band tree root.
1244 __isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
1245 __isl_keep isl_schedule_tree *tree)
1247 if (!tree)
1248 return NULL;
1250 if (tree->type != isl_schedule_node_band)
1251 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1252 "not a band node", return NULL);
1254 return isl_schedule_band_get_ast_build_options(tree->band);
1257 /* Replace the AST build options associated to band tree root by "options".
1258 * Updated the anchored field if the anchoredness of the root node itself
1259 * changes.
1261 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
1262 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
1264 int was_anchored;
1266 tree = isl_schedule_tree_cow(tree);
1267 if (!tree || !options)
1268 goto error;
1270 if (tree->type != isl_schedule_node_band)
1271 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1272 "not a band node", goto error);
1274 was_anchored = isl_schedule_tree_is_anchored(tree);
1275 tree->band = isl_schedule_band_set_ast_build_options(tree->band,
1276 options);
1277 if (!tree->band)
1278 return isl_schedule_tree_free(tree);
1279 if (isl_schedule_tree_is_anchored(tree) != was_anchored)
1280 tree = isl_schedule_tree_update_anchored(tree);
1282 return tree;
1283 error:
1284 isl_schedule_tree_free(tree);
1285 isl_union_set_free(options);
1286 return NULL;
1289 /* Return the context of the context tree root.
1291 __isl_give isl_set *isl_schedule_tree_context_get_context(
1292 __isl_keep isl_schedule_tree *tree)
1294 if (!tree)
1295 return NULL;
1297 if (tree->type != isl_schedule_node_context)
1298 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1299 "not a context node", return NULL);
1301 return isl_set_copy(tree->context);
1304 /* Return the domain of the domain tree root.
1306 __isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
1307 __isl_keep isl_schedule_tree *tree)
1309 if (!tree)
1310 return NULL;
1312 if (tree->type != isl_schedule_node_domain)
1313 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1314 "not a domain node", return NULL);
1316 return isl_union_set_copy(tree->domain);
1319 /* Replace the domain of domain tree root "tree" by "domain".
1321 __isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
1322 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1324 tree = isl_schedule_tree_cow(tree);
1325 if (!tree || !domain)
1326 goto error;
1328 if (tree->type != isl_schedule_node_domain)
1329 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1330 "not a domain node", goto error);
1332 isl_union_set_free(tree->domain);
1333 tree->domain = domain;
1335 return tree;
1336 error:
1337 isl_schedule_tree_free(tree);
1338 isl_union_set_free(domain);
1339 return NULL;
1342 /* Return the contraction of the expansion tree root.
1344 __isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
1345 __isl_keep isl_schedule_tree *tree)
1347 if (!tree)
1348 return NULL;
1350 if (tree->type != isl_schedule_node_expansion)
1351 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1352 "not an expansion node", return NULL);
1354 return isl_union_pw_multi_aff_copy(tree->contraction);
1357 /* Return the expansion of the expansion tree root.
1359 __isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
1360 __isl_keep isl_schedule_tree *tree)
1362 if (!tree)
1363 return NULL;
1365 if (tree->type != isl_schedule_node_expansion)
1366 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1367 "not an expansion node", return NULL);
1369 return isl_union_map_copy(tree->expansion);
1372 /* Replace the contraction and the expansion of the expansion tree root "tree"
1373 * by "contraction" and "expansion".
1375 __isl_give isl_schedule_tree *
1376 isl_schedule_tree_expansion_set_contraction_and_expansion(
1377 __isl_take isl_schedule_tree *tree,
1378 __isl_take isl_union_pw_multi_aff *contraction,
1379 __isl_take isl_union_map *expansion)
1381 tree = isl_schedule_tree_cow(tree);
1382 if (!tree || !contraction || !expansion)
1383 goto error;
1385 if (tree->type != isl_schedule_node_expansion)
1386 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1387 "not an expansion node", return NULL);
1389 isl_union_pw_multi_aff_free(tree->contraction);
1390 tree->contraction = contraction;
1391 isl_union_map_free(tree->expansion);
1392 tree->expansion = expansion;
1394 return tree;
1395 error:
1396 isl_schedule_tree_free(tree);
1397 isl_union_pw_multi_aff_free(contraction);
1398 isl_union_map_free(expansion);
1399 return NULL;
1402 /* Return the extension of the extension tree root.
1404 __isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
1405 __isl_take isl_schedule_tree *tree)
1407 if (!tree)
1408 return NULL;
1410 if (tree->type != isl_schedule_node_extension)
1411 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1412 "not an extension node", return NULL);
1414 return isl_union_map_copy(tree->extension);
1417 /* Replace the extension of extension tree root "tree" by "extension".
1419 __isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
1420 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
1422 tree = isl_schedule_tree_cow(tree);
1423 if (!tree || !extension)
1424 goto error;
1426 if (tree->type != isl_schedule_node_extension)
1427 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1428 "not an extension node", return NULL);
1429 isl_union_map_free(tree->extension);
1430 tree->extension = extension;
1432 return tree;
1433 error:
1434 isl_schedule_tree_free(tree);
1435 isl_union_map_free(extension);
1436 return NULL;
1439 /* Return the filter of the filter tree root.
1441 __isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
1442 __isl_keep isl_schedule_tree *tree)
1444 if (!tree)
1445 return NULL;
1447 if (tree->type != isl_schedule_node_filter)
1448 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1449 "not a filter node", return NULL);
1451 return isl_union_set_copy(tree->filter);
1454 /* Replace the filter of the filter tree root by "filter".
1456 __isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
1457 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
1459 tree = isl_schedule_tree_cow(tree);
1460 if (!tree || !filter)
1461 goto error;
1463 if (tree->type != isl_schedule_node_filter)
1464 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1465 "not a filter node", return NULL);
1467 isl_union_set_free(tree->filter);
1468 tree->filter = filter;
1470 return tree;
1471 error:
1472 isl_schedule_tree_free(tree);
1473 isl_union_set_free(filter);
1474 return NULL;
1477 /* Return the guard of the guard tree root.
1479 __isl_give isl_set *isl_schedule_tree_guard_get_guard(
1480 __isl_take isl_schedule_tree *tree)
1482 if (!tree)
1483 return NULL;
1485 if (tree->type != isl_schedule_node_guard)
1486 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1487 "not a guard node", return NULL);
1489 return isl_set_copy(tree->guard);
1492 /* Return the mark identifier of the mark tree root "tree".
1494 __isl_give isl_id *isl_schedule_tree_mark_get_id(
1495 __isl_keep isl_schedule_tree *tree)
1497 if (!tree)
1498 return NULL;
1500 if (tree->type != isl_schedule_node_mark)
1501 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1502 "not a mark node", return NULL);
1504 return isl_id_copy(tree->mark);
1507 /* Set dim to the range dimension of "map" and abort the search.
1509 static isl_stat set_range_dim(__isl_take isl_map *map, void *user)
1511 int *dim = user;
1513 *dim = isl_map_dim(map, isl_dim_out);
1514 isl_map_free(map);
1516 return isl_stat_error;
1519 /* Return the dimension of the range of "umap".
1520 * "umap" is assumed not to be empty and
1521 * all maps inside "umap" are assumed to have the same range.
1523 * We extract the range dimension from the first map in "umap".
1525 static int range_dim(__isl_keep isl_union_map *umap)
1527 int dim = -1;
1529 if (!umap)
1530 return -1;
1531 if (isl_union_map_n_map(umap) == 0)
1532 isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
1533 "unexpected empty input", return -1);
1535 isl_union_map_foreach_map(umap, &set_range_dim, &dim);
1537 return dim;
1540 /* Append an "extra" number of zeros to the range of "umap" and
1541 * return the result.
1543 static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
1544 int extra)
1546 isl_union_set *dom;
1547 isl_space *space;
1548 isl_multi_val *mv;
1549 isl_union_pw_multi_aff *suffix;
1550 isl_union_map *universe;
1551 isl_union_map *suffix_umap;
1553 universe = isl_union_map_universe(isl_union_map_copy(umap));
1554 dom = isl_union_map_domain(universe);
1555 space = isl_union_set_get_space(dom);
1556 space = isl_space_set_from_params(space);
1557 space = isl_space_add_dims(space, isl_dim_set, extra);
1558 mv = isl_multi_val_zero(space);
1560 suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
1561 suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
1562 umap = isl_union_map_flat_range_product(umap, suffix_umap);
1564 return umap;
1567 /* Should we skip the root of "tree" while looking for the first
1568 * descendant with schedule information?
1569 * That is, is it impossible to derive any information about
1570 * the iteration domain from this node?
1572 * We do not want to skip leaf or error nodes because there is
1573 * no point in looking any deeper from these nodes.
1574 * We can only extract partial iteration domain information
1575 * from an extension node, but extension nodes are not supported
1576 * by the caller and it will error out on them.
1578 static int domain_less(__isl_keep isl_schedule_tree *tree)
1580 enum isl_schedule_node_type type;
1582 type = isl_schedule_tree_get_type(tree);
1583 switch (type) {
1584 case isl_schedule_node_band:
1585 return isl_schedule_tree_band_n_member(tree) == 0;
1586 case isl_schedule_node_context:
1587 case isl_schedule_node_guard:
1588 case isl_schedule_node_mark:
1589 return 1;
1590 case isl_schedule_node_leaf:
1591 case isl_schedule_node_error:
1592 case isl_schedule_node_domain:
1593 case isl_schedule_node_expansion:
1594 case isl_schedule_node_extension:
1595 case isl_schedule_node_filter:
1596 case isl_schedule_node_set:
1597 case isl_schedule_node_sequence:
1598 return 0;
1602 /* Move down to the first descendant of "tree" that contains any schedule
1603 * information or return "leaf" if there is no such descendant.
1605 __isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
1606 __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
1608 while (domain_less(tree)) {
1609 if (!isl_schedule_tree_has_children(tree)) {
1610 isl_schedule_tree_free(tree);
1611 return isl_schedule_tree_copy(leaf);
1613 tree = isl_schedule_tree_child(tree, 0);
1616 return tree;
1619 static __isl_give isl_union_map *subtree_schedule_extend(
1620 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);
1622 /* Extend the schedule map "outer" with the subtree schedule
1623 * of the (single) child of "tree", if any.
1625 * If "tree" does not have any descendants (apart from those that
1626 * do not carry any schedule information), then we simply return "outer".
1627 * Otherwise, we extend the schedule map "outer" with the subtree schedule
1628 * of the single child.
1630 static __isl_give isl_union_map *subtree_schedule_extend_child(
1631 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1633 isl_schedule_tree *child;
1634 isl_union_map *res;
1636 if (!tree)
1637 return isl_union_map_free(outer);
1638 if (!isl_schedule_tree_has_children(tree))
1639 return outer;
1640 child = isl_schedule_tree_get_child(tree, 0);
1641 if (!child)
1642 return isl_union_map_free(outer);
1643 res = subtree_schedule_extend(child, outer);
1644 isl_schedule_tree_free(child);
1645 return res;
1648 /* Extract the parameter space from one of the children of "tree",
1649 * which are assumed to be filters.
1651 static __isl_give isl_space *extract_space_from_filter_child(
1652 __isl_keep isl_schedule_tree *tree)
1654 isl_space *space;
1655 isl_union_set *dom;
1656 isl_schedule_tree *child;
1658 child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
1659 dom = isl_schedule_tree_filter_get_filter(child);
1660 space = isl_union_set_get_space(dom);
1661 isl_union_set_free(dom);
1662 isl_schedule_tree_free(child);
1664 return space;
1667 /* Extend the schedule map "outer" with the subtree schedule
1668 * of a set or sequence node.
1670 * The schedule for the set or sequence node itself is composed of
1671 * pieces of the form
1673 * filter -> []
1675 * or
1677 * filter -> [index]
1679 * The first form is used if there is only a single child or
1680 * if the current node is a set node and the schedule_separate_components
1681 * option is not set.
1683 * Each of the pieces above is extended with the subtree schedule of
1684 * the child of the corresponding filter, if any, padded with zeros
1685 * to ensure that all pieces have the same range dimension.
1687 static __isl_give isl_union_map *subtree_schedule_extend_from_children(
1688 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1690 int i, n;
1691 int dim;
1692 int separate;
1693 isl_ctx *ctx;
1694 isl_val *v = NULL;
1695 isl_multi_val *mv;
1696 isl_space *space;
1697 isl_union_map *umap;
1699 if (!tree)
1700 return NULL;
1702 ctx = isl_schedule_tree_get_ctx(tree);
1703 if (!tree->children)
1704 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1705 "missing children", return NULL);
1706 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
1707 if (n == 0)
1708 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1709 "missing children", return NULL);
1711 separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
1712 isl_options_get_schedule_separate_components(ctx));
1714 space = extract_space_from_filter_child(tree);
1716 umap = isl_union_map_empty(isl_space_copy(space));
1717 space = isl_space_set_from_params(space);
1718 if (separate) {
1719 space = isl_space_add_dims(space, isl_dim_set, 1);
1720 v = isl_val_zero(ctx);
1722 mv = isl_multi_val_zero(space);
1724 dim = isl_multi_val_dim(mv, isl_dim_set);
1725 for (i = 0; i < n; ++i) {
1726 isl_union_pw_multi_aff *upma;
1727 isl_union_map *umap_i;
1728 isl_union_set *dom;
1729 isl_schedule_tree *child;
1730 int dim_i;
1731 int empty;
1733 child = isl_schedule_tree_list_get_schedule_tree(
1734 tree->children, i);
1735 dom = isl_schedule_tree_filter_get_filter(child);
1737 if (separate) {
1738 mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
1739 v = isl_val_add_ui(v, 1);
1741 upma = isl_union_pw_multi_aff_multi_val_on_domain(dom,
1742 isl_multi_val_copy(mv));
1743 umap_i = isl_union_map_from_union_pw_multi_aff(upma);
1744 umap_i = isl_union_map_flat_range_product(
1745 isl_union_map_copy(outer), umap_i);
1746 umap_i = subtree_schedule_extend_child(child, umap_i);
1747 isl_schedule_tree_free(child);
1749 empty = isl_union_map_is_empty(umap_i);
1750 if (empty < 0)
1751 umap_i = isl_union_map_free(umap_i);
1752 else if (empty) {
1753 isl_union_map_free(umap_i);
1754 continue;
1757 dim_i = range_dim(umap_i);
1758 if (dim_i < 0) {
1759 umap = isl_union_map_free(umap);
1760 } else if (dim < dim_i) {
1761 umap = append_range(umap, dim_i - dim);
1762 dim = dim_i;
1763 } else if (dim_i < dim) {
1764 umap_i = append_range(umap_i, dim - dim_i);
1766 umap = isl_union_map_union(umap, umap_i);
1769 isl_val_free(v);
1770 isl_multi_val_free(mv);
1771 isl_union_map_free(outer);
1773 return umap;
1776 /* Extend the schedule map "outer" with the subtree schedule of "tree".
1778 * If the root of the tree is a set or a sequence, then we extend
1779 * the schedule map in subtree_schedule_extend_from_children.
1780 * Otherwise, we extend the schedule map with the partial schedule
1781 * corresponding to the root of the tree and then continue with
1782 * the single child of this root.
1783 * In the special case of an expansion, the schedule map is "extended"
1784 * by applying the expansion to the domain of the schedule map.
1786 static __isl_give isl_union_map *subtree_schedule_extend(
1787 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1789 isl_multi_union_pw_aff *mupa;
1790 isl_union_map *umap;
1791 isl_union_set *domain;
1793 if (!tree)
1794 return NULL;
1796 switch (tree->type) {
1797 case isl_schedule_node_error:
1798 return isl_union_map_free(outer);
1799 case isl_schedule_node_extension:
1800 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1801 "cannot construct subtree schedule of tree "
1802 "with extension nodes",
1803 return isl_union_map_free(outer));
1804 case isl_schedule_node_context:
1805 case isl_schedule_node_guard:
1806 case isl_schedule_node_mark:
1807 return subtree_schedule_extend_child(tree, outer);
1808 case isl_schedule_node_band:
1809 if (isl_schedule_tree_band_n_member(tree) == 0)
1810 return subtree_schedule_extend_child(tree, outer);
1811 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1812 umap = isl_union_map_from_multi_union_pw_aff(mupa);
1813 outer = isl_union_map_flat_range_product(outer, umap);
1814 umap = subtree_schedule_extend_child(tree, outer);
1815 break;
1816 case isl_schedule_node_domain:
1817 domain = isl_schedule_tree_domain_get_domain(tree);
1818 umap = isl_union_map_from_domain(domain);
1819 outer = isl_union_map_flat_range_product(outer, umap);
1820 umap = subtree_schedule_extend_child(tree, outer);
1821 break;
1822 case isl_schedule_node_expansion:
1823 umap = isl_schedule_tree_expansion_get_expansion(tree);
1824 outer = isl_union_map_apply_domain(outer, umap);
1825 umap = subtree_schedule_extend_child(tree, outer);
1826 break;
1827 case isl_schedule_node_filter:
1828 domain = isl_schedule_tree_filter_get_filter(tree);
1829 umap = isl_union_map_from_domain(domain);
1830 outer = isl_union_map_flat_range_product(outer, umap);
1831 umap = subtree_schedule_extend_child(tree, outer);
1832 break;
1833 case isl_schedule_node_leaf:
1834 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1835 "leaf node should be handled by caller", return NULL);
1836 case isl_schedule_node_set:
1837 case isl_schedule_node_sequence:
1838 umap = subtree_schedule_extend_from_children(tree, outer);
1839 break;
1842 return umap;
1845 static __isl_give isl_union_set *initial_domain(
1846 __isl_keep isl_schedule_tree *tree);
1848 /* Extract a universe domain from the children of the tree root "tree",
1849 * which is a set or sequence, meaning that its children are filters.
1850 * In particular, return the union of the universes of the filters.
1852 static __isl_give isl_union_set *initial_domain_from_children(
1853 __isl_keep isl_schedule_tree *tree)
1855 int i, n;
1856 isl_space *space;
1857 isl_union_set *domain;
1859 if (!tree->children)
1860 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1861 "missing children", return NULL);
1862 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
1863 if (n == 0)
1864 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1865 "missing children", return NULL);
1867 space = extract_space_from_filter_child(tree);
1868 domain = isl_union_set_empty(space);
1870 for (i = 0; i < n; ++i) {
1871 isl_schedule_tree *child;
1872 isl_union_set *domain_i;
1874 child = isl_schedule_tree_get_child(tree, i);
1875 domain_i = initial_domain(child);
1876 domain = isl_union_set_union(domain, domain_i);
1877 isl_schedule_tree_free(child);
1880 return domain;
1883 /* Extract a universe domain from the tree root "tree".
1884 * The caller is responsible for making sure that this node
1885 * would not be skipped by isl_schedule_tree_first_schedule_descendant
1886 * and that it is not a leaf node.
1888 static __isl_give isl_union_set *initial_domain(
1889 __isl_keep isl_schedule_tree *tree)
1891 isl_multi_union_pw_aff *mupa;
1892 isl_union_set *domain;
1893 isl_union_map *exp;
1895 if (!tree)
1896 return NULL;
1898 switch (tree->type) {
1899 case isl_schedule_node_error:
1900 return NULL;
1901 case isl_schedule_node_context:
1902 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1903 "context node should be handled by caller",
1904 return NULL);
1905 case isl_schedule_node_guard:
1906 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1907 "guard node should be handled by caller",
1908 return NULL);
1909 case isl_schedule_node_mark:
1910 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1911 "mark node should be handled by caller",
1912 return NULL);
1913 case isl_schedule_node_extension:
1914 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1915 "cannot construct subtree schedule of tree "
1916 "with extension nodes", return NULL);
1917 case isl_schedule_node_band:
1918 if (isl_schedule_tree_band_n_member(tree) == 0)
1919 isl_die(isl_schedule_tree_get_ctx(tree),
1920 isl_error_internal,
1921 "0D band should be handled by caller",
1922 return NULL);
1923 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1924 domain = isl_multi_union_pw_aff_domain(mupa);
1925 domain = isl_union_set_universe(domain);
1926 break;
1927 case isl_schedule_node_domain:
1928 domain = isl_schedule_tree_domain_get_domain(tree);
1929 domain = isl_union_set_universe(domain);
1930 break;
1931 case isl_schedule_node_expansion:
1932 exp = isl_schedule_tree_expansion_get_expansion(tree);
1933 exp = isl_union_map_universe(exp);
1934 domain = isl_union_map_domain(exp);
1935 break;
1936 case isl_schedule_node_filter:
1937 domain = isl_schedule_tree_filter_get_filter(tree);
1938 domain = isl_union_set_universe(domain);
1939 break;
1940 case isl_schedule_node_leaf:
1941 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1942 "leaf node should be handled by caller", return NULL);
1943 case isl_schedule_node_set:
1944 case isl_schedule_node_sequence:
1945 domain = initial_domain_from_children(tree);
1946 break;
1949 return domain;
1952 /* Return the subtree schedule of a node that contains some schedule
1953 * information, i.e., a node that would not be skipped by
1954 * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
1956 * If the tree contains any expansions, then the returned subtree
1957 * schedule is formulated in terms of the expanded domains.
1958 * The tree is not allowed to contain any extension nodes.
1960 * We start with an initial zero-dimensional subtree schedule based
1961 * on the domain information in the root node and then extend it
1962 * based on the schedule information in the root node and its descendants.
1964 __isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
1965 __isl_keep isl_schedule_tree *tree)
1967 isl_union_set *domain;
1968 isl_union_map *umap;
1970 domain = initial_domain(tree);
1971 umap = isl_union_map_from_domain(domain);
1972 return subtree_schedule_extend(tree, umap);
1975 /* Multiply the partial schedule of the band root node of "tree"
1976 * with the factors in "mv".
1978 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
1979 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
1981 if (!tree || !mv)
1982 goto error;
1983 if (tree->type != isl_schedule_node_band)
1984 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1985 "not a band node", goto error);
1987 tree = isl_schedule_tree_cow(tree);
1988 if (!tree)
1989 goto error;
1991 tree->band = isl_schedule_band_scale(tree->band, mv);
1992 if (!tree->band)
1993 return isl_schedule_tree_free(tree);
1995 return tree;
1996 error:
1997 isl_schedule_tree_free(tree);
1998 isl_multi_val_free(mv);
1999 return NULL;
2002 /* Divide the partial schedule of the band root node of "tree"
2003 * by the factors in "mv".
2005 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
2006 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
2008 if (!tree || !mv)
2009 goto error;
2010 if (tree->type != isl_schedule_node_band)
2011 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2012 "not a band node", goto error);
2014 tree = isl_schedule_tree_cow(tree);
2015 if (!tree)
2016 goto error;
2018 tree->band = isl_schedule_band_scale_down(tree->band, mv);
2019 if (!tree->band)
2020 return isl_schedule_tree_free(tree);
2022 return tree;
2023 error:
2024 isl_schedule_tree_free(tree);
2025 isl_multi_val_free(mv);
2026 return NULL;
2029 /* Given two trees with sequence roots, replace the child at position
2030 * "pos" of "tree" with the children of "child".
2032 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
2033 __isl_take isl_schedule_tree *tree, int pos,
2034 __isl_take isl_schedule_tree *child)
2036 int n;
2037 isl_schedule_tree_list *list1, *list2;
2039 tree = isl_schedule_tree_cow(tree);
2040 if (!tree || !child)
2041 goto error;
2042 if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
2043 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2044 "not a sequence node", goto error);
2045 n = isl_schedule_tree_n_children(tree);
2046 if (pos < 0 || pos >= n)
2047 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2048 "position out of bounds", goto error);
2049 if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence)
2050 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2051 "not a sequence node", goto error);
2053 list1 = isl_schedule_tree_list_copy(tree->children);
2054 list1 = isl_schedule_tree_list_drop(list1, pos, n - pos);
2055 list2 = isl_schedule_tree_list_copy(tree->children);
2056 list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1);
2057 list1 = isl_schedule_tree_list_concat(list1,
2058 isl_schedule_tree_list_copy(child->children));
2059 list1 = isl_schedule_tree_list_concat(list1, list2);
2061 isl_schedule_tree_free(tree);
2062 isl_schedule_tree_free(child);
2063 return isl_schedule_tree_from_children(isl_schedule_node_sequence,
2064 list1);
2065 error:
2066 isl_schedule_tree_free(tree);
2067 isl_schedule_tree_free(child);
2068 return NULL;
2071 /* Tile the band root node of "tree" with tile sizes "sizes".
2073 * We duplicate the band node, change the schedule of one of them
2074 * to the tile schedule and the other to the point schedule and then
2075 * attach the point band as a child to the tile band.
2077 __isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
2078 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
2080 isl_schedule_tree *child = NULL;
2082 if (!tree || !sizes)
2083 goto error;
2084 if (tree->type != isl_schedule_node_band)
2085 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2086 "not a band node", goto error);
2088 child = isl_schedule_tree_copy(tree);
2089 tree = isl_schedule_tree_cow(tree);
2090 child = isl_schedule_tree_cow(child);
2091 if (!tree || !child)
2092 goto error;
2094 tree->band = isl_schedule_band_tile(tree->band,
2095 isl_multi_val_copy(sizes));
2096 if (!tree->band)
2097 goto error;
2098 child->band = isl_schedule_band_point(child->band, tree->band, sizes);
2099 if (!child->band)
2100 child = isl_schedule_tree_free(child);
2102 tree = isl_schedule_tree_replace_child(tree, 0, child);
2104 return tree;
2105 error:
2106 isl_schedule_tree_free(child);
2107 isl_schedule_tree_free(tree);
2108 isl_multi_val_free(sizes);
2109 return NULL;
2112 /* Split the band root node of "tree" into two nested band nodes,
2113 * one with the first "pos" dimensions and
2114 * one with the remaining dimensions.
2116 __isl_give isl_schedule_tree *isl_schedule_tree_band_split(
2117 __isl_take isl_schedule_tree *tree, int pos)
2119 int n;
2120 isl_schedule_tree *child;
2122 if (!tree)
2123 return NULL;
2124 if (tree->type != isl_schedule_node_band)
2125 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2126 "not a band node", return isl_schedule_tree_free(tree));
2128 n = isl_schedule_tree_band_n_member(tree);
2129 if (pos < 0 || pos > n)
2130 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2131 "position out of bounds",
2132 return isl_schedule_tree_free(tree));
2134 child = isl_schedule_tree_copy(tree);
2135 tree = isl_schedule_tree_cow(tree);
2136 child = isl_schedule_tree_cow(child);
2137 if (!tree || !child)
2138 goto error;
2140 child->band = isl_schedule_band_drop(child->band, 0, pos);
2141 tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
2142 if (!child->band || !tree->band)
2143 goto error;
2145 tree = isl_schedule_tree_replace_child(tree, 0, child);
2147 return tree;
2148 error:
2149 isl_schedule_tree_free(child);
2150 isl_schedule_tree_free(tree);
2151 return NULL;
2154 /* Attach "tree2" at each of the leaves of "tree1".
2156 * If "tree1" does not have any explicit children, then make "tree2"
2157 * its single child. Otherwise, attach "tree2" to the leaves of
2158 * each of the children of "tree1".
2160 __isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
2161 __isl_take isl_schedule_tree *tree1,
2162 __isl_take isl_schedule_tree *tree2)
2164 int i, n;
2166 if (!tree1 || !tree2)
2167 goto error;
2168 n = isl_schedule_tree_n_children(tree1);
2169 if (n == 0) {
2170 isl_schedule_tree_list *list;
2171 list = isl_schedule_tree_list_from_schedule_tree(tree2);
2172 tree1 = isl_schedule_tree_set_children(tree1, list);
2173 return tree1;
2175 for (i = 0; i < n; ++i) {
2176 isl_schedule_tree *child;
2178 child = isl_schedule_tree_get_child(tree1, i);
2179 child = isl_schedule_tree_append_to_leaves(child,
2180 isl_schedule_tree_copy(tree2));
2181 tree1 = isl_schedule_tree_replace_child(tree1, i, child);
2184 isl_schedule_tree_free(tree2);
2185 return tree1;
2186 error:
2187 isl_schedule_tree_free(tree1);
2188 isl_schedule_tree_free(tree2);
2189 return NULL;
2192 /* Reset the user pointer on all identifiers of parameters and tuples
2193 * in the root of "tree".
2195 __isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
2196 __isl_take isl_schedule_tree *tree)
2198 if (isl_schedule_tree_is_leaf(tree))
2199 return tree;
2201 tree = isl_schedule_tree_cow(tree);
2202 if (!tree)
2203 return NULL;
2205 switch (tree->type) {
2206 case isl_schedule_node_error:
2207 return isl_schedule_tree_free(tree);
2208 case isl_schedule_node_band:
2209 tree->band = isl_schedule_band_reset_user(tree->band);
2210 if (!tree->band)
2211 return isl_schedule_tree_free(tree);
2212 break;
2213 case isl_schedule_node_context:
2214 tree->context = isl_set_reset_user(tree->context);
2215 if (!tree->context)
2216 return isl_schedule_tree_free(tree);
2217 break;
2218 case isl_schedule_node_domain:
2219 tree->domain = isl_union_set_reset_user(tree->domain);
2220 if (!tree->domain)
2221 return isl_schedule_tree_free(tree);
2222 break;
2223 case isl_schedule_node_expansion:
2224 tree->contraction =
2225 isl_union_pw_multi_aff_reset_user(tree->contraction);
2226 tree->expansion = isl_union_map_reset_user(tree->expansion);
2227 if (!tree->contraction || !tree->expansion)
2228 return isl_schedule_tree_free(tree);
2229 break;
2230 case isl_schedule_node_extension:
2231 tree->extension = isl_union_map_reset_user(tree->extension);
2232 if (!tree->extension)
2233 return isl_schedule_tree_free(tree);
2234 break;
2235 case isl_schedule_node_filter:
2236 tree->filter = isl_union_set_reset_user(tree->filter);
2237 if (!tree->filter)
2238 return isl_schedule_tree_free(tree);
2239 break;
2240 case isl_schedule_node_guard:
2241 tree->guard = isl_set_reset_user(tree->guard);
2242 if (!tree->guard)
2243 return isl_schedule_tree_free(tree);
2244 break;
2245 case isl_schedule_node_leaf:
2246 case isl_schedule_node_mark:
2247 case isl_schedule_node_sequence:
2248 case isl_schedule_node_set:
2249 break;
2252 return tree;
2255 /* Align the parameters of the root of "tree" to those of "space".
2257 __isl_give isl_schedule_tree *isl_schedule_tree_align_params(
2258 __isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
2260 if (!space)
2261 goto error;
2263 if (isl_schedule_tree_is_leaf(tree)) {
2264 isl_space_free(space);
2265 return tree;
2268 tree = isl_schedule_tree_cow(tree);
2269 if (!tree)
2270 goto error;
2272 switch (tree->type) {
2273 case isl_schedule_node_error:
2274 goto error;
2275 case isl_schedule_node_band:
2276 tree->band = isl_schedule_band_align_params(tree->band, space);
2277 if (!tree->band)
2278 return isl_schedule_tree_free(tree);
2279 break;
2280 case isl_schedule_node_context:
2281 tree->context = isl_set_align_params(tree->context, space);
2282 if (!tree->context)
2283 return isl_schedule_tree_free(tree);
2284 break;
2285 case isl_schedule_node_domain:
2286 tree->domain = isl_union_set_align_params(tree->domain, space);
2287 if (!tree->domain)
2288 return isl_schedule_tree_free(tree);
2289 break;
2290 case isl_schedule_node_expansion:
2291 tree->contraction =
2292 isl_union_pw_multi_aff_align_params(tree->contraction,
2293 isl_space_copy(space));
2294 tree->expansion = isl_union_map_align_params(tree->expansion,
2295 space);
2296 if (!tree->contraction || !tree->expansion)
2297 return isl_schedule_tree_free(tree);
2298 break;
2299 case isl_schedule_node_extension:
2300 tree->extension = isl_union_map_align_params(tree->extension,
2301 space);
2302 if (!tree->extension)
2303 return isl_schedule_tree_free(tree);
2304 break;
2305 case isl_schedule_node_filter:
2306 tree->filter = isl_union_set_align_params(tree->filter, space);
2307 if (!tree->filter)
2308 return isl_schedule_tree_free(tree);
2309 break;
2310 case isl_schedule_node_guard:
2311 tree->guard = isl_set_align_params(tree->guard, space);
2312 if (!tree->guard)
2313 return isl_schedule_tree_free(tree);
2314 break;
2315 case isl_schedule_node_leaf:
2316 case isl_schedule_node_mark:
2317 case isl_schedule_node_sequence:
2318 case isl_schedule_node_set:
2319 isl_space_free(space);
2320 break;
2323 return tree;
2324 error:
2325 isl_space_free(space);
2326 isl_schedule_tree_free(tree);
2327 return NULL;
2330 /* Does "tree" involve the iteration domain?
2331 * That is, does it need to be modified
2332 * by isl_schedule_tree_pullback_union_pw_multi_aff?
2334 static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
2336 if (!tree)
2337 return -1;
2339 switch (tree->type) {
2340 case isl_schedule_node_error:
2341 return -1;
2342 case isl_schedule_node_band:
2343 case isl_schedule_node_domain:
2344 case isl_schedule_node_expansion:
2345 case isl_schedule_node_extension:
2346 case isl_schedule_node_filter:
2347 return 1;
2348 case isl_schedule_node_context:
2349 case isl_schedule_node_leaf:
2350 case isl_schedule_node_guard:
2351 case isl_schedule_node_mark:
2352 case isl_schedule_node_sequence:
2353 case isl_schedule_node_set:
2354 return 0;
2358 /* Compute the pullback of the root node of "tree" by the function
2359 * represented by "upma".
2360 * In other words, plug in "upma" in the iteration domains of
2361 * the root node of "tree".
2362 * We currently do not handle expansion nodes.
2364 * We first check if the root node involves any iteration domains.
2365 * If so, we handle the specific cases.
2367 __isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
2368 __isl_take isl_schedule_tree *tree,
2369 __isl_take isl_union_pw_multi_aff *upma)
2371 int involves;
2373 if (!tree || !upma)
2374 goto error;
2376 involves = involves_iteration_domain(tree);
2377 if (involves < 0)
2378 goto error;
2379 if (!involves) {
2380 isl_union_pw_multi_aff_free(upma);
2381 return tree;
2384 tree = isl_schedule_tree_cow(tree);
2385 if (!tree)
2386 goto error;
2388 if (tree->type == isl_schedule_node_band) {
2389 tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
2390 tree->band, upma);
2391 if (!tree->band)
2392 return isl_schedule_tree_free(tree);
2393 } else if (tree->type == isl_schedule_node_domain) {
2394 tree->domain =
2395 isl_union_set_preimage_union_pw_multi_aff(tree->domain,
2396 upma);
2397 if (!tree->domain)
2398 return isl_schedule_tree_free(tree);
2399 } else if (tree->type == isl_schedule_node_expansion) {
2400 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
2401 "cannot pullback expansion node", goto error);
2402 } else if (tree->type == isl_schedule_node_extension) {
2403 tree->extension =
2404 isl_union_map_preimage_range_union_pw_multi_aff(
2405 tree->extension, upma);
2406 if (!tree->extension)
2407 return isl_schedule_tree_free(tree);
2408 } else if (tree->type == isl_schedule_node_filter) {
2409 tree->filter =
2410 isl_union_set_preimage_union_pw_multi_aff(tree->filter,
2411 upma);
2412 if (!tree->filter)
2413 return isl_schedule_tree_free(tree);
2416 return tree;
2417 error:
2418 isl_union_pw_multi_aff_free(upma);
2419 isl_schedule_tree_free(tree);
2420 return NULL;
2423 /* Compute the gist of the band tree root with respect to "context".
2425 __isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
2426 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
2428 if (!tree)
2429 return NULL;
2430 if (tree->type != isl_schedule_node_band)
2431 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2432 "not a band node", goto error);
2433 tree = isl_schedule_tree_cow(tree);
2434 if (!tree)
2435 goto error;
2437 tree->band = isl_schedule_band_gist(tree->band, context);
2438 if (!tree->band)
2439 return isl_schedule_tree_free(tree);
2440 return tree;
2441 error:
2442 isl_union_set_free(context);
2443 isl_schedule_tree_free(tree);
2444 return NULL;
2447 /* Are any members in "band" marked coincident?
2449 static int any_coincident(__isl_keep isl_schedule_band *band)
2451 int i, n;
2453 n = isl_schedule_band_n_member(band);
2454 for (i = 0; i < n; ++i)
2455 if (isl_schedule_band_member_get_coincident(band, i))
2456 return 1;
2458 return 0;
2461 /* Print the band node "band" to "p".
2463 * The permutable and coincident properties are only printed if they
2464 * are different from the defaults.
2465 * The coincident property is always printed in YAML flow style.
2467 static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
2468 __isl_keep isl_schedule_band *band)
2470 isl_union_set *options;
2471 int empty;
2473 p = isl_printer_print_str(p, "schedule");
2474 p = isl_printer_yaml_next(p);
2475 p = isl_printer_print_str(p, "\"");
2476 p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
2477 p = isl_printer_print_str(p, "\"");
2478 if (isl_schedule_band_get_permutable(band)) {
2479 p = isl_printer_yaml_next(p);
2480 p = isl_printer_print_str(p, "permutable");
2481 p = isl_printer_yaml_next(p);
2482 p = isl_printer_print_int(p, 1);
2484 if (any_coincident(band)) {
2485 int i, n;
2486 int style;
2488 p = isl_printer_yaml_next(p);
2489 p = isl_printer_print_str(p, "coincident");
2490 p = isl_printer_yaml_next(p);
2491 style = isl_printer_get_yaml_style(p);
2492 p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
2493 p = isl_printer_yaml_start_sequence(p);
2494 n = isl_schedule_band_n_member(band);
2495 for (i = 0; i < n; ++i) {
2496 p = isl_printer_print_int(p,
2497 isl_schedule_band_member_get_coincident(band, i));
2498 p = isl_printer_yaml_next(p);
2500 p = isl_printer_yaml_end_sequence(p);
2501 p = isl_printer_set_yaml_style(p, style);
2503 options = isl_schedule_band_get_ast_build_options(band);
2504 empty = isl_union_set_is_empty(options);
2505 if (empty < 0)
2506 p = isl_printer_free(p);
2507 if (!empty) {
2508 p = isl_printer_yaml_next(p);
2509 p = isl_printer_print_str(p, "options");
2510 p = isl_printer_yaml_next(p);
2511 p = isl_printer_print_str(p, "\"");
2512 p = isl_printer_print_union_set(p, options);
2513 p = isl_printer_print_str(p, "\"");
2515 isl_union_set_free(options);
2517 return p;
2520 /* Print "tree" to "p".
2522 * If "n_ancestor" is non-negative, then "child_pos" contains the child
2523 * positions of a descendant of the current node that should be marked
2524 * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor"
2525 * is zero, then the current node should be marked.
2526 * The marking is only printed in YAML block format.
2528 * Implicit leaf nodes are not printed, except if they correspond
2529 * to the node that should be marked.
2531 __isl_give isl_printer *isl_printer_print_schedule_tree_mark(
2532 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
2533 int n_ancestor, int *child_pos)
2535 int i, n;
2536 int sequence = 0;
2537 int block;
2539 block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;
2541 p = isl_printer_yaml_start_mapping(p);
2542 if (n_ancestor == 0 && block) {
2543 p = isl_printer_print_str(p, "# YOU ARE HERE");
2544 p = isl_printer_end_line(p);
2545 p = isl_printer_start_line(p);
2547 switch (tree->type) {
2548 case isl_schedule_node_error:
2549 p = isl_printer_print_str(p, "ERROR");
2550 break;
2551 case isl_schedule_node_leaf:
2552 p = isl_printer_print_str(p, "leaf");
2553 break;
2554 case isl_schedule_node_sequence:
2555 p = isl_printer_print_str(p, "sequence");
2556 sequence = 1;
2557 break;
2558 case isl_schedule_node_set:
2559 p = isl_printer_print_str(p, "set");
2560 sequence = 1;
2561 break;
2562 case isl_schedule_node_context:
2563 p = isl_printer_print_str(p, "context");
2564 p = isl_printer_yaml_next(p);
2565 p = isl_printer_print_str(p, "\"");
2566 p = isl_printer_print_set(p, tree->context);
2567 p = isl_printer_print_str(p, "\"");
2568 break;
2569 case isl_schedule_node_domain:
2570 p = isl_printer_print_str(p, "domain");
2571 p = isl_printer_yaml_next(p);
2572 p = isl_printer_print_str(p, "\"");
2573 p = isl_printer_print_union_set(p, tree->domain);
2574 p = isl_printer_print_str(p, "\"");
2575 break;
2576 case isl_schedule_node_expansion:
2577 p = isl_printer_print_str(p, "contraction");
2578 p = isl_printer_yaml_next(p);
2579 p = isl_printer_print_str(p, "\"");
2580 p = isl_printer_print_union_pw_multi_aff(p, tree->contraction);
2581 p = isl_printer_print_str(p, "\"");
2582 p = isl_printer_yaml_next(p);
2583 p = isl_printer_print_str(p, "expansion");
2584 p = isl_printer_yaml_next(p);
2585 p = isl_printer_print_str(p, "\"");
2586 p = isl_printer_print_union_map(p, tree->expansion);
2587 p = isl_printer_print_str(p, "\"");
2588 break;
2589 case isl_schedule_node_extension:
2590 p = isl_printer_print_str(p, "extension");
2591 p = isl_printer_yaml_next(p);
2592 p = isl_printer_print_str(p, "\"");
2593 p = isl_printer_print_union_map(p, tree->extension);
2594 p = isl_printer_print_str(p, "\"");
2595 break;
2596 case isl_schedule_node_filter:
2597 p = isl_printer_print_str(p, "filter");
2598 p = isl_printer_yaml_next(p);
2599 p = isl_printer_print_str(p, "\"");
2600 p = isl_printer_print_union_set(p, tree->filter);
2601 p = isl_printer_print_str(p, "\"");
2602 break;
2603 case isl_schedule_node_guard:
2604 p = isl_printer_print_str(p, "guard");
2605 p = isl_printer_yaml_next(p);
2606 p = isl_printer_print_str(p, "\"");
2607 p = isl_printer_print_set(p, tree->guard);
2608 p = isl_printer_print_str(p, "\"");
2609 break;
2610 case isl_schedule_node_mark:
2611 p = isl_printer_print_str(p, "mark");
2612 p = isl_printer_yaml_next(p);
2613 p = isl_printer_print_str(p, "\"");
2614 p = isl_printer_print_str(p, isl_id_get_name(tree->mark));
2615 p = isl_printer_print_str(p, "\"");
2616 break;
2617 case isl_schedule_node_band:
2618 p = print_tree_band(p, tree->band);
2619 break;
2621 p = isl_printer_yaml_next(p);
2623 if (!tree->children) {
2624 if (n_ancestor > 0 && block) {
2625 isl_schedule_tree *leaf;
2627 p = isl_printer_print_str(p, "child");
2628 p = isl_printer_yaml_next(p);
2629 leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
2630 p = isl_printer_print_schedule_tree_mark(p,
2631 leaf, 0, NULL);
2632 isl_schedule_tree_free(leaf);
2633 p = isl_printer_yaml_next(p);
2635 return isl_printer_yaml_end_mapping(p);
2638 if (sequence) {
2639 p = isl_printer_yaml_start_sequence(p);
2640 } else {
2641 p = isl_printer_print_str(p, "child");
2642 p = isl_printer_yaml_next(p);
2645 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
2646 for (i = 0; i < n; ++i) {
2647 isl_schedule_tree *t;
2649 t = isl_schedule_tree_get_child(tree, i);
2650 if (n_ancestor > 0 && child_pos[0] == i)
2651 p = isl_printer_print_schedule_tree_mark(p, t,
2652 n_ancestor - 1, child_pos + 1);
2653 else
2654 p = isl_printer_print_schedule_tree_mark(p, t,
2655 -1, NULL);
2656 isl_schedule_tree_free(t);
2658 p = isl_printer_yaml_next(p);
2661 if (sequence)
2662 p = isl_printer_yaml_end_sequence(p);
2663 p = isl_printer_yaml_end_mapping(p);
2665 return p;
2668 /* Print "tree" to "p".
2670 __isl_give isl_printer *isl_printer_print_schedule_tree(
2671 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
2673 return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
2676 void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
2678 isl_ctx *ctx;
2679 isl_printer *printer;
2681 if (!tree)
2682 return;
2684 ctx = isl_schedule_tree_get_ctx(tree);
2685 printer = isl_printer_to_file(ctx, stderr);
2686 printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
2687 printer = isl_printer_print_schedule_tree(printer, tree);
2689 isl_printer_free(printer);