isl_map_simplify.c: coalesce_divs: use isl_basic_map_var_offset
[isl.git] / isl_schedule_tree.c
blob8ed933a12466244f37785541946adf372a9ccf42
1 /*
2 * Copyright 2013-2014 Ecole Normale Superieure
3 * Copyright 2014 INRIA Rocquencourt
4 * Copyright 2016 INRIA Paris
6 * Use of this software is governed by the MIT license
8 * Written by Sven Verdoolaege,
9 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
10 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
11 * B.P. 105 - 78153 Le Chesnay, France
12 * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12,
13 * CS 42112, 75589 Paris Cedex 12, France
16 #include <isl/id.h>
17 #include <isl/val.h>
18 #include <isl/space.h>
19 #include <isl/map.h>
20 #include <isl_schedule_band.h>
21 #include <isl_schedule_private.h>
23 #undef EL
24 #define EL isl_schedule_tree
26 #include <isl_list_templ.h>
28 #undef BASE
29 #define BASE schedule_tree
31 #include <isl_list_templ.c>
33 /* Is "tree" the leaf of a schedule tree?
35 int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree)
37 return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf;
40 /* Create a new schedule tree of type "type".
41 * The caller is responsible for filling in the type specific fields and
42 * the children.
44 * By default, the single node tree does not have any anchored nodes.
45 * The caller is responsible for updating the anchored field if needed.
47 static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx,
48 enum isl_schedule_node_type type)
50 isl_schedule_tree *tree;
52 if (type == isl_schedule_node_error)
53 return NULL;
55 tree = isl_calloc_type(ctx, isl_schedule_tree);
56 if (!tree)
57 return NULL;
59 tree->ref = 1;
60 tree->ctx = ctx;
61 isl_ctx_ref(ctx);
62 tree->type = type;
63 tree->anchored = 0;
65 return tree;
68 /* Return a fresh copy of "tree".
70 __isl_take isl_schedule_tree *isl_schedule_tree_dup(
71 __isl_keep isl_schedule_tree *tree)
73 isl_ctx *ctx;
74 isl_schedule_tree *dup;
76 if (!tree)
77 return NULL;
79 ctx = isl_schedule_tree_get_ctx(tree);
80 dup = isl_schedule_tree_alloc(ctx, tree->type);
81 if (!dup)
82 return NULL;
84 switch (tree->type) {
85 case isl_schedule_node_error:
86 isl_die(ctx, isl_error_internal,
87 "allocation should have failed",
88 return isl_schedule_tree_free(dup));
89 case isl_schedule_node_band:
90 dup->band = isl_schedule_band_copy(tree->band);
91 if (!dup->band)
92 return isl_schedule_tree_free(dup);
93 break;
94 case isl_schedule_node_context:
95 dup->context = isl_set_copy(tree->context);
96 if (!dup->context)
97 return isl_schedule_tree_free(dup);
98 break;
99 case isl_schedule_node_domain:
100 dup->domain = isl_union_set_copy(tree->domain);
101 if (!dup->domain)
102 return isl_schedule_tree_free(dup);
103 break;
104 case isl_schedule_node_expansion:
105 dup->contraction =
106 isl_union_pw_multi_aff_copy(tree->contraction);
107 dup->expansion = isl_union_map_copy(tree->expansion);
108 if (!dup->contraction || !dup->expansion)
109 return isl_schedule_tree_free(dup);
110 break;
111 case isl_schedule_node_extension:
112 dup->extension = isl_union_map_copy(tree->extension);
113 if (!dup->extension)
114 return isl_schedule_tree_free(dup);
115 break;
116 case isl_schedule_node_filter:
117 dup->filter = isl_union_set_copy(tree->filter);
118 if (!dup->filter)
119 return isl_schedule_tree_free(dup);
120 break;
121 case isl_schedule_node_guard:
122 dup->guard = isl_set_copy(tree->guard);
123 if (!dup->guard)
124 return isl_schedule_tree_free(dup);
125 break;
126 case isl_schedule_node_mark:
127 dup->mark = isl_id_copy(tree->mark);
128 if (!dup->mark)
129 return isl_schedule_tree_free(dup);
130 break;
131 case isl_schedule_node_leaf:
132 case isl_schedule_node_sequence:
133 case isl_schedule_node_set:
134 break;
137 if (tree->children) {
138 dup->children = isl_schedule_tree_list_copy(tree->children);
139 if (!dup->children)
140 return isl_schedule_tree_free(dup);
142 dup->anchored = tree->anchored;
144 return dup;
147 /* Return an isl_schedule_tree that is equal to "tree" and that has only
148 * a single reference.
150 __isl_give isl_schedule_tree *isl_schedule_tree_cow(
151 __isl_take isl_schedule_tree *tree)
153 if (!tree)
154 return NULL;
156 if (tree->ref == 1)
157 return tree;
158 tree->ref--;
159 return isl_schedule_tree_dup(tree);
162 /* Return a new reference to "tree".
164 __isl_give isl_schedule_tree *isl_schedule_tree_copy(
165 __isl_keep isl_schedule_tree *tree)
167 if (!tree)
168 return NULL;
170 tree->ref++;
171 return tree;
174 /* Free "tree" and return NULL.
176 __isl_null isl_schedule_tree *isl_schedule_tree_free(
177 __isl_take isl_schedule_tree *tree)
179 if (!tree)
180 return NULL;
181 if (--tree->ref > 0)
182 return NULL;
184 switch (tree->type) {
185 case isl_schedule_node_band:
186 isl_schedule_band_free(tree->band);
187 break;
188 case isl_schedule_node_context:
189 isl_set_free(tree->context);
190 break;
191 case isl_schedule_node_domain:
192 isl_union_set_free(tree->domain);
193 break;
194 case isl_schedule_node_expansion:
195 isl_union_pw_multi_aff_free(tree->contraction);
196 isl_union_map_free(tree->expansion);
197 break;
198 case isl_schedule_node_extension:
199 isl_union_map_free(tree->extension);
200 break;
201 case isl_schedule_node_filter:
202 isl_union_set_free(tree->filter);
203 break;
204 case isl_schedule_node_guard:
205 isl_set_free(tree->guard);
206 break;
207 case isl_schedule_node_mark:
208 isl_id_free(tree->mark);
209 break;
210 case isl_schedule_node_sequence:
211 case isl_schedule_node_set:
212 case isl_schedule_node_error:
213 case isl_schedule_node_leaf:
214 break;
216 isl_schedule_tree_list_free(tree->children);
217 isl_ctx_deref(tree->ctx);
218 free(tree);
220 return NULL;
223 /* Create and return a new leaf schedule tree.
225 __isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx)
227 return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf);
230 /* Create a new band schedule tree referring to "band"
231 * with no children.
233 __isl_give isl_schedule_tree *isl_schedule_tree_from_band(
234 __isl_take isl_schedule_band *band)
236 isl_ctx *ctx;
237 isl_schedule_tree *tree;
239 if (!band)
240 return NULL;
242 ctx = isl_schedule_band_get_ctx(band);
243 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band);
244 if (!tree)
245 goto error;
247 tree->band = band;
248 tree->anchored = isl_schedule_band_is_anchored(band);
250 return tree;
251 error:
252 isl_schedule_band_free(band);
253 return NULL;
256 /* Create a new context schedule tree with the given context and no children.
257 * Since the context references the outer schedule dimension,
258 * the tree is anchored.
260 __isl_give isl_schedule_tree *isl_schedule_tree_from_context(
261 __isl_take isl_set *context)
263 isl_ctx *ctx;
264 isl_schedule_tree *tree;
266 if (!context)
267 return NULL;
269 ctx = isl_set_get_ctx(context);
270 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context);
271 if (!tree)
272 goto error;
274 tree->context = context;
275 tree->anchored = 1;
277 return tree;
278 error:
279 isl_set_free(context);
280 return NULL;
283 /* Create a new domain schedule tree with the given domain and no children.
285 __isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
286 __isl_take isl_union_set *domain)
288 isl_ctx *ctx;
289 isl_schedule_tree *tree;
291 if (!domain)
292 return NULL;
294 ctx = isl_union_set_get_ctx(domain);
295 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain);
296 if (!tree)
297 goto error;
299 tree->domain = domain;
301 return tree;
302 error:
303 isl_union_set_free(domain);
304 return NULL;
307 /* Create a new expansion schedule tree with the given contraction and
308 * expansion and no children.
310 __isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
311 __isl_take isl_union_pw_multi_aff *contraction,
312 __isl_take isl_union_map *expansion)
314 isl_ctx *ctx;
315 isl_schedule_tree *tree;
317 if (!contraction || !expansion)
318 goto error;
320 ctx = isl_union_map_get_ctx(expansion);
321 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion);
322 if (!tree)
323 goto error;
325 tree->contraction = contraction;
326 tree->expansion = expansion;
328 return tree;
329 error:
330 isl_union_pw_multi_aff_free(contraction);
331 isl_union_map_free(expansion);
332 return NULL;
335 /* Create a new extension schedule tree with the given extension and
336 * no children.
337 * Since the domain of the extension refers to the outer schedule dimension,
338 * the tree is anchored.
340 __isl_give isl_schedule_tree *isl_schedule_tree_from_extension(
341 __isl_take isl_union_map *extension)
343 isl_ctx *ctx;
344 isl_schedule_tree *tree;
346 if (!extension)
347 return NULL;
349 ctx = isl_union_map_get_ctx(extension);
350 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension);
351 if (!tree)
352 goto error;
354 tree->extension = extension;
355 tree->anchored = 1;
357 return tree;
358 error:
359 isl_union_map_free(extension);
360 return NULL;
363 /* Create a new filter schedule tree with the given filter and no children.
365 __isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
366 __isl_take isl_union_set *filter)
368 isl_ctx *ctx;
369 isl_schedule_tree *tree;
371 if (!filter)
372 return NULL;
374 ctx = isl_union_set_get_ctx(filter);
375 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter);
376 if (!tree)
377 goto error;
379 tree->filter = filter;
381 return tree;
382 error:
383 isl_union_set_free(filter);
384 return NULL;
387 /* Create a new guard schedule tree with the given guard and no children.
388 * Since the guard references the outer schedule dimension,
389 * the tree is anchored.
391 __isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
392 __isl_take isl_set *guard)
394 isl_ctx *ctx;
395 isl_schedule_tree *tree;
397 if (!guard)
398 return NULL;
400 ctx = isl_set_get_ctx(guard);
401 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard);
402 if (!tree)
403 goto error;
405 tree->guard = guard;
406 tree->anchored = 1;
408 return tree;
409 error:
410 isl_set_free(guard);
411 return NULL;
414 /* Create a new mark schedule tree with the given mark identifier and
415 * no children.
417 __isl_give isl_schedule_tree *isl_schedule_tree_from_mark(
418 __isl_take isl_id *mark)
420 isl_ctx *ctx;
421 isl_schedule_tree *tree;
423 if (!mark)
424 return NULL;
426 ctx = isl_id_get_ctx(mark);
427 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark);
428 if (!tree)
429 goto error;
431 tree->mark = mark;
433 return tree;
434 error:
435 isl_id_free(mark);
436 return NULL;
439 /* Does "tree" have any node that depends on its position
440 * in the complete schedule tree?
442 isl_bool isl_schedule_tree_is_subtree_anchored(
443 __isl_keep isl_schedule_tree *tree)
445 return tree ? tree->anchored : isl_bool_error;
448 /* Does the root node of "tree" depend on its position in the complete
449 * schedule tree?
450 * Band nodes may be anchored depending on the associated AST build options.
451 * Context, extension and guard nodes are always anchored.
453 int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
455 if (!tree)
456 return -1;
458 switch (isl_schedule_tree_get_type(tree)) {
459 case isl_schedule_node_error:
460 return -1;
461 case isl_schedule_node_band:
462 return isl_schedule_band_is_anchored(tree->band);
463 case isl_schedule_node_context:
464 case isl_schedule_node_extension:
465 case isl_schedule_node_guard:
466 return 1;
467 case isl_schedule_node_domain:
468 case isl_schedule_node_expansion:
469 case isl_schedule_node_filter:
470 case isl_schedule_node_leaf:
471 case isl_schedule_node_mark:
472 case isl_schedule_node_sequence:
473 case isl_schedule_node_set:
474 return 0;
477 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
478 "unhandled case", return -1);
481 /* Update the anchored field of "tree" based on whether the root node
482 * itself in anchored and the anchored fields of the children.
484 * This function should be called whenever the children of a tree node
485 * are changed or the anchoredness of the tree root itself changes.
487 __isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
488 __isl_take isl_schedule_tree *tree)
490 int i, n;
491 int anchored;
493 anchored = isl_schedule_tree_is_anchored(tree);
494 n = isl_schedule_tree_n_children(tree);
495 if (anchored < 0 || n < 0)
496 return isl_schedule_tree_free(tree);
498 for (i = 0; !anchored && i < n; ++i) {
499 isl_schedule_tree *child;
501 child = isl_schedule_tree_get_child(tree, i);
502 if (!child)
503 return isl_schedule_tree_free(tree);
504 anchored = child->anchored;
505 isl_schedule_tree_free(child);
508 if (anchored == tree->anchored)
509 return tree;
510 tree = isl_schedule_tree_cow(tree);
511 if (!tree)
512 return NULL;
513 tree->anchored = anchored;
514 return tree;
517 /* Create a new tree of the given type (isl_schedule_node_sequence or
518 * isl_schedule_node_set) with the given children.
520 __isl_give isl_schedule_tree *isl_schedule_tree_from_children(
521 enum isl_schedule_node_type type,
522 __isl_take isl_schedule_tree_list *list)
524 isl_ctx *ctx;
525 isl_schedule_tree *tree;
527 if (!list)
528 return NULL;
530 ctx = isl_schedule_tree_list_get_ctx(list);
531 tree = isl_schedule_tree_alloc(ctx, type);
532 if (!tree)
533 goto error;
535 tree->children = list;
536 tree = isl_schedule_tree_update_anchored(tree);
538 return tree;
539 error:
540 isl_schedule_tree_list_free(list);
541 return NULL;
544 /* Construct a tree with a root node of type "type" and as children
545 * "tree1" and "tree2".
546 * If the root of one (or both) of the input trees is itself of type "type",
547 * then the tree is replaced by its children.
549 __isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
550 enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
551 __isl_take isl_schedule_tree *tree2)
553 isl_ctx *ctx;
554 isl_schedule_tree_list *list;
556 if (!tree1 || !tree2)
557 goto error;
559 ctx = isl_schedule_tree_get_ctx(tree1);
560 if (isl_schedule_tree_get_type(tree1) == type) {
561 list = isl_schedule_tree_list_copy(tree1->children);
562 isl_schedule_tree_free(tree1);
563 } else {
564 list = isl_schedule_tree_list_alloc(ctx, 2);
565 list = isl_schedule_tree_list_add(list, tree1);
567 if (isl_schedule_tree_get_type(tree2) == type) {
568 isl_schedule_tree_list *children;
570 children = isl_schedule_tree_list_copy(tree2->children);
571 list = isl_schedule_tree_list_concat(list, children);
572 isl_schedule_tree_free(tree2);
573 } else {
574 list = isl_schedule_tree_list_add(list, tree2);
577 return isl_schedule_tree_from_children(type, list);
578 error:
579 isl_schedule_tree_free(tree1);
580 isl_schedule_tree_free(tree2);
581 return NULL;
584 /* Construct a tree with a sequence root node and as children
585 * "tree1" and "tree2".
586 * If the root of one (or both) of the input trees is itself a sequence,
587 * then the tree is replaced by its children.
589 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
590 __isl_take isl_schedule_tree *tree1,
591 __isl_take isl_schedule_tree *tree2)
593 return isl_schedule_tree_from_pair(isl_schedule_node_sequence,
594 tree1, tree2);
597 /* Construct a tree with a set root node and as children
598 * "tree1" and "tree2".
599 * If the root of one (or both) of the input trees is itself a set,
600 * then the tree is replaced by its children.
602 __isl_give isl_schedule_tree *isl_schedule_tree_set_pair(
603 __isl_take isl_schedule_tree *tree1,
604 __isl_take isl_schedule_tree *tree2)
606 return isl_schedule_tree_from_pair(isl_schedule_node_set, tree1, tree2);
609 /* Return the isl_ctx to which "tree" belongs.
611 isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
613 return tree ? tree->ctx : NULL;
616 /* Return the type of the root of the tree or isl_schedule_node_error
617 * on error.
619 enum isl_schedule_node_type isl_schedule_tree_get_type(
620 __isl_keep isl_schedule_tree *tree)
622 return tree ? tree->type : isl_schedule_node_error;
625 /* Are "tree1" and "tree2" obviously equal to each other?
627 isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
628 __isl_keep isl_schedule_tree *tree2)
630 isl_bool equal;
631 int i, n;
633 if (!tree1 || !tree2)
634 return isl_bool_error;
635 if (tree1 == tree2)
636 return isl_bool_true;
637 if (tree1->type != tree2->type)
638 return isl_bool_false;
640 switch (tree1->type) {
641 case isl_schedule_node_band:
642 equal = isl_schedule_band_plain_is_equal(tree1->band,
643 tree2->band);
644 break;
645 case isl_schedule_node_context:
646 equal = isl_set_is_equal(tree1->context, tree2->context);
647 break;
648 case isl_schedule_node_domain:
649 equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
650 break;
651 case isl_schedule_node_expansion:
652 equal = isl_union_map_is_equal(tree1->expansion,
653 tree2->expansion);
654 if (equal >= 0 && equal)
655 equal = isl_union_pw_multi_aff_plain_is_equal(
656 tree1->contraction, tree2->contraction);
657 break;
658 case isl_schedule_node_extension:
659 equal = isl_union_map_is_equal(tree1->extension,
660 tree2->extension);
661 break;
662 case isl_schedule_node_filter:
663 equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
664 break;
665 case isl_schedule_node_guard:
666 equal = isl_set_is_equal(tree1->guard, tree2->guard);
667 break;
668 case isl_schedule_node_mark:
669 equal = tree1->mark == tree2->mark;
670 break;
671 case isl_schedule_node_leaf:
672 case isl_schedule_node_sequence:
673 case isl_schedule_node_set:
674 equal = isl_bool_true;
675 break;
676 case isl_schedule_node_error:
677 equal = isl_bool_error;
678 break;
681 if (equal < 0 || !equal)
682 return equal;
684 n = isl_schedule_tree_n_children(tree1);
685 if (n != isl_schedule_tree_n_children(tree2))
686 return isl_bool_false;
687 for (i = 0; i < n; ++i) {
688 isl_schedule_tree *child1, *child2;
690 child1 = isl_schedule_tree_get_child(tree1, i);
691 child2 = isl_schedule_tree_get_child(tree2, i);
692 equal = isl_schedule_tree_plain_is_equal(child1, child2);
693 isl_schedule_tree_free(child1);
694 isl_schedule_tree_free(child2);
696 if (equal < 0 || !equal)
697 return equal;
700 return isl_bool_true;
703 /* Does "tree" have any children, other than an implicit leaf.
705 int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
707 if (!tree)
708 return -1;
710 return tree->children != NULL;
713 /* Return the number of children of "tree", excluding implicit leaves.
714 * The "children" field is NULL if there are
715 * no children (except for the implicit leaves).
717 int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
719 if (!tree)
720 return -1;
722 if (!tree->children)
723 return 0;
724 return isl_schedule_tree_list_n_schedule_tree(tree->children);
727 /* Return a copy of the (explicit) child at position "pos" of "tree".
729 __isl_give isl_schedule_tree *isl_schedule_tree_get_child(
730 __isl_keep isl_schedule_tree *tree, int pos)
732 if (!tree)
733 return NULL;
734 if (!tree->children)
735 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
736 "schedule tree has no explicit children", return NULL);
737 return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
740 /* Return a copy of the (explicit) child at position "pos" of "tree" and
741 * free "tree".
743 __isl_give isl_schedule_tree *isl_schedule_tree_child(
744 __isl_take isl_schedule_tree *tree, int pos)
746 isl_schedule_tree *child;
748 child = isl_schedule_tree_get_child(tree, pos);
749 isl_schedule_tree_free(tree);
750 return child;
753 /* Remove all (explicit) children from "tree".
755 __isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
756 __isl_take isl_schedule_tree *tree)
758 tree = isl_schedule_tree_cow(tree);
759 if (!tree)
760 return NULL;
761 tree->children = isl_schedule_tree_list_free(tree->children);
762 return tree;
765 /* Remove the child at position "pos" from the children of "tree".
766 * If there was only one child to begin with, then remove all children.
768 __isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
769 __isl_take isl_schedule_tree *tree, int pos)
771 int n;
773 tree = isl_schedule_tree_cow(tree);
775 n = isl_schedule_tree_n_children(tree);
776 if (n < 0)
777 return isl_schedule_tree_free(tree);
778 if (n == 0)
779 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
780 "tree does not have any explicit children",
781 return isl_schedule_tree_free(tree));
782 if (pos < 0 || pos >= n)
783 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
784 "position out of bounds",
785 return isl_schedule_tree_free(tree));
786 if (n == 1)
787 return isl_schedule_tree_reset_children(tree);
789 tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
790 if (!tree->children)
791 return isl_schedule_tree_free(tree);
793 return tree;
796 /* Replace the child at position "pos" of "tree" by "child".
798 * If the new child is a leaf, then it is not explicitly
799 * recorded in the list of children. Instead, the list of children
800 * (which is assumed to have only one element) is removed.
801 * Note that the children of set and sequence nodes are always
802 * filters, so they cannot be replaced by empty trees.
804 __isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
805 __isl_take isl_schedule_tree *tree, int pos,
806 __isl_take isl_schedule_tree *child)
808 tree = isl_schedule_tree_cow(tree);
809 if (!tree || !child)
810 goto error;
812 if (isl_schedule_tree_is_leaf(child)) {
813 isl_schedule_tree_free(child);
814 if (!tree->children && pos == 0)
815 return tree;
816 if (isl_schedule_tree_n_children(tree) != 1)
817 isl_die(isl_schedule_tree_get_ctx(tree),
818 isl_error_internal,
819 "can only replace single child by leaf",
820 goto error);
821 return isl_schedule_tree_reset_children(tree);
824 if (!tree->children && pos == 0)
825 tree->children =
826 isl_schedule_tree_list_from_schedule_tree(child);
827 else
828 tree->children = isl_schedule_tree_list_set_schedule_tree(
829 tree->children, pos, child);
831 if (!tree->children)
832 return isl_schedule_tree_free(tree);
833 tree = isl_schedule_tree_update_anchored(tree);
835 return tree;
836 error:
837 isl_schedule_tree_free(tree);
838 isl_schedule_tree_free(child);
839 return NULL;
842 /* Replace the (explicit) children of "tree" by "children"?
844 __isl_give isl_schedule_tree *isl_schedule_tree_set_children(
845 __isl_take isl_schedule_tree *tree,
846 __isl_take isl_schedule_tree_list *children)
848 tree = isl_schedule_tree_cow(tree);
849 if (!tree || !children)
850 goto error;
851 isl_schedule_tree_list_free(tree->children);
852 tree->children = children;
853 return tree;
854 error:
855 isl_schedule_tree_free(tree);
856 isl_schedule_tree_list_free(children);
857 return NULL;
860 /* Create a new band schedule tree referring to "band"
861 * with "tree" as single child.
863 __isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
864 __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
866 isl_schedule_tree *res;
868 res = isl_schedule_tree_from_band(band);
869 return isl_schedule_tree_replace_child(res, 0, tree);
872 /* Create a new context schedule tree with the given context and
873 * with "tree" as single child.
875 __isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
876 __isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
878 isl_schedule_tree *res;
880 res = isl_schedule_tree_from_context(context);
881 return isl_schedule_tree_replace_child(res, 0, tree);
884 /* Create a new domain schedule tree with the given domain and
885 * with "tree" as single child.
887 __isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
888 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
890 isl_schedule_tree *res;
892 res = isl_schedule_tree_from_domain(domain);
893 return isl_schedule_tree_replace_child(res, 0, tree);
896 /* Create a new expansion schedule tree with the given contraction and
897 * expansion and with "tree" as single child.
899 __isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
900 __isl_take isl_schedule_tree *tree,
901 __isl_take isl_union_pw_multi_aff *contraction,
902 __isl_take isl_union_map *expansion)
904 isl_schedule_tree *res;
906 res = isl_schedule_tree_from_expansion(contraction, expansion);
907 return isl_schedule_tree_replace_child(res, 0, tree);
910 /* Create a new extension schedule tree with the given extension and
911 * with "tree" as single child.
913 __isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
914 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
916 isl_schedule_tree *res;
918 res = isl_schedule_tree_from_extension(extension);
919 return isl_schedule_tree_replace_child(res, 0, tree);
922 /* Create a new filter schedule tree with the given filter and single child.
924 * If the root of "tree" is itself a filter node, then the two
925 * filter nodes are merged into one node.
927 __isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
928 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
930 isl_schedule_tree *res;
932 if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
933 isl_union_set *tree_filter;
935 tree_filter = isl_schedule_tree_filter_get_filter(tree);
936 tree_filter = isl_union_set_intersect(tree_filter, filter);
937 tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
938 return tree;
941 res = isl_schedule_tree_from_filter(filter);
942 return isl_schedule_tree_replace_child(res, 0, tree);
945 /* Insert a filter node with filter set "filter"
946 * in each of the children of "tree".
948 __isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
949 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
951 int i, n;
953 if (!tree || !filter)
954 goto error;
956 n = isl_schedule_tree_n_children(tree);
957 for (i = 0; i < n; ++i) {
958 isl_schedule_tree *child;
960 child = isl_schedule_tree_get_child(tree, i);
961 child = isl_schedule_tree_insert_filter(child,
962 isl_union_set_copy(filter));
963 tree = isl_schedule_tree_replace_child(tree, i, child);
966 isl_union_set_free(filter);
967 return tree;
968 error:
969 isl_union_set_free(filter);
970 isl_schedule_tree_free(tree);
971 return NULL;
974 /* Create a new guard schedule tree with the given guard and
975 * with "tree" as single child.
977 __isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
978 __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
980 isl_schedule_tree *res;
982 res = isl_schedule_tree_from_guard(guard);
983 return isl_schedule_tree_replace_child(res, 0, tree);
986 /* Create a new mark schedule tree with the given mark identifier and
987 * single child.
989 __isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
990 __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
992 isl_schedule_tree *res;
994 res = isl_schedule_tree_from_mark(mark);
995 return isl_schedule_tree_replace_child(res, 0, tree);
998 /* Return the number of members in the band tree root.
1000 unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
1002 if (!tree)
1003 return 0;
1005 if (tree->type != isl_schedule_node_band)
1006 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1007 "not a band node", return 0);
1009 return isl_schedule_band_n_member(tree->band);
1012 /* Is the band member at position "pos" of the band tree root
1013 * marked coincident?
1015 isl_bool isl_schedule_tree_band_member_get_coincident(
1016 __isl_keep isl_schedule_tree *tree, int pos)
1018 if (!tree)
1019 return isl_bool_error;
1021 if (tree->type != isl_schedule_node_band)
1022 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1023 "not a band node", return isl_bool_error);
1025 return isl_schedule_band_member_get_coincident(tree->band, pos);
1028 /* Mark the given band member as being coincident or not
1029 * according to "coincident".
1031 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
1032 __isl_take isl_schedule_tree *tree, int pos, int coincident)
1034 if (!tree)
1035 return NULL;
1036 if (tree->type != isl_schedule_node_band)
1037 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1038 "not a band node", return isl_schedule_tree_free(tree));
1039 if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
1040 coincident)
1041 return tree;
1042 tree = isl_schedule_tree_cow(tree);
1043 if (!tree)
1044 return NULL;
1046 tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
1047 coincident);
1048 if (!tree->band)
1049 return isl_schedule_tree_free(tree);
1050 return tree;
1053 /* Is the band tree root marked permutable?
1055 isl_bool isl_schedule_tree_band_get_permutable(
1056 __isl_keep isl_schedule_tree *tree)
1058 if (!tree)
1059 return isl_bool_error;
1061 if (tree->type != isl_schedule_node_band)
1062 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1063 "not a band node", return isl_bool_error);
1065 return isl_schedule_band_get_permutable(tree->band);
1068 /* Mark the band tree root permutable or not according to "permutable"?
1070 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
1071 __isl_take isl_schedule_tree *tree, int permutable)
1073 if (!tree)
1074 return NULL;
1075 if (tree->type != isl_schedule_node_band)
1076 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1077 "not a band node", return isl_schedule_tree_free(tree));
1078 if (isl_schedule_tree_band_get_permutable(tree) == permutable)
1079 return tree;
1080 tree = isl_schedule_tree_cow(tree);
1081 if (!tree)
1082 return NULL;
1084 tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
1085 if (!tree->band)
1086 return isl_schedule_tree_free(tree);
1087 return tree;
1090 /* Return the schedule space of the band tree root.
1092 __isl_give isl_space *isl_schedule_tree_band_get_space(
1093 __isl_keep isl_schedule_tree *tree)
1095 if (!tree)
1096 return NULL;
1098 if (tree->type != isl_schedule_node_band)
1099 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1100 "not a band node", return NULL);
1102 return isl_schedule_band_get_space(tree->band);
1105 /* Intersect the domain of the band schedule of the band tree root
1106 * with "domain".
1108 __isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
1109 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1111 if (!tree || !domain)
1112 goto error;
1114 if (tree->type != isl_schedule_node_band)
1115 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1116 "not a band node", goto error);
1118 tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
1119 if (!tree->band)
1120 return isl_schedule_tree_free(tree);
1122 return tree;
1123 error:
1124 isl_schedule_tree_free(tree);
1125 isl_union_set_free(domain);
1126 return NULL;
1129 /* Return the schedule of the band tree root in isolation.
1131 __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
1132 __isl_keep isl_schedule_tree *tree)
1134 if (!tree)
1135 return NULL;
1137 if (tree->type != isl_schedule_node_band)
1138 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1139 "not a band node", return NULL);
1141 return isl_schedule_band_get_partial_schedule(tree->band);
1144 /* Replace the schedule of the band tree root by "schedule".
1146 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
1147 __isl_take isl_schedule_tree *tree,
1148 __isl_take isl_multi_union_pw_aff *schedule)
1150 tree = isl_schedule_tree_cow(tree);
1151 if (!tree || !schedule)
1152 goto error;
1154 if (tree->type != isl_schedule_node_band)
1155 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1156 "not a band node", return NULL);
1157 tree->band = isl_schedule_band_set_partial_schedule(tree->band,
1158 schedule);
1160 return tree;
1161 error:
1162 isl_schedule_tree_free(tree);
1163 isl_multi_union_pw_aff_free(schedule);
1164 return NULL;
1167 /* Return the loop AST generation type for the band member
1168 * of the band tree root at position "pos".
1170 enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
1171 __isl_keep isl_schedule_tree *tree, int pos)
1173 if (!tree)
1174 return isl_ast_loop_error;
1176 if (tree->type != isl_schedule_node_band)
1177 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1178 "not a band node", return isl_ast_loop_error);
1180 return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
1183 /* Set the loop AST generation type for the band member of the band tree root
1184 * at position "pos" to "type".
1186 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
1187 __isl_take isl_schedule_tree *tree, int pos,
1188 enum isl_ast_loop_type type)
1190 tree = isl_schedule_tree_cow(tree);
1191 if (!tree)
1192 return NULL;
1194 if (tree->type != isl_schedule_node_band)
1195 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1196 "not a band node", return isl_schedule_tree_free(tree));
1198 tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
1199 pos, type);
1200 if (!tree->band)
1201 return isl_schedule_tree_free(tree);
1203 return tree;
1206 /* Return the loop AST generation type for the band member
1207 * of the band tree root at position "pos" for the isolated part.
1209 enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
1210 __isl_keep isl_schedule_tree *tree, int pos)
1212 if (!tree)
1213 return isl_ast_loop_error;
1215 if (tree->type != isl_schedule_node_band)
1216 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1217 "not a band node", return isl_ast_loop_error);
1219 return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
1220 pos);
1223 /* Set the loop AST generation type for the band member of the band tree root
1224 * at position "pos" for the isolated part to "type".
1226 __isl_give isl_schedule_tree *
1227 isl_schedule_tree_band_member_set_isolate_ast_loop_type(
1228 __isl_take isl_schedule_tree *tree, int pos,
1229 enum isl_ast_loop_type type)
1231 tree = isl_schedule_tree_cow(tree);
1232 if (!tree)
1233 return NULL;
1235 if (tree->type != isl_schedule_node_band)
1236 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1237 "not a band node", return isl_schedule_tree_free(tree));
1239 tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
1240 tree->band, pos, type);
1241 if (!tree->band)
1242 return isl_schedule_tree_free(tree);
1244 return tree;
1247 /* Return the AST build options associated to the band tree root.
1249 __isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
1250 __isl_keep isl_schedule_tree *tree)
1252 if (!tree)
1253 return NULL;
1255 if (tree->type != isl_schedule_node_band)
1256 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1257 "not a band node", return NULL);
1259 return isl_schedule_band_get_ast_build_options(tree->band);
1262 /* Replace the AST build options associated to band tree root by "options".
1263 * Updated the anchored field if the anchoredness of the root node itself
1264 * changes.
1266 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
1267 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
1269 int was_anchored;
1271 tree = isl_schedule_tree_cow(tree);
1272 if (!tree || !options)
1273 goto error;
1275 if (tree->type != isl_schedule_node_band)
1276 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1277 "not a band node", goto error);
1279 was_anchored = isl_schedule_tree_is_anchored(tree);
1280 tree->band = isl_schedule_band_set_ast_build_options(tree->band,
1281 options);
1282 if (!tree->band)
1283 return isl_schedule_tree_free(tree);
1284 if (isl_schedule_tree_is_anchored(tree) != was_anchored)
1285 tree = isl_schedule_tree_update_anchored(tree);
1287 return tree;
1288 error:
1289 isl_schedule_tree_free(tree);
1290 isl_union_set_free(options);
1291 return NULL;
1294 /* Return the "isolate" option associated to the band tree root of "tree",
1295 * which is assumed to appear at schedule depth "depth".
1297 __isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option(
1298 __isl_keep isl_schedule_tree *tree, int depth)
1300 if (!tree)
1301 return NULL;
1303 if (tree->type != isl_schedule_node_band)
1304 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1305 "not a band node", return NULL);
1307 return isl_schedule_band_get_ast_isolate_option(tree->band, depth);
1310 /* Return the context of the context tree root.
1312 __isl_give isl_set *isl_schedule_tree_context_get_context(
1313 __isl_keep isl_schedule_tree *tree)
1315 if (!tree)
1316 return NULL;
1318 if (tree->type != isl_schedule_node_context)
1319 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1320 "not a context node", return NULL);
1322 return isl_set_copy(tree->context);
1325 /* Return the domain of the domain tree root.
1327 __isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
1328 __isl_keep isl_schedule_tree *tree)
1330 if (!tree)
1331 return NULL;
1333 if (tree->type != isl_schedule_node_domain)
1334 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1335 "not a domain node", return NULL);
1337 return isl_union_set_copy(tree->domain);
1340 /* Replace the domain of domain tree root "tree" by "domain".
1342 __isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
1343 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
1345 tree = isl_schedule_tree_cow(tree);
1346 if (!tree || !domain)
1347 goto error;
1349 if (tree->type != isl_schedule_node_domain)
1350 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1351 "not a domain node", goto error);
1353 isl_union_set_free(tree->domain);
1354 tree->domain = domain;
1356 return tree;
1357 error:
1358 isl_schedule_tree_free(tree);
1359 isl_union_set_free(domain);
1360 return NULL;
1363 /* Return the contraction of the expansion tree root.
1365 __isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
1366 __isl_keep isl_schedule_tree *tree)
1368 if (!tree)
1369 return NULL;
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 return isl_union_pw_multi_aff_copy(tree->contraction);
1378 /* Return the expansion of the expansion tree root.
1380 __isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
1381 __isl_keep isl_schedule_tree *tree)
1383 if (!tree)
1384 return NULL;
1386 if (tree->type != isl_schedule_node_expansion)
1387 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1388 "not an expansion node", return NULL);
1390 return isl_union_map_copy(tree->expansion);
1393 /* Replace the contraction and the expansion of the expansion tree root "tree"
1394 * by "contraction" and "expansion".
1396 __isl_give isl_schedule_tree *
1397 isl_schedule_tree_expansion_set_contraction_and_expansion(
1398 __isl_take isl_schedule_tree *tree,
1399 __isl_take isl_union_pw_multi_aff *contraction,
1400 __isl_take isl_union_map *expansion)
1402 tree = isl_schedule_tree_cow(tree);
1403 if (!tree || !contraction || !expansion)
1404 goto error;
1406 if (tree->type != isl_schedule_node_expansion)
1407 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1408 "not an expansion node", return NULL);
1410 isl_union_pw_multi_aff_free(tree->contraction);
1411 tree->contraction = contraction;
1412 isl_union_map_free(tree->expansion);
1413 tree->expansion = expansion;
1415 return tree;
1416 error:
1417 isl_schedule_tree_free(tree);
1418 isl_union_pw_multi_aff_free(contraction);
1419 isl_union_map_free(expansion);
1420 return NULL;
1423 /* Return the extension of the extension tree root.
1425 __isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
1426 __isl_take isl_schedule_tree *tree)
1428 if (!tree)
1429 return NULL;
1431 if (tree->type != isl_schedule_node_extension)
1432 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1433 "not an extension node", return NULL);
1435 return isl_union_map_copy(tree->extension);
1438 /* Replace the extension of extension tree root "tree" by "extension".
1440 __isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
1441 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
1443 tree = isl_schedule_tree_cow(tree);
1444 if (!tree || !extension)
1445 goto error;
1447 if (tree->type != isl_schedule_node_extension)
1448 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1449 "not an extension node", return NULL);
1450 isl_union_map_free(tree->extension);
1451 tree->extension = extension;
1453 return tree;
1454 error:
1455 isl_schedule_tree_free(tree);
1456 isl_union_map_free(extension);
1457 return NULL;
1460 /* Return the filter of the filter tree root.
1462 __isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
1463 __isl_keep isl_schedule_tree *tree)
1465 if (!tree)
1466 return NULL;
1468 if (tree->type != isl_schedule_node_filter)
1469 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1470 "not a filter node", return NULL);
1472 return isl_union_set_copy(tree->filter);
1475 /* Replace the filter of the filter tree root by "filter".
1477 __isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
1478 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
1480 tree = isl_schedule_tree_cow(tree);
1481 if (!tree || !filter)
1482 goto error;
1484 if (tree->type != isl_schedule_node_filter)
1485 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1486 "not a filter node", return NULL);
1488 isl_union_set_free(tree->filter);
1489 tree->filter = filter;
1491 return tree;
1492 error:
1493 isl_schedule_tree_free(tree);
1494 isl_union_set_free(filter);
1495 return NULL;
1498 /* Return the guard of the guard tree root.
1500 __isl_give isl_set *isl_schedule_tree_guard_get_guard(
1501 __isl_take isl_schedule_tree *tree)
1503 if (!tree)
1504 return NULL;
1506 if (tree->type != isl_schedule_node_guard)
1507 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1508 "not a guard node", return NULL);
1510 return isl_set_copy(tree->guard);
1513 /* Return the mark identifier of the mark tree root "tree".
1515 __isl_give isl_id *isl_schedule_tree_mark_get_id(
1516 __isl_keep isl_schedule_tree *tree)
1518 if (!tree)
1519 return NULL;
1521 if (tree->type != isl_schedule_node_mark)
1522 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1523 "not a mark node", return NULL);
1525 return isl_id_copy(tree->mark);
1528 /* Set dim to the range dimension of "map" and abort the search.
1530 static isl_stat set_range_dim(__isl_take isl_map *map, void *user)
1532 int *dim = user;
1534 *dim = isl_map_dim(map, isl_dim_out);
1535 isl_map_free(map);
1537 return isl_stat_error;
1540 /* Return the dimension of the range of "umap".
1541 * "umap" is assumed not to be empty and
1542 * all maps inside "umap" are assumed to have the same range.
1544 * We extract the range dimension from the first map in "umap".
1546 static int range_dim(__isl_keep isl_union_map *umap)
1548 int dim = -1;
1550 if (!umap)
1551 return -1;
1552 if (isl_union_map_n_map(umap) == 0)
1553 isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
1554 "unexpected empty input", return -1);
1556 isl_union_map_foreach_map(umap, &set_range_dim, &dim);
1558 return dim;
1561 /* Append an "extra" number of zeros to the range of "umap" and
1562 * return the result.
1564 static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
1565 int extra)
1567 isl_union_set *dom;
1568 isl_space *space;
1569 isl_multi_val *mv;
1570 isl_union_pw_multi_aff *suffix;
1571 isl_union_map *universe;
1572 isl_union_map *suffix_umap;
1574 universe = isl_union_map_universe(isl_union_map_copy(umap));
1575 dom = isl_union_map_domain(universe);
1576 space = isl_union_set_get_space(dom);
1577 space = isl_space_set_from_params(space);
1578 space = isl_space_add_dims(space, isl_dim_set, extra);
1579 mv = isl_multi_val_zero(space);
1581 suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
1582 suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
1583 umap = isl_union_map_flat_range_product(umap, suffix_umap);
1585 return umap;
1588 /* Should we skip the root of "tree" while looking for the first
1589 * descendant with schedule information?
1590 * That is, is it impossible to derive any information about
1591 * the iteration domain from this node?
1593 * We do not want to skip leaf or error nodes because there is
1594 * no point in looking any deeper from these nodes.
1595 * We can only extract partial iteration domain information
1596 * from an extension node, but extension nodes are not supported
1597 * by the caller and it will error out on them.
1599 static isl_bool domain_less(__isl_keep isl_schedule_tree *tree)
1601 enum isl_schedule_node_type type;
1603 type = isl_schedule_tree_get_type(tree);
1604 switch (type) {
1605 case isl_schedule_node_band:
1606 return isl_schedule_tree_band_n_member(tree) == 0;
1607 case isl_schedule_node_context:
1608 case isl_schedule_node_guard:
1609 case isl_schedule_node_mark:
1610 return isl_bool_true;
1611 case isl_schedule_node_leaf:
1612 case isl_schedule_node_error:
1613 case isl_schedule_node_domain:
1614 case isl_schedule_node_expansion:
1615 case isl_schedule_node_extension:
1616 case isl_schedule_node_filter:
1617 case isl_schedule_node_set:
1618 case isl_schedule_node_sequence:
1619 return isl_bool_false;
1622 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1623 "unhandled case", return isl_bool_error);
1626 /* Move down to the first descendant of "tree" that contains any schedule
1627 * information or return "leaf" if there is no such descendant.
1629 __isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
1630 __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
1632 isl_bool down;
1634 while ((down = domain_less(tree)) == isl_bool_true) {
1635 if (!isl_schedule_tree_has_children(tree)) {
1636 isl_schedule_tree_free(tree);
1637 return isl_schedule_tree_copy(leaf);
1639 tree = isl_schedule_tree_child(tree, 0);
1642 if (down < 0)
1643 return isl_schedule_tree_free(tree);
1645 return tree;
1648 static __isl_give isl_union_map *subtree_schedule_extend(
1649 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);
1651 /* Extend the schedule map "outer" with the subtree schedule
1652 * of the (single) child of "tree", if any.
1654 * If "tree" does not have any descendants (apart from those that
1655 * do not carry any schedule information), then we simply return "outer".
1656 * Otherwise, we extend the schedule map "outer" with the subtree schedule
1657 * of the single child.
1659 static __isl_give isl_union_map *subtree_schedule_extend_child(
1660 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1662 isl_schedule_tree *child;
1663 isl_union_map *res;
1665 if (!tree)
1666 return isl_union_map_free(outer);
1667 if (!isl_schedule_tree_has_children(tree))
1668 return outer;
1669 child = isl_schedule_tree_get_child(tree, 0);
1670 if (!child)
1671 return isl_union_map_free(outer);
1672 res = subtree_schedule_extend(child, outer);
1673 isl_schedule_tree_free(child);
1674 return res;
1677 /* Extract the parameter space from one of the children of "tree",
1678 * which are assumed to be filters.
1680 static __isl_give isl_space *extract_space_from_filter_child(
1681 __isl_keep isl_schedule_tree *tree)
1683 isl_space *space;
1684 isl_union_set *dom;
1685 isl_schedule_tree *child;
1687 child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
1688 dom = isl_schedule_tree_filter_get_filter(child);
1689 space = isl_union_set_get_space(dom);
1690 isl_union_set_free(dom);
1691 isl_schedule_tree_free(child);
1693 return space;
1696 /* Extend the schedule map "outer" with the subtree schedule
1697 * of a set or sequence node.
1699 * The schedule for the set or sequence node itself is composed of
1700 * pieces of the form
1702 * filter -> []
1704 * or
1706 * filter -> [index]
1708 * The first form is used if there is only a single child or
1709 * if the current node is a set node and the schedule_separate_components
1710 * option is not set.
1712 * Each of the pieces above is extended with the subtree schedule of
1713 * the child of the corresponding filter, if any, padded with zeros
1714 * to ensure that all pieces have the same range dimension.
1716 static __isl_give isl_union_map *subtree_schedule_extend_from_children(
1717 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1719 int i, n;
1720 int dim;
1721 int separate;
1722 isl_ctx *ctx;
1723 isl_val *v = NULL;
1724 isl_multi_val *mv;
1725 isl_space *space;
1726 isl_union_map *umap;
1728 n = isl_schedule_tree_n_children(tree);
1729 if (n < 0)
1730 return isl_union_map_free(outer);
1731 if (n == 0)
1732 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1733 "missing children", return isl_union_map_free(outer));
1735 ctx = isl_schedule_tree_get_ctx(tree);
1736 separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
1737 isl_options_get_schedule_separate_components(ctx));
1739 space = isl_space_params_alloc(ctx, 0);
1741 umap = isl_union_map_empty(isl_space_copy(space));
1742 space = isl_space_set_from_params(space);
1743 if (separate) {
1744 space = isl_space_add_dims(space, isl_dim_set, 1);
1745 v = isl_val_zero(ctx);
1747 mv = isl_multi_val_zero(space);
1749 dim = isl_multi_val_dim(mv, isl_dim_set);
1750 for (i = 0; i < n; ++i) {
1751 isl_multi_val *mv_copy;
1752 isl_union_pw_multi_aff *upma;
1753 isl_union_map *umap_i;
1754 isl_union_set *dom;
1755 isl_schedule_tree *child;
1756 int dim_i;
1757 isl_bool empty;
1759 child = isl_schedule_tree_list_get_schedule_tree(
1760 tree->children, i);
1761 dom = isl_schedule_tree_filter_get_filter(child);
1763 if (separate) {
1764 mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
1765 v = isl_val_add_ui(v, 1);
1767 mv_copy = isl_multi_val_copy(mv);
1768 space = isl_union_set_get_space(dom);
1769 mv_copy = isl_multi_val_align_params(mv_copy, space);
1770 upma = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv_copy);
1771 umap_i = isl_union_map_from_union_pw_multi_aff(upma);
1772 umap_i = isl_union_map_flat_range_product(
1773 isl_union_map_copy(outer), umap_i);
1774 umap_i = subtree_schedule_extend_child(child, umap_i);
1775 isl_schedule_tree_free(child);
1777 empty = isl_union_map_is_empty(umap_i);
1778 if (empty < 0)
1779 umap_i = isl_union_map_free(umap_i);
1780 else if (empty) {
1781 isl_union_map_free(umap_i);
1782 continue;
1785 dim_i = range_dim(umap_i);
1786 if (dim_i < 0) {
1787 umap = isl_union_map_free(umap);
1788 } else if (dim < dim_i) {
1789 umap = append_range(umap, dim_i - dim);
1790 dim = dim_i;
1791 } else if (dim_i < dim) {
1792 umap_i = append_range(umap_i, dim - dim_i);
1794 umap = isl_union_map_union(umap, umap_i);
1797 isl_val_free(v);
1798 isl_multi_val_free(mv);
1799 isl_union_map_free(outer);
1801 return umap;
1804 /* Extend the schedule map "outer" with the subtree schedule of "tree".
1806 * If the root of the tree is a set or a sequence, then we extend
1807 * the schedule map in subtree_schedule_extend_from_children.
1808 * Otherwise, we extend the schedule map with the partial schedule
1809 * corresponding to the root of the tree and then continue with
1810 * the single child of this root.
1811 * In the special case of an expansion, the schedule map is "extended"
1812 * by applying the expansion to the domain of the schedule map.
1814 static __isl_give isl_union_map *subtree_schedule_extend(
1815 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
1817 isl_multi_union_pw_aff *mupa;
1818 isl_union_map *umap;
1819 isl_union_set *domain;
1821 if (!tree)
1822 return NULL;
1824 switch (tree->type) {
1825 case isl_schedule_node_error:
1826 return isl_union_map_free(outer);
1827 case isl_schedule_node_extension:
1828 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1829 "cannot construct subtree schedule of tree "
1830 "with extension nodes",
1831 return isl_union_map_free(outer));
1832 case isl_schedule_node_context:
1833 case isl_schedule_node_guard:
1834 case isl_schedule_node_mark:
1835 return subtree_schedule_extend_child(tree, outer);
1836 case isl_schedule_node_band:
1837 if (isl_schedule_tree_band_n_member(tree) == 0)
1838 return subtree_schedule_extend_child(tree, outer);
1839 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1840 umap = isl_union_map_from_multi_union_pw_aff(mupa);
1841 outer = isl_union_map_flat_range_product(outer, umap);
1842 umap = subtree_schedule_extend_child(tree, outer);
1843 break;
1844 case isl_schedule_node_domain:
1845 domain = isl_schedule_tree_domain_get_domain(tree);
1846 umap = isl_union_map_from_domain(domain);
1847 outer = isl_union_map_flat_range_product(outer, umap);
1848 umap = subtree_schedule_extend_child(tree, outer);
1849 break;
1850 case isl_schedule_node_expansion:
1851 umap = isl_schedule_tree_expansion_get_expansion(tree);
1852 outer = isl_union_map_apply_domain(outer, umap);
1853 umap = subtree_schedule_extend_child(tree, outer);
1854 break;
1855 case isl_schedule_node_filter:
1856 domain = isl_schedule_tree_filter_get_filter(tree);
1857 umap = isl_union_map_from_domain(domain);
1858 outer = isl_union_map_flat_range_product(outer, umap);
1859 umap = subtree_schedule_extend_child(tree, outer);
1860 break;
1861 case isl_schedule_node_leaf:
1862 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1863 "leaf node should be handled by caller", return NULL);
1864 case isl_schedule_node_set:
1865 case isl_schedule_node_sequence:
1866 umap = subtree_schedule_extend_from_children(tree, outer);
1867 break;
1870 return umap;
1873 static __isl_give isl_union_set *initial_domain(
1874 __isl_keep isl_schedule_tree *tree);
1876 /* Extract a universe domain from the children of the tree root "tree",
1877 * which is a set or sequence, meaning that its children are filters.
1878 * In particular, return the union of the universes of the filters.
1880 static __isl_give isl_union_set *initial_domain_from_children(
1881 __isl_keep isl_schedule_tree *tree)
1883 int i, n;
1884 isl_space *space;
1885 isl_union_set *domain;
1887 n = isl_schedule_tree_n_children(tree);
1888 if (n < 0)
1889 return NULL;
1890 if (n == 0)
1891 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1892 "missing children", return NULL);
1894 space = extract_space_from_filter_child(tree);
1895 domain = isl_union_set_empty(space);
1897 for (i = 0; i < n; ++i) {
1898 isl_schedule_tree *child;
1899 isl_union_set *domain_i;
1901 child = isl_schedule_tree_get_child(tree, i);
1902 domain_i = initial_domain(child);
1903 domain = isl_union_set_union(domain, domain_i);
1904 isl_schedule_tree_free(child);
1907 return domain;
1910 /* Extract a universe domain from the tree root "tree".
1911 * The caller is responsible for making sure that this node
1912 * would not be skipped by isl_schedule_tree_first_schedule_descendant
1913 * and that it is not a leaf node.
1915 static __isl_give isl_union_set *initial_domain(
1916 __isl_keep isl_schedule_tree *tree)
1918 isl_multi_union_pw_aff *mupa;
1919 isl_union_set *domain;
1920 isl_union_map *exp;
1922 if (!tree)
1923 return NULL;
1925 switch (tree->type) {
1926 case isl_schedule_node_error:
1927 return NULL;
1928 case isl_schedule_node_context:
1929 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1930 "context node should be handled by caller",
1931 return NULL);
1932 case isl_schedule_node_guard:
1933 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1934 "guard node should be handled by caller",
1935 return NULL);
1936 case isl_schedule_node_mark:
1937 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1938 "mark node should be handled by caller",
1939 return NULL);
1940 case isl_schedule_node_extension:
1941 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
1942 "cannot construct subtree schedule of tree "
1943 "with extension nodes", return NULL);
1944 case isl_schedule_node_band:
1945 if (isl_schedule_tree_band_n_member(tree) == 0)
1946 isl_die(isl_schedule_tree_get_ctx(tree),
1947 isl_error_internal,
1948 "0D band should be handled by caller",
1949 return NULL);
1950 mupa = isl_schedule_band_get_partial_schedule(tree->band);
1951 domain = isl_multi_union_pw_aff_domain(mupa);
1952 domain = isl_union_set_universe(domain);
1953 break;
1954 case isl_schedule_node_domain:
1955 domain = isl_schedule_tree_domain_get_domain(tree);
1956 domain = isl_union_set_universe(domain);
1957 break;
1958 case isl_schedule_node_expansion:
1959 exp = isl_schedule_tree_expansion_get_expansion(tree);
1960 exp = isl_union_map_universe(exp);
1961 domain = isl_union_map_domain(exp);
1962 break;
1963 case isl_schedule_node_filter:
1964 domain = isl_schedule_tree_filter_get_filter(tree);
1965 domain = isl_union_set_universe(domain);
1966 break;
1967 case isl_schedule_node_leaf:
1968 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
1969 "leaf node should be handled by caller", return NULL);
1970 case isl_schedule_node_set:
1971 case isl_schedule_node_sequence:
1972 domain = initial_domain_from_children(tree);
1973 break;
1976 return domain;
1979 /* Return the subtree schedule of a node that contains some schedule
1980 * information, i.e., a node that would not be skipped by
1981 * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
1983 * If the tree contains any expansions, then the returned subtree
1984 * schedule is formulated in terms of the expanded domains.
1985 * The tree is not allowed to contain any extension nodes.
1987 * We start with an initial zero-dimensional subtree schedule based
1988 * on the domain information in the root node and then extend it
1989 * based on the schedule information in the root node and its descendants.
1991 __isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
1992 __isl_keep isl_schedule_tree *tree)
1994 isl_union_set *domain;
1995 isl_union_map *umap;
1997 domain = initial_domain(tree);
1998 umap = isl_union_map_from_domain(domain);
1999 return subtree_schedule_extend(tree, umap);
2002 /* Multiply the partial schedule of the band root node of "tree"
2003 * with the factors in "mv".
2005 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
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(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 /* Divide the partial schedule of the band root node of "tree"
2030 * by the factors in "mv".
2032 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
2033 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
2035 if (!tree || !mv)
2036 goto error;
2037 if (tree->type != isl_schedule_node_band)
2038 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2039 "not a band node", goto error);
2041 tree = isl_schedule_tree_cow(tree);
2042 if (!tree)
2043 goto error;
2045 tree->band = isl_schedule_band_scale_down(tree->band, mv);
2046 if (!tree->band)
2047 return isl_schedule_tree_free(tree);
2049 return tree;
2050 error:
2051 isl_schedule_tree_free(tree);
2052 isl_multi_val_free(mv);
2053 return NULL;
2056 /* Reduce the partial schedule of the band root node of "tree"
2057 * modulo the factors in "mv".
2059 __isl_give isl_schedule_tree *isl_schedule_tree_band_mod(
2060 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
2062 if (!tree || !mv)
2063 goto error;
2064 if (tree->type != isl_schedule_node_band)
2065 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2066 "not a band node", goto error);
2068 tree = isl_schedule_tree_cow(tree);
2069 if (!tree)
2070 goto error;
2072 tree->band = isl_schedule_band_mod(tree->band, mv);
2073 if (!tree->band)
2074 return isl_schedule_tree_free(tree);
2076 return tree;
2077 error:
2078 isl_schedule_tree_free(tree);
2079 isl_multi_val_free(mv);
2080 return NULL;
2083 /* Shift the partial schedule of the band root node of "tree" by "shift".
2085 __isl_give isl_schedule_tree *isl_schedule_tree_band_shift(
2086 __isl_take isl_schedule_tree *tree,
2087 __isl_take isl_multi_union_pw_aff *shift)
2089 if (!tree || !shift)
2090 goto error;
2091 if (tree->type != isl_schedule_node_band)
2092 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2093 "not a band node", goto error);
2095 tree = isl_schedule_tree_cow(tree);
2096 if (!tree)
2097 goto error;
2099 tree->band = isl_schedule_band_shift(tree->band, shift);
2100 if (!tree->band)
2101 return isl_schedule_tree_free(tree);
2103 return tree;
2104 error:
2105 isl_schedule_tree_free(tree);
2106 isl_multi_union_pw_aff_free(shift);
2107 return NULL;
2110 /* Given two trees with sequence roots, replace the child at position
2111 * "pos" of "tree" with the children of "child".
2113 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
2114 __isl_take isl_schedule_tree *tree, int pos,
2115 __isl_take isl_schedule_tree *child)
2117 int n;
2118 isl_schedule_tree_list *list1, *list2;
2120 tree = isl_schedule_tree_cow(tree);
2121 if (!tree || !child)
2122 goto error;
2123 if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
2124 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2125 "not a sequence node", goto error);
2126 n = isl_schedule_tree_n_children(tree);
2127 if (pos < 0 || pos >= n)
2128 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2129 "position out of bounds", goto error);
2130 if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence)
2131 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2132 "not a sequence node", goto error);
2134 list1 = isl_schedule_tree_list_copy(tree->children);
2135 list1 = isl_schedule_tree_list_drop(list1, pos, n - pos);
2136 list2 = isl_schedule_tree_list_copy(tree->children);
2137 list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1);
2138 list1 = isl_schedule_tree_list_concat(list1,
2139 isl_schedule_tree_list_copy(child->children));
2140 list1 = isl_schedule_tree_list_concat(list1, list2);
2142 isl_schedule_tree_free(tree);
2143 isl_schedule_tree_free(child);
2144 return isl_schedule_tree_from_children(isl_schedule_node_sequence,
2145 list1);
2146 error:
2147 isl_schedule_tree_free(tree);
2148 isl_schedule_tree_free(child);
2149 return NULL;
2152 /* Tile the band root node of "tree" with tile sizes "sizes".
2154 * We duplicate the band node, change the schedule of one of them
2155 * to the tile schedule and the other to the point schedule and then
2156 * attach the point band as a child to the tile band.
2158 __isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
2159 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
2161 isl_schedule_tree *child = NULL;
2163 if (!tree || !sizes)
2164 goto error;
2165 if (tree->type != isl_schedule_node_band)
2166 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2167 "not a band node", goto error);
2169 child = isl_schedule_tree_copy(tree);
2170 tree = isl_schedule_tree_cow(tree);
2171 child = isl_schedule_tree_cow(child);
2172 if (!tree || !child)
2173 goto error;
2175 tree->band = isl_schedule_band_tile(tree->band,
2176 isl_multi_val_copy(sizes));
2177 if (!tree->band)
2178 goto error;
2179 child->band = isl_schedule_band_point(child->band, tree->band, sizes);
2180 if (!child->band)
2181 child = isl_schedule_tree_free(child);
2183 tree = isl_schedule_tree_replace_child(tree, 0, child);
2185 return tree;
2186 error:
2187 isl_schedule_tree_free(child);
2188 isl_schedule_tree_free(tree);
2189 isl_multi_val_free(sizes);
2190 return NULL;
2193 /* Given an isolate AST generation option "isolate" for a band of size pos + n,
2194 * return the corresponding option for a band covering the first "pos"
2195 * members.
2197 * The input isolate option is of the form
2199 * isolate[[flattened outer bands] -> [pos; n]]
2201 * The output isolate option is of the form
2203 * isolate[[flattened outer bands] -> [pos]]
2205 static __isl_give isl_set *isolate_initial(__isl_keep isl_set *isolate,
2206 int pos, int n)
2208 isl_id *id;
2209 isl_map *map;
2211 isolate = isl_set_copy(isolate);
2212 id = isl_set_get_tuple_id(isolate);
2213 map = isl_set_unwrap(isolate);
2214 map = isl_map_project_out(map, isl_dim_out, pos, n);
2215 isolate = isl_map_wrap(map);
2216 isolate = isl_set_set_tuple_id(isolate, id);
2218 return isolate;
2221 /* Given an isolate AST generation option "isolate" for a band of size pos + n,
2222 * return the corresponding option for a band covering the final "n"
2223 * members within a band covering the first "pos" members.
2225 * The input isolate option is of the form
2227 * isolate[[flattened outer bands] -> [pos; n]]
2229 * The output isolate option is of the form
2231 * isolate[[flattened outer bands; pos] -> [n]]
2234 * The range is first split into
2236 * isolate[[flattened outer bands] -> [[pos] -> [n]]]
2238 * and then the first pos members are moved to the domain
2240 * isolate[[[flattened outer bands] -> [pos]] -> [n]]
2242 * after which the domain is flattened to obtain the desired output.
2244 static __isl_give isl_set *isolate_final(__isl_keep isl_set *isolate,
2245 int pos, int n)
2247 isl_id *id;
2248 isl_space *space;
2249 isl_multi_aff *ma1, *ma2;
2250 isl_map *map;
2252 isolate = isl_set_copy(isolate);
2253 id = isl_set_get_tuple_id(isolate);
2254 map = isl_set_unwrap(isolate);
2255 space = isl_space_range(isl_map_get_space(map));
2256 ma1 = isl_multi_aff_project_out_map(isl_space_copy(space),
2257 isl_dim_set, pos, n);
2258 ma2 = isl_multi_aff_project_out_map(space, isl_dim_set, 0, pos);
2259 ma1 = isl_multi_aff_range_product(ma1, ma2);
2260 map = isl_map_apply_range(map, isl_map_from_multi_aff(ma1));
2261 map = isl_map_uncurry(map);
2262 map = isl_map_flatten_domain(map);
2263 isolate = isl_map_wrap(map);
2264 isolate = isl_set_set_tuple_id(isolate, id);
2266 return isolate;
2269 /* Split the band root node of "tree" into two nested band nodes,
2270 * one with the first "pos" dimensions and
2271 * one with the remaining dimensions.
2272 * The tree is itself positioned at schedule depth "depth".
2274 * The loop AST generation type options and the isolate option
2275 * are split over the two band nodes.
2277 __isl_give isl_schedule_tree *isl_schedule_tree_band_split(
2278 __isl_take isl_schedule_tree *tree, int pos, int depth)
2280 int n;
2281 isl_set *isolate, *tree_isolate, *child_isolate;
2282 isl_schedule_tree *child;
2284 if (!tree)
2285 return NULL;
2286 if (tree->type != isl_schedule_node_band)
2287 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2288 "not a band node", return isl_schedule_tree_free(tree));
2290 n = isl_schedule_tree_band_n_member(tree);
2291 if (pos < 0 || pos > n)
2292 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2293 "position out of bounds",
2294 return isl_schedule_tree_free(tree));
2296 child = isl_schedule_tree_copy(tree);
2297 tree = isl_schedule_tree_cow(tree);
2298 child = isl_schedule_tree_cow(child);
2299 if (!tree || !child)
2300 goto error;
2302 isolate = isl_schedule_tree_band_get_ast_isolate_option(tree, depth);
2303 tree_isolate = isolate_initial(isolate, pos, n - pos);
2304 child_isolate = isolate_final(isolate, pos, n - pos);
2305 child->band = isl_schedule_band_drop(child->band, 0, pos);
2306 child->band = isl_schedule_band_replace_ast_build_option(child->band,
2307 isl_set_copy(isolate), child_isolate);
2308 tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
2309 tree->band = isl_schedule_band_replace_ast_build_option(tree->band,
2310 isl_set_copy(isolate), tree_isolate);
2311 isl_set_free(isolate);
2312 if (!child->band || !tree->band)
2313 goto error;
2315 tree = isl_schedule_tree_replace_child(tree, 0, child);
2317 return tree;
2318 error:
2319 isl_schedule_tree_free(child);
2320 isl_schedule_tree_free(tree);
2321 return NULL;
2324 /* Attach "tree2" at each of the leaves of "tree1".
2326 * If "tree1" does not have any explicit children, then make "tree2"
2327 * its single child. Otherwise, attach "tree2" to the leaves of
2328 * each of the children of "tree1".
2330 __isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
2331 __isl_take isl_schedule_tree *tree1,
2332 __isl_take isl_schedule_tree *tree2)
2334 int i, n;
2336 if (!tree1 || !tree2)
2337 goto error;
2338 n = isl_schedule_tree_n_children(tree1);
2339 if (n == 0) {
2340 isl_schedule_tree_list *list;
2341 list = isl_schedule_tree_list_from_schedule_tree(tree2);
2342 tree1 = isl_schedule_tree_set_children(tree1, list);
2343 return tree1;
2345 for (i = 0; i < n; ++i) {
2346 isl_schedule_tree *child;
2348 child = isl_schedule_tree_get_child(tree1, i);
2349 child = isl_schedule_tree_append_to_leaves(child,
2350 isl_schedule_tree_copy(tree2));
2351 tree1 = isl_schedule_tree_replace_child(tree1, i, child);
2354 isl_schedule_tree_free(tree2);
2355 return tree1;
2356 error:
2357 isl_schedule_tree_free(tree1);
2358 isl_schedule_tree_free(tree2);
2359 return NULL;
2362 /* Reset the user pointer on all identifiers of parameters and tuples
2363 * in the root of "tree".
2365 __isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
2366 __isl_take isl_schedule_tree *tree)
2368 if (isl_schedule_tree_is_leaf(tree))
2369 return tree;
2371 tree = isl_schedule_tree_cow(tree);
2372 if (!tree)
2373 return NULL;
2375 switch (tree->type) {
2376 case isl_schedule_node_error:
2377 return isl_schedule_tree_free(tree);
2378 case isl_schedule_node_band:
2379 tree->band = isl_schedule_band_reset_user(tree->band);
2380 if (!tree->band)
2381 return isl_schedule_tree_free(tree);
2382 break;
2383 case isl_schedule_node_context:
2384 tree->context = isl_set_reset_user(tree->context);
2385 if (!tree->context)
2386 return isl_schedule_tree_free(tree);
2387 break;
2388 case isl_schedule_node_domain:
2389 tree->domain = isl_union_set_reset_user(tree->domain);
2390 if (!tree->domain)
2391 return isl_schedule_tree_free(tree);
2392 break;
2393 case isl_schedule_node_expansion:
2394 tree->contraction =
2395 isl_union_pw_multi_aff_reset_user(tree->contraction);
2396 tree->expansion = isl_union_map_reset_user(tree->expansion);
2397 if (!tree->contraction || !tree->expansion)
2398 return isl_schedule_tree_free(tree);
2399 break;
2400 case isl_schedule_node_extension:
2401 tree->extension = isl_union_map_reset_user(tree->extension);
2402 if (!tree->extension)
2403 return isl_schedule_tree_free(tree);
2404 break;
2405 case isl_schedule_node_filter:
2406 tree->filter = isl_union_set_reset_user(tree->filter);
2407 if (!tree->filter)
2408 return isl_schedule_tree_free(tree);
2409 break;
2410 case isl_schedule_node_guard:
2411 tree->guard = isl_set_reset_user(tree->guard);
2412 if (!tree->guard)
2413 return isl_schedule_tree_free(tree);
2414 break;
2415 case isl_schedule_node_leaf:
2416 case isl_schedule_node_mark:
2417 case isl_schedule_node_sequence:
2418 case isl_schedule_node_set:
2419 break;
2422 return tree;
2425 /* Align the parameters of the root of "tree" to those of "space".
2427 __isl_give isl_schedule_tree *isl_schedule_tree_align_params(
2428 __isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
2430 if (!space)
2431 goto error;
2433 if (isl_schedule_tree_is_leaf(tree)) {
2434 isl_space_free(space);
2435 return tree;
2438 tree = isl_schedule_tree_cow(tree);
2439 if (!tree)
2440 goto error;
2442 switch (tree->type) {
2443 case isl_schedule_node_error:
2444 goto error;
2445 case isl_schedule_node_band:
2446 tree->band = isl_schedule_band_align_params(tree->band, space);
2447 if (!tree->band)
2448 return isl_schedule_tree_free(tree);
2449 break;
2450 case isl_schedule_node_context:
2451 tree->context = isl_set_align_params(tree->context, space);
2452 if (!tree->context)
2453 return isl_schedule_tree_free(tree);
2454 break;
2455 case isl_schedule_node_domain:
2456 tree->domain = isl_union_set_align_params(tree->domain, space);
2457 if (!tree->domain)
2458 return isl_schedule_tree_free(tree);
2459 break;
2460 case isl_schedule_node_expansion:
2461 tree->contraction =
2462 isl_union_pw_multi_aff_align_params(tree->contraction,
2463 isl_space_copy(space));
2464 tree->expansion = isl_union_map_align_params(tree->expansion,
2465 space);
2466 if (!tree->contraction || !tree->expansion)
2467 return isl_schedule_tree_free(tree);
2468 break;
2469 case isl_schedule_node_extension:
2470 tree->extension = isl_union_map_align_params(tree->extension,
2471 space);
2472 if (!tree->extension)
2473 return isl_schedule_tree_free(tree);
2474 break;
2475 case isl_schedule_node_filter:
2476 tree->filter = isl_union_set_align_params(tree->filter, space);
2477 if (!tree->filter)
2478 return isl_schedule_tree_free(tree);
2479 break;
2480 case isl_schedule_node_guard:
2481 tree->guard = isl_set_align_params(tree->guard, space);
2482 if (!tree->guard)
2483 return isl_schedule_tree_free(tree);
2484 break;
2485 case isl_schedule_node_leaf:
2486 case isl_schedule_node_mark:
2487 case isl_schedule_node_sequence:
2488 case isl_schedule_node_set:
2489 isl_space_free(space);
2490 break;
2493 return tree;
2494 error:
2495 isl_space_free(space);
2496 isl_schedule_tree_free(tree);
2497 return NULL;
2500 /* Does "tree" involve the iteration domain?
2501 * That is, does it need to be modified
2502 * by isl_schedule_tree_pullback_union_pw_multi_aff?
2504 static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
2506 if (!tree)
2507 return -1;
2509 switch (tree->type) {
2510 case isl_schedule_node_error:
2511 return -1;
2512 case isl_schedule_node_band:
2513 case isl_schedule_node_domain:
2514 case isl_schedule_node_expansion:
2515 case isl_schedule_node_extension:
2516 case isl_schedule_node_filter:
2517 return 1;
2518 case isl_schedule_node_context:
2519 case isl_schedule_node_leaf:
2520 case isl_schedule_node_guard:
2521 case isl_schedule_node_mark:
2522 case isl_schedule_node_sequence:
2523 case isl_schedule_node_set:
2524 return 0;
2527 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
2528 "unhandled case", return -1);
2531 /* Compute the pullback of the root node of "tree" by the function
2532 * represented by "upma".
2533 * In other words, plug in "upma" in the iteration domains of
2534 * the root node of "tree".
2535 * We currently do not handle expansion nodes.
2537 * We first check if the root node involves any iteration domains.
2538 * If so, we handle the specific cases.
2540 __isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
2541 __isl_take isl_schedule_tree *tree,
2542 __isl_take isl_union_pw_multi_aff *upma)
2544 int involves;
2546 if (!tree || !upma)
2547 goto error;
2549 involves = involves_iteration_domain(tree);
2550 if (involves < 0)
2551 goto error;
2552 if (!involves) {
2553 isl_union_pw_multi_aff_free(upma);
2554 return tree;
2557 tree = isl_schedule_tree_cow(tree);
2558 if (!tree)
2559 goto error;
2561 if (tree->type == isl_schedule_node_band) {
2562 tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
2563 tree->band, upma);
2564 if (!tree->band)
2565 return isl_schedule_tree_free(tree);
2566 } else if (tree->type == isl_schedule_node_domain) {
2567 tree->domain =
2568 isl_union_set_preimage_union_pw_multi_aff(tree->domain,
2569 upma);
2570 if (!tree->domain)
2571 return isl_schedule_tree_free(tree);
2572 } else if (tree->type == isl_schedule_node_expansion) {
2573 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
2574 "cannot pullback expansion node", goto error);
2575 } else if (tree->type == isl_schedule_node_extension) {
2576 tree->extension =
2577 isl_union_map_preimage_range_union_pw_multi_aff(
2578 tree->extension, upma);
2579 if (!tree->extension)
2580 return isl_schedule_tree_free(tree);
2581 } else if (tree->type == isl_schedule_node_filter) {
2582 tree->filter =
2583 isl_union_set_preimage_union_pw_multi_aff(tree->filter,
2584 upma);
2585 if (!tree->filter)
2586 return isl_schedule_tree_free(tree);
2589 return tree;
2590 error:
2591 isl_union_pw_multi_aff_free(upma);
2592 isl_schedule_tree_free(tree);
2593 return NULL;
2596 /* Compute the gist of the band tree root with respect to "context".
2598 __isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
2599 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
2601 if (!tree)
2602 return NULL;
2603 if (tree->type != isl_schedule_node_band)
2604 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
2605 "not a band node", goto error);
2606 tree = isl_schedule_tree_cow(tree);
2607 if (!tree)
2608 goto error;
2610 tree->band = isl_schedule_band_gist(tree->band, context);
2611 if (!tree->band)
2612 return isl_schedule_tree_free(tree);
2613 return tree;
2614 error:
2615 isl_union_set_free(context);
2616 isl_schedule_tree_free(tree);
2617 return NULL;
2620 /* Are any members in "band" marked coincident?
2622 static isl_bool any_coincident(__isl_keep isl_schedule_band *band)
2624 int i, n;
2626 n = isl_schedule_band_n_member(band);
2627 for (i = 0; i < n; ++i) {
2628 isl_bool coincident;
2630 coincident = isl_schedule_band_member_get_coincident(band, i);
2631 if (coincident < 0 || coincident)
2632 return coincident;
2635 return isl_bool_false;
2638 /* Print the band node "band" to "p".
2640 * The permutable and coincident properties are only printed if they
2641 * are different from the defaults.
2642 * The coincident property is always printed in YAML flow style.
2644 static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
2645 __isl_keep isl_schedule_band *band)
2647 isl_union_set *options;
2648 isl_bool empty;
2649 isl_bool coincident;
2651 p = isl_printer_print_str(p, "schedule");
2652 p = isl_printer_yaml_next(p);
2653 p = isl_printer_print_str(p, "\"");
2654 p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
2655 p = isl_printer_print_str(p, "\"");
2656 if (isl_schedule_band_get_permutable(band)) {
2657 p = isl_printer_yaml_next(p);
2658 p = isl_printer_print_str(p, "permutable");
2659 p = isl_printer_yaml_next(p);
2660 p = isl_printer_print_int(p, 1);
2662 coincident = any_coincident(band);
2663 if (coincident < 0)
2664 return isl_printer_free(p);
2665 if (coincident) {
2666 int i, n;
2667 int style;
2669 p = isl_printer_yaml_next(p);
2670 p = isl_printer_print_str(p, "coincident");
2671 p = isl_printer_yaml_next(p);
2672 style = isl_printer_get_yaml_style(p);
2673 p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
2674 p = isl_printer_yaml_start_sequence(p);
2675 n = isl_schedule_band_n_member(band);
2676 for (i = 0; i < n; ++i) {
2677 p = isl_printer_print_int(p,
2678 isl_schedule_band_member_get_coincident(band, i));
2679 p = isl_printer_yaml_next(p);
2681 p = isl_printer_yaml_end_sequence(p);
2682 p = isl_printer_set_yaml_style(p, style);
2684 options = isl_schedule_band_get_ast_build_options(band);
2685 empty = isl_union_set_is_empty(options);
2686 if (empty < 0)
2687 p = isl_printer_free(p);
2688 if (!empty) {
2689 p = isl_printer_yaml_next(p);
2690 p = isl_printer_print_str(p, "options");
2691 p = isl_printer_yaml_next(p);
2692 p = isl_printer_print_str(p, "\"");
2693 p = isl_printer_print_union_set(p, options);
2694 p = isl_printer_print_str(p, "\"");
2696 isl_union_set_free(options);
2698 return p;
2701 /* Print "tree" to "p".
2703 * If "n_ancestor" is non-negative, then "child_pos" contains the child
2704 * positions of a descendant of the current node that should be marked
2705 * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor"
2706 * is zero, then the current node should be marked.
2707 * The marking is only printed in YAML block format.
2709 * Implicit leaf nodes are not printed, except if they correspond
2710 * to the node that should be marked.
2712 __isl_give isl_printer *isl_printer_print_schedule_tree_mark(
2713 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
2714 int n_ancestor, int *child_pos)
2716 int i, n;
2717 int sequence = 0;
2718 int block;
2720 block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;
2722 p = isl_printer_yaml_start_mapping(p);
2723 if (n_ancestor == 0 && block) {
2724 p = isl_printer_print_str(p, "# YOU ARE HERE");
2725 p = isl_printer_end_line(p);
2726 p = isl_printer_start_line(p);
2728 switch (tree->type) {
2729 case isl_schedule_node_error:
2730 p = isl_printer_print_str(p, "ERROR");
2731 break;
2732 case isl_schedule_node_leaf:
2733 p = isl_printer_print_str(p, "leaf");
2734 break;
2735 case isl_schedule_node_sequence:
2736 p = isl_printer_print_str(p, "sequence");
2737 sequence = 1;
2738 break;
2739 case isl_schedule_node_set:
2740 p = isl_printer_print_str(p, "set");
2741 sequence = 1;
2742 break;
2743 case isl_schedule_node_context:
2744 p = isl_printer_print_str(p, "context");
2745 p = isl_printer_yaml_next(p);
2746 p = isl_printer_print_str(p, "\"");
2747 p = isl_printer_print_set(p, tree->context);
2748 p = isl_printer_print_str(p, "\"");
2749 break;
2750 case isl_schedule_node_domain:
2751 p = isl_printer_print_str(p, "domain");
2752 p = isl_printer_yaml_next(p);
2753 p = isl_printer_print_str(p, "\"");
2754 p = isl_printer_print_union_set(p, tree->domain);
2755 p = isl_printer_print_str(p, "\"");
2756 break;
2757 case isl_schedule_node_expansion:
2758 p = isl_printer_print_str(p, "contraction");
2759 p = isl_printer_yaml_next(p);
2760 p = isl_printer_print_str(p, "\"");
2761 p = isl_printer_print_union_pw_multi_aff(p, tree->contraction);
2762 p = isl_printer_print_str(p, "\"");
2763 p = isl_printer_yaml_next(p);
2764 p = isl_printer_print_str(p, "expansion");
2765 p = isl_printer_yaml_next(p);
2766 p = isl_printer_print_str(p, "\"");
2767 p = isl_printer_print_union_map(p, tree->expansion);
2768 p = isl_printer_print_str(p, "\"");
2769 break;
2770 case isl_schedule_node_extension:
2771 p = isl_printer_print_str(p, "extension");
2772 p = isl_printer_yaml_next(p);
2773 p = isl_printer_print_str(p, "\"");
2774 p = isl_printer_print_union_map(p, tree->extension);
2775 p = isl_printer_print_str(p, "\"");
2776 break;
2777 case isl_schedule_node_filter:
2778 p = isl_printer_print_str(p, "filter");
2779 p = isl_printer_yaml_next(p);
2780 p = isl_printer_print_str(p, "\"");
2781 p = isl_printer_print_union_set(p, tree->filter);
2782 p = isl_printer_print_str(p, "\"");
2783 break;
2784 case isl_schedule_node_guard:
2785 p = isl_printer_print_str(p, "guard");
2786 p = isl_printer_yaml_next(p);
2787 p = isl_printer_print_str(p, "\"");
2788 p = isl_printer_print_set(p, tree->guard);
2789 p = isl_printer_print_str(p, "\"");
2790 break;
2791 case isl_schedule_node_mark:
2792 p = isl_printer_print_str(p, "mark");
2793 p = isl_printer_yaml_next(p);
2794 p = isl_printer_print_str(p, "\"");
2795 p = isl_printer_print_str(p, isl_id_get_name(tree->mark));
2796 p = isl_printer_print_str(p, "\"");
2797 break;
2798 case isl_schedule_node_band:
2799 p = print_tree_band(p, tree->band);
2800 break;
2802 p = isl_printer_yaml_next(p);
2804 n = isl_schedule_tree_n_children(tree);
2805 if (n < 0)
2806 return isl_printer_free(p);
2807 if (n == 0) {
2808 if (n_ancestor > 0 && block) {
2809 isl_schedule_tree *leaf;
2811 p = isl_printer_print_str(p, "child");
2812 p = isl_printer_yaml_next(p);
2813 leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
2814 p = isl_printer_print_schedule_tree_mark(p,
2815 leaf, 0, NULL);
2816 isl_schedule_tree_free(leaf);
2817 p = isl_printer_yaml_next(p);
2819 return isl_printer_yaml_end_mapping(p);
2822 if (sequence) {
2823 p = isl_printer_yaml_start_sequence(p);
2824 } else {
2825 p = isl_printer_print_str(p, "child");
2826 p = isl_printer_yaml_next(p);
2829 for (i = 0; i < n; ++i) {
2830 isl_schedule_tree *t;
2832 t = isl_schedule_tree_get_child(tree, i);
2833 if (n_ancestor > 0 && child_pos[0] == i)
2834 p = isl_printer_print_schedule_tree_mark(p, t,
2835 n_ancestor - 1, child_pos + 1);
2836 else
2837 p = isl_printer_print_schedule_tree_mark(p, t,
2838 -1, NULL);
2839 isl_schedule_tree_free(t);
2841 p = isl_printer_yaml_next(p);
2844 if (sequence)
2845 p = isl_printer_yaml_end_sequence(p);
2846 p = isl_printer_yaml_end_mapping(p);
2848 return p;
2851 /* Print "tree" to "p".
2853 __isl_give isl_printer *isl_printer_print_schedule_tree(
2854 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
2856 return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
2859 void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
2861 isl_ctx *ctx;
2862 isl_printer *printer;
2864 if (!tree)
2865 return;
2867 ctx = isl_schedule_tree_get_ctx(tree);
2868 printer = isl_printer_to_file(ctx, stderr);
2869 printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
2870 printer = isl_printer_print_schedule_tree(printer, tree);
2872 isl_printer_free(printer);