Merge branch 'maint'
[isl.git] / isl_schedule_tree.c
blobf832b8701ff88324273a1d47206988108b654031
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 __isl_give isl_schedule_tree *isl_schedule_tree_cow(
145 __isl_take isl_schedule_tree *tree)
147 if (!tree)
148 return NULL;
150 if (tree->ref == 1)
151 return tree;
152 tree->ref--;
153 return isl_schedule_tree_dup(tree);
156 /* Return a new reference to "tree".
158 __isl_give isl_schedule_tree *isl_schedule_tree_copy(
159 __isl_keep isl_schedule_tree *tree)
161 if (!tree)
162 return NULL;
164 tree->ref++;
165 return tree;
168 /* Free "tree" and return NULL.
170 __isl_null isl_schedule_tree *isl_schedule_tree_free(
171 __isl_take isl_schedule_tree *tree)
173 if (!tree)
174 return NULL;
175 if (--tree->ref > 0)
176 return NULL;
178 switch (tree->type) {
179 case isl_schedule_node_band:
180 isl_schedule_band_free(tree->band);
181 break;
182 case isl_schedule_node_context:
183 isl_set_free(tree->context);
184 break;
185 case isl_schedule_node_domain:
186 isl_union_set_free(tree->domain);
187 break;
188 case isl_schedule_node_expansion:
189 isl_union_pw_multi_aff_free(tree->contraction);
190 isl_union_map_free(tree->expansion);
191 break;
192 case isl_schedule_node_extension:
193 isl_union_map_free(tree->extension);
194 break;
195 case isl_schedule_node_filter:
196 isl_union_set_free(tree->filter);
197 break;
198 case isl_schedule_node_guard:
199 isl_set_free(tree->guard);
200 break;
201 case isl_schedule_node_mark:
202 isl_id_free(tree->mark);
203 break;
204 case isl_schedule_node_sequence:
205 case isl_schedule_node_set:
206 case isl_schedule_node_error:
207 case isl_schedule_node_leaf:
208 break;
210 isl_schedule_tree_list_free(tree->children);
211 isl_ctx_deref(tree->ctx);
212 free(tree);
214 return NULL;
217 /* Create and return a new leaf schedule tree.
219 __isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx)
221 return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf);
224 /* Create a new band schedule tree referring to "band"
225 * with no children.
227 __isl_give isl_schedule_tree *isl_schedule_tree_from_band(
228 __isl_take isl_schedule_band *band)
230 isl_ctx *ctx;
231 isl_schedule_tree *tree;
233 if (!band)
234 return NULL;
236 ctx = isl_schedule_band_get_ctx(band);
237 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band);
238 if (!tree)
239 goto error;
241 tree->band = band;
242 tree->anchored = isl_schedule_band_is_anchored(band);
244 return tree;
245 error:
246 isl_schedule_band_free(band);
247 return NULL;
250 /* Create a new context schedule tree with the given context and no children.
251 * Since the context references the outer schedule dimension,
252 * the tree is anchored.
254 __isl_give isl_schedule_tree *isl_schedule_tree_from_context(
255 __isl_take isl_set *context)
257 isl_ctx *ctx;
258 isl_schedule_tree *tree;
260 if (!context)
261 return NULL;
263 ctx = isl_set_get_ctx(context);
264 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context);
265 if (!tree)
266 goto error;
268 tree->context = context;
269 tree->anchored = 1;
271 return tree;
272 error:
273 isl_set_free(context);
274 return NULL;
277 /* Create a new domain schedule tree with the given domain and no children.
279 __isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
280 __isl_take isl_union_set *domain)
282 isl_ctx *ctx;
283 isl_schedule_tree *tree;
285 if (!domain)
286 return NULL;
288 ctx = isl_union_set_get_ctx(domain);
289 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain);
290 if (!tree)
291 goto error;
293 tree->domain = domain;
295 return tree;
296 error:
297 isl_union_set_free(domain);
298 return NULL;
301 /* Create a new expansion schedule tree with the given contraction and
302 * expansion and no children.
304 __isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
305 __isl_take isl_union_pw_multi_aff *contraction,
306 __isl_take isl_union_map *expansion)
308 isl_ctx *ctx;
309 isl_schedule_tree *tree;
311 if (!contraction || !expansion)
312 goto error;
314 ctx = isl_union_map_get_ctx(expansion);
315 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion);
316 if (!tree)
317 goto error;
319 tree->contraction = contraction;
320 tree->expansion = expansion;
322 return tree;
323 error:
324 isl_union_pw_multi_aff_free(contraction);
325 isl_union_map_free(expansion);
326 return NULL;
329 /* Create a new extension schedule tree with the given extension and
330 * no children.
331 * Since the domain of the extension refers to the outer schedule dimension,
332 * the tree is anchored.
334 __isl_give isl_schedule_tree *isl_schedule_tree_from_extension(
335 __isl_take isl_union_map *extension)
337 isl_ctx *ctx;
338 isl_schedule_tree *tree;
340 if (!extension)
341 return NULL;
343 ctx = isl_union_map_get_ctx(extension);
344 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension);
345 if (!tree)
346 goto error;
348 tree->extension = extension;
349 tree->anchored = 1;
351 return tree;
352 error:
353 isl_union_map_free(extension);
354 return NULL;
357 /* Create a new filter schedule tree with the given filter and no children.
359 __isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
360 __isl_take isl_union_set *filter)
362 isl_ctx *ctx;
363 isl_schedule_tree *tree;
365 if (!filter)
366 return NULL;
368 ctx = isl_union_set_get_ctx(filter);
369 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter);
370 if (!tree)
371 goto error;
373 tree->filter = filter;
375 return tree;
376 error:
377 isl_union_set_free(filter);
378 return NULL;
381 /* Create a new guard schedule tree with the given guard and no children.
382 * Since the guard references the outer schedule dimension,
383 * the tree is anchored.
385 __isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
386 __isl_take isl_set *guard)
388 isl_ctx *ctx;
389 isl_schedule_tree *tree;
391 if (!guard)
392 return NULL;
394 ctx = isl_set_get_ctx(guard);
395 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard);
396 if (!tree)
397 goto error;
399 tree->guard = guard;
400 tree->anchored = 1;
402 return tree;
403 error:
404 isl_set_free(guard);
405 return NULL;
408 /* Create a new mark schedule tree with the given mark identifier and
409 * no children.
411 __isl_give isl_schedule_tree *isl_schedule_tree_from_mark(
412 __isl_take isl_id *mark)
414 isl_ctx *ctx;
415 isl_schedule_tree *tree;
417 if (!mark)
418 return NULL;
420 ctx = isl_id_get_ctx(mark);
421 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark);
422 if (!tree)
423 goto error;
425 tree->mark = mark;
427 return tree;
428 error:
429 isl_id_free(mark);
430 return NULL;
433 /* Does "tree" have any node that depends on its position
434 * in the complete schedule tree?
436 isl_bool isl_schedule_tree_is_subtree_anchored(
437 __isl_keep isl_schedule_tree *tree)
439 return tree ? tree->anchored : isl_bool_error;
442 /* Does the root node of "tree" depend on its position in the complete
443 * schedule tree?
444 * Band nodes may be anchored depending on the associated AST build options.
445 * Context, extension and guard nodes are always anchored.
447 int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
449 if (!tree)
450 return -1;
452 switch (isl_schedule_tree_get_type(tree)) {
453 case isl_schedule_node_error:
454 return -1;
455 case isl_schedule_node_band:
456 return isl_schedule_band_is_anchored(tree->band);
457 case isl_schedule_node_context:
458 case isl_schedule_node_extension:
459 case isl_schedule_node_guard:
460 return 1;
461 case isl_schedule_node_domain:
462 case isl_schedule_node_expansion:
463 case isl_schedule_node_filter:
464 case isl_schedule_node_leaf:
465 case isl_schedule_node_mark:
466 case isl_schedule_node_sequence:
467 case isl_schedule_node_set:
468 return 0;
471 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
472 "unhandled case", return -1);
475 /* Update the anchored field of "tree" based on whether the root node
476 * itself in anchored and the anchored fields of the children.
478 * This function should be called whenever the children of a tree node
479 * are changed or the anchoredness of the tree root itself changes.
481 __isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
482 __isl_take isl_schedule_tree *tree)
484 int i, n;
485 int anchored;
487 if (!tree)
488 return NULL;
490 anchored = isl_schedule_tree_is_anchored(tree);
491 if (anchored < 0)
492 return isl_schedule_tree_free(tree);
494 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
495 for (i = 0; !anchored && i < n; ++i) {
496 isl_schedule_tree *child;
498 child = isl_schedule_tree_get_child(tree, i);
499 if (!child)
500 return isl_schedule_tree_free(tree);
501 anchored = child->anchored;
502 isl_schedule_tree_free(child);
505 if (anchored == tree->anchored)
506 return tree;
507 tree = isl_schedule_tree_cow(tree);
508 if (!tree)
509 return NULL;
510 tree->anchored = anchored;
511 return tree;
514 /* Create a new tree of the given type (isl_schedule_node_sequence or
515 * isl_schedule_node_set) with the given children.
517 __isl_give isl_schedule_tree *isl_schedule_tree_from_children(
518 enum isl_schedule_node_type type,
519 __isl_take isl_schedule_tree_list *list)
521 isl_ctx *ctx;
522 isl_schedule_tree *tree;
524 if (!list)
525 return NULL;
527 ctx = isl_schedule_tree_list_get_ctx(list);
528 tree = isl_schedule_tree_alloc(ctx, type);
529 if (!tree)
530 goto error;
532 tree->children = list;
533 tree = isl_schedule_tree_update_anchored(tree);
535 return tree;
536 error:
537 isl_schedule_tree_list_free(list);
538 return NULL;
541 /* Construct a tree with a root node of type "type" and as children
542 * "tree1" and "tree2".
543 * If the root of one (or both) of the input trees is itself of type "type",
544 * then the tree is replaced by its children.
546 __isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
547 enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
548 __isl_take isl_schedule_tree *tree2)
550 isl_ctx *ctx;
551 isl_schedule_tree_list *list;
553 if (!tree1 || !tree2)
554 goto error;
556 ctx = isl_schedule_tree_get_ctx(tree1);
557 if (isl_schedule_tree_get_type(tree1) == type) {
558 list = isl_schedule_tree_list_copy(tree1->children);
559 isl_schedule_tree_free(tree1);
560 } else {
561 list = isl_schedule_tree_list_alloc(ctx, 2);
562 list = isl_schedule_tree_list_add(list, tree1);
564 if (isl_schedule_tree_get_type(tree2) == type) {
565 isl_schedule_tree_list *children;
567 children = isl_schedule_tree_list_copy(tree2->children);
568 list = isl_schedule_tree_list_concat(list, children);
569 isl_schedule_tree_free(tree2);
570 } else {
571 list = isl_schedule_tree_list_add(list, tree2);
574 return isl_schedule_tree_from_children(type, list);
575 error:
576 isl_schedule_tree_free(tree1);
577 isl_schedule_tree_free(tree2);
578 return NULL;
581 /* Construct a tree with a sequence root node and as children
582 * "tree1" and "tree2".
583 * If the root of one (or both) of the input trees is itself a sequence,
584 * then the tree is replaced by its children.
586 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
587 __isl_take isl_schedule_tree *tree1,
588 __isl_take isl_schedule_tree *tree2)
590 return isl_schedule_tree_from_pair(isl_schedule_node_sequence,
591 tree1, tree2);
594 /* Return the isl_ctx to which "tree" belongs.
596 isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
598 return tree ? tree->ctx : NULL;
601 /* Return the type of the root of the tree or isl_schedule_node_error
602 * on error.
604 enum isl_schedule_node_type isl_schedule_tree_get_type(
605 __isl_keep isl_schedule_tree *tree)
607 return tree ? tree->type : isl_schedule_node_error;
610 /* Are "tree1" and "tree2" obviously equal to each other?
612 isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
613 __isl_keep isl_schedule_tree *tree2)
615 isl_bool equal;
616 int i, n;
618 if (!tree1 || !tree2)
619 return isl_bool_error;
620 if (tree1 == tree2)
621 return isl_bool_true;
622 if (tree1->type != tree2->type)
623 return isl_bool_false;
625 switch (tree1->type) {
626 case isl_schedule_node_band:
627 equal = isl_schedule_band_plain_is_equal(tree1->band,
628 tree2->band);
629 break;
630 case isl_schedule_node_context:
631 equal = isl_set_is_equal(tree1->context, tree2->context);
632 break;
633 case isl_schedule_node_domain:
634 equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
635 break;
636 case isl_schedule_node_expansion:
637 equal = isl_union_map_is_equal(tree1->expansion,
638 tree2->expansion);
639 if (equal >= 0 && equal)
640 equal = isl_union_pw_multi_aff_plain_is_equal(
641 tree1->contraction, tree2->contraction);
642 break;
643 case isl_schedule_node_extension:
644 equal = isl_union_map_is_equal(tree1->extension,
645 tree2->extension);
646 break;
647 case isl_schedule_node_filter:
648 equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
649 break;
650 case isl_schedule_node_guard:
651 equal = isl_set_is_equal(tree1->guard, tree2->guard);
652 break;
653 case isl_schedule_node_mark:
654 equal = tree1->mark == tree2->mark;
655 break;
656 case isl_schedule_node_leaf:
657 case isl_schedule_node_sequence:
658 case isl_schedule_node_set:
659 equal = isl_bool_true;
660 break;
661 case isl_schedule_node_error:
662 equal = isl_bool_error;
663 break;
666 if (equal < 0 || !equal)
667 return equal;
669 n = isl_schedule_tree_n_children(tree1);
670 if (n != isl_schedule_tree_n_children(tree2))
671 return isl_bool_false;
672 for (i = 0; i < n; ++i) {
673 isl_schedule_tree *child1, *child2;
675 child1 = isl_schedule_tree_get_child(tree1, i);
676 child2 = isl_schedule_tree_get_child(tree2, i);
677 equal = isl_schedule_tree_plain_is_equal(child1, child2);
678 isl_schedule_tree_free(child1);
679 isl_schedule_tree_free(child2);
681 if (equal < 0 || !equal)
682 return equal;
685 return isl_bool_true;
688 /* Does "tree" have any children, other than an implicit leaf.
690 int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
692 if (!tree)
693 return -1;
695 return tree->children != NULL;
698 /* Return the number of children of "tree", excluding implicit leaves.
700 int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
702 if (!tree)
703 return -1;
705 return isl_schedule_tree_list_n_schedule_tree(tree->children);
708 /* Return a copy of the (explicit) child at position "pos" of "tree".
710 __isl_give isl_schedule_tree *isl_schedule_tree_get_child(
711 __isl_keep isl_schedule_tree *tree, int pos)
713 if (!tree)
714 return NULL;
715 if (!tree->children)
716 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
717 "schedule tree has no explicit children", return NULL);
718 return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
721 /* Return a copy of the (explicit) child at position "pos" of "tree" and
722 * free "tree".
724 __isl_give isl_schedule_tree *isl_schedule_tree_child(
725 __isl_take isl_schedule_tree *tree, int pos)
727 isl_schedule_tree *child;
729 child = isl_schedule_tree_get_child(tree, pos);
730 isl_schedule_tree_free(tree);
731 return child;
734 /* Remove all (explicit) children from "tree".
736 __isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
737 __isl_take isl_schedule_tree *tree)
739 tree = isl_schedule_tree_cow(tree);
740 if (!tree)
741 return NULL;
742 tree->children = isl_schedule_tree_list_free(tree->children);
743 return tree;
746 /* Remove the child at position "pos" from the children of "tree".
747 * If there was only one child to begin with, then remove all children.
749 __isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
750 __isl_take isl_schedule_tree *tree, int pos)
752 int n;
754 tree = isl_schedule_tree_cow(tree);
755 if (!tree)
756 return NULL;
758 if (!isl_schedule_tree_has_children(tree))
759 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
760 "tree does not have any explicit children",
761 return isl_schedule_tree_free(tree));
762 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
763 if (pos < 0 || pos >= n)
764 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
765 "position out of bounds",
766 return isl_schedule_tree_free(tree));
767 if (n == 1)
768 return isl_schedule_tree_reset_children(tree);
770 tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
771 if (!tree->children)
772 return isl_schedule_tree_free(tree);
774 return tree;
777 /* Replace the child at position "pos" of "tree" by "child".
779 * If the new child is a leaf, then it is not explicitly
780 * recorded in the list of children. Instead, the list of children
781 * (which is assumed to have only one element) is removed.
782 * Note that the children of set and sequence nodes are always
783 * filters, so they cannot be replaced by empty trees.
785 __isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
786 __isl_take isl_schedule_tree *tree, int pos,
787 __isl_take isl_schedule_tree *child)
789 tree = isl_schedule_tree_cow(tree);
790 if (!tree || !child)
791 goto error;
793 if (isl_schedule_tree_is_leaf(child)) {
794 isl_schedule_tree_free(child);
795 if (!tree->children && pos == 0)
796 return tree;
797 if (isl_schedule_tree_n_children(tree) != 1)
798 isl_die(isl_schedule_tree_get_ctx(tree),
799 isl_error_internal,
800 "can only replace single child by leaf",
801 goto error);
802 return isl_schedule_tree_reset_children(tree);
805 if (!tree->children && pos == 0)
806 tree->children =
807 isl_schedule_tree_list_from_schedule_tree(child);
808 else
809 tree->children = isl_schedule_tree_list_set_schedule_tree(
810 tree->children, pos, child);
812 if (!tree->children)
813 return isl_schedule_tree_free(tree);
814 tree = isl_schedule_tree_update_anchored(tree);
816 return tree;
817 error:
818 isl_schedule_tree_free(tree);
819 isl_schedule_tree_free(child);
820 return NULL;
823 /* Replace the (explicit) children of "tree" by "children"?
825 __isl_give isl_schedule_tree *isl_schedule_tree_set_children(
826 __isl_take isl_schedule_tree *tree,
827 __isl_take isl_schedule_tree_list *children)
829 tree = isl_schedule_tree_cow(tree);
830 if (!tree || !children)
831 goto error;
832 isl_schedule_tree_list_free(tree->children);
833 tree->children = children;
834 return tree;
835 error:
836 isl_schedule_tree_free(tree);
837 isl_schedule_tree_list_free(children);
838 return NULL;
841 /* Create a new band schedule tree referring to "band"
842 * with "tree" as single child.
844 __isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
845 __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
847 isl_schedule_tree *res;
849 res = isl_schedule_tree_from_band(band);
850 return isl_schedule_tree_replace_child(res, 0, tree);
853 /* Create a new context schedule tree with the given context and
854 * with "tree" as single child.
856 __isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
857 __isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
859 isl_schedule_tree *res;
861 res = isl_schedule_tree_from_context(context);
862 return isl_schedule_tree_replace_child(res, 0, tree);
865 /* Create a new domain schedule tree with the given domain and
866 * with "tree" as single child.
868 __isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
869 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
871 isl_schedule_tree *res;
873 res = isl_schedule_tree_from_domain(domain);
874 return isl_schedule_tree_replace_child(res, 0, tree);
877 /* Create a new expansion schedule tree with the given contraction and
878 * expansion and with "tree" as single child.
880 __isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
881 __isl_take isl_schedule_tree *tree,
882 __isl_take isl_union_pw_multi_aff *contraction,
883 __isl_take isl_union_map *expansion)
885 isl_schedule_tree *res;
887 res = isl_schedule_tree_from_expansion(contraction, expansion);
888 return isl_schedule_tree_replace_child(res, 0, tree);
891 /* Create a new extension schedule tree with the given extension and
892 * with "tree" as single child.
894 __isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
895 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
897 isl_schedule_tree *res;
899 res = isl_schedule_tree_from_extension(extension);
900 return isl_schedule_tree_replace_child(res, 0, tree);
903 /* Create a new filter schedule tree with the given filter and single child.
905 * If the root of "tree" is itself a filter node, then the two
906 * filter nodes are merged into one node.
908 __isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
909 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
911 isl_schedule_tree *res;
913 if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
914 isl_union_set *tree_filter;
916 tree_filter = isl_schedule_tree_filter_get_filter(tree);
917 tree_filter = isl_union_set_intersect(tree_filter, filter);
918 tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
919 return tree;
922 res = isl_schedule_tree_from_filter(filter);
923 return isl_schedule_tree_replace_child(res, 0, tree);
926 /* Insert a filter node with filter set "filter"
927 * in each of the children of "tree".
929 __isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
930 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
932 int i, n;
934 if (!tree || !filter)
935 goto error;
937 n = isl_schedule_tree_n_children(tree);
938 for (i = 0; i < n; ++i) {
939 isl_schedule_tree *child;
941 child = isl_schedule_tree_get_child(tree, i);
942 child = isl_schedule_tree_insert_filter(child,
943 isl_union_set_copy(filter));
944 tree = isl_schedule_tree_replace_child(tree, i, child);
947 isl_union_set_free(filter);
948 return tree;
949 error:
950 isl_union_set_free(filter);
951 isl_schedule_tree_free(tree);
952 return NULL;
955 /* Create a new guard schedule tree with the given guard and
956 * with "tree" as single child.
958 __isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
959 __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
961 isl_schedule_tree *res;
963 res = isl_schedule_tree_from_guard(guard);
964 return isl_schedule_tree_replace_child(res, 0, tree);
967 /* Create a new mark schedule tree with the given mark identifier and
968 * single child.
970 __isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
971 __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
973 isl_schedule_tree *res;
975 res = isl_schedule_tree_from_mark(mark);
976 return isl_schedule_tree_replace_child(res, 0, tree);
979 /* Return the number of members in the band tree root.
981 unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
983 if (!tree)
984 return 0;
986 if (tree->type != isl_schedule_node_band)
987 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
988 "not a band node", return 0);
990 return isl_schedule_band_n_member(tree->band);
993 /* Is the band member at position "pos" of the band tree root
994 * marked coincident?
996 isl_bool isl_schedule_tree_band_member_get_coincident(
997 __isl_keep isl_schedule_tree *tree, int pos)
999 if (!tree)
1000 return isl_bool_error;
1002 if (tree->type != isl_schedule_node_band)
1003 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1004 "not a band node", return isl_bool_error);
1006 return isl_schedule_band_member_get_coincident(tree->band, pos);
1009 /* Mark the given band member as being coincident or not
1010 * according to "coincident".
1012 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
1013 __isl_take isl_schedule_tree *tree, int pos, int coincident)
1015 if (!tree)
1016 return NULL;
1017 if (tree->type != isl_schedule_node_band)
1018 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1019 "not a band node", return isl_schedule_tree_free(tree));
1020 if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
1021 coincident)
1022 return tree;
1023 tree = isl_schedule_tree_cow(tree);
1024 if (!tree)
1025 return NULL;
1027 tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
1028 coincident);
1029 if (!tree->band)
1030 return isl_schedule_tree_free(tree);
1031 return tree;
1034 /* Is the band tree root marked permutable?
1036 isl_bool isl_schedule_tree_band_get_permutable(
1037 __isl_keep isl_schedule_tree *tree)
1039 if (!tree)
1040 return isl_bool_error;
1042 if (tree->type != isl_schedule_node_band)
1043 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1044 "not a band node", return isl_bool_error);
1046 return isl_schedule_band_get_permutable(tree->band);
1049 /* Mark the band tree root permutable or not according to "permutable"?
1051 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
1052 __isl_take isl_schedule_tree *tree, int permutable)
1054 if (!tree)
1055 return NULL;
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_schedule_tree_free(tree));
1059 if (isl_schedule_tree_band_get_permutable(tree) == permutable)
1060 return tree;
1061 tree = isl_schedule_tree_cow(tree);
1062 if (!tree)
1063 return NULL;
1065 tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
1066 if (!tree->band)
1067 return isl_schedule_tree_free(tree);
1068 return tree;
1071 /* Return the schedule space of the band tree root.
1073 __isl_give isl_space *isl_schedule_tree_band_get_space(
1074 __isl_keep isl_schedule_tree *tree)
1076 if (!tree)
1077 return NULL;
1079 if (tree->type != isl_schedule_node_band)
1080 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1081 "not a band node", return NULL);
1083 return isl_schedule_band_get_space(tree->band);
1086 /* Intersect the domain of the band schedule of the band tree root
1087 * with "domain".
1089 __isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
1090 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1092 if (!tree || !domain)
1093 goto error;
1095 if (tree->type != isl_schedule_node_band)
1096 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1097 "not a band node", goto error);
1099 tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
1100 if (!tree->band)
1101 return isl_schedule_tree_free(tree);
1103 return tree;
1104 error:
1105 isl_schedule_tree_free(tree);
1106 isl_union_set_free(domain);
1107 return NULL;
1110 /* Return the schedule of the band tree root in isolation.
1112 __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
1113 __isl_keep isl_schedule_tree *tree)
1115 if (!tree)
1116 return NULL;
1118 if (tree->type != isl_schedule_node_band)
1119 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1120 "not a band node", return NULL);
1122 return isl_schedule_band_get_partial_schedule(tree->band);
1125 /* Replace the schedule of the band tree root by "schedule".
1127 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
1128 __isl_take isl_schedule_tree *tree,
1129 __isl_take isl_multi_union_pw_aff *schedule)
1131 tree = isl_schedule_tree_cow(tree);
1132 if (!tree || !schedule)
1133 goto error;
1135 if (tree->type != isl_schedule_node_band)
1136 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1137 "not a band node", return NULL);
1138 tree->band = isl_schedule_band_set_partial_schedule(tree->band,
1139 schedule);
1141 return tree;
1142 error:
1143 isl_schedule_tree_free(tree);
1144 isl_multi_union_pw_aff_free(schedule);
1145 return NULL;
1148 /* Return the loop AST generation type for the band member
1149 * of the band tree root at position "pos".
1151 enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
1152 __isl_keep isl_schedule_tree *tree, int pos)
1154 if (!tree)
1155 return isl_ast_loop_error;
1157 if (tree->type != isl_schedule_node_band)
1158 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1159 "not a band node", return isl_ast_loop_error);
1161 return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
1164 /* Set the loop AST generation type for the band member of the band tree root
1165 * at position "pos" to "type".
1167 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
1168 __isl_take isl_schedule_tree *tree, int pos,
1169 enum isl_ast_loop_type type)
1171 tree = isl_schedule_tree_cow(tree);
1172 if (!tree)
1173 return NULL;
1175 if (tree->type != isl_schedule_node_band)
1176 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1177 "not a band node", return isl_schedule_tree_free(tree));
1179 tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
1180 pos, type);
1181 if (!tree->band)
1182 return isl_schedule_tree_free(tree);
1184 return tree;
1187 /* Return the loop AST generation type for the band member
1188 * of the band tree root at position "pos" for the isolated part.
1190 enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
1191 __isl_keep isl_schedule_tree *tree, int pos)
1193 if (!tree)
1194 return isl_ast_loop_error;
1196 if (tree->type != isl_schedule_node_band)
1197 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1198 "not a band node", return isl_ast_loop_error);
1200 return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
1201 pos);
1204 /* Set the loop AST generation type for the band member of the band tree root
1205 * at position "pos" for the isolated part to "type".
1207 __isl_give isl_schedule_tree *
1208 isl_schedule_tree_band_member_set_isolate_ast_loop_type(
1209 __isl_take isl_schedule_tree *tree, int pos,
1210 enum isl_ast_loop_type type)
1212 tree = isl_schedule_tree_cow(tree);
1213 if (!tree)
1214 return NULL;
1216 if (tree->type != isl_schedule_node_band)
1217 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1218 "not a band node", return isl_schedule_tree_free(tree));
1220 tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
1221 tree->band, pos, type);
1222 if (!tree->band)
1223 return isl_schedule_tree_free(tree);
1225 return tree;
1228 /* Return the AST build options associated to the band tree root.
1230 __isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
1231 __isl_keep isl_schedule_tree *tree)
1233 if (!tree)
1234 return NULL;
1236 if (tree->type != isl_schedule_node_band)
1237 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1238 "not a band node", return NULL);
1240 return isl_schedule_band_get_ast_build_options(tree->band);
1243 /* Replace the AST build options associated to band tree root by "options".
1244 * Updated the anchored field if the anchoredness of the root node itself
1245 * changes.
1247 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
1248 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
1250 int was_anchored;
1252 tree = isl_schedule_tree_cow(tree);
1253 if (!tree || !options)
1254 goto error;
1256 if (tree->type != isl_schedule_node_band)
1257 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1258 "not a band node", goto error);
1260 was_anchored = isl_schedule_tree_is_anchored(tree);
1261 tree->band = isl_schedule_band_set_ast_build_options(tree->band,
1262 options);
1263 if (!tree->band)
1264 return isl_schedule_tree_free(tree);
1265 if (isl_schedule_tree_is_anchored(tree) != was_anchored)
1266 tree = isl_schedule_tree_update_anchored(tree);
1268 return tree;
1269 error:
1270 isl_schedule_tree_free(tree);
1271 isl_union_set_free(options);
1272 return NULL;
1275 /* Return the context of the context tree root.
1277 __isl_give isl_set *isl_schedule_tree_context_get_context(
1278 __isl_keep isl_schedule_tree *tree)
1280 if (!tree)
1281 return NULL;
1283 if (tree->type != isl_schedule_node_context)
1284 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1285 "not a context node", return NULL);
1287 return isl_set_copy(tree->context);
1290 /* Return the domain of the domain tree root.
1292 __isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
1293 __isl_keep isl_schedule_tree *tree)
1295 if (!tree)
1296 return NULL;
1298 if (tree->type != isl_schedule_node_domain)
1299 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1300 "not a domain node", return NULL);
1302 return isl_union_set_copy(tree->domain);
1305 /* Replace the domain of domain tree root "tree" by "domain".
1307 __isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
1308 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1310 tree = isl_schedule_tree_cow(tree);
1311 if (!tree || !domain)
1312 goto error;
1314 if (tree->type != isl_schedule_node_domain)
1315 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1316 "not a domain node", goto error);
1318 isl_union_set_free(tree->domain);
1319 tree->domain = domain;
1321 return tree;
1322 error:
1323 isl_schedule_tree_free(tree);
1324 isl_union_set_free(domain);
1325 return NULL;
1328 /* Return the contraction of the expansion tree root.
1330 __isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
1331 __isl_keep isl_schedule_tree *tree)
1333 if (!tree)
1334 return NULL;
1336 if (tree->type != isl_schedule_node_expansion)
1337 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1338 "not an expansion node", return NULL);
1340 return isl_union_pw_multi_aff_copy(tree->contraction);
1343 /* Return the expansion of the expansion tree root.
1345 __isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
1346 __isl_keep isl_schedule_tree *tree)
1348 if (!tree)
1349 return NULL;
1351 if (tree->type != isl_schedule_node_expansion)
1352 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1353 "not an expansion node", return NULL);
1355 return isl_union_map_copy(tree->expansion);
1358 /* Replace the contraction and the expansion of the expansion tree root "tree"
1359 * by "contraction" and "expansion".
1361 __isl_give isl_schedule_tree *
1362 isl_schedule_tree_expansion_set_contraction_and_expansion(
1363 __isl_take isl_schedule_tree *tree,
1364 __isl_take isl_union_pw_multi_aff *contraction,
1365 __isl_take isl_union_map *expansion)
1367 tree = isl_schedule_tree_cow(tree);
1368 if (!tree || !contraction || !expansion)
1369 goto error;
1371 if (tree->type != isl_schedule_node_expansion)
1372 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1373 "not an expansion node", return NULL);
1375 isl_union_pw_multi_aff_free(tree->contraction);
1376 tree->contraction = contraction;
1377 isl_union_map_free(tree->expansion);
1378 tree->expansion = expansion;
1380 return tree;
1381 error:
1382 isl_schedule_tree_free(tree);
1383 isl_union_pw_multi_aff_free(contraction);
1384 isl_union_map_free(expansion);
1385 return NULL;
1388 /* Return the extension of the extension tree root.
1390 __isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
1391 __isl_take isl_schedule_tree *tree)
1393 if (!tree)
1394 return NULL;
1396 if (tree->type != isl_schedule_node_extension)
1397 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1398 "not an extension node", return NULL);
1400 return isl_union_map_copy(tree->extension);
1403 /* Replace the extension of extension tree root "tree" by "extension".
1405 __isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
1406 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
1408 tree = isl_schedule_tree_cow(tree);
1409 if (!tree || !extension)
1410 goto error;
1412 if (tree->type != isl_schedule_node_extension)
1413 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1414 "not an extension node", return NULL);
1415 isl_union_map_free(tree->extension);
1416 tree->extension = extension;
1418 return tree;
1419 error:
1420 isl_schedule_tree_free(tree);
1421 isl_union_map_free(extension);
1422 return NULL;
1425 /* Return the filter of the filter tree root.
1427 __isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
1428 __isl_keep isl_schedule_tree *tree)
1430 if (!tree)
1431 return NULL;
1433 if (tree->type != isl_schedule_node_filter)
1434 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1435 "not a filter node", return NULL);
1437 return isl_union_set_copy(tree->filter);
1440 /* Replace the filter of the filter tree root by "filter".
1442 __isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
1443 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
1445 tree = isl_schedule_tree_cow(tree);
1446 if (!tree || !filter)
1447 goto error;
1449 if (tree->type != isl_schedule_node_filter)
1450 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1451 "not a filter node", return NULL);
1453 isl_union_set_free(tree->filter);
1454 tree->filter = filter;
1456 return tree;
1457 error:
1458 isl_schedule_tree_free(tree);
1459 isl_union_set_free(filter);
1460 return NULL;
1463 /* Return the guard of the guard tree root.
1465 __isl_give isl_set *isl_schedule_tree_guard_get_guard(
1466 __isl_take isl_schedule_tree *tree)
1468 if (!tree)
1469 return NULL;
1471 if (tree->type != isl_schedule_node_guard)
1472 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1473 "not a guard node", return NULL);
1475 return isl_set_copy(tree->guard);
1478 /* Return the mark identifier of the mark tree root "tree".
1480 __isl_give isl_id *isl_schedule_tree_mark_get_id(
1481 __isl_keep isl_schedule_tree *tree)
1483 if (!tree)
1484 return NULL;
1486 if (tree->type != isl_schedule_node_mark)
1487 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1488 "not a mark node", return NULL);
1490 return isl_id_copy(tree->mark);
1493 /* Set dim to the range dimension of "map" and abort the search.
1495 static isl_stat set_range_dim(__isl_take isl_map *map, void *user)
1497 int *dim = user;
1499 *dim = isl_map_dim(map, isl_dim_out);
1500 isl_map_free(map);
1502 return isl_stat_error;
1505 /* Return the dimension of the range of "umap".
1506 * "umap" is assumed not to be empty and
1507 * all maps inside "umap" are assumed to have the same range.
1509 * We extract the range dimension from the first map in "umap".
1511 static int range_dim(__isl_keep isl_union_map *umap)
1513 int dim = -1;
1515 if (!umap)
1516 return -1;
1517 if (isl_union_map_n_map(umap) == 0)
1518 isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
1519 "unexpected empty input", return -1);
1521 isl_union_map_foreach_map(umap, &set_range_dim, &dim);
1523 return dim;
1526 /* Append an "extra" number of zeros to the range of "umap" and
1527 * return the result.
1529 static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
1530 int extra)
1532 isl_union_set *dom;
1533 isl_space *space;
1534 isl_multi_val *mv;
1535 isl_union_pw_multi_aff *suffix;
1536 isl_union_map *universe;
1537 isl_union_map *suffix_umap;
1539 universe = isl_union_map_universe(isl_union_map_copy(umap));
1540 dom = isl_union_map_domain(universe);
1541 space = isl_union_set_get_space(dom);
1542 space = isl_space_set_from_params(space);
1543 space = isl_space_add_dims(space, isl_dim_set, extra);
1544 mv = isl_multi_val_zero(space);
1546 suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
1547 suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
1548 umap = isl_union_map_flat_range_product(umap, suffix_umap);
1550 return umap;
1553 /* Should we skip the root of "tree" while looking for the first
1554 * descendant with schedule information?
1555 * That is, is it impossible to derive any information about
1556 * the iteration domain from this node?
1558 * We do not want to skip leaf or error nodes because there is
1559 * no point in looking any deeper from these nodes.
1560 * We can only extract partial iteration domain information
1561 * from an extension node, but extension nodes are not supported
1562 * by the caller and it will error out on them.
1564 static int domain_less(__isl_keep isl_schedule_tree *tree)
1566 enum isl_schedule_node_type type;
1568 type = isl_schedule_tree_get_type(tree);
1569 switch (type) {
1570 case isl_schedule_node_band:
1571 return isl_schedule_tree_band_n_member(tree) == 0;
1572 case isl_schedule_node_context:
1573 case isl_schedule_node_guard:
1574 case isl_schedule_node_mark:
1575 return 1;
1576 case isl_schedule_node_leaf:
1577 case isl_schedule_node_error:
1578 case isl_schedule_node_domain:
1579 case isl_schedule_node_expansion:
1580 case isl_schedule_node_extension:
1581 case isl_schedule_node_filter:
1582 case isl_schedule_node_set:
1583 case isl_schedule_node_sequence:
1584 return 0;
1587 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1588 "unhandled case", return 0);
1591 /* Move down to the first descendant of "tree" that contains any schedule
1592 * information or return "leaf" if there is no such descendant.
1594 __isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
1595 __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
1597 while (domain_less(tree)) {
1598 if (!isl_schedule_tree_has_children(tree)) {
1599 isl_schedule_tree_free(tree);
1600 return isl_schedule_tree_copy(leaf);
1602 tree = isl_schedule_tree_child(tree, 0);
1605 return tree;
1608 static __isl_give isl_union_map *subtree_schedule_extend(
1609 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);
1611 /* Extend the schedule map "outer" with the subtree schedule
1612 * of the (single) child of "tree", if any.
1614 * If "tree" does not have any descendants (apart from those that
1615 * do not carry any schedule information), then we simply return "outer".
1616 * Otherwise, we extend the schedule map "outer" with the subtree schedule
1617 * of the single child.
1619 static __isl_give isl_union_map *subtree_schedule_extend_child(
1620 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1622 isl_schedule_tree *child;
1623 isl_union_map *res;
1625 if (!tree)
1626 return isl_union_map_free(outer);
1627 if (!isl_schedule_tree_has_children(tree))
1628 return outer;
1629 child = isl_schedule_tree_get_child(tree, 0);
1630 if (!child)
1631 return isl_union_map_free(outer);
1632 res = subtree_schedule_extend(child, outer);
1633 isl_schedule_tree_free(child);
1634 return res;
1637 /* Extract the parameter space from one of the children of "tree",
1638 * which are assumed to be filters.
1640 static __isl_give isl_space *extract_space_from_filter_child(
1641 __isl_keep isl_schedule_tree *tree)
1643 isl_space *space;
1644 isl_union_set *dom;
1645 isl_schedule_tree *child;
1647 child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
1648 dom = isl_schedule_tree_filter_get_filter(child);
1649 space = isl_union_set_get_space(dom);
1650 isl_union_set_free(dom);
1651 isl_schedule_tree_free(child);
1653 return space;
1656 /* Extend the schedule map "outer" with the subtree schedule
1657 * of a set or sequence node.
1659 * The schedule for the set or sequence node itself is composed of
1660 * pieces of the form
1662 * filter -> []
1664 * or
1666 * filter -> [index]
1668 * The first form is used if there is only a single child or
1669 * if the current node is a set node and the schedule_separate_components
1670 * option is not set.
1672 * Each of the pieces above is extended with the subtree schedule of
1673 * the child of the corresponding filter, if any, padded with zeros
1674 * to ensure that all pieces have the same range dimension.
1676 static __isl_give isl_union_map *subtree_schedule_extend_from_children(
1677 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1679 int i, n;
1680 int dim;
1681 int separate;
1682 isl_ctx *ctx;
1683 isl_val *v = NULL;
1684 isl_multi_val *mv;
1685 isl_space *space;
1686 isl_union_map *umap;
1688 if (!tree)
1689 return NULL;
1691 ctx = isl_schedule_tree_get_ctx(tree);
1692 if (!tree->children)
1693 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1694 "missing children", return NULL);
1695 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
1696 if (n == 0)
1697 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1698 "missing children", return NULL);
1700 separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
1701 isl_options_get_schedule_separate_components(ctx));
1703 space = extract_space_from_filter_child(tree);
1705 umap = isl_union_map_empty(isl_space_copy(space));
1706 space = isl_space_set_from_params(space);
1707 if (separate) {
1708 space = isl_space_add_dims(space, isl_dim_set, 1);
1709 v = isl_val_zero(ctx);
1711 mv = isl_multi_val_zero(space);
1713 dim = isl_multi_val_dim(mv, isl_dim_set);
1714 for (i = 0; i < n; ++i) {
1715 isl_union_pw_multi_aff *upma;
1716 isl_union_map *umap_i;
1717 isl_union_set *dom;
1718 isl_schedule_tree *child;
1719 int dim_i;
1720 int empty;
1722 child = isl_schedule_tree_list_get_schedule_tree(
1723 tree->children, i);
1724 dom = isl_schedule_tree_filter_get_filter(child);
1726 if (separate) {
1727 mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
1728 v = isl_val_add_ui(v, 1);
1730 upma = isl_union_pw_multi_aff_multi_val_on_domain(dom,
1731 isl_multi_val_copy(mv));
1732 umap_i = isl_union_map_from_union_pw_multi_aff(upma);
1733 umap_i = isl_union_map_flat_range_product(
1734 isl_union_map_copy(outer), umap_i);
1735 umap_i = subtree_schedule_extend_child(child, umap_i);
1736 isl_schedule_tree_free(child);
1738 empty = isl_union_map_is_empty(umap_i);
1739 if (empty < 0)
1740 umap_i = isl_union_map_free(umap_i);
1741 else if (empty) {
1742 isl_union_map_free(umap_i);
1743 continue;
1746 dim_i = range_dim(umap_i);
1747 if (dim_i < 0) {
1748 umap = isl_union_map_free(umap);
1749 } else if (dim < dim_i) {
1750 umap = append_range(umap, dim_i - dim);
1751 dim = dim_i;
1752 } else if (dim_i < dim) {
1753 umap_i = append_range(umap_i, dim - dim_i);
1755 umap = isl_union_map_union(umap, umap_i);
1758 isl_val_free(v);
1759 isl_multi_val_free(mv);
1760 isl_union_map_free(outer);
1762 return umap;
1765 /* Extend the schedule map "outer" with the subtree schedule of "tree".
1767 * If the root of the tree is a set or a sequence, then we extend
1768 * the schedule map in subtree_schedule_extend_from_children.
1769 * Otherwise, we extend the schedule map with the partial schedule
1770 * corresponding to the root of the tree and then continue with
1771 * the single child of this root.
1772 * In the special case of an expansion, the schedule map is "extended"
1773 * by applying the expansion to the domain of the schedule map.
1775 static __isl_give isl_union_map *subtree_schedule_extend(
1776 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1778 isl_multi_union_pw_aff *mupa;
1779 isl_union_map *umap;
1780 isl_union_set *domain;
1782 if (!tree)
1783 return NULL;
1785 switch (tree->type) {
1786 case isl_schedule_node_error:
1787 return isl_union_map_free(outer);
1788 case isl_schedule_node_extension:
1789 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1790 "cannot construct subtree schedule of tree "
1791 "with extension nodes",
1792 return isl_union_map_free(outer));
1793 case isl_schedule_node_context:
1794 case isl_schedule_node_guard:
1795 case isl_schedule_node_mark:
1796 return subtree_schedule_extend_child(tree, outer);
1797 case isl_schedule_node_band:
1798 if (isl_schedule_tree_band_n_member(tree) == 0)
1799 return subtree_schedule_extend_child(tree, outer);
1800 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1801 umap = isl_union_map_from_multi_union_pw_aff(mupa);
1802 outer = isl_union_map_flat_range_product(outer, umap);
1803 umap = subtree_schedule_extend_child(tree, outer);
1804 break;
1805 case isl_schedule_node_domain:
1806 domain = isl_schedule_tree_domain_get_domain(tree);
1807 umap = isl_union_map_from_domain(domain);
1808 outer = isl_union_map_flat_range_product(outer, umap);
1809 umap = subtree_schedule_extend_child(tree, outer);
1810 break;
1811 case isl_schedule_node_expansion:
1812 umap = isl_schedule_tree_expansion_get_expansion(tree);
1813 outer = isl_union_map_apply_domain(outer, umap);
1814 umap = subtree_schedule_extend_child(tree, outer);
1815 break;
1816 case isl_schedule_node_filter:
1817 domain = isl_schedule_tree_filter_get_filter(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_leaf:
1823 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1824 "leaf node should be handled by caller", return NULL);
1825 case isl_schedule_node_set:
1826 case isl_schedule_node_sequence:
1827 umap = subtree_schedule_extend_from_children(tree, outer);
1828 break;
1831 return umap;
1834 static __isl_give isl_union_set *initial_domain(
1835 __isl_keep isl_schedule_tree *tree);
1837 /* Extract a universe domain from the children of the tree root "tree",
1838 * which is a set or sequence, meaning that its children are filters.
1839 * In particular, return the union of the universes of the filters.
1841 static __isl_give isl_union_set *initial_domain_from_children(
1842 __isl_keep isl_schedule_tree *tree)
1844 int i, n;
1845 isl_space *space;
1846 isl_union_set *domain;
1848 if (!tree->children)
1849 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1850 "missing children", return NULL);
1851 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
1852 if (n == 0)
1853 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1854 "missing children", return NULL);
1856 space = extract_space_from_filter_child(tree);
1857 domain = isl_union_set_empty(space);
1859 for (i = 0; i < n; ++i) {
1860 isl_schedule_tree *child;
1861 isl_union_set *domain_i;
1863 child = isl_schedule_tree_get_child(tree, i);
1864 domain_i = initial_domain(child);
1865 domain = isl_union_set_union(domain, domain_i);
1866 isl_schedule_tree_free(child);
1869 return domain;
1872 /* Extract a universe domain from the tree root "tree".
1873 * The caller is responsible for making sure that this node
1874 * would not be skipped by isl_schedule_tree_first_schedule_descendant
1875 * and that it is not a leaf node.
1877 static __isl_give isl_union_set *initial_domain(
1878 __isl_keep isl_schedule_tree *tree)
1880 isl_multi_union_pw_aff *mupa;
1881 isl_union_set *domain;
1882 isl_union_map *exp;
1884 if (!tree)
1885 return NULL;
1887 switch (tree->type) {
1888 case isl_schedule_node_error:
1889 return NULL;
1890 case isl_schedule_node_context:
1891 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1892 "context node should be handled by caller",
1893 return NULL);
1894 case isl_schedule_node_guard:
1895 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1896 "guard node should be handled by caller",
1897 return NULL);
1898 case isl_schedule_node_mark:
1899 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1900 "mark node should be handled by caller",
1901 return NULL);
1902 case isl_schedule_node_extension:
1903 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1904 "cannot construct subtree schedule of tree "
1905 "with extension nodes", return NULL);
1906 case isl_schedule_node_band:
1907 if (isl_schedule_tree_band_n_member(tree) == 0)
1908 isl_die(isl_schedule_tree_get_ctx(tree),
1909 isl_error_internal,
1910 "0D band should be handled by caller",
1911 return NULL);
1912 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1913 domain = isl_multi_union_pw_aff_domain(mupa);
1914 domain = isl_union_set_universe(domain);
1915 break;
1916 case isl_schedule_node_domain:
1917 domain = isl_schedule_tree_domain_get_domain(tree);
1918 domain = isl_union_set_universe(domain);
1919 break;
1920 case isl_schedule_node_expansion:
1921 exp = isl_schedule_tree_expansion_get_expansion(tree);
1922 exp = isl_union_map_universe(exp);
1923 domain = isl_union_map_domain(exp);
1924 break;
1925 case isl_schedule_node_filter:
1926 domain = isl_schedule_tree_filter_get_filter(tree);
1927 domain = isl_union_set_universe(domain);
1928 break;
1929 case isl_schedule_node_leaf:
1930 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1931 "leaf node should be handled by caller", return NULL);
1932 case isl_schedule_node_set:
1933 case isl_schedule_node_sequence:
1934 domain = initial_domain_from_children(tree);
1935 break;
1938 return domain;
1941 /* Return the subtree schedule of a node that contains some schedule
1942 * information, i.e., a node that would not be skipped by
1943 * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
1945 * If the tree contains any expansions, then the returned subtree
1946 * schedule is formulated in terms of the expanded domains.
1947 * The tree is not allowed to contain any extension nodes.
1949 * We start with an initial zero-dimensional subtree schedule based
1950 * on the domain information in the root node and then extend it
1951 * based on the schedule information in the root node and its descendants.
1953 __isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
1954 __isl_keep isl_schedule_tree *tree)
1956 isl_union_set *domain;
1957 isl_union_map *umap;
1959 domain = initial_domain(tree);
1960 umap = isl_union_map_from_domain(domain);
1961 return subtree_schedule_extend(tree, umap);
1964 /* Multiply the partial schedule of the band root node of "tree"
1965 * with the factors in "mv".
1967 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
1968 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
1970 if (!tree || !mv)
1971 goto error;
1972 if (tree->type != isl_schedule_node_band)
1973 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1974 "not a band node", goto error);
1976 tree = isl_schedule_tree_cow(tree);
1977 if (!tree)
1978 goto error;
1980 tree->band = isl_schedule_band_scale(tree->band, mv);
1981 if (!tree->band)
1982 return isl_schedule_tree_free(tree);
1984 return tree;
1985 error:
1986 isl_schedule_tree_free(tree);
1987 isl_multi_val_free(mv);
1988 return NULL;
1991 /* Divide the partial schedule of the band root node of "tree"
1992 * by the factors in "mv".
1994 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
1995 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
1997 if (!tree || !mv)
1998 goto error;
1999 if (tree->type != isl_schedule_node_band)
2000 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2001 "not a band node", goto error);
2003 tree = isl_schedule_tree_cow(tree);
2004 if (!tree)
2005 goto error;
2007 tree->band = isl_schedule_band_scale_down(tree->band, mv);
2008 if (!tree->band)
2009 return isl_schedule_tree_free(tree);
2011 return tree;
2012 error:
2013 isl_schedule_tree_free(tree);
2014 isl_multi_val_free(mv);
2015 return NULL;
2018 /* Reduce the partial schedule of the band root node of "tree"
2019 * modulo the factors in "mv".
2021 __isl_give isl_schedule_tree *isl_schedule_tree_band_mod(
2022 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
2024 if (!tree || !mv)
2025 goto error;
2026 if (tree->type != isl_schedule_node_band)
2027 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2028 "not a band node", goto error);
2030 tree = isl_schedule_tree_cow(tree);
2031 if (!tree)
2032 goto error;
2034 tree->band = isl_schedule_band_mod(tree->band, mv);
2035 if (!tree->band)
2036 return isl_schedule_tree_free(tree);
2038 return tree;
2039 error:
2040 isl_schedule_tree_free(tree);
2041 isl_multi_val_free(mv);
2042 return NULL;
2045 /* Shift the partial schedule of the band root node of "tree" by "shift".
2047 __isl_give isl_schedule_tree *isl_schedule_tree_band_shift(
2048 __isl_take isl_schedule_tree *tree,
2049 __isl_take isl_multi_union_pw_aff *shift)
2051 if (!tree || !shift)
2052 goto error;
2053 if (tree->type != isl_schedule_node_band)
2054 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2055 "not a band node", goto error);
2057 tree = isl_schedule_tree_cow(tree);
2058 if (!tree)
2059 goto error;
2061 tree->band = isl_schedule_band_shift(tree->band, shift);
2062 if (!tree->band)
2063 return isl_schedule_tree_free(tree);
2065 return tree;
2066 error:
2067 isl_schedule_tree_free(tree);
2068 isl_multi_union_pw_aff_free(shift);
2069 return NULL;
2072 /* Given two trees with sequence roots, replace the child at position
2073 * "pos" of "tree" with the children of "child".
2075 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
2076 __isl_take isl_schedule_tree *tree, int pos,
2077 __isl_take isl_schedule_tree *child)
2079 int n;
2080 isl_schedule_tree_list *list1, *list2;
2082 tree = isl_schedule_tree_cow(tree);
2083 if (!tree || !child)
2084 goto error;
2085 if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
2086 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2087 "not a sequence node", goto error);
2088 n = isl_schedule_tree_n_children(tree);
2089 if (pos < 0 || pos >= n)
2090 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2091 "position out of bounds", goto error);
2092 if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence)
2093 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2094 "not a sequence node", goto error);
2096 list1 = isl_schedule_tree_list_copy(tree->children);
2097 list1 = isl_schedule_tree_list_drop(list1, pos, n - pos);
2098 list2 = isl_schedule_tree_list_copy(tree->children);
2099 list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1);
2100 list1 = isl_schedule_tree_list_concat(list1,
2101 isl_schedule_tree_list_copy(child->children));
2102 list1 = isl_schedule_tree_list_concat(list1, list2);
2104 isl_schedule_tree_free(tree);
2105 isl_schedule_tree_free(child);
2106 return isl_schedule_tree_from_children(isl_schedule_node_sequence,
2107 list1);
2108 error:
2109 isl_schedule_tree_free(tree);
2110 isl_schedule_tree_free(child);
2111 return NULL;
2114 /* Tile the band root node of "tree" with tile sizes "sizes".
2116 * We duplicate the band node, change the schedule of one of them
2117 * to the tile schedule and the other to the point schedule and then
2118 * attach the point band as a child to the tile band.
2120 __isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
2121 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
2123 isl_schedule_tree *child = NULL;
2125 if (!tree || !sizes)
2126 goto error;
2127 if (tree->type != isl_schedule_node_band)
2128 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2129 "not a band node", goto error);
2131 child = isl_schedule_tree_copy(tree);
2132 tree = isl_schedule_tree_cow(tree);
2133 child = isl_schedule_tree_cow(child);
2134 if (!tree || !child)
2135 goto error;
2137 tree->band = isl_schedule_band_tile(tree->band,
2138 isl_multi_val_copy(sizes));
2139 if (!tree->band)
2140 goto error;
2141 child->band = isl_schedule_band_point(child->band, tree->band, sizes);
2142 if (!child->band)
2143 child = isl_schedule_tree_free(child);
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 isl_multi_val_free(sizes);
2152 return NULL;
2155 /* Split the band root node of "tree" into two nested band nodes,
2156 * one with the first "pos" dimensions and
2157 * one with the remaining dimensions.
2159 __isl_give isl_schedule_tree *isl_schedule_tree_band_split(
2160 __isl_take isl_schedule_tree *tree, int pos)
2162 int n;
2163 isl_schedule_tree *child;
2165 if (!tree)
2166 return NULL;
2167 if (tree->type != isl_schedule_node_band)
2168 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2169 "not a band node", return isl_schedule_tree_free(tree));
2171 n = isl_schedule_tree_band_n_member(tree);
2172 if (pos < 0 || pos > n)
2173 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2174 "position out of bounds",
2175 return isl_schedule_tree_free(tree));
2177 child = isl_schedule_tree_copy(tree);
2178 tree = isl_schedule_tree_cow(tree);
2179 child = isl_schedule_tree_cow(child);
2180 if (!tree || !child)
2181 goto error;
2183 child->band = isl_schedule_band_drop(child->band, 0, pos);
2184 tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
2185 if (!child->band || !tree->band)
2186 goto error;
2188 tree = isl_schedule_tree_replace_child(tree, 0, child);
2190 return tree;
2191 error:
2192 isl_schedule_tree_free(child);
2193 isl_schedule_tree_free(tree);
2194 return NULL;
2197 /* Attach "tree2" at each of the leaves of "tree1".
2199 * If "tree1" does not have any explicit children, then make "tree2"
2200 * its single child. Otherwise, attach "tree2" to the leaves of
2201 * each of the children of "tree1".
2203 __isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
2204 __isl_take isl_schedule_tree *tree1,
2205 __isl_take isl_schedule_tree *tree2)
2207 int i, n;
2209 if (!tree1 || !tree2)
2210 goto error;
2211 n = isl_schedule_tree_n_children(tree1);
2212 if (n == 0) {
2213 isl_schedule_tree_list *list;
2214 list = isl_schedule_tree_list_from_schedule_tree(tree2);
2215 tree1 = isl_schedule_tree_set_children(tree1, list);
2216 return tree1;
2218 for (i = 0; i < n; ++i) {
2219 isl_schedule_tree *child;
2221 child = isl_schedule_tree_get_child(tree1, i);
2222 child = isl_schedule_tree_append_to_leaves(child,
2223 isl_schedule_tree_copy(tree2));
2224 tree1 = isl_schedule_tree_replace_child(tree1, i, child);
2227 isl_schedule_tree_free(tree2);
2228 return tree1;
2229 error:
2230 isl_schedule_tree_free(tree1);
2231 isl_schedule_tree_free(tree2);
2232 return NULL;
2235 /* Reset the user pointer on all identifiers of parameters and tuples
2236 * in the root of "tree".
2238 __isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
2239 __isl_take isl_schedule_tree *tree)
2241 if (isl_schedule_tree_is_leaf(tree))
2242 return tree;
2244 tree = isl_schedule_tree_cow(tree);
2245 if (!tree)
2246 return NULL;
2248 switch (tree->type) {
2249 case isl_schedule_node_error:
2250 return isl_schedule_tree_free(tree);
2251 case isl_schedule_node_band:
2252 tree->band = isl_schedule_band_reset_user(tree->band);
2253 if (!tree->band)
2254 return isl_schedule_tree_free(tree);
2255 break;
2256 case isl_schedule_node_context:
2257 tree->context = isl_set_reset_user(tree->context);
2258 if (!tree->context)
2259 return isl_schedule_tree_free(tree);
2260 break;
2261 case isl_schedule_node_domain:
2262 tree->domain = isl_union_set_reset_user(tree->domain);
2263 if (!tree->domain)
2264 return isl_schedule_tree_free(tree);
2265 break;
2266 case isl_schedule_node_expansion:
2267 tree->contraction =
2268 isl_union_pw_multi_aff_reset_user(tree->contraction);
2269 tree->expansion = isl_union_map_reset_user(tree->expansion);
2270 if (!tree->contraction || !tree->expansion)
2271 return isl_schedule_tree_free(tree);
2272 break;
2273 case isl_schedule_node_extension:
2274 tree->extension = isl_union_map_reset_user(tree->extension);
2275 if (!tree->extension)
2276 return isl_schedule_tree_free(tree);
2277 break;
2278 case isl_schedule_node_filter:
2279 tree->filter = isl_union_set_reset_user(tree->filter);
2280 if (!tree->filter)
2281 return isl_schedule_tree_free(tree);
2282 break;
2283 case isl_schedule_node_guard:
2284 tree->guard = isl_set_reset_user(tree->guard);
2285 if (!tree->guard)
2286 return isl_schedule_tree_free(tree);
2287 break;
2288 case isl_schedule_node_leaf:
2289 case isl_schedule_node_mark:
2290 case isl_schedule_node_sequence:
2291 case isl_schedule_node_set:
2292 break;
2295 return tree;
2298 /* Align the parameters of the root of "tree" to those of "space".
2300 __isl_give isl_schedule_tree *isl_schedule_tree_align_params(
2301 __isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
2303 if (!space)
2304 goto error;
2306 if (isl_schedule_tree_is_leaf(tree)) {
2307 isl_space_free(space);
2308 return tree;
2311 tree = isl_schedule_tree_cow(tree);
2312 if (!tree)
2313 goto error;
2315 switch (tree->type) {
2316 case isl_schedule_node_error:
2317 goto error;
2318 case isl_schedule_node_band:
2319 tree->band = isl_schedule_band_align_params(tree->band, space);
2320 if (!tree->band)
2321 return isl_schedule_tree_free(tree);
2322 break;
2323 case isl_schedule_node_context:
2324 tree->context = isl_set_align_params(tree->context, space);
2325 if (!tree->context)
2326 return isl_schedule_tree_free(tree);
2327 break;
2328 case isl_schedule_node_domain:
2329 tree->domain = isl_union_set_align_params(tree->domain, space);
2330 if (!tree->domain)
2331 return isl_schedule_tree_free(tree);
2332 break;
2333 case isl_schedule_node_expansion:
2334 tree->contraction =
2335 isl_union_pw_multi_aff_align_params(tree->contraction,
2336 isl_space_copy(space));
2337 tree->expansion = isl_union_map_align_params(tree->expansion,
2338 space);
2339 if (!tree->contraction || !tree->expansion)
2340 return isl_schedule_tree_free(tree);
2341 break;
2342 case isl_schedule_node_extension:
2343 tree->extension = isl_union_map_align_params(tree->extension,
2344 space);
2345 if (!tree->extension)
2346 return isl_schedule_tree_free(tree);
2347 break;
2348 case isl_schedule_node_filter:
2349 tree->filter = isl_union_set_align_params(tree->filter, space);
2350 if (!tree->filter)
2351 return isl_schedule_tree_free(tree);
2352 break;
2353 case isl_schedule_node_guard:
2354 tree->guard = isl_set_align_params(tree->guard, space);
2355 if (!tree->guard)
2356 return isl_schedule_tree_free(tree);
2357 break;
2358 case isl_schedule_node_leaf:
2359 case isl_schedule_node_mark:
2360 case isl_schedule_node_sequence:
2361 case isl_schedule_node_set:
2362 isl_space_free(space);
2363 break;
2366 return tree;
2367 error:
2368 isl_space_free(space);
2369 isl_schedule_tree_free(tree);
2370 return NULL;
2373 /* Does "tree" involve the iteration domain?
2374 * That is, does it need to be modified
2375 * by isl_schedule_tree_pullback_union_pw_multi_aff?
2377 static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
2379 if (!tree)
2380 return -1;
2382 switch (tree->type) {
2383 case isl_schedule_node_error:
2384 return -1;
2385 case isl_schedule_node_band:
2386 case isl_schedule_node_domain:
2387 case isl_schedule_node_expansion:
2388 case isl_schedule_node_extension:
2389 case isl_schedule_node_filter:
2390 return 1;
2391 case isl_schedule_node_context:
2392 case isl_schedule_node_leaf:
2393 case isl_schedule_node_guard:
2394 case isl_schedule_node_mark:
2395 case isl_schedule_node_sequence:
2396 case isl_schedule_node_set:
2397 return 0;
2400 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
2401 "unhandled case", return -1);
2404 /* Compute the pullback of the root node of "tree" by the function
2405 * represented by "upma".
2406 * In other words, plug in "upma" in the iteration domains of
2407 * the root node of "tree".
2408 * We currently do not handle expansion nodes.
2410 * We first check if the root node involves any iteration domains.
2411 * If so, we handle the specific cases.
2413 __isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
2414 __isl_take isl_schedule_tree *tree,
2415 __isl_take isl_union_pw_multi_aff *upma)
2417 int involves;
2419 if (!tree || !upma)
2420 goto error;
2422 involves = involves_iteration_domain(tree);
2423 if (involves < 0)
2424 goto error;
2425 if (!involves) {
2426 isl_union_pw_multi_aff_free(upma);
2427 return tree;
2430 tree = isl_schedule_tree_cow(tree);
2431 if (!tree)
2432 goto error;
2434 if (tree->type == isl_schedule_node_band) {
2435 tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
2436 tree->band, upma);
2437 if (!tree->band)
2438 return isl_schedule_tree_free(tree);
2439 } else if (tree->type == isl_schedule_node_domain) {
2440 tree->domain =
2441 isl_union_set_preimage_union_pw_multi_aff(tree->domain,
2442 upma);
2443 if (!tree->domain)
2444 return isl_schedule_tree_free(tree);
2445 } else if (tree->type == isl_schedule_node_expansion) {
2446 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
2447 "cannot pullback expansion node", goto error);
2448 } else if (tree->type == isl_schedule_node_extension) {
2449 tree->extension =
2450 isl_union_map_preimage_range_union_pw_multi_aff(
2451 tree->extension, upma);
2452 if (!tree->extension)
2453 return isl_schedule_tree_free(tree);
2454 } else if (tree->type == isl_schedule_node_filter) {
2455 tree->filter =
2456 isl_union_set_preimage_union_pw_multi_aff(tree->filter,
2457 upma);
2458 if (!tree->filter)
2459 return isl_schedule_tree_free(tree);
2462 return tree;
2463 error:
2464 isl_union_pw_multi_aff_free(upma);
2465 isl_schedule_tree_free(tree);
2466 return NULL;
2469 /* Compute the gist of the band tree root with respect to "context".
2471 __isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
2472 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
2474 if (!tree)
2475 return NULL;
2476 if (tree->type != isl_schedule_node_band)
2477 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2478 "not a band node", goto error);
2479 tree = isl_schedule_tree_cow(tree);
2480 if (!tree)
2481 goto error;
2483 tree->band = isl_schedule_band_gist(tree->band, context);
2484 if (!tree->band)
2485 return isl_schedule_tree_free(tree);
2486 return tree;
2487 error:
2488 isl_union_set_free(context);
2489 isl_schedule_tree_free(tree);
2490 return NULL;
2493 /* Are any members in "band" marked coincident?
2495 static int any_coincident(__isl_keep isl_schedule_band *band)
2497 int i, n;
2499 n = isl_schedule_band_n_member(band);
2500 for (i = 0; i < n; ++i)
2501 if (isl_schedule_band_member_get_coincident(band, i))
2502 return 1;
2504 return 0;
2507 /* Print the band node "band" to "p".
2509 * The permutable and coincident properties are only printed if they
2510 * are different from the defaults.
2511 * The coincident property is always printed in YAML flow style.
2513 static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
2514 __isl_keep isl_schedule_band *band)
2516 isl_union_set *options;
2517 int empty;
2519 p = isl_printer_print_str(p, "schedule");
2520 p = isl_printer_yaml_next(p);
2521 p = isl_printer_print_str(p, "\"");
2522 p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
2523 p = isl_printer_print_str(p, "\"");
2524 if (isl_schedule_band_get_permutable(band)) {
2525 p = isl_printer_yaml_next(p);
2526 p = isl_printer_print_str(p, "permutable");
2527 p = isl_printer_yaml_next(p);
2528 p = isl_printer_print_int(p, 1);
2530 if (any_coincident(band)) {
2531 int i, n;
2532 int style;
2534 p = isl_printer_yaml_next(p);
2535 p = isl_printer_print_str(p, "coincident");
2536 p = isl_printer_yaml_next(p);
2537 style = isl_printer_get_yaml_style(p);
2538 p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
2539 p = isl_printer_yaml_start_sequence(p);
2540 n = isl_schedule_band_n_member(band);
2541 for (i = 0; i < n; ++i) {
2542 p = isl_printer_print_int(p,
2543 isl_schedule_band_member_get_coincident(band, i));
2544 p = isl_printer_yaml_next(p);
2546 p = isl_printer_yaml_end_sequence(p);
2547 p = isl_printer_set_yaml_style(p, style);
2549 options = isl_schedule_band_get_ast_build_options(band);
2550 empty = isl_union_set_is_empty(options);
2551 if (empty < 0)
2552 p = isl_printer_free(p);
2553 if (!empty) {
2554 p = isl_printer_yaml_next(p);
2555 p = isl_printer_print_str(p, "options");
2556 p = isl_printer_yaml_next(p);
2557 p = isl_printer_print_str(p, "\"");
2558 p = isl_printer_print_union_set(p, options);
2559 p = isl_printer_print_str(p, "\"");
2561 isl_union_set_free(options);
2563 return p;
2566 /* Print "tree" to "p".
2568 * If "n_ancestor" is non-negative, then "child_pos" contains the child
2569 * positions of a descendant of the current node that should be marked
2570 * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor"
2571 * is zero, then the current node should be marked.
2572 * The marking is only printed in YAML block format.
2574 * Implicit leaf nodes are not printed, except if they correspond
2575 * to the node that should be marked.
2577 __isl_give isl_printer *isl_printer_print_schedule_tree_mark(
2578 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
2579 int n_ancestor, int *child_pos)
2581 int i, n;
2582 int sequence = 0;
2583 int block;
2585 block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;
2587 p = isl_printer_yaml_start_mapping(p);
2588 if (n_ancestor == 0 && block) {
2589 p = isl_printer_print_str(p, "# YOU ARE HERE");
2590 p = isl_printer_end_line(p);
2591 p = isl_printer_start_line(p);
2593 switch (tree->type) {
2594 case isl_schedule_node_error:
2595 p = isl_printer_print_str(p, "ERROR");
2596 break;
2597 case isl_schedule_node_leaf:
2598 p = isl_printer_print_str(p, "leaf");
2599 break;
2600 case isl_schedule_node_sequence:
2601 p = isl_printer_print_str(p, "sequence");
2602 sequence = 1;
2603 break;
2604 case isl_schedule_node_set:
2605 p = isl_printer_print_str(p, "set");
2606 sequence = 1;
2607 break;
2608 case isl_schedule_node_context:
2609 p = isl_printer_print_str(p, "context");
2610 p = isl_printer_yaml_next(p);
2611 p = isl_printer_print_str(p, "\"");
2612 p = isl_printer_print_set(p, tree->context);
2613 p = isl_printer_print_str(p, "\"");
2614 break;
2615 case isl_schedule_node_domain:
2616 p = isl_printer_print_str(p, "domain");
2617 p = isl_printer_yaml_next(p);
2618 p = isl_printer_print_str(p, "\"");
2619 p = isl_printer_print_union_set(p, tree->domain);
2620 p = isl_printer_print_str(p, "\"");
2621 break;
2622 case isl_schedule_node_expansion:
2623 p = isl_printer_print_str(p, "contraction");
2624 p = isl_printer_yaml_next(p);
2625 p = isl_printer_print_str(p, "\"");
2626 p = isl_printer_print_union_pw_multi_aff(p, tree->contraction);
2627 p = isl_printer_print_str(p, "\"");
2628 p = isl_printer_yaml_next(p);
2629 p = isl_printer_print_str(p, "expansion");
2630 p = isl_printer_yaml_next(p);
2631 p = isl_printer_print_str(p, "\"");
2632 p = isl_printer_print_union_map(p, tree->expansion);
2633 p = isl_printer_print_str(p, "\"");
2634 break;
2635 case isl_schedule_node_extension:
2636 p = isl_printer_print_str(p, "extension");
2637 p = isl_printer_yaml_next(p);
2638 p = isl_printer_print_str(p, "\"");
2639 p = isl_printer_print_union_map(p, tree->extension);
2640 p = isl_printer_print_str(p, "\"");
2641 break;
2642 case isl_schedule_node_filter:
2643 p = isl_printer_print_str(p, "filter");
2644 p = isl_printer_yaml_next(p);
2645 p = isl_printer_print_str(p, "\"");
2646 p = isl_printer_print_union_set(p, tree->filter);
2647 p = isl_printer_print_str(p, "\"");
2648 break;
2649 case isl_schedule_node_guard:
2650 p = isl_printer_print_str(p, "guard");
2651 p = isl_printer_yaml_next(p);
2652 p = isl_printer_print_str(p, "\"");
2653 p = isl_printer_print_set(p, tree->guard);
2654 p = isl_printer_print_str(p, "\"");
2655 break;
2656 case isl_schedule_node_mark:
2657 p = isl_printer_print_str(p, "mark");
2658 p = isl_printer_yaml_next(p);
2659 p = isl_printer_print_str(p, "\"");
2660 p = isl_printer_print_str(p, isl_id_get_name(tree->mark));
2661 p = isl_printer_print_str(p, "\"");
2662 break;
2663 case isl_schedule_node_band:
2664 p = print_tree_band(p, tree->band);
2665 break;
2667 p = isl_printer_yaml_next(p);
2669 if (!tree->children) {
2670 if (n_ancestor > 0 && block) {
2671 isl_schedule_tree *leaf;
2673 p = isl_printer_print_str(p, "child");
2674 p = isl_printer_yaml_next(p);
2675 leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
2676 p = isl_printer_print_schedule_tree_mark(p,
2677 leaf, 0, NULL);
2678 isl_schedule_tree_free(leaf);
2679 p = isl_printer_yaml_next(p);
2681 return isl_printer_yaml_end_mapping(p);
2684 if (sequence) {
2685 p = isl_printer_yaml_start_sequence(p);
2686 } else {
2687 p = isl_printer_print_str(p, "child");
2688 p = isl_printer_yaml_next(p);
2691 n = isl_schedule_tree_list_n_schedule_tree(tree->children);
2692 for (i = 0; i < n; ++i) {
2693 isl_schedule_tree *t;
2695 t = isl_schedule_tree_get_child(tree, i);
2696 if (n_ancestor > 0 && child_pos[0] == i)
2697 p = isl_printer_print_schedule_tree_mark(p, t,
2698 n_ancestor - 1, child_pos + 1);
2699 else
2700 p = isl_printer_print_schedule_tree_mark(p, t,
2701 -1, NULL);
2702 isl_schedule_tree_free(t);
2704 p = isl_printer_yaml_next(p);
2707 if (sequence)
2708 p = isl_printer_yaml_end_sequence(p);
2709 p = isl_printer_yaml_end_mapping(p);
2711 return p;
2714 /* Print "tree" to "p".
2716 __isl_give isl_printer *isl_printer_print_schedule_tree(
2717 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
2719 return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
2722 void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
2724 isl_ctx *ctx;
2725 isl_printer *printer;
2727 if (!tree)
2728 return;
2730 ctx = isl_schedule_tree_get_ctx(tree);
2731 printer = isl_printer_to_file(ctx, stderr);
2732 printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
2733 printer = isl_printer_print_schedule_tree(printer, tree);
2735 isl_printer_free(printer);