LCOV - code coverage report
Current view: top level - metalib_isl - isl_schedule_tree.c (source / functions) Hit Total Coverage
Test: 2018-10-31_point_maint_greina16.lcov Lines: 0 1305 0.0 %
Date: 2018-11-01 11:27:00 Functions: 0 102 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2013-2014 Ecole Normale Superieure
       3             :  * Copyright 2014      INRIA Rocquencourt
       4             :  * Copyright 2016      INRIA Paris
       5             :  *
       6             :  * Use of this software is governed by the MIT license
       7             :  *
       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
      14             :  */
      15             : 
      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>
      22             : 
      23             : #undef EL
      24             : #define EL isl_schedule_tree
      25             : 
      26             : #include <isl_list_templ.h>
      27             : 
      28             : #undef BASE
      29             : #define BASE schedule_tree
      30             : 
      31             : #include <isl_list_templ.c>
      32             : 
      33             : /* Is "tree" the leaf of a schedule tree?
      34             :  */
      35           0 : int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree)
      36             : {
      37           0 :         return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf;
      38             : }
      39             : 
      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.
      43             :  *
      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.
      46             :  */
      47           0 : static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx,
      48             :         enum isl_schedule_node_type type)
      49             : {
      50             :         isl_schedule_tree *tree;
      51             : 
      52           0 :         if (type == isl_schedule_node_error)
      53           0 :                 return NULL;
      54             : 
      55           0 :         tree = isl_calloc_type(ctx, isl_schedule_tree);
      56           0 :         if (!tree)
      57           0 :                 return NULL;
      58             : 
      59           0 :         tree->ref = 1;
      60           0 :         tree->ctx = ctx;
      61           0 :         isl_ctx_ref(ctx);
      62           0 :         tree->type = type;
      63           0 :         tree->anchored = 0;
      64             : 
      65           0 :         return tree;
      66             : }
      67             : 
      68             : /* Return a fresh copy of "tree".
      69             :  */
      70           0 : __isl_take isl_schedule_tree *isl_schedule_tree_dup(
      71             :         __isl_keep isl_schedule_tree *tree)
      72             : {
      73             :         isl_ctx *ctx;
      74             :         isl_schedule_tree *dup;
      75             : 
      76           0 :         if (!tree)
      77           0 :                 return NULL;
      78             : 
      79           0 :         ctx = isl_schedule_tree_get_ctx(tree);
      80           0 :         dup = isl_schedule_tree_alloc(ctx, tree->type);
      81           0 :         if (!dup)
      82           0 :                 return NULL;
      83             : 
      84           0 :         switch (tree->type) {
      85             :         case isl_schedule_node_error:
      86           0 :                 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           0 :                 dup->band = isl_schedule_band_copy(tree->band);
      91           0 :                 if (!dup->band)
      92           0 :                         return isl_schedule_tree_free(dup);
      93           0 :                 break;
      94             :         case isl_schedule_node_context:
      95           0 :                 dup->context = isl_set_copy(tree->context);
      96           0 :                 if (!dup->context)
      97           0 :                         return isl_schedule_tree_free(dup);
      98           0 :                 break;
      99             :         case isl_schedule_node_domain:
     100           0 :                 dup->domain = isl_union_set_copy(tree->domain);
     101           0 :                 if (!dup->domain)
     102           0 :                         return isl_schedule_tree_free(dup);
     103           0 :                 break;
     104             :         case isl_schedule_node_expansion:
     105           0 :                 dup->contraction =
     106           0 :                         isl_union_pw_multi_aff_copy(tree->contraction);
     107           0 :                 dup->expansion = isl_union_map_copy(tree->expansion);
     108           0 :                 if (!dup->contraction || !dup->expansion)
     109           0 :                         return isl_schedule_tree_free(dup);
     110           0 :                 break;
     111             :         case isl_schedule_node_extension:
     112           0 :                 dup->extension = isl_union_map_copy(tree->extension);
     113           0 :                 if (!dup->extension)
     114           0 :                         return isl_schedule_tree_free(dup);
     115           0 :                 break;
     116             :         case isl_schedule_node_filter:
     117           0 :                 dup->filter = isl_union_set_copy(tree->filter);
     118           0 :                 if (!dup->filter)
     119           0 :                         return isl_schedule_tree_free(dup);
     120           0 :                 break;
     121             :         case isl_schedule_node_guard:
     122           0 :                 dup->guard = isl_set_copy(tree->guard);
     123           0 :                 if (!dup->guard)
     124           0 :                         return isl_schedule_tree_free(dup);
     125           0 :                 break;
     126             :         case isl_schedule_node_mark:
     127           0 :                 dup->mark = isl_id_copy(tree->mark);
     128           0 :                 if (!dup->mark)
     129           0 :                         return isl_schedule_tree_free(dup);
     130           0 :                 break;
     131             :         case isl_schedule_node_leaf:
     132             :         case isl_schedule_node_sequence:
     133             :         case isl_schedule_node_set:
     134           0 :                 break;
     135             :         }
     136             : 
     137           0 :         if (tree->children) {
     138           0 :                 dup->children = isl_schedule_tree_list_copy(tree->children);
     139           0 :                 if (!dup->children)
     140           0 :                         return isl_schedule_tree_free(dup);
     141             :         }
     142           0 :         dup->anchored = tree->anchored;
     143             : 
     144           0 :         return dup;
     145             : }
     146             : 
     147             : /* Return an isl_schedule_tree that is equal to "tree" and that has only
     148             :  * a single reference.
     149             :  */
     150           0 : __isl_give isl_schedule_tree *isl_schedule_tree_cow(
     151             :         __isl_take isl_schedule_tree *tree)
     152             : {
     153           0 :         if (!tree)
     154           0 :                 return NULL;
     155             : 
     156           0 :         if (tree->ref == 1)
     157           0 :                 return tree;
     158           0 :         tree->ref--;
     159           0 :         return isl_schedule_tree_dup(tree);
     160             : }
     161             : 
     162             : /* Return a new reference to "tree".
     163             :  */
     164           0 : __isl_give isl_schedule_tree *isl_schedule_tree_copy(
     165             :         __isl_keep isl_schedule_tree *tree)
     166             : {
     167           0 :         if (!tree)
     168           0 :                 return NULL;
     169             : 
     170           0 :         tree->ref++;
     171           0 :         return tree;
     172             : }
     173             : 
     174             : /* Free "tree" and return NULL.
     175             :  */
     176           0 : __isl_null isl_schedule_tree *isl_schedule_tree_free(
     177             :         __isl_take isl_schedule_tree *tree)
     178             : {
     179           0 :         if (!tree)
     180           0 :                 return NULL;
     181           0 :         if (--tree->ref > 0)
     182           0 :                 return NULL;
     183             : 
     184           0 :         switch (tree->type) {
     185             :         case isl_schedule_node_band:
     186           0 :                 isl_schedule_band_free(tree->band);
     187           0 :                 break;
     188             :         case isl_schedule_node_context:
     189           0 :                 isl_set_free(tree->context);
     190           0 :                 break;
     191             :         case isl_schedule_node_domain:
     192           0 :                 isl_union_set_free(tree->domain);
     193           0 :                 break;
     194             :         case isl_schedule_node_expansion:
     195           0 :                 isl_union_pw_multi_aff_free(tree->contraction);
     196           0 :                 isl_union_map_free(tree->expansion);
     197           0 :                 break;
     198             :         case isl_schedule_node_extension:
     199           0 :                 isl_union_map_free(tree->extension);
     200           0 :                 break;
     201             :         case isl_schedule_node_filter:
     202           0 :                 isl_union_set_free(tree->filter);
     203           0 :                 break;
     204             :         case isl_schedule_node_guard:
     205           0 :                 isl_set_free(tree->guard);
     206           0 :                 break;
     207             :         case isl_schedule_node_mark:
     208           0 :                 isl_id_free(tree->mark);
     209           0 :                 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           0 :                 break;
     215             :         }
     216           0 :         isl_schedule_tree_list_free(tree->children);
     217           0 :         isl_ctx_deref(tree->ctx);
     218           0 :         free(tree);
     219             : 
     220           0 :         return NULL;
     221             : }
     222             : 
     223             : /* Create and return a new leaf schedule tree.
     224             :  */
     225           0 : __isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx)
     226             : {
     227           0 :         return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf);
     228             : }
     229             : 
     230             : /* Create a new band schedule tree referring to "band"
     231             :  * with no children.
     232             :  */
     233           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_band(
     234             :         __isl_take isl_schedule_band *band)
     235             : {
     236             :         isl_ctx *ctx;
     237             :         isl_schedule_tree *tree;
     238             : 
     239           0 :         if (!band)
     240           0 :                 return NULL;
     241             : 
     242           0 :         ctx = isl_schedule_band_get_ctx(band);
     243           0 :         tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band);
     244           0 :         if (!tree)
     245           0 :                 goto error;
     246             : 
     247           0 :         tree->band = band;
     248           0 :         tree->anchored = isl_schedule_band_is_anchored(band);
     249             : 
     250           0 :         return tree;
     251             : error:
     252           0 :         isl_schedule_band_free(band);
     253           0 :         return NULL;
     254             : }
     255             : 
     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.
     259             :  */
     260           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_context(
     261             :         __isl_take isl_set *context)
     262             : {
     263             :         isl_ctx *ctx;
     264             :         isl_schedule_tree *tree;
     265             : 
     266           0 :         if (!context)
     267           0 :                 return NULL;
     268             : 
     269           0 :         ctx = isl_set_get_ctx(context);
     270           0 :         tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context);
     271           0 :         if (!tree)
     272           0 :                 goto error;
     273             : 
     274           0 :         tree->context = context;
     275           0 :         tree->anchored = 1;
     276             : 
     277           0 :         return tree;
     278             : error:
     279           0 :         isl_set_free(context);
     280           0 :         return NULL;
     281             : }
     282             : 
     283             : /* Create a new domain schedule tree with the given domain and no children.
     284             :  */
     285           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
     286             :         __isl_take isl_union_set *domain)
     287             : {
     288             :         isl_ctx *ctx;
     289             :         isl_schedule_tree *tree;
     290             : 
     291           0 :         if (!domain)
     292           0 :                 return NULL;
     293             : 
     294           0 :         ctx = isl_union_set_get_ctx(domain);
     295           0 :         tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain);
     296           0 :         if (!tree)
     297           0 :                 goto error;
     298             : 
     299           0 :         tree->domain = domain;
     300             : 
     301           0 :         return tree;
     302             : error:
     303           0 :         isl_union_set_free(domain);
     304           0 :         return NULL;
     305             : }
     306             : 
     307             : /* Create a new expansion schedule tree with the given contraction and
     308             :  * expansion and no children.
     309             :  */
     310           0 : __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)
     313             : {
     314             :         isl_ctx *ctx;
     315             :         isl_schedule_tree *tree;
     316             : 
     317           0 :         if (!contraction || !expansion)
     318             :                 goto error;
     319             : 
     320           0 :         ctx = isl_union_map_get_ctx(expansion);
     321           0 :         tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion);
     322           0 :         if (!tree)
     323           0 :                 goto error;
     324             : 
     325           0 :         tree->contraction = contraction;
     326           0 :         tree->expansion = expansion;
     327             : 
     328           0 :         return tree;
     329             : error:
     330           0 :         isl_union_pw_multi_aff_free(contraction);
     331           0 :         isl_union_map_free(expansion);
     332           0 :         return NULL;
     333             : }
     334             : 
     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.
     339             :  */
     340           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_extension(
     341             :         __isl_take isl_union_map *extension)
     342             : {
     343             :         isl_ctx *ctx;
     344             :         isl_schedule_tree *tree;
     345             : 
     346           0 :         if (!extension)
     347           0 :                 return NULL;
     348             : 
     349           0 :         ctx = isl_union_map_get_ctx(extension);
     350           0 :         tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension);
     351           0 :         if (!tree)
     352           0 :                 goto error;
     353             : 
     354           0 :         tree->extension = extension;
     355           0 :         tree->anchored = 1;
     356             : 
     357           0 :         return tree;
     358             : error:
     359           0 :         isl_union_map_free(extension);
     360           0 :         return NULL;
     361             : }
     362             : 
     363             : /* Create a new filter schedule tree with the given filter and no children.
     364             :  */
     365           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
     366             :         __isl_take isl_union_set *filter)
     367             : {
     368             :         isl_ctx *ctx;
     369             :         isl_schedule_tree *tree;
     370             : 
     371           0 :         if (!filter)
     372           0 :                 return NULL;
     373             : 
     374           0 :         ctx = isl_union_set_get_ctx(filter);
     375           0 :         tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter);
     376           0 :         if (!tree)
     377           0 :                 goto error;
     378             : 
     379           0 :         tree->filter = filter;
     380             : 
     381           0 :         return tree;
     382             : error:
     383           0 :         isl_union_set_free(filter);
     384           0 :         return NULL;
     385             : }
     386             : 
     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.
     390             :  */
     391           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
     392             :         __isl_take isl_set *guard)
     393             : {
     394             :         isl_ctx *ctx;
     395             :         isl_schedule_tree *tree;
     396             : 
     397           0 :         if (!guard)
     398           0 :                 return NULL;
     399             : 
     400           0 :         ctx = isl_set_get_ctx(guard);
     401           0 :         tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard);
     402           0 :         if (!tree)
     403           0 :                 goto error;
     404             : 
     405           0 :         tree->guard = guard;
     406           0 :         tree->anchored = 1;
     407             : 
     408           0 :         return tree;
     409             : error:
     410           0 :         isl_set_free(guard);
     411           0 :         return NULL;
     412             : }
     413             : 
     414             : /* Create a new mark schedule tree with the given mark identifier and
     415             :  * no children.
     416             :  */
     417           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_mark(
     418             :         __isl_take isl_id *mark)
     419             : {
     420             :         isl_ctx *ctx;
     421             :         isl_schedule_tree *tree;
     422             : 
     423           0 :         if (!mark)
     424           0 :                 return NULL;
     425             : 
     426           0 :         ctx = isl_id_get_ctx(mark);
     427           0 :         tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark);
     428           0 :         if (!tree)
     429           0 :                 goto error;
     430             : 
     431           0 :         tree->mark = mark;
     432             : 
     433           0 :         return tree;
     434             : error:
     435           0 :         isl_id_free(mark);
     436           0 :         return NULL;
     437             : }
     438             : 
     439             : /* Does "tree" have any node that depends on its position
     440             :  * in the complete schedule tree?
     441             :  */
     442           0 : isl_bool isl_schedule_tree_is_subtree_anchored(
     443             :         __isl_keep isl_schedule_tree *tree)
     444             : {
     445           0 :         return tree ? tree->anchored : isl_bool_error;
     446             : }
     447             : 
     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.
     452             :  */
     453           0 : int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
     454             : {
     455           0 :         if (!tree)
     456           0 :                 return -1;
     457             : 
     458           0 :         switch (isl_schedule_tree_get_type(tree)) {
     459             :         case isl_schedule_node_error:
     460           0 :                 return -1;
     461             :         case isl_schedule_node_band:
     462           0 :                 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           0 :                 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           0 :                 return 0;
     475             :         }
     476             : 
     477           0 :         isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
     478             :                 "unhandled case", return -1);
     479             : }
     480             : 
     481             : /* Update the anchored field of "tree" based on whether the root node
     482             :  * itself in anchored and the anchored fields of the children.
     483             :  *
     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.
     486             :  */
     487           0 : __isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
     488             :         __isl_take isl_schedule_tree *tree)
     489             : {
     490             :         int i, n;
     491             :         int anchored;
     492             : 
     493           0 :         if (!tree)
     494           0 :                 return NULL;
     495             : 
     496           0 :         anchored = isl_schedule_tree_is_anchored(tree);
     497           0 :         if (anchored < 0)
     498           0 :                 return isl_schedule_tree_free(tree);
     499             : 
     500           0 :         n = isl_schedule_tree_list_n_schedule_tree(tree->children);
     501           0 :         for (i = 0; !anchored && i < n; ++i) {
     502             :                 isl_schedule_tree *child;
     503             : 
     504           0 :                 child = isl_schedule_tree_get_child(tree, i);
     505           0 :                 if (!child)
     506           0 :                         return isl_schedule_tree_free(tree);
     507           0 :                 anchored = child->anchored;
     508           0 :                 isl_schedule_tree_free(child);
     509             :         }
     510             : 
     511           0 :         if (anchored == tree->anchored)
     512           0 :                 return tree;
     513           0 :         tree = isl_schedule_tree_cow(tree);
     514           0 :         if (!tree)
     515           0 :                 return NULL;
     516           0 :         tree->anchored = anchored;
     517           0 :         return tree;
     518             : }
     519             : 
     520             : /* Create a new tree of the given type (isl_schedule_node_sequence or
     521             :  * isl_schedule_node_set) with the given children.
     522             :  */
     523           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_children(
     524             :         enum isl_schedule_node_type type,
     525             :         __isl_take isl_schedule_tree_list *list)
     526             : {
     527             :         isl_ctx *ctx;
     528             :         isl_schedule_tree *tree;
     529             : 
     530           0 :         if (!list)
     531           0 :                 return NULL;
     532             : 
     533           0 :         ctx = isl_schedule_tree_list_get_ctx(list);
     534           0 :         tree = isl_schedule_tree_alloc(ctx, type);
     535           0 :         if (!tree)
     536           0 :                 goto error;
     537             : 
     538           0 :         tree->children = list;
     539           0 :         tree = isl_schedule_tree_update_anchored(tree);
     540             : 
     541           0 :         return tree;
     542             : error:
     543           0 :         isl_schedule_tree_list_free(list);
     544           0 :         return NULL;
     545             : }
     546             : 
     547             : /* Construct a tree with a root node of type "type" and as children
     548             :  * "tree1" and "tree2".
     549             :  * If the root of one (or both) of the input trees is itself of type "type",
     550             :  * then the tree is replaced by its children.
     551             :  */
     552           0 : __isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
     553             :         enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
     554             :         __isl_take isl_schedule_tree *tree2)
     555             : {
     556             :         isl_ctx *ctx;
     557             :         isl_schedule_tree_list *list;
     558             : 
     559           0 :         if (!tree1 || !tree2)
     560             :                 goto error;
     561             : 
     562           0 :         ctx = isl_schedule_tree_get_ctx(tree1);
     563           0 :         if (isl_schedule_tree_get_type(tree1) == type) {
     564           0 :                 list = isl_schedule_tree_list_copy(tree1->children);
     565           0 :                 isl_schedule_tree_free(tree1);
     566             :         } else {
     567           0 :                 list = isl_schedule_tree_list_alloc(ctx, 2);
     568           0 :                 list = isl_schedule_tree_list_add(list, tree1);
     569             :         }
     570           0 :         if (isl_schedule_tree_get_type(tree2) == type) {
     571             :                 isl_schedule_tree_list *children;
     572             : 
     573           0 :                 children = isl_schedule_tree_list_copy(tree2->children);
     574           0 :                 list = isl_schedule_tree_list_concat(list, children);
     575           0 :                 isl_schedule_tree_free(tree2);
     576             :         } else {
     577           0 :                 list = isl_schedule_tree_list_add(list, tree2);
     578             :         }
     579             : 
     580           0 :         return isl_schedule_tree_from_children(type, list);
     581             : error:
     582           0 :         isl_schedule_tree_free(tree1);
     583           0 :         isl_schedule_tree_free(tree2);
     584           0 :         return NULL;
     585             : }
     586             : 
     587             : /* Construct a tree with a sequence root node and as children
     588             :  * "tree1" and "tree2".
     589             :  * If the root of one (or both) of the input trees is itself a sequence,
     590             :  * then the tree is replaced by its children.
     591             :  */
     592           0 : __isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
     593             :         __isl_take isl_schedule_tree *tree1,
     594             :         __isl_take isl_schedule_tree *tree2)
     595             : {
     596           0 :         return isl_schedule_tree_from_pair(isl_schedule_node_sequence,
     597             :                                                 tree1, tree2);
     598             : }
     599             : 
     600             : /* Construct a tree with a set root node and as children
     601             :  * "tree1" and "tree2".
     602             :  * If the root of one (or both) of the input trees is itself a set,
     603             :  * then the tree is replaced by its children.
     604             :  */
     605           0 : __isl_give isl_schedule_tree *isl_schedule_tree_set_pair(
     606             :         __isl_take isl_schedule_tree *tree1,
     607             :         __isl_take isl_schedule_tree *tree2)
     608             : {
     609           0 :         return isl_schedule_tree_from_pair(isl_schedule_node_set, tree1, tree2);
     610             : }
     611             : 
     612             : /* Return the isl_ctx to which "tree" belongs.
     613             :  */
     614           0 : isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
     615             : {
     616           0 :         return tree ? tree->ctx : NULL;
     617             : }
     618             : 
     619             : /* Return the type of the root of the tree or isl_schedule_node_error
     620             :  * on error.
     621             :  */
     622           0 : enum isl_schedule_node_type isl_schedule_tree_get_type(
     623             :         __isl_keep isl_schedule_tree *tree)
     624             : {
     625           0 :         return tree ? tree->type : isl_schedule_node_error;
     626             : }
     627             : 
     628             : /* Are "tree1" and "tree2" obviously equal to each other?
     629             :  */
     630           0 : isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
     631             :         __isl_keep isl_schedule_tree *tree2)
     632             : {
     633             :         isl_bool equal;
     634             :         int i, n;
     635             : 
     636           0 :         if (!tree1 || !tree2)
     637           0 :                 return isl_bool_error;
     638           0 :         if (tree1 == tree2)
     639           0 :                 return isl_bool_true;
     640           0 :         if (tree1->type != tree2->type)
     641           0 :                 return isl_bool_false;
     642             : 
     643           0 :         switch (tree1->type) {
     644             :         case isl_schedule_node_band:
     645           0 :                 equal = isl_schedule_band_plain_is_equal(tree1->band,
     646             :                                                         tree2->band);
     647           0 :                 break;
     648             :         case isl_schedule_node_context:
     649           0 :                 equal = isl_set_is_equal(tree1->context, tree2->context);
     650           0 :                 break;
     651             :         case isl_schedule_node_domain:
     652           0 :                 equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
     653           0 :                 break;
     654             :         case isl_schedule_node_expansion:
     655           0 :                 equal = isl_union_map_is_equal(tree1->expansion,
     656             :                                                 tree2->expansion);
     657           0 :                 if (equal >= 0 && equal)
     658           0 :                         equal = isl_union_pw_multi_aff_plain_is_equal(
     659             :                                     tree1->contraction, tree2->contraction);
     660           0 :                 break;
     661             :         case isl_schedule_node_extension:
     662           0 :                 equal = isl_union_map_is_equal(tree1->extension,
     663             :                                                 tree2->extension);
     664           0 :                 break;
     665             :         case isl_schedule_node_filter:
     666           0 :                 equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
     667           0 :                 break;
     668             :         case isl_schedule_node_guard:
     669           0 :                 equal = isl_set_is_equal(tree1->guard, tree2->guard);
     670           0 :                 break;
     671             :         case isl_schedule_node_mark:
     672           0 :                 equal = tree1->mark == tree2->mark;
     673           0 :                 break;
     674             :         case isl_schedule_node_leaf:
     675             :         case isl_schedule_node_sequence:
     676             :         case isl_schedule_node_set:
     677           0 :                 equal = isl_bool_true;
     678           0 :                 break;
     679             :         case isl_schedule_node_error:
     680           0 :                 equal = isl_bool_error;
     681           0 :                 break;
     682             :         }
     683             : 
     684           0 :         if (equal < 0 || !equal)
     685           0 :                 return equal;
     686             : 
     687           0 :         n = isl_schedule_tree_n_children(tree1);
     688           0 :         if (n != isl_schedule_tree_n_children(tree2))
     689           0 :                 return isl_bool_false;
     690           0 :         for (i = 0; i < n; ++i) {
     691             :                 isl_schedule_tree *child1, *child2;
     692             : 
     693           0 :                 child1 = isl_schedule_tree_get_child(tree1, i);
     694           0 :                 child2 = isl_schedule_tree_get_child(tree2, i);
     695           0 :                 equal = isl_schedule_tree_plain_is_equal(child1, child2);
     696           0 :                 isl_schedule_tree_free(child1);
     697           0 :                 isl_schedule_tree_free(child2);
     698             : 
     699           0 :                 if (equal < 0 || !equal)
     700           0 :                         return equal;
     701             :         }
     702             : 
     703           0 :         return isl_bool_true;
     704             : }
     705             : 
     706             : /* Does "tree" have any children, other than an implicit leaf.
     707             :  */
     708           0 : int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
     709             : {
     710           0 :         if (!tree)
     711           0 :                 return -1;
     712             : 
     713           0 :         return tree->children != NULL;
     714             : }
     715             : 
     716             : /* Return the number of children of "tree", excluding implicit leaves.
     717             :  */
     718           0 : int isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
     719             : {
     720           0 :         if (!tree)
     721           0 :                 return -1;
     722             : 
     723           0 :         return isl_schedule_tree_list_n_schedule_tree(tree->children);
     724             : }
     725             : 
     726             : /* Return a copy of the (explicit) child at position "pos" of "tree".
     727             :  */
     728           0 : __isl_give isl_schedule_tree *isl_schedule_tree_get_child(
     729             :         __isl_keep isl_schedule_tree *tree, int pos)
     730             : {
     731           0 :         if (!tree)
     732           0 :                 return NULL;
     733           0 :         if (!tree->children)
     734           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
     735             :                         "schedule tree has no explicit children", return NULL);
     736           0 :         return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
     737             : }
     738             : 
     739             : /* Return a copy of the (explicit) child at position "pos" of "tree" and
     740             :  * free "tree".
     741             :  */
     742           0 : __isl_give isl_schedule_tree *isl_schedule_tree_child(
     743             :         __isl_take isl_schedule_tree *tree, int pos)
     744             : {
     745             :         isl_schedule_tree *child;
     746             : 
     747           0 :         child = isl_schedule_tree_get_child(tree, pos);
     748           0 :         isl_schedule_tree_free(tree);
     749           0 :         return child;
     750             : }
     751             : 
     752             : /* Remove all (explicit) children from "tree".
     753             :  */
     754           0 : __isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
     755             :         __isl_take isl_schedule_tree *tree)
     756             : {
     757           0 :         tree = isl_schedule_tree_cow(tree);
     758           0 :         if (!tree)
     759           0 :                 return NULL;
     760           0 :         tree->children = isl_schedule_tree_list_free(tree->children);
     761           0 :         return tree;
     762             : }
     763             : 
     764             : /* Remove the child at position "pos" from the children of "tree".
     765             :  * If there was only one child to begin with, then remove all children.
     766             :  */
     767           0 : __isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
     768             :         __isl_take isl_schedule_tree *tree, int pos)
     769             : {
     770             :         int n;
     771             : 
     772           0 :         tree = isl_schedule_tree_cow(tree);
     773           0 :         if (!tree)
     774           0 :                 return NULL;
     775             : 
     776           0 :         if (!isl_schedule_tree_has_children(tree))
     777           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
     778             :                         "tree does not have any explicit children",
     779             :                         return isl_schedule_tree_free(tree));
     780           0 :         n = isl_schedule_tree_list_n_schedule_tree(tree->children);
     781           0 :         if (pos < 0 || pos >= n)
     782           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
     783             :                         "position out of bounds",
     784             :                         return isl_schedule_tree_free(tree));
     785           0 :         if (n == 1)
     786           0 :                 return isl_schedule_tree_reset_children(tree);
     787             : 
     788           0 :         tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
     789           0 :         if (!tree->children)
     790           0 :                 return isl_schedule_tree_free(tree);
     791             : 
     792           0 :         return tree;
     793             : }
     794             : 
     795             : /* Replace the child at position "pos" of "tree" by "child".
     796             :  *
     797             :  * If the new child is a leaf, then it is not explicitly
     798             :  * recorded in the list of children.  Instead, the list of children
     799             :  * (which is assumed to have only one element) is removed.
     800             :  * Note that the children of set and sequence nodes are always
     801             :  * filters, so they cannot be replaced by empty trees.
     802             :  */
     803           0 : __isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
     804             :         __isl_take isl_schedule_tree *tree, int pos,
     805             :         __isl_take isl_schedule_tree *child)
     806             : {
     807           0 :         tree = isl_schedule_tree_cow(tree);
     808           0 :         if (!tree || !child)
     809             :                 goto error;
     810             : 
     811           0 :         if (isl_schedule_tree_is_leaf(child)) {
     812           0 :                 isl_schedule_tree_free(child);
     813           0 :                 if (!tree->children && pos == 0)
     814           0 :                         return tree;
     815           0 :                 if (isl_schedule_tree_n_children(tree) != 1)
     816           0 :                         isl_die(isl_schedule_tree_get_ctx(tree),
     817             :                                 isl_error_internal,
     818             :                                 "can only replace single child by leaf",
     819             :                                 goto error);
     820           0 :                 return isl_schedule_tree_reset_children(tree);
     821             :         }
     822             : 
     823           0 :         if (!tree->children && pos == 0)
     824           0 :                 tree->children =
     825           0 :                         isl_schedule_tree_list_from_schedule_tree(child);
     826             :         else
     827           0 :                 tree->children = isl_schedule_tree_list_set_schedule_tree(
     828           0 :                                 tree->children, pos, child);
     829             : 
     830           0 :         if (!tree->children)
     831           0 :                 return isl_schedule_tree_free(tree);
     832           0 :         tree = isl_schedule_tree_update_anchored(tree);
     833             : 
     834           0 :         return tree;
     835             : error:
     836           0 :         isl_schedule_tree_free(tree);
     837           0 :         isl_schedule_tree_free(child);
     838           0 :         return NULL;
     839             : }
     840             : 
     841             : /* Replace the (explicit) children of "tree" by "children"?
     842             :  */
     843           0 : __isl_give isl_schedule_tree *isl_schedule_tree_set_children(
     844             :         __isl_take isl_schedule_tree *tree,
     845             :         __isl_take isl_schedule_tree_list *children)
     846             : {
     847           0 :         tree = isl_schedule_tree_cow(tree);
     848           0 :         if (!tree || !children)
     849             :                 goto error;
     850           0 :         isl_schedule_tree_list_free(tree->children);
     851           0 :         tree->children = children;
     852           0 :         return tree;
     853             : error:
     854           0 :         isl_schedule_tree_free(tree);
     855           0 :         isl_schedule_tree_list_free(children);
     856           0 :         return NULL;
     857             : }
     858             : 
     859             : /* Create a new band schedule tree referring to "band"
     860             :  * with "tree" as single child.
     861             :  */
     862           0 : __isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
     863             :         __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
     864             : {
     865             :         isl_schedule_tree *res;
     866             : 
     867           0 :         res = isl_schedule_tree_from_band(band);
     868           0 :         return isl_schedule_tree_replace_child(res, 0, tree);
     869             : }
     870             : 
     871             : /* Create a new context schedule tree with the given context and
     872             :  * with "tree" as single child.
     873             :  */
     874           0 : __isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
     875             :         __isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
     876             : {
     877             :         isl_schedule_tree *res;
     878             : 
     879           0 :         res = isl_schedule_tree_from_context(context);
     880           0 :         return isl_schedule_tree_replace_child(res, 0, tree);
     881             : }
     882             : 
     883             : /* Create a new domain schedule tree with the given domain and
     884             :  * with "tree" as single child.
     885             :  */
     886           0 : __isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
     887             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
     888             : {
     889             :         isl_schedule_tree *res;
     890             : 
     891           0 :         res = isl_schedule_tree_from_domain(domain);
     892           0 :         return isl_schedule_tree_replace_child(res, 0, tree);
     893             : }
     894             : 
     895             : /* Create a new expansion schedule tree with the given contraction and
     896             :  * expansion and with "tree" as single child.
     897             :  */
     898           0 : __isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
     899             :         __isl_take isl_schedule_tree *tree,
     900             :         __isl_take isl_union_pw_multi_aff *contraction,
     901             :         __isl_take isl_union_map *expansion)
     902             : {
     903             :         isl_schedule_tree *res;
     904             : 
     905           0 :         res = isl_schedule_tree_from_expansion(contraction, expansion);
     906           0 :         return isl_schedule_tree_replace_child(res, 0, tree);
     907             : }
     908             : 
     909             : /* Create a new extension schedule tree with the given extension and
     910             :  * with "tree" as single child.
     911             :  */
     912           0 : __isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
     913             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
     914             : {
     915             :         isl_schedule_tree *res;
     916             : 
     917           0 :         res = isl_schedule_tree_from_extension(extension);
     918           0 :         return isl_schedule_tree_replace_child(res, 0, tree);
     919             : }
     920             : 
     921             : /* Create a new filter schedule tree with the given filter and single child.
     922             :  *
     923             :  * If the root of "tree" is itself a filter node, then the two
     924             :  * filter nodes are merged into one node.
     925             :  */
     926           0 : __isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
     927             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
     928             : {
     929             :         isl_schedule_tree *res;
     930             : 
     931           0 :         if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
     932             :                 isl_union_set *tree_filter;
     933             : 
     934           0 :                 tree_filter = isl_schedule_tree_filter_get_filter(tree);
     935           0 :                 tree_filter = isl_union_set_intersect(tree_filter, filter);
     936           0 :                 tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
     937           0 :                 return tree;
     938             :         }
     939             : 
     940           0 :         res = isl_schedule_tree_from_filter(filter);
     941           0 :         return isl_schedule_tree_replace_child(res, 0, tree);
     942             : }
     943             : 
     944             : /* Insert a filter node with filter set "filter"
     945             :  * in each of the children of "tree".
     946             :  */
     947           0 : __isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
     948             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
     949             : {
     950             :         int i, n;
     951             : 
     952           0 :         if (!tree || !filter)
     953             :                 goto error;
     954             : 
     955           0 :         n = isl_schedule_tree_n_children(tree);
     956           0 :         for (i = 0; i < n; ++i) {
     957             :                 isl_schedule_tree *child;
     958             : 
     959           0 :                 child = isl_schedule_tree_get_child(tree, i);
     960           0 :                 child = isl_schedule_tree_insert_filter(child,
     961             :                                                     isl_union_set_copy(filter));
     962           0 :                 tree = isl_schedule_tree_replace_child(tree, i, child);
     963             :         }
     964             : 
     965           0 :         isl_union_set_free(filter);
     966           0 :         return tree;
     967             : error:
     968           0 :         isl_union_set_free(filter);
     969           0 :         isl_schedule_tree_free(tree);
     970           0 :         return NULL;
     971             : }
     972             : 
     973             : /* Create a new guard schedule tree with the given guard and
     974             :  * with "tree" as single child.
     975             :  */
     976           0 : __isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
     977             :         __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
     978             : {
     979             :         isl_schedule_tree *res;
     980             : 
     981           0 :         res = isl_schedule_tree_from_guard(guard);
     982           0 :         return isl_schedule_tree_replace_child(res, 0, tree);
     983             : }
     984             : 
     985             : /* Create a new mark schedule tree with the given mark identifier and
     986             :  * single child.
     987             :  */
     988           0 : __isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
     989             :         __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
     990             : {
     991             :         isl_schedule_tree *res;
     992             : 
     993           0 :         res = isl_schedule_tree_from_mark(mark);
     994           0 :         return isl_schedule_tree_replace_child(res, 0, tree);
     995             : }
     996             : 
     997             : /* Return the number of members in the band tree root.
     998             :  */
     999           0 : unsigned isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
    1000             : {
    1001           0 :         if (!tree)
    1002           0 :                 return 0;
    1003             : 
    1004           0 :         if (tree->type != isl_schedule_node_band)
    1005           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1006             :                         "not a band node", return 0);
    1007             : 
    1008           0 :         return isl_schedule_band_n_member(tree->band);
    1009             : }
    1010             : 
    1011             : /* Is the band member at position "pos" of the band tree root
    1012             :  * marked coincident?
    1013             :  */
    1014           0 : isl_bool isl_schedule_tree_band_member_get_coincident(
    1015             :         __isl_keep isl_schedule_tree *tree, int pos)
    1016             : {
    1017           0 :         if (!tree)
    1018           0 :                 return isl_bool_error;
    1019             : 
    1020           0 :         if (tree->type != isl_schedule_node_band)
    1021           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1022             :                         "not a band node", return isl_bool_error);
    1023             : 
    1024           0 :         return isl_schedule_band_member_get_coincident(tree->band, pos);
    1025             : }
    1026             : 
    1027             : /* Mark the given band member as being coincident or not
    1028             :  * according to "coincident".
    1029             :  */
    1030           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
    1031             :         __isl_take isl_schedule_tree *tree, int pos, int coincident)
    1032             : {
    1033           0 :         if (!tree)
    1034           0 :                 return NULL;
    1035           0 :         if (tree->type != isl_schedule_node_band)
    1036           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1037             :                         "not a band node", return isl_schedule_tree_free(tree));
    1038           0 :         if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
    1039             :                                                                     coincident)
    1040           0 :                 return tree;
    1041           0 :         tree = isl_schedule_tree_cow(tree);
    1042           0 :         if (!tree)
    1043           0 :                 return NULL;
    1044             : 
    1045           0 :         tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
    1046             :                                                         coincident);
    1047           0 :         if (!tree->band)
    1048           0 :                 return isl_schedule_tree_free(tree);
    1049           0 :         return tree;
    1050             : }
    1051             : 
    1052             : /* Is the band tree root marked permutable?
    1053             :  */
    1054           0 : isl_bool isl_schedule_tree_band_get_permutable(
    1055             :         __isl_keep isl_schedule_tree *tree)
    1056             : {
    1057           0 :         if (!tree)
    1058           0 :                 return isl_bool_error;
    1059             : 
    1060           0 :         if (tree->type != isl_schedule_node_band)
    1061           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1062             :                         "not a band node", return isl_bool_error);
    1063             : 
    1064           0 :         return isl_schedule_band_get_permutable(tree->band);
    1065             : }
    1066             : 
    1067             : /* Mark the band tree root permutable or not according to "permutable"?
    1068             :  */
    1069           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
    1070             :         __isl_take isl_schedule_tree *tree, int permutable)
    1071             : {
    1072           0 :         if (!tree)
    1073           0 :                 return NULL;
    1074           0 :         if (tree->type != isl_schedule_node_band)
    1075           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1076             :                         "not a band node", return isl_schedule_tree_free(tree));
    1077           0 :         if (isl_schedule_tree_band_get_permutable(tree) == permutable)
    1078           0 :                 return tree;
    1079           0 :         tree = isl_schedule_tree_cow(tree);
    1080           0 :         if (!tree)
    1081           0 :                 return NULL;
    1082             : 
    1083           0 :         tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
    1084           0 :         if (!tree->band)
    1085           0 :                 return isl_schedule_tree_free(tree);
    1086           0 :         return tree;
    1087             : }
    1088             : 
    1089             : /* Return the schedule space of the band tree root.
    1090             :  */
    1091           0 : __isl_give isl_space *isl_schedule_tree_band_get_space(
    1092             :         __isl_keep isl_schedule_tree *tree)
    1093             : {
    1094           0 :         if (!tree)
    1095           0 :                 return NULL;
    1096             : 
    1097           0 :         if (tree->type != isl_schedule_node_band)
    1098           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1099             :                         "not a band node", return NULL);
    1100             : 
    1101           0 :         return isl_schedule_band_get_space(tree->band);
    1102             : }
    1103             : 
    1104             : /* Intersect the domain of the band schedule of the band tree root
    1105             :  * with "domain".
    1106             :  */
    1107           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
    1108             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
    1109             : {
    1110           0 :         if (!tree || !domain)
    1111             :                 goto error;
    1112             : 
    1113           0 :         if (tree->type != isl_schedule_node_band)
    1114           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1115             :                         "not a band node", goto error);
    1116             : 
    1117           0 :         tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
    1118           0 :         if (!tree->band)
    1119           0 :                 return isl_schedule_tree_free(tree);
    1120             : 
    1121           0 :         return tree;
    1122             : error:
    1123           0 :         isl_schedule_tree_free(tree);
    1124           0 :         isl_union_set_free(domain);
    1125           0 :         return NULL;
    1126             : }
    1127             : 
    1128             : /* Return the schedule of the band tree root in isolation.
    1129             :  */
    1130           0 : __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
    1131             :         __isl_keep isl_schedule_tree *tree)
    1132             : {
    1133           0 :         if (!tree)
    1134           0 :                 return NULL;
    1135             : 
    1136           0 :         if (tree->type != isl_schedule_node_band)
    1137           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1138             :                         "not a band node", return NULL);
    1139             : 
    1140           0 :         return isl_schedule_band_get_partial_schedule(tree->band);
    1141             : }
    1142             : 
    1143             : /* Replace the schedule of the band tree root by "schedule".
    1144             :  */
    1145           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
    1146             :         __isl_take isl_schedule_tree *tree,
    1147             :         __isl_take isl_multi_union_pw_aff *schedule)
    1148             : {
    1149           0 :         tree = isl_schedule_tree_cow(tree);
    1150           0 :         if (!tree || !schedule)
    1151             :                 goto error;
    1152             : 
    1153           0 :         if (tree->type != isl_schedule_node_band)
    1154           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1155             :                         "not a band node", return NULL);
    1156           0 :         tree->band = isl_schedule_band_set_partial_schedule(tree->band,
    1157             :                                                                 schedule);
    1158             : 
    1159           0 :         return tree;
    1160             : error:
    1161           0 :         isl_schedule_tree_free(tree);
    1162           0 :         isl_multi_union_pw_aff_free(schedule);
    1163           0 :         return NULL;
    1164             : }
    1165             : 
    1166             : /* Return the loop AST generation type for the band member
    1167             :  * of the band tree root at position "pos".
    1168             :  */
    1169           0 : enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
    1170             :         __isl_keep isl_schedule_tree *tree, int pos)
    1171             : {
    1172           0 :         if (!tree)
    1173           0 :                 return isl_ast_loop_error;
    1174             : 
    1175           0 :         if (tree->type != isl_schedule_node_band)
    1176           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1177             :                         "not a band node", return isl_ast_loop_error);
    1178             : 
    1179           0 :         return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
    1180             : }
    1181             : 
    1182             : /* Set the loop AST generation type for the band member of the band tree root
    1183             :  * at position "pos" to "type".
    1184             :  */
    1185           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
    1186             :         __isl_take isl_schedule_tree *tree, int pos,
    1187             :         enum isl_ast_loop_type type)
    1188             : {
    1189           0 :         tree = isl_schedule_tree_cow(tree);
    1190           0 :         if (!tree)
    1191           0 :                 return NULL;
    1192             : 
    1193           0 :         if (tree->type != isl_schedule_node_band)
    1194           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1195             :                         "not a band node", return isl_schedule_tree_free(tree));
    1196             : 
    1197           0 :         tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
    1198             :                                                                 pos, type);
    1199           0 :         if (!tree->band)
    1200           0 :                 return isl_schedule_tree_free(tree);
    1201             : 
    1202           0 :         return tree;
    1203             : }
    1204             : 
    1205             : /* Return the loop AST generation type for the band member
    1206             :  * of the band tree root at position "pos" for the isolated part.
    1207             :  */
    1208           0 : enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
    1209             :         __isl_keep isl_schedule_tree *tree, int pos)
    1210             : {
    1211           0 :         if (!tree)
    1212           0 :                 return isl_ast_loop_error;
    1213             : 
    1214           0 :         if (tree->type != isl_schedule_node_band)
    1215           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1216             :                         "not a band node", return isl_ast_loop_error);
    1217             : 
    1218           0 :         return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
    1219             :                                                                         pos);
    1220             : }
    1221             : 
    1222             : /* Set the loop AST generation type for the band member of the band tree root
    1223             :  * at position "pos" for the isolated part to "type".
    1224             :  */
    1225             : __isl_give isl_schedule_tree *
    1226           0 : isl_schedule_tree_band_member_set_isolate_ast_loop_type(
    1227             :         __isl_take isl_schedule_tree *tree, int pos,
    1228             :         enum isl_ast_loop_type type)
    1229             : {
    1230           0 :         tree = isl_schedule_tree_cow(tree);
    1231           0 :         if (!tree)
    1232           0 :                 return NULL;
    1233             : 
    1234           0 :         if (tree->type != isl_schedule_node_band)
    1235           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1236             :                         "not a band node", return isl_schedule_tree_free(tree));
    1237             : 
    1238           0 :         tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
    1239             :                                                         tree->band, pos, type);
    1240           0 :         if (!tree->band)
    1241           0 :                 return isl_schedule_tree_free(tree);
    1242             : 
    1243           0 :         return tree;
    1244             : }
    1245             : 
    1246             : /* Return the AST build options associated to the band tree root.
    1247             :  */
    1248           0 : __isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
    1249             :         __isl_keep isl_schedule_tree *tree)
    1250             : {
    1251           0 :         if (!tree)
    1252           0 :                 return NULL;
    1253             : 
    1254           0 :         if (tree->type != isl_schedule_node_band)
    1255           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1256             :                         "not a band node", return NULL);
    1257             : 
    1258           0 :         return isl_schedule_band_get_ast_build_options(tree->band);
    1259             : }
    1260             : 
    1261             : /* Replace the AST build options associated to band tree root by "options".
    1262             :  * Updated the anchored field if the anchoredness of the root node itself
    1263             :  * changes.
    1264             :  */
    1265           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
    1266             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
    1267             : {
    1268             :         int was_anchored;
    1269             : 
    1270           0 :         tree = isl_schedule_tree_cow(tree);
    1271           0 :         if (!tree || !options)
    1272             :                 goto error;
    1273             : 
    1274           0 :         if (tree->type != isl_schedule_node_band)
    1275           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1276             :                         "not a band node", goto error);
    1277             : 
    1278           0 :         was_anchored = isl_schedule_tree_is_anchored(tree);
    1279           0 :         tree->band = isl_schedule_band_set_ast_build_options(tree->band,
    1280             :                                                                 options);
    1281           0 :         if (!tree->band)
    1282           0 :                 return isl_schedule_tree_free(tree);
    1283           0 :         if (isl_schedule_tree_is_anchored(tree) != was_anchored)
    1284           0 :                 tree = isl_schedule_tree_update_anchored(tree);
    1285             : 
    1286           0 :         return tree;
    1287             : error:
    1288           0 :         isl_schedule_tree_free(tree);
    1289           0 :         isl_union_set_free(options);
    1290           0 :         return NULL;
    1291             : }
    1292             : 
    1293             : /* Return the "isolate" option associated to the band tree root of "tree",
    1294             :  * which is assumed to appear at schedule depth "depth".
    1295             :  */
    1296           0 : __isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option(
    1297             :         __isl_keep isl_schedule_tree *tree, int depth)
    1298             : {
    1299           0 :         if (!tree)
    1300           0 :                 return NULL;
    1301             : 
    1302           0 :         if (tree->type != isl_schedule_node_band)
    1303           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1304             :                         "not a band node", return NULL);
    1305             : 
    1306           0 :         return isl_schedule_band_get_ast_isolate_option(tree->band, depth);
    1307             : }
    1308             : 
    1309             : /* Return the context of the context tree root.
    1310             :  */
    1311           0 : __isl_give isl_set *isl_schedule_tree_context_get_context(
    1312             :         __isl_keep isl_schedule_tree *tree)
    1313             : {
    1314           0 :         if (!tree)
    1315           0 :                 return NULL;
    1316             : 
    1317           0 :         if (tree->type != isl_schedule_node_context)
    1318           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1319             :                         "not a context node", return NULL);
    1320             : 
    1321           0 :         return isl_set_copy(tree->context);
    1322             : }
    1323             : 
    1324             : /* Return the domain of the domain tree root.
    1325             :  */
    1326           0 : __isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
    1327             :         __isl_keep isl_schedule_tree *tree)
    1328             : {
    1329           0 :         if (!tree)
    1330           0 :                 return NULL;
    1331             : 
    1332           0 :         if (tree->type != isl_schedule_node_domain)
    1333           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1334             :                         "not a domain node", return NULL);
    1335             : 
    1336           0 :         return isl_union_set_copy(tree->domain);
    1337             : }
    1338             : 
    1339             : /* Replace the domain of domain tree root "tree" by "domain".
    1340             :  */
    1341           0 : __isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
    1342             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
    1343             : {
    1344           0 :         tree = isl_schedule_tree_cow(tree);
    1345           0 :         if (!tree || !domain)
    1346             :                 goto error;
    1347             : 
    1348           0 :         if (tree->type != isl_schedule_node_domain)
    1349           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1350             :                         "not a domain node", goto error);
    1351             : 
    1352           0 :         isl_union_set_free(tree->domain);
    1353           0 :         tree->domain = domain;
    1354             : 
    1355           0 :         return tree;
    1356             : error:
    1357           0 :         isl_schedule_tree_free(tree);
    1358           0 :         isl_union_set_free(domain);
    1359           0 :         return NULL;
    1360             : }
    1361             : 
    1362             : /* Return the contraction of the expansion tree root.
    1363             :  */
    1364           0 : __isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
    1365             :         __isl_keep isl_schedule_tree *tree)
    1366             : {
    1367           0 :         if (!tree)
    1368           0 :                 return NULL;
    1369             : 
    1370           0 :         if (tree->type != isl_schedule_node_expansion)
    1371           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1372             :                         "not an expansion node", return NULL);
    1373             : 
    1374           0 :         return isl_union_pw_multi_aff_copy(tree->contraction);
    1375             : }
    1376             : 
    1377             : /* Return the expansion of the expansion tree root.
    1378             :  */
    1379           0 : __isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
    1380             :         __isl_keep isl_schedule_tree *tree)
    1381             : {
    1382           0 :         if (!tree)
    1383           0 :                 return NULL;
    1384             : 
    1385           0 :         if (tree->type != isl_schedule_node_expansion)
    1386           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1387             :                         "not an expansion node", return NULL);
    1388             : 
    1389           0 :         return isl_union_map_copy(tree->expansion);
    1390             : }
    1391             : 
    1392             : /* Replace the contraction and the expansion of the expansion tree root "tree"
    1393             :  * by "contraction" and "expansion".
    1394             :  */
    1395             : __isl_give isl_schedule_tree *
    1396           0 : isl_schedule_tree_expansion_set_contraction_and_expansion(
    1397             :         __isl_take isl_schedule_tree *tree,
    1398             :         __isl_take isl_union_pw_multi_aff *contraction,
    1399             :         __isl_take isl_union_map *expansion)
    1400             : {
    1401           0 :         tree = isl_schedule_tree_cow(tree);
    1402           0 :         if (!tree || !contraction || !expansion)
    1403             :                 goto error;
    1404             : 
    1405           0 :         if (tree->type != isl_schedule_node_expansion)
    1406           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1407             :                         "not an expansion node", return NULL);
    1408             : 
    1409           0 :         isl_union_pw_multi_aff_free(tree->contraction);
    1410           0 :         tree->contraction = contraction;
    1411           0 :         isl_union_map_free(tree->expansion);
    1412           0 :         tree->expansion = expansion;
    1413             : 
    1414           0 :         return tree;
    1415             : error:
    1416           0 :         isl_schedule_tree_free(tree);
    1417           0 :         isl_union_pw_multi_aff_free(contraction);
    1418           0 :         isl_union_map_free(expansion);
    1419           0 :         return NULL;
    1420             : }
    1421             : 
    1422             : /* Return the extension of the extension tree root.
    1423             :  */
    1424           0 : __isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
    1425             :         __isl_take isl_schedule_tree *tree)
    1426             : {
    1427           0 :         if (!tree)
    1428           0 :                 return NULL;
    1429             : 
    1430           0 :         if (tree->type != isl_schedule_node_extension)
    1431           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1432             :                         "not an extension node", return NULL);
    1433             : 
    1434           0 :         return isl_union_map_copy(tree->extension);
    1435             : }
    1436             : 
    1437             : /* Replace the extension of extension tree root "tree" by "extension".
    1438             :  */
    1439           0 : __isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
    1440             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
    1441             : {
    1442           0 :         tree = isl_schedule_tree_cow(tree);
    1443           0 :         if (!tree || !extension)
    1444             :                 goto error;
    1445             : 
    1446           0 :         if (tree->type != isl_schedule_node_extension)
    1447           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1448             :                         "not an extension node", return NULL);
    1449           0 :         isl_union_map_free(tree->extension);
    1450           0 :         tree->extension = extension;
    1451             : 
    1452           0 :         return tree;
    1453             : error:
    1454           0 :         isl_schedule_tree_free(tree);
    1455           0 :         isl_union_map_free(extension);
    1456           0 :         return NULL;
    1457             : }
    1458             : 
    1459             : /* Return the filter of the filter tree root.
    1460             :  */
    1461           0 : __isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
    1462             :         __isl_keep isl_schedule_tree *tree)
    1463             : {
    1464           0 :         if (!tree)
    1465           0 :                 return NULL;
    1466             : 
    1467           0 :         if (tree->type != isl_schedule_node_filter)
    1468           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1469             :                         "not a filter node", return NULL);
    1470             : 
    1471           0 :         return isl_union_set_copy(tree->filter);
    1472             : }
    1473             : 
    1474             : /* Replace the filter of the filter tree root by "filter".
    1475             :  */
    1476           0 : __isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
    1477             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
    1478             : {
    1479           0 :         tree = isl_schedule_tree_cow(tree);
    1480           0 :         if (!tree || !filter)
    1481             :                 goto error;
    1482             : 
    1483           0 :         if (tree->type != isl_schedule_node_filter)
    1484           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1485             :                         "not a filter node", return NULL);
    1486             : 
    1487           0 :         isl_union_set_free(tree->filter);
    1488           0 :         tree->filter = filter;
    1489             : 
    1490           0 :         return tree;
    1491             : error:
    1492           0 :         isl_schedule_tree_free(tree);
    1493           0 :         isl_union_set_free(filter);
    1494           0 :         return NULL;
    1495             : }
    1496             : 
    1497             : /* Return the guard of the guard tree root.
    1498             :  */
    1499           0 : __isl_give isl_set *isl_schedule_tree_guard_get_guard(
    1500             :         __isl_take isl_schedule_tree *tree)
    1501             : {
    1502           0 :         if (!tree)
    1503           0 :                 return NULL;
    1504             : 
    1505           0 :         if (tree->type != isl_schedule_node_guard)
    1506           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1507             :                         "not a guard node", return NULL);
    1508             : 
    1509           0 :         return isl_set_copy(tree->guard);
    1510             : }
    1511             : 
    1512             : /* Return the mark identifier of the mark tree root "tree".
    1513             :  */
    1514           0 : __isl_give isl_id *isl_schedule_tree_mark_get_id(
    1515             :         __isl_keep isl_schedule_tree *tree)
    1516             : {
    1517           0 :         if (!tree)
    1518           0 :                 return NULL;
    1519             : 
    1520           0 :         if (tree->type != isl_schedule_node_mark)
    1521           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1522             :                         "not a mark node", return NULL);
    1523             : 
    1524           0 :         return isl_id_copy(tree->mark);
    1525             : }
    1526             : 
    1527             : /* Set dim to the range dimension of "map" and abort the search.
    1528             :  */
    1529           0 : static isl_stat set_range_dim(__isl_take isl_map *map, void *user)
    1530             : {
    1531           0 :         int *dim = user;
    1532             : 
    1533           0 :         *dim = isl_map_dim(map, isl_dim_out);
    1534           0 :         isl_map_free(map);
    1535             : 
    1536           0 :         return isl_stat_error;
    1537             : }
    1538             : 
    1539             : /* Return the dimension of the range of "umap".
    1540             :  * "umap" is assumed not to be empty and
    1541             :  * all maps inside "umap" are assumed to have the same range.
    1542             :  *
    1543             :  * We extract the range dimension from the first map in "umap".
    1544             :  */
    1545           0 : static int range_dim(__isl_keep isl_union_map *umap)
    1546             : {
    1547           0 :         int dim = -1;
    1548             : 
    1549           0 :         if (!umap)
    1550           0 :                 return -1;
    1551           0 :         if (isl_union_map_n_map(umap) == 0)
    1552           0 :                 isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
    1553             :                         "unexpected empty input", return -1);
    1554             : 
    1555           0 :         isl_union_map_foreach_map(umap, &set_range_dim, &dim);
    1556             : 
    1557           0 :         return dim;
    1558             : }
    1559             : 
    1560             : /* Append an "extra" number of zeros to the range of "umap" and
    1561             :  * return the result.
    1562             :  */
    1563           0 : static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
    1564             :         int extra)
    1565             : {
    1566             :         isl_union_set *dom;
    1567             :         isl_space *space;
    1568             :         isl_multi_val *mv;
    1569             :         isl_union_pw_multi_aff *suffix;
    1570             :         isl_union_map *universe;
    1571             :         isl_union_map *suffix_umap;
    1572             : 
    1573           0 :         universe = isl_union_map_universe(isl_union_map_copy(umap));
    1574           0 :         dom = isl_union_map_domain(universe);
    1575           0 :         space = isl_union_set_get_space(dom);
    1576           0 :         space = isl_space_set_from_params(space);
    1577           0 :         space = isl_space_add_dims(space, isl_dim_set, extra);
    1578           0 :         mv = isl_multi_val_zero(space);
    1579             : 
    1580           0 :         suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
    1581           0 :         suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
    1582           0 :         umap = isl_union_map_flat_range_product(umap, suffix_umap);
    1583             : 
    1584           0 :         return umap;
    1585             : }
    1586             : 
    1587             : /* Should we skip the root of "tree" while looking for the first
    1588             :  * descendant with schedule information?
    1589             :  * That is, is it impossible to derive any information about
    1590             :  * the iteration domain from this node?
    1591             :  *
    1592             :  * We do not want to skip leaf or error nodes because there is
    1593             :  * no point in looking any deeper from these nodes.
    1594             :  * We can only extract partial iteration domain information
    1595             :  * from an extension node, but extension nodes are not supported
    1596             :  * by the caller and it will error out on them.
    1597             :  */
    1598           0 : static int domain_less(__isl_keep isl_schedule_tree *tree)
    1599             : {
    1600             :         enum isl_schedule_node_type type;
    1601             : 
    1602           0 :         type = isl_schedule_tree_get_type(tree);
    1603           0 :         switch (type) {
    1604             :         case isl_schedule_node_band:
    1605           0 :                 return isl_schedule_tree_band_n_member(tree) == 0;
    1606             :         case isl_schedule_node_context:
    1607             :         case isl_schedule_node_guard:
    1608             :         case isl_schedule_node_mark:
    1609           0 :                 return 1;
    1610             :         case isl_schedule_node_leaf:
    1611             :         case isl_schedule_node_error:
    1612             :         case isl_schedule_node_domain:
    1613             :         case isl_schedule_node_expansion:
    1614             :         case isl_schedule_node_extension:
    1615             :         case isl_schedule_node_filter:
    1616             :         case isl_schedule_node_set:
    1617             :         case isl_schedule_node_sequence:
    1618           0 :                 return 0;
    1619             :         }
    1620             : 
    1621           0 :         isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1622             :                 "unhandled case", return 0);
    1623             : }
    1624             : 
    1625             : /* Move down to the first descendant of "tree" that contains any schedule
    1626             :  * information or return "leaf" if there is no such descendant.
    1627             :  */
    1628           0 : __isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
    1629             :         __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
    1630             : {
    1631           0 :         while (domain_less(tree)) {
    1632           0 :                 if (!isl_schedule_tree_has_children(tree)) {
    1633           0 :                         isl_schedule_tree_free(tree);
    1634           0 :                         return isl_schedule_tree_copy(leaf);
    1635             :                 }
    1636           0 :                 tree = isl_schedule_tree_child(tree, 0);
    1637             :         }
    1638             : 
    1639           0 :         return tree;
    1640             : }
    1641             : 
    1642             : static __isl_give isl_union_map *subtree_schedule_extend(
    1643             :         __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);
    1644             : 
    1645             : /* Extend the schedule map "outer" with the subtree schedule
    1646             :  * of the (single) child of "tree", if any.
    1647             :  *
    1648             :  * If "tree" does not have any descendants (apart from those that
    1649             :  * do not carry any schedule information), then we simply return "outer".
    1650             :  * Otherwise, we extend the schedule map "outer" with the subtree schedule
    1651             :  * of the single child.
    1652             :  */
    1653           0 : static __isl_give isl_union_map *subtree_schedule_extend_child(
    1654             :         __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
    1655             : {
    1656             :         isl_schedule_tree *child;
    1657             :         isl_union_map *res;
    1658             : 
    1659           0 :         if (!tree)
    1660           0 :                 return isl_union_map_free(outer);
    1661           0 :         if (!isl_schedule_tree_has_children(tree))
    1662           0 :                 return outer;
    1663           0 :         child = isl_schedule_tree_get_child(tree, 0);
    1664           0 :         if (!child)
    1665           0 :                 return isl_union_map_free(outer);
    1666           0 :         res = subtree_schedule_extend(child, outer);
    1667           0 :         isl_schedule_tree_free(child);
    1668           0 :         return res;
    1669             : }
    1670             : 
    1671             : /* Extract the parameter space from one of the children of "tree",
    1672             :  * which are assumed to be filters.
    1673             :  */
    1674           0 : static __isl_give isl_space *extract_space_from_filter_child(
    1675             :         __isl_keep isl_schedule_tree *tree)
    1676             : {
    1677             :         isl_space *space;
    1678             :         isl_union_set *dom;
    1679             :         isl_schedule_tree *child;
    1680             : 
    1681           0 :         child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
    1682           0 :         dom = isl_schedule_tree_filter_get_filter(child);
    1683           0 :         space = isl_union_set_get_space(dom);
    1684           0 :         isl_union_set_free(dom);
    1685           0 :         isl_schedule_tree_free(child);
    1686             : 
    1687           0 :         return space;
    1688             : }
    1689             : 
    1690             : /* Extend the schedule map "outer" with the subtree schedule
    1691             :  * of a set or sequence node.
    1692             :  *
    1693             :  * The schedule for the set or sequence node itself is composed of
    1694             :  * pieces of the form
    1695             :  *
    1696             :  *      filter -> []
    1697             :  *
    1698             :  * or
    1699             :  *
    1700             :  *      filter -> [index]
    1701             :  *
    1702             :  * The first form is used if there is only a single child or
    1703             :  * if the current node is a set node and the schedule_separate_components
    1704             :  * option is not set.
    1705             :  *
    1706             :  * Each of the pieces above is extended with the subtree schedule of
    1707             :  * the child of the corresponding filter, if any, padded with zeros
    1708             :  * to ensure that all pieces have the same range dimension.
    1709             :  */
    1710           0 : static __isl_give isl_union_map *subtree_schedule_extend_from_children(
    1711             :         __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
    1712             : {
    1713             :         int i, n;
    1714             :         int dim;
    1715             :         int separate;
    1716             :         isl_ctx *ctx;
    1717           0 :         isl_val *v = NULL;
    1718             :         isl_multi_val *mv;
    1719             :         isl_space *space;
    1720             :         isl_union_map *umap;
    1721             : 
    1722           0 :         if (!tree)
    1723           0 :                 return isl_union_map_free(outer);
    1724             : 
    1725           0 :         ctx = isl_schedule_tree_get_ctx(tree);
    1726           0 :         if (!tree->children)
    1727           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1728             :                         "missing children", return isl_union_map_free(outer));
    1729           0 :         n = isl_schedule_tree_list_n_schedule_tree(tree->children);
    1730           0 :         if (n == 0)
    1731           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1732             :                         "missing children", return isl_union_map_free(outer));
    1733             : 
    1734           0 :         separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
    1735           0 :                             isl_options_get_schedule_separate_components(ctx));
    1736             : 
    1737           0 :         space = isl_space_params_alloc(ctx, 0);
    1738             : 
    1739           0 :         umap = isl_union_map_empty(isl_space_copy(space));
    1740           0 :         space = isl_space_set_from_params(space);
    1741           0 :         if (separate) {
    1742           0 :                 space = isl_space_add_dims(space, isl_dim_set, 1);
    1743           0 :                 v = isl_val_zero(ctx);
    1744             :         }
    1745           0 :         mv = isl_multi_val_zero(space);
    1746             : 
    1747           0 :         dim = isl_multi_val_dim(mv, isl_dim_set);
    1748           0 :         for (i = 0; i < n; ++i) {
    1749             :                 isl_multi_val *mv_copy;
    1750             :                 isl_union_pw_multi_aff *upma;
    1751             :                 isl_union_map *umap_i;
    1752             :                 isl_union_set *dom;
    1753             :                 isl_schedule_tree *child;
    1754             :                 int dim_i;
    1755             :                 int empty;
    1756             : 
    1757           0 :                 child = isl_schedule_tree_list_get_schedule_tree(
    1758             :                                                         tree->children, i);
    1759           0 :                 dom = isl_schedule_tree_filter_get_filter(child);
    1760             : 
    1761           0 :                 if (separate) {
    1762           0 :                         mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
    1763           0 :                         v = isl_val_add_ui(v, 1);
    1764             :                 }
    1765           0 :                 mv_copy = isl_multi_val_copy(mv);
    1766           0 :                 space = isl_union_set_get_space(dom);
    1767           0 :                 mv_copy = isl_multi_val_align_params(mv_copy, space);
    1768           0 :                 upma = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv_copy);
    1769           0 :                 umap_i = isl_union_map_from_union_pw_multi_aff(upma);
    1770           0 :                 umap_i = isl_union_map_flat_range_product(
    1771             :                                             isl_union_map_copy(outer), umap_i);
    1772           0 :                 umap_i = subtree_schedule_extend_child(child, umap_i);
    1773           0 :                 isl_schedule_tree_free(child);
    1774             : 
    1775           0 :                 empty = isl_union_map_is_empty(umap_i);
    1776           0 :                 if (empty < 0)
    1777           0 :                         umap_i = isl_union_map_free(umap_i);
    1778           0 :                 else if (empty) {
    1779           0 :                         isl_union_map_free(umap_i);
    1780           0 :                         continue;
    1781             :                 }
    1782             : 
    1783           0 :                 dim_i = range_dim(umap_i);
    1784           0 :                 if (dim_i < 0) {
    1785           0 :                         umap = isl_union_map_free(umap);
    1786           0 :                 } else if (dim < dim_i) {
    1787           0 :                         umap = append_range(umap, dim_i - dim);
    1788           0 :                         dim = dim_i;
    1789           0 :                 } else if (dim_i < dim) {
    1790           0 :                         umap_i = append_range(umap_i, dim - dim_i);
    1791             :                 }
    1792           0 :                 umap = isl_union_map_union(umap, umap_i);
    1793             :         }
    1794             : 
    1795           0 :         isl_val_free(v);
    1796           0 :         isl_multi_val_free(mv);
    1797           0 :         isl_union_map_free(outer);
    1798             : 
    1799           0 :         return umap;
    1800             : }
    1801             : 
    1802             : /* Extend the schedule map "outer" with the subtree schedule of "tree".
    1803             :  *
    1804             :  * If the root of the tree is a set or a sequence, then we extend
    1805             :  * the schedule map in subtree_schedule_extend_from_children.
    1806             :  * Otherwise, we extend the schedule map with the partial schedule
    1807             :  * corresponding to the root of the tree and then continue with
    1808             :  * the single child of this root.
    1809             :  * In the special case of an expansion, the schedule map is "extended"
    1810             :  * by applying the expansion to the domain of the schedule map.
    1811             :  */
    1812           0 : static __isl_give isl_union_map *subtree_schedule_extend(
    1813             :         __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
    1814             : {
    1815             :         isl_multi_union_pw_aff *mupa;
    1816             :         isl_union_map *umap;
    1817             :         isl_union_set *domain;
    1818             : 
    1819           0 :         if (!tree)
    1820           0 :                 return NULL;
    1821             : 
    1822           0 :         switch (tree->type) {
    1823             :         case isl_schedule_node_error:
    1824           0 :                 return isl_union_map_free(outer);
    1825             :         case isl_schedule_node_extension:
    1826           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1827             :                         "cannot construct subtree schedule of tree "
    1828             :                         "with extension nodes",
    1829             :                         return isl_union_map_free(outer));
    1830             :         case isl_schedule_node_context:
    1831             :         case isl_schedule_node_guard:
    1832             :         case isl_schedule_node_mark:
    1833           0 :                 return subtree_schedule_extend_child(tree, outer);
    1834             :         case isl_schedule_node_band:
    1835           0 :                 if (isl_schedule_tree_band_n_member(tree) == 0)
    1836           0 :                         return subtree_schedule_extend_child(tree, outer);
    1837           0 :                 mupa = isl_schedule_band_get_partial_schedule(tree->band);
    1838           0 :                 umap = isl_union_map_from_multi_union_pw_aff(mupa);
    1839           0 :                 outer = isl_union_map_flat_range_product(outer, umap);
    1840           0 :                 umap = subtree_schedule_extend_child(tree, outer);
    1841           0 :                 break;
    1842             :         case isl_schedule_node_domain:
    1843           0 :                 domain = isl_schedule_tree_domain_get_domain(tree);
    1844           0 :                 umap = isl_union_map_from_domain(domain);
    1845           0 :                 outer = isl_union_map_flat_range_product(outer, umap);
    1846           0 :                 umap = subtree_schedule_extend_child(tree, outer);
    1847           0 :                 break;
    1848             :         case isl_schedule_node_expansion:
    1849           0 :                 umap = isl_schedule_tree_expansion_get_expansion(tree);
    1850           0 :                 outer = isl_union_map_apply_domain(outer, umap);
    1851           0 :                 umap = subtree_schedule_extend_child(tree, outer);
    1852           0 :                 break;
    1853             :         case isl_schedule_node_filter:
    1854           0 :                 domain = isl_schedule_tree_filter_get_filter(tree);
    1855           0 :                 umap = isl_union_map_from_domain(domain);
    1856           0 :                 outer = isl_union_map_flat_range_product(outer, umap);
    1857           0 :                 umap = subtree_schedule_extend_child(tree, outer);
    1858           0 :                 break;
    1859             :         case isl_schedule_node_leaf:
    1860           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1861             :                         "leaf node should be handled by caller", return NULL);
    1862             :         case isl_schedule_node_set:
    1863             :         case isl_schedule_node_sequence:
    1864           0 :                 umap = subtree_schedule_extend_from_children(tree, outer);
    1865           0 :                 break;
    1866             :         }
    1867             : 
    1868           0 :         return umap;
    1869             : }
    1870             : 
    1871             : static __isl_give isl_union_set *initial_domain(
    1872             :         __isl_keep isl_schedule_tree *tree);
    1873             : 
    1874             : /* Extract a universe domain from the children of the tree root "tree",
    1875             :  * which is a set or sequence, meaning that its children are filters.
    1876             :  * In particular, return the union of the universes of the filters.
    1877             :  */
    1878           0 : static __isl_give isl_union_set *initial_domain_from_children(
    1879             :         __isl_keep isl_schedule_tree *tree)
    1880             : {
    1881             :         int i, n;
    1882             :         isl_space *space;
    1883             :         isl_union_set *domain;
    1884             : 
    1885           0 :         if (!tree->children)
    1886           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1887             :                         "missing children", return NULL);
    1888           0 :         n = isl_schedule_tree_list_n_schedule_tree(tree->children);
    1889           0 :         if (n == 0)
    1890           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1891             :                         "missing children", return NULL);
    1892             : 
    1893           0 :         space = extract_space_from_filter_child(tree);
    1894           0 :         domain = isl_union_set_empty(space);
    1895             : 
    1896           0 :         for (i = 0; i < n; ++i) {
    1897             :                 isl_schedule_tree *child;
    1898             :                 isl_union_set *domain_i;
    1899             : 
    1900           0 :                 child = isl_schedule_tree_get_child(tree, i);
    1901           0 :                 domain_i = initial_domain(child);
    1902           0 :                 domain = isl_union_set_union(domain, domain_i);
    1903           0 :                 isl_schedule_tree_free(child);
    1904             :         }
    1905             : 
    1906           0 :         return domain;
    1907             : }
    1908             : 
    1909             : /* Extract a universe domain from the tree root "tree".
    1910             :  * The caller is responsible for making sure that this node
    1911             :  * would not be skipped by isl_schedule_tree_first_schedule_descendant
    1912             :  * and that it is not a leaf node.
    1913             :  */
    1914           0 : static __isl_give isl_union_set *initial_domain(
    1915             :         __isl_keep isl_schedule_tree *tree)
    1916             : {
    1917             :         isl_multi_union_pw_aff *mupa;
    1918             :         isl_union_set *domain;
    1919             :         isl_union_map *exp;
    1920             : 
    1921           0 :         if (!tree)
    1922           0 :                 return NULL;
    1923             : 
    1924           0 :         switch (tree->type) {
    1925             :         case isl_schedule_node_error:
    1926           0 :                 return NULL;
    1927             :         case isl_schedule_node_context:
    1928           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1929             :                         "context node should be handled by caller",
    1930             :                         return NULL);
    1931             :         case isl_schedule_node_guard:
    1932           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1933             :                         "guard node should be handled by caller",
    1934             :                         return NULL);
    1935             :         case isl_schedule_node_mark:
    1936           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1937             :                         "mark node should be handled by caller",
    1938             :                         return NULL);
    1939             :         case isl_schedule_node_extension:
    1940           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    1941             :                         "cannot construct subtree schedule of tree "
    1942             :                         "with extension nodes", return NULL);
    1943             :         case isl_schedule_node_band:
    1944           0 :                 if (isl_schedule_tree_band_n_member(tree) == 0)
    1945           0 :                         isl_die(isl_schedule_tree_get_ctx(tree),
    1946             :                                 isl_error_internal,
    1947             :                                 "0D band should be handled by caller",
    1948             :                                 return NULL);
    1949           0 :                 mupa = isl_schedule_band_get_partial_schedule(tree->band);
    1950           0 :                 domain = isl_multi_union_pw_aff_domain(mupa);
    1951           0 :                 domain = isl_union_set_universe(domain);
    1952           0 :                 break;
    1953             :         case isl_schedule_node_domain:
    1954           0 :                 domain = isl_schedule_tree_domain_get_domain(tree);
    1955           0 :                 domain = isl_union_set_universe(domain);
    1956           0 :                 break;
    1957             :         case isl_schedule_node_expansion:
    1958           0 :                 exp = isl_schedule_tree_expansion_get_expansion(tree);
    1959           0 :                 exp = isl_union_map_universe(exp);
    1960           0 :                 domain = isl_union_map_domain(exp);
    1961           0 :                 break;
    1962             :         case isl_schedule_node_filter:
    1963           0 :                 domain = isl_schedule_tree_filter_get_filter(tree);
    1964           0 :                 domain = isl_union_set_universe(domain);
    1965           0 :                 break;
    1966             :         case isl_schedule_node_leaf:
    1967           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    1968             :                         "leaf node should be handled by caller", return NULL);
    1969             :         case isl_schedule_node_set:
    1970             :         case isl_schedule_node_sequence:
    1971           0 :                 domain = initial_domain_from_children(tree);
    1972           0 :                 break;
    1973             :         }
    1974             : 
    1975           0 :         return domain;
    1976             : }
    1977             : 
    1978             : /* Return the subtree schedule of a node that contains some schedule
    1979             :  * information, i.e., a node that would not be skipped by
    1980             :  * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
    1981             :  *
    1982             :  * If the tree contains any expansions, then the returned subtree
    1983             :  * schedule is formulated in terms of the expanded domains.
    1984             :  * The tree is not allowed to contain any extension nodes.
    1985             :  *
    1986             :  * We start with an initial zero-dimensional subtree schedule based
    1987             :  * on the domain information in the root node and then extend it
    1988             :  * based on the schedule information in the root node and its descendants.
    1989             :  */
    1990           0 : __isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
    1991             :         __isl_keep isl_schedule_tree *tree)
    1992             : {
    1993             :         isl_union_set *domain;
    1994             :         isl_union_map *umap;
    1995             : 
    1996           0 :         domain = initial_domain(tree);
    1997           0 :         umap = isl_union_map_from_domain(domain);
    1998           0 :         return subtree_schedule_extend(tree, umap);
    1999             : }
    2000             : 
    2001             : /* Multiply the partial schedule of the band root node of "tree"
    2002             :  * with the factors in "mv".
    2003             :  */
    2004           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
    2005             :         __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
    2006             : {
    2007           0 :         if (!tree || !mv)
    2008             :                 goto error;
    2009           0 :         if (tree->type != isl_schedule_node_band)
    2010           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2011             :                         "not a band node", goto error);
    2012             : 
    2013           0 :         tree = isl_schedule_tree_cow(tree);
    2014           0 :         if (!tree)
    2015           0 :                 goto error;
    2016             : 
    2017           0 :         tree->band = isl_schedule_band_scale(tree->band, mv);
    2018           0 :         if (!tree->band)
    2019           0 :                 return isl_schedule_tree_free(tree);
    2020             : 
    2021           0 :         return tree;
    2022             : error:
    2023           0 :         isl_schedule_tree_free(tree);
    2024           0 :         isl_multi_val_free(mv);
    2025           0 :         return NULL;
    2026             : }
    2027             : 
    2028             : /* Divide the partial schedule of the band root node of "tree"
    2029             :  * by the factors in "mv".
    2030             :  */
    2031           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
    2032             :         __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
    2033             : {
    2034           0 :         if (!tree || !mv)
    2035             :                 goto error;
    2036           0 :         if (tree->type != isl_schedule_node_band)
    2037           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2038             :                         "not a band node", goto error);
    2039             : 
    2040           0 :         tree = isl_schedule_tree_cow(tree);
    2041           0 :         if (!tree)
    2042           0 :                 goto error;
    2043             : 
    2044           0 :         tree->band = isl_schedule_band_scale_down(tree->band, mv);
    2045           0 :         if (!tree->band)
    2046           0 :                 return isl_schedule_tree_free(tree);
    2047             : 
    2048           0 :         return tree;
    2049             : error:
    2050           0 :         isl_schedule_tree_free(tree);
    2051           0 :         isl_multi_val_free(mv);
    2052           0 :         return NULL;
    2053             : }
    2054             : 
    2055             : /* Reduce the partial schedule of the band root node of "tree"
    2056             :  * modulo the factors in "mv".
    2057             :  */
    2058           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_mod(
    2059             :         __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
    2060             : {
    2061           0 :         if (!tree || !mv)
    2062             :                 goto error;
    2063           0 :         if (tree->type != isl_schedule_node_band)
    2064           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2065             :                         "not a band node", goto error);
    2066             : 
    2067           0 :         tree = isl_schedule_tree_cow(tree);
    2068           0 :         if (!tree)
    2069           0 :                 goto error;
    2070             : 
    2071           0 :         tree->band = isl_schedule_band_mod(tree->band, mv);
    2072           0 :         if (!tree->band)
    2073           0 :                 return isl_schedule_tree_free(tree);
    2074             : 
    2075           0 :         return tree;
    2076             : error:
    2077           0 :         isl_schedule_tree_free(tree);
    2078           0 :         isl_multi_val_free(mv);
    2079           0 :         return NULL;
    2080             : }
    2081             : 
    2082             : /* Shift the partial schedule of the band root node of "tree" by "shift".
    2083             :  */
    2084           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_shift(
    2085             :         __isl_take isl_schedule_tree *tree,
    2086             :         __isl_take isl_multi_union_pw_aff *shift)
    2087             : {
    2088           0 :         if (!tree || !shift)
    2089             :                 goto error;
    2090           0 :         if (tree->type != isl_schedule_node_band)
    2091           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2092             :                         "not a band node", goto error);
    2093             : 
    2094           0 :         tree = isl_schedule_tree_cow(tree);
    2095           0 :         if (!tree)
    2096           0 :                 goto error;
    2097             : 
    2098           0 :         tree->band = isl_schedule_band_shift(tree->band, shift);
    2099           0 :         if (!tree->band)
    2100           0 :                 return isl_schedule_tree_free(tree);
    2101             : 
    2102           0 :         return tree;
    2103             : error:
    2104           0 :         isl_schedule_tree_free(tree);
    2105           0 :         isl_multi_union_pw_aff_free(shift);
    2106           0 :         return NULL;
    2107             : }
    2108             : 
    2109             : /* Given two trees with sequence roots, replace the child at position
    2110             :  * "pos" of "tree" with the children of "child".
    2111             :  */
    2112           0 : __isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
    2113             :         __isl_take isl_schedule_tree *tree, int pos,
    2114             :         __isl_take isl_schedule_tree *child)
    2115             : {
    2116             :         int n;
    2117             :         isl_schedule_tree_list *list1, *list2;
    2118             : 
    2119           0 :         tree = isl_schedule_tree_cow(tree);
    2120           0 :         if (!tree || !child)
    2121             :                 goto error;
    2122           0 :         if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
    2123           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2124             :                         "not a sequence node", goto error);
    2125           0 :         n = isl_schedule_tree_n_children(tree);
    2126           0 :         if (pos < 0 || pos >= n)
    2127           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2128             :                         "position out of bounds", goto error);
    2129           0 :         if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence)
    2130           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2131             :                         "not a sequence node", goto error);
    2132             : 
    2133           0 :         list1 = isl_schedule_tree_list_copy(tree->children);
    2134           0 :         list1 = isl_schedule_tree_list_drop(list1, pos, n - pos);
    2135           0 :         list2 = isl_schedule_tree_list_copy(tree->children);
    2136           0 :         list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1);
    2137           0 :         list1 = isl_schedule_tree_list_concat(list1,
    2138             :                                 isl_schedule_tree_list_copy(child->children));
    2139           0 :         list1 = isl_schedule_tree_list_concat(list1, list2);
    2140             : 
    2141           0 :         isl_schedule_tree_free(tree);
    2142           0 :         isl_schedule_tree_free(child);
    2143           0 :         return isl_schedule_tree_from_children(isl_schedule_node_sequence,
    2144             :                                                 list1);
    2145             : error:
    2146           0 :         isl_schedule_tree_free(tree);
    2147           0 :         isl_schedule_tree_free(child);
    2148           0 :         return NULL;
    2149             : }
    2150             : 
    2151             : /* Tile the band root node of "tree" with tile sizes "sizes".
    2152             :  *
    2153             :  * We duplicate the band node, change the schedule of one of them
    2154             :  * to the tile schedule and the other to the point schedule and then
    2155             :  * attach the point band as a child to the tile band.
    2156             :  */
    2157           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
    2158             :         __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
    2159             : {
    2160           0 :         isl_schedule_tree *child = NULL;
    2161             : 
    2162           0 :         if (!tree || !sizes)
    2163             :                 goto error;
    2164           0 :         if (tree->type != isl_schedule_node_band)
    2165           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2166             :                         "not a band node", goto error);
    2167             : 
    2168           0 :         child = isl_schedule_tree_copy(tree);
    2169           0 :         tree = isl_schedule_tree_cow(tree);
    2170           0 :         child = isl_schedule_tree_cow(child);
    2171           0 :         if (!tree || !child)
    2172             :                 goto error;
    2173             : 
    2174           0 :         tree->band = isl_schedule_band_tile(tree->band,
    2175             :                                             isl_multi_val_copy(sizes));
    2176           0 :         if (!tree->band)
    2177           0 :                 goto error;
    2178           0 :         child->band = isl_schedule_band_point(child->band, tree->band, sizes);
    2179           0 :         if (!child->band)
    2180           0 :                 child = isl_schedule_tree_free(child);
    2181             : 
    2182           0 :         tree = isl_schedule_tree_replace_child(tree, 0, child);
    2183             : 
    2184           0 :         return tree;
    2185             : error:
    2186           0 :         isl_schedule_tree_free(child);
    2187           0 :         isl_schedule_tree_free(tree);
    2188           0 :         isl_multi_val_free(sizes);
    2189           0 :         return NULL;
    2190             : }
    2191             : 
    2192             : /* Given an isolate AST generation option "isolate" for a band of size pos + n,
    2193             :  * return the corresponding option for a band covering the first "pos"
    2194             :  * members.
    2195             :  *
    2196             :  * The input isolate option is of the form
    2197             :  *
    2198             :  *      isolate[[flattened outer bands] -> [pos; n]]
    2199             :  *
    2200             :  * The output isolate option is of the form
    2201             :  *
    2202             :  *      isolate[[flattened outer bands] -> [pos]]
    2203             :  */
    2204           0 : static __isl_give isl_set *isolate_initial(__isl_keep isl_set *isolate,
    2205             :         int pos, int n)
    2206             : {
    2207             :         isl_id *id;
    2208             :         isl_map *map;
    2209             : 
    2210           0 :         isolate = isl_set_copy(isolate);
    2211           0 :         id = isl_set_get_tuple_id(isolate);
    2212           0 :         map = isl_set_unwrap(isolate);
    2213           0 :         map = isl_map_project_out(map, isl_dim_out, pos, n);
    2214           0 :         isolate = isl_map_wrap(map);
    2215           0 :         isolate = isl_set_set_tuple_id(isolate, id);
    2216             : 
    2217           0 :         return isolate;
    2218             : }
    2219             : 
    2220             : /* Given an isolate AST generation option "isolate" for a band of size pos + n,
    2221             :  * return the corresponding option for a band covering the final "n"
    2222             :  * members within a band covering the first "pos" members.
    2223             :  *
    2224             :  * The input isolate option is of the form
    2225             :  *
    2226             :  *      isolate[[flattened outer bands] -> [pos; n]]
    2227             :  *
    2228             :  * The output isolate option is of the form
    2229             :  *
    2230             :  *      isolate[[flattened outer bands; pos] -> [n]]
    2231             :  *
    2232             :  *
    2233             :  * The range is first split into
    2234             :  *
    2235             :  *      isolate[[flattened outer bands] -> [[pos] -> [n]]]
    2236             :  *
    2237             :  * and then the first pos members are moved to the domain
    2238             :  *
    2239             :  *      isolate[[[flattened outer bands] -> [pos]] -> [n]]
    2240             :  *
    2241             :  * after which the domain is flattened to obtain the desired output.
    2242             :  */
    2243           0 : static __isl_give isl_set *isolate_final(__isl_keep isl_set *isolate,
    2244             :         int pos, int n)
    2245             : {
    2246             :         isl_id *id;
    2247             :         isl_space *space;
    2248             :         isl_multi_aff *ma1, *ma2;
    2249             :         isl_map *map;
    2250             : 
    2251           0 :         isolate = isl_set_copy(isolate);
    2252           0 :         id = isl_set_get_tuple_id(isolate);
    2253           0 :         map = isl_set_unwrap(isolate);
    2254           0 :         space = isl_space_range(isl_map_get_space(map));
    2255           0 :         ma1 = isl_multi_aff_project_out_map(isl_space_copy(space),
    2256             :                                                    isl_dim_set, pos, n);
    2257           0 :         ma2 = isl_multi_aff_project_out_map(space, isl_dim_set, 0, pos);
    2258           0 :         ma1 = isl_multi_aff_range_product(ma1, ma2);
    2259           0 :         map = isl_map_apply_range(map, isl_map_from_multi_aff(ma1));
    2260           0 :         map = isl_map_uncurry(map);
    2261           0 :         map = isl_map_flatten_domain(map);
    2262           0 :         isolate = isl_map_wrap(map);
    2263           0 :         isolate = isl_set_set_tuple_id(isolate, id);
    2264             : 
    2265           0 :         return isolate;
    2266             : }
    2267             : 
    2268             : /* Split the band root node of "tree" into two nested band nodes,
    2269             :  * one with the first "pos" dimensions and
    2270             :  * one with the remaining dimensions.
    2271             :  * The tree is itself positioned at schedule depth "depth".
    2272             :  *
    2273             :  * The loop AST generation type options and the isolate option
    2274             :  * are split over the two band nodes.
    2275             :  */
    2276           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_split(
    2277             :         __isl_take isl_schedule_tree *tree, int pos, int depth)
    2278             : {
    2279             :         int n;
    2280             :         isl_set *isolate, *tree_isolate, *child_isolate;
    2281             :         isl_schedule_tree *child;
    2282             : 
    2283           0 :         if (!tree)
    2284           0 :                 return NULL;
    2285           0 :         if (tree->type != isl_schedule_node_band)
    2286           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2287             :                         "not a band node", return isl_schedule_tree_free(tree));
    2288             : 
    2289           0 :         n = isl_schedule_tree_band_n_member(tree);
    2290           0 :         if (pos < 0 || pos > n)
    2291           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2292             :                         "position out of bounds",
    2293             :                         return isl_schedule_tree_free(tree));
    2294             : 
    2295           0 :         child = isl_schedule_tree_copy(tree);
    2296           0 :         tree = isl_schedule_tree_cow(tree);
    2297           0 :         child = isl_schedule_tree_cow(child);
    2298           0 :         if (!tree || !child)
    2299             :                 goto error;
    2300             : 
    2301           0 :         isolate = isl_schedule_tree_band_get_ast_isolate_option(tree, depth);
    2302           0 :         tree_isolate = isolate_initial(isolate, pos, n - pos);
    2303           0 :         child_isolate = isolate_final(isolate, pos, n - pos);
    2304           0 :         child->band = isl_schedule_band_drop(child->band, 0, pos);
    2305           0 :         child->band = isl_schedule_band_replace_ast_build_option(child->band,
    2306             :                                         isl_set_copy(isolate), child_isolate);
    2307           0 :         tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
    2308           0 :         tree->band = isl_schedule_band_replace_ast_build_option(tree->band,
    2309             :                                         isl_set_copy(isolate), tree_isolate);
    2310           0 :         isl_set_free(isolate);
    2311           0 :         if (!child->band || !tree->band)
    2312             :                 goto error;
    2313             : 
    2314           0 :         tree = isl_schedule_tree_replace_child(tree, 0, child);
    2315             : 
    2316           0 :         return tree;
    2317             : error:
    2318           0 :         isl_schedule_tree_free(child);
    2319           0 :         isl_schedule_tree_free(tree);
    2320           0 :         return NULL;
    2321             : }
    2322             : 
    2323             : /* Attach "tree2" at each of the leaves of "tree1".
    2324             :  *
    2325             :  * If "tree1" does not have any explicit children, then make "tree2"
    2326             :  * its single child.  Otherwise, attach "tree2" to the leaves of
    2327             :  * each of the children of "tree1".
    2328             :  */
    2329           0 : __isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
    2330             :         __isl_take isl_schedule_tree *tree1,
    2331             :         __isl_take isl_schedule_tree *tree2)
    2332             : {
    2333             :         int i, n;
    2334             : 
    2335           0 :         if (!tree1 || !tree2)
    2336             :                 goto error;
    2337           0 :         n = isl_schedule_tree_n_children(tree1);
    2338           0 :         if (n == 0) {
    2339             :                 isl_schedule_tree_list *list;
    2340           0 :                 list = isl_schedule_tree_list_from_schedule_tree(tree2);
    2341           0 :                 tree1 = isl_schedule_tree_set_children(tree1, list);
    2342           0 :                 return tree1;
    2343             :         }
    2344           0 :         for (i = 0; i < n; ++i) {
    2345             :                 isl_schedule_tree *child;
    2346             : 
    2347           0 :                 child = isl_schedule_tree_get_child(tree1, i);
    2348           0 :                 child = isl_schedule_tree_append_to_leaves(child,
    2349             :                                         isl_schedule_tree_copy(tree2));
    2350           0 :                 tree1 = isl_schedule_tree_replace_child(tree1, i, child);
    2351             :         }
    2352             : 
    2353           0 :         isl_schedule_tree_free(tree2);
    2354           0 :         return tree1;
    2355             : error:
    2356           0 :         isl_schedule_tree_free(tree1);
    2357           0 :         isl_schedule_tree_free(tree2);
    2358           0 :         return NULL;
    2359             : }
    2360             : 
    2361             : /* Reset the user pointer on all identifiers of parameters and tuples
    2362             :  * in the root of "tree".
    2363             :  */
    2364           0 : __isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
    2365             :         __isl_take isl_schedule_tree *tree)
    2366             : {
    2367           0 :         if (isl_schedule_tree_is_leaf(tree))
    2368           0 :                 return tree;
    2369             : 
    2370           0 :         tree = isl_schedule_tree_cow(tree);
    2371           0 :         if (!tree)
    2372           0 :                 return NULL;
    2373             : 
    2374           0 :         switch (tree->type) {
    2375             :         case isl_schedule_node_error:
    2376           0 :                 return isl_schedule_tree_free(tree);
    2377             :         case isl_schedule_node_band:
    2378           0 :                 tree->band = isl_schedule_band_reset_user(tree->band);
    2379           0 :                 if (!tree->band)
    2380           0 :                         return isl_schedule_tree_free(tree);
    2381           0 :                 break;
    2382             :         case isl_schedule_node_context:
    2383           0 :                 tree->context = isl_set_reset_user(tree->context);
    2384           0 :                 if (!tree->context)
    2385           0 :                         return isl_schedule_tree_free(tree);
    2386           0 :                 break;
    2387             :         case isl_schedule_node_domain:
    2388           0 :                 tree->domain = isl_union_set_reset_user(tree->domain);
    2389           0 :                 if (!tree->domain)
    2390           0 :                         return isl_schedule_tree_free(tree);
    2391           0 :                 break;
    2392             :         case isl_schedule_node_expansion:
    2393           0 :                 tree->contraction =
    2394           0 :                         isl_union_pw_multi_aff_reset_user(tree->contraction);
    2395           0 :                 tree->expansion = isl_union_map_reset_user(tree->expansion);
    2396           0 :                 if (!tree->contraction || !tree->expansion)
    2397           0 :                         return isl_schedule_tree_free(tree);
    2398           0 :                 break;
    2399             :         case isl_schedule_node_extension:
    2400           0 :                 tree->extension = isl_union_map_reset_user(tree->extension);
    2401           0 :                 if (!tree->extension)
    2402           0 :                         return isl_schedule_tree_free(tree);
    2403           0 :                 break;
    2404             :         case isl_schedule_node_filter:
    2405           0 :                 tree->filter = isl_union_set_reset_user(tree->filter);
    2406           0 :                 if (!tree->filter)
    2407           0 :                         return isl_schedule_tree_free(tree);
    2408           0 :                 break;
    2409             :         case isl_schedule_node_guard:
    2410           0 :                 tree->guard = isl_set_reset_user(tree->guard);
    2411           0 :                 if (!tree->guard)
    2412           0 :                         return isl_schedule_tree_free(tree);
    2413           0 :                 break;
    2414             :         case isl_schedule_node_leaf:
    2415             :         case isl_schedule_node_mark:
    2416             :         case isl_schedule_node_sequence:
    2417             :         case isl_schedule_node_set:
    2418           0 :                 break;
    2419             :         }
    2420             : 
    2421           0 :         return tree;
    2422             : }
    2423             : 
    2424             : /* Align the parameters of the root of "tree" to those of "space".
    2425             :  */
    2426           0 : __isl_give isl_schedule_tree *isl_schedule_tree_align_params(
    2427             :         __isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
    2428             : {
    2429           0 :         if (!space)
    2430           0 :                 goto error;
    2431             : 
    2432           0 :         if (isl_schedule_tree_is_leaf(tree)) {
    2433           0 :                 isl_space_free(space);
    2434           0 :                 return tree;
    2435             :         }
    2436             : 
    2437           0 :         tree = isl_schedule_tree_cow(tree);
    2438           0 :         if (!tree)
    2439           0 :                 goto error;
    2440             : 
    2441           0 :         switch (tree->type) {
    2442             :         case isl_schedule_node_error:
    2443           0 :                 goto error;
    2444             :         case isl_schedule_node_band:
    2445           0 :                 tree->band = isl_schedule_band_align_params(tree->band, space);
    2446           0 :                 if (!tree->band)
    2447           0 :                         return isl_schedule_tree_free(tree);
    2448           0 :                 break;
    2449             :         case isl_schedule_node_context:
    2450           0 :                 tree->context = isl_set_align_params(tree->context, space);
    2451           0 :                 if (!tree->context)
    2452           0 :                         return isl_schedule_tree_free(tree);
    2453           0 :                 break;
    2454             :         case isl_schedule_node_domain:
    2455           0 :                 tree->domain = isl_union_set_align_params(tree->domain, space);
    2456           0 :                 if (!tree->domain)
    2457           0 :                         return isl_schedule_tree_free(tree);
    2458           0 :                 break;
    2459             :         case isl_schedule_node_expansion:
    2460           0 :                 tree->contraction =
    2461           0 :                         isl_union_pw_multi_aff_align_params(tree->contraction,
    2462             :                                                         isl_space_copy(space));
    2463           0 :                 tree->expansion = isl_union_map_align_params(tree->expansion,
    2464             :                                                                 space);
    2465           0 :                 if (!tree->contraction || !tree->expansion)
    2466           0 :                         return isl_schedule_tree_free(tree);
    2467           0 :                 break;
    2468             :         case isl_schedule_node_extension:
    2469           0 :                 tree->extension = isl_union_map_align_params(tree->extension,
    2470             :                                                                 space);
    2471           0 :                 if (!tree->extension)
    2472           0 :                         return isl_schedule_tree_free(tree);
    2473           0 :                 break;
    2474             :         case isl_schedule_node_filter:
    2475           0 :                 tree->filter = isl_union_set_align_params(tree->filter, space);
    2476           0 :                 if (!tree->filter)
    2477           0 :                         return isl_schedule_tree_free(tree);
    2478           0 :                 break;
    2479             :         case isl_schedule_node_guard:
    2480           0 :                 tree->guard = isl_set_align_params(tree->guard, space);
    2481           0 :                 if (!tree->guard)
    2482           0 :                         return isl_schedule_tree_free(tree);
    2483           0 :                 break;
    2484             :         case isl_schedule_node_leaf:
    2485             :         case isl_schedule_node_mark:
    2486             :         case isl_schedule_node_sequence:
    2487             :         case isl_schedule_node_set:
    2488           0 :                 isl_space_free(space);
    2489           0 :                 break;
    2490             :         }
    2491             : 
    2492           0 :         return tree;
    2493             : error:
    2494           0 :         isl_space_free(space);
    2495           0 :         isl_schedule_tree_free(tree);
    2496           0 :         return NULL;
    2497             : }
    2498             : 
    2499             : /* Does "tree" involve the iteration domain?
    2500             :  * That is, does it need to be modified
    2501             :  * by isl_schedule_tree_pullback_union_pw_multi_aff?
    2502             :  */
    2503           0 : static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
    2504             : {
    2505           0 :         if (!tree)
    2506           0 :                 return -1;
    2507             : 
    2508           0 :         switch (tree->type) {
    2509             :         case isl_schedule_node_error:
    2510           0 :                 return -1;
    2511             :         case isl_schedule_node_band:
    2512             :         case isl_schedule_node_domain:
    2513             :         case isl_schedule_node_expansion:
    2514             :         case isl_schedule_node_extension:
    2515             :         case isl_schedule_node_filter:
    2516           0 :                 return 1;
    2517             :         case isl_schedule_node_context:
    2518             :         case isl_schedule_node_leaf:
    2519             :         case isl_schedule_node_guard:
    2520             :         case isl_schedule_node_mark:
    2521             :         case isl_schedule_node_sequence:
    2522             :         case isl_schedule_node_set:
    2523           0 :                 return 0;
    2524             :         }
    2525             : 
    2526           0 :         isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
    2527             :                 "unhandled case", return -1);
    2528             : }
    2529             : 
    2530             : /* Compute the pullback of the root node of "tree" by the function
    2531             :  * represented by "upma".
    2532             :  * In other words, plug in "upma" in the iteration domains of
    2533             :  * the root node of "tree".
    2534             :  * We currently do not handle expansion nodes.
    2535             :  *
    2536             :  * We first check if the root node involves any iteration domains.
    2537             :  * If so, we handle the specific cases.
    2538             :  */
    2539           0 : __isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
    2540             :         __isl_take isl_schedule_tree *tree,
    2541             :         __isl_take isl_union_pw_multi_aff *upma)
    2542             : {
    2543             :         int involves;
    2544             : 
    2545           0 :         if (!tree || !upma)
    2546             :                 goto error;
    2547             : 
    2548           0 :         involves = involves_iteration_domain(tree);
    2549           0 :         if (involves < 0)
    2550           0 :                 goto error;
    2551           0 :         if (!involves) {
    2552           0 :                 isl_union_pw_multi_aff_free(upma);
    2553           0 :                 return tree;
    2554             :         }
    2555             : 
    2556           0 :         tree = isl_schedule_tree_cow(tree);
    2557           0 :         if (!tree)
    2558           0 :                 goto error;
    2559             : 
    2560           0 :         if (tree->type == isl_schedule_node_band) {
    2561           0 :                 tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
    2562             :                                                             tree->band, upma);
    2563           0 :                 if (!tree->band)
    2564           0 :                         return isl_schedule_tree_free(tree);
    2565           0 :         } else if (tree->type == isl_schedule_node_domain) {
    2566           0 :                 tree->domain =
    2567           0 :                         isl_union_set_preimage_union_pw_multi_aff(tree->domain,
    2568             :                                                                         upma);
    2569           0 :                 if (!tree->domain)
    2570           0 :                         return isl_schedule_tree_free(tree);
    2571           0 :         } else if (tree->type == isl_schedule_node_expansion) {
    2572           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
    2573             :                         "cannot pullback expansion node", goto error);
    2574           0 :         } else if (tree->type == isl_schedule_node_extension) {
    2575           0 :                 tree->extension =
    2576           0 :                         isl_union_map_preimage_range_union_pw_multi_aff(
    2577             :                             tree->extension, upma);
    2578           0 :                 if (!tree->extension)
    2579           0 :                         return isl_schedule_tree_free(tree);
    2580           0 :         } else if (tree->type == isl_schedule_node_filter) {
    2581           0 :                 tree->filter =
    2582           0 :                         isl_union_set_preimage_union_pw_multi_aff(tree->filter,
    2583             :                                                                         upma);
    2584           0 :                 if (!tree->filter)
    2585           0 :                         return isl_schedule_tree_free(tree);
    2586             :         }
    2587             : 
    2588           0 :         return tree;
    2589             : error:
    2590           0 :         isl_union_pw_multi_aff_free(upma);
    2591           0 :         isl_schedule_tree_free(tree);
    2592           0 :         return NULL;
    2593             : }
    2594             : 
    2595             : /* Compute the gist of the band tree root with respect to "context".
    2596             :  */
    2597           0 : __isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
    2598             :         __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
    2599             : {
    2600           0 :         if (!tree)
    2601           0 :                 return NULL;
    2602           0 :         if (tree->type != isl_schedule_node_band)
    2603           0 :                 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
    2604             :                         "not a band node", goto error);
    2605           0 :         tree = isl_schedule_tree_cow(tree);
    2606           0 :         if (!tree)
    2607           0 :                 goto error;
    2608             : 
    2609           0 :         tree->band = isl_schedule_band_gist(tree->band, context);
    2610           0 :         if (!tree->band)
    2611           0 :                 return isl_schedule_tree_free(tree);
    2612           0 :         return tree;
    2613             : error:
    2614           0 :         isl_union_set_free(context);
    2615           0 :         isl_schedule_tree_free(tree);
    2616           0 :         return NULL;
    2617             : }
    2618             : 
    2619             : /* Are any members in "band" marked coincident?
    2620             :  */
    2621           0 : static isl_bool any_coincident(__isl_keep isl_schedule_band *band)
    2622             : {
    2623             :         int i, n;
    2624             : 
    2625           0 :         n = isl_schedule_band_n_member(band);
    2626           0 :         for (i = 0; i < n; ++i) {
    2627             :                 isl_bool coincident;
    2628             : 
    2629           0 :                 coincident = isl_schedule_band_member_get_coincident(band, i);
    2630           0 :                 if (coincident < 0 || coincident)
    2631           0 :                         return coincident;
    2632             :         }
    2633             : 
    2634           0 :         return isl_bool_false;
    2635             : }
    2636             : 
    2637             : /* Print the band node "band" to "p".
    2638             :  *
    2639             :  * The permutable and coincident properties are only printed if they
    2640             :  * are different from the defaults.
    2641             :  * The coincident property is always printed in YAML flow style.
    2642             :  */
    2643           0 : static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
    2644             :         __isl_keep isl_schedule_band *band)
    2645             : {
    2646             :         isl_union_set *options;
    2647             :         int empty;
    2648             :         isl_bool coincident;
    2649             : 
    2650           0 :         p = isl_printer_print_str(p, "schedule");
    2651           0 :         p = isl_printer_yaml_next(p);
    2652           0 :         p = isl_printer_print_str(p, "\"");
    2653           0 :         p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
    2654           0 :         p = isl_printer_print_str(p, "\"");
    2655           0 :         if (isl_schedule_band_get_permutable(band)) {
    2656           0 :                 p = isl_printer_yaml_next(p);
    2657           0 :                 p = isl_printer_print_str(p, "permutable");
    2658           0 :                 p = isl_printer_yaml_next(p);
    2659           0 :                 p = isl_printer_print_int(p, 1);
    2660             :         }
    2661           0 :         coincident = any_coincident(band);
    2662           0 :         if (coincident < 0)
    2663           0 :                 return isl_printer_free(p);
    2664           0 :         if (coincident) {
    2665             :                 int i, n;
    2666             :                 int style;
    2667             : 
    2668           0 :                 p = isl_printer_yaml_next(p);
    2669           0 :                 p = isl_printer_print_str(p, "coincident");
    2670           0 :                 p = isl_printer_yaml_next(p);
    2671           0 :                 style = isl_printer_get_yaml_style(p);
    2672           0 :                 p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
    2673           0 :                 p = isl_printer_yaml_start_sequence(p);
    2674           0 :                 n = isl_schedule_band_n_member(band);
    2675           0 :                 for (i = 0; i < n; ++i) {
    2676           0 :                         p = isl_printer_print_int(p,
    2677           0 :                             isl_schedule_band_member_get_coincident(band, i));
    2678           0 :                         p = isl_printer_yaml_next(p);
    2679             :                 }
    2680           0 :                 p = isl_printer_yaml_end_sequence(p);
    2681           0 :                 p = isl_printer_set_yaml_style(p, style);
    2682             :         }
    2683           0 :         options = isl_schedule_band_get_ast_build_options(band);
    2684           0 :         empty = isl_union_set_is_empty(options);
    2685           0 :         if (empty < 0)
    2686           0 :                 p = isl_printer_free(p);
    2687           0 :         if (!empty) {
    2688           0 :                 p = isl_printer_yaml_next(p);
    2689           0 :                 p = isl_printer_print_str(p, "options");
    2690           0 :                 p = isl_printer_yaml_next(p);
    2691           0 :                 p = isl_printer_print_str(p, "\"");
    2692           0 :                 p = isl_printer_print_union_set(p, options);
    2693           0 :                 p = isl_printer_print_str(p, "\"");
    2694             :         }
    2695           0 :         isl_union_set_free(options);
    2696             : 
    2697           0 :         return p;
    2698             : }
    2699             : 
    2700             : /* Print "tree" to "p".
    2701             :  *
    2702             :  * If "n_ancestor" is non-negative, then "child_pos" contains the child
    2703             :  * positions of a descendant of the current node that should be marked
    2704             :  * (by the comment "YOU ARE HERE").  In particular, if "n_ancestor"
    2705             :  * is zero, then the current node should be marked.
    2706             :  * The marking is only printed in YAML block format.
    2707             :  *
    2708             :  * Implicit leaf nodes are not printed, except if they correspond
    2709             :  * to the node that should be marked.
    2710             :  */
    2711           0 : __isl_give isl_printer *isl_printer_print_schedule_tree_mark(
    2712             :         __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
    2713             :         int n_ancestor, int *child_pos)
    2714             : {
    2715             :         int i, n;
    2716           0 :         int sequence = 0;
    2717             :         int block;
    2718             : 
    2719           0 :         block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;
    2720             : 
    2721           0 :         p = isl_printer_yaml_start_mapping(p);
    2722           0 :         if (n_ancestor == 0 && block) {
    2723           0 :                 p = isl_printer_print_str(p, "# YOU ARE HERE");
    2724           0 :                 p = isl_printer_end_line(p);
    2725           0 :                 p = isl_printer_start_line(p);
    2726             :         }
    2727           0 :         switch (tree->type) {
    2728             :         case isl_schedule_node_error:
    2729           0 :                 p = isl_printer_print_str(p, "ERROR");
    2730           0 :                 break;
    2731             :         case isl_schedule_node_leaf:
    2732           0 :                 p = isl_printer_print_str(p, "leaf");
    2733           0 :                 break;
    2734             :         case isl_schedule_node_sequence:
    2735           0 :                 p = isl_printer_print_str(p, "sequence");
    2736           0 :                 sequence = 1;
    2737           0 :                 break;
    2738             :         case isl_schedule_node_set:
    2739           0 :                 p = isl_printer_print_str(p, "set");
    2740           0 :                 sequence = 1;
    2741           0 :                 break;
    2742             :         case isl_schedule_node_context:
    2743           0 :                 p = isl_printer_print_str(p, "context");
    2744           0 :                 p = isl_printer_yaml_next(p);
    2745           0 :                 p = isl_printer_print_str(p, "\"");
    2746           0 :                 p = isl_printer_print_set(p, tree->context);
    2747           0 :                 p = isl_printer_print_str(p, "\"");
    2748           0 :                 break;
    2749             :         case isl_schedule_node_domain:
    2750           0 :                 p = isl_printer_print_str(p, "domain");
    2751           0 :                 p = isl_printer_yaml_next(p);
    2752           0 :                 p = isl_printer_print_str(p, "\"");
    2753           0 :                 p = isl_printer_print_union_set(p, tree->domain);
    2754           0 :                 p = isl_printer_print_str(p, "\"");
    2755           0 :                 break;
    2756             :         case isl_schedule_node_expansion:
    2757           0 :                 p = isl_printer_print_str(p, "contraction");
    2758           0 :                 p = isl_printer_yaml_next(p);
    2759           0 :                 p = isl_printer_print_str(p, "\"");
    2760           0 :                 p = isl_printer_print_union_pw_multi_aff(p, tree->contraction);
    2761           0 :                 p = isl_printer_print_str(p, "\"");
    2762           0 :                 p = isl_printer_yaml_next(p);
    2763           0 :                 p = isl_printer_print_str(p, "expansion");
    2764           0 :                 p = isl_printer_yaml_next(p);
    2765           0 :                 p = isl_printer_print_str(p, "\"");
    2766           0 :                 p = isl_printer_print_union_map(p, tree->expansion);
    2767           0 :                 p = isl_printer_print_str(p, "\"");
    2768           0 :                 break;
    2769             :         case isl_schedule_node_extension:
    2770           0 :                 p = isl_printer_print_str(p, "extension");
    2771           0 :                 p = isl_printer_yaml_next(p);
    2772           0 :                 p = isl_printer_print_str(p, "\"");
    2773           0 :                 p = isl_printer_print_union_map(p, tree->extension);
    2774           0 :                 p = isl_printer_print_str(p, "\"");
    2775           0 :                 break;
    2776             :         case isl_schedule_node_filter:
    2777           0 :                 p = isl_printer_print_str(p, "filter");
    2778           0 :                 p = isl_printer_yaml_next(p);
    2779           0 :                 p = isl_printer_print_str(p, "\"");
    2780           0 :                 p = isl_printer_print_union_set(p, tree->filter);
    2781           0 :                 p = isl_printer_print_str(p, "\"");
    2782           0 :                 break;
    2783             :         case isl_schedule_node_guard:
    2784           0 :                 p = isl_printer_print_str(p, "guard");
    2785           0 :                 p = isl_printer_yaml_next(p);
    2786           0 :                 p = isl_printer_print_str(p, "\"");
    2787           0 :                 p = isl_printer_print_set(p, tree->guard);
    2788           0 :                 p = isl_printer_print_str(p, "\"");
    2789           0 :                 break;
    2790             :         case isl_schedule_node_mark:
    2791           0 :                 p = isl_printer_print_str(p, "mark");
    2792           0 :                 p = isl_printer_yaml_next(p);
    2793           0 :                 p = isl_printer_print_str(p, "\"");
    2794           0 :                 p = isl_printer_print_str(p, isl_id_get_name(tree->mark));
    2795           0 :                 p = isl_printer_print_str(p, "\"");
    2796           0 :                 break;
    2797             :         case isl_schedule_node_band:
    2798           0 :                 p = print_tree_band(p, tree->band);
    2799           0 :                 break;
    2800             :         }
    2801           0 :         p = isl_printer_yaml_next(p);
    2802             : 
    2803           0 :         if (!tree->children) {
    2804           0 :                 if (n_ancestor > 0 && block) {
    2805             :                         isl_schedule_tree *leaf;
    2806             : 
    2807           0 :                         p = isl_printer_print_str(p, "child");
    2808           0 :                         p = isl_printer_yaml_next(p);
    2809           0 :                         leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
    2810           0 :                         p = isl_printer_print_schedule_tree_mark(p,
    2811             :                                         leaf, 0, NULL);
    2812           0 :                         isl_schedule_tree_free(leaf);
    2813           0 :                         p = isl_printer_yaml_next(p);
    2814             :                 }
    2815           0 :                 return isl_printer_yaml_end_mapping(p);
    2816             :         }
    2817             : 
    2818           0 :         if (sequence) {
    2819           0 :                 p = isl_printer_yaml_start_sequence(p);
    2820             :         } else {
    2821           0 :                 p = isl_printer_print_str(p, "child");
    2822           0 :                 p = isl_printer_yaml_next(p);
    2823             :         }
    2824             : 
    2825           0 :         n = isl_schedule_tree_list_n_schedule_tree(tree->children);
    2826           0 :         for (i = 0; i < n; ++i) {
    2827             :                 isl_schedule_tree *t;
    2828             : 
    2829           0 :                 t = isl_schedule_tree_get_child(tree, i);
    2830           0 :                 if (n_ancestor > 0 && child_pos[0] == i)
    2831           0 :                         p = isl_printer_print_schedule_tree_mark(p, t,
    2832             :                                                 n_ancestor - 1, child_pos + 1);
    2833             :                 else
    2834           0 :                         p = isl_printer_print_schedule_tree_mark(p, t,
    2835             :                                                 -1, NULL);
    2836           0 :                 isl_schedule_tree_free(t);
    2837             : 
    2838           0 :                 p = isl_printer_yaml_next(p);
    2839             :         }
    2840             : 
    2841           0 :         if (sequence)
    2842           0 :                 p = isl_printer_yaml_end_sequence(p);
    2843           0 :         p = isl_printer_yaml_end_mapping(p);
    2844             : 
    2845           0 :         return p;
    2846             : }
    2847             : 
    2848             : /* Print "tree" to "p".
    2849             :  */
    2850           0 : __isl_give isl_printer *isl_printer_print_schedule_tree(
    2851             :         __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
    2852             : {
    2853           0 :         return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
    2854             : }
    2855             : 
    2856           0 : void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
    2857             : {
    2858             :         isl_ctx *ctx;
    2859             :         isl_printer *printer;
    2860             : 
    2861           0 :         if (!tree)
    2862           0 :                 return;
    2863             : 
    2864           0 :         ctx = isl_schedule_tree_get_ctx(tree);
    2865           0 :         printer = isl_printer_to_file(ctx, stderr);
    2866           0 :         printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
    2867           0 :         printer = isl_printer_print_schedule_tree(printer, tree);
    2868             : 
    2869           0 :         isl_printer_free(printer);
    2870             : }

Generated by: LCOV version 1.12