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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012      Ecole Normale Superieure
       3             :  * Copyright 2014      INRIA Rocquencourt
       4             :  *
       5             :  * Use of this software is governed by the MIT license
       6             :  *
       7             :  * Written by Sven Verdoolaege,
       8             :  * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
       9             :  * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
      10             :  * B.P. 105 - 78153 Le Chesnay, France
      11             :  */
      12             : 
      13             : #include <isl/id.h>
      14             : #include <isl/space.h>
      15             : #include <isl_ast_private.h>
      16             : #include <isl_ast_build_expr.h>
      17             : #include <isl_ast_build_private.h>
      18             : #include <isl_ast_graft_private.h>
      19             : 
      20             : static __isl_give isl_ast_graft *isl_ast_graft_copy(
      21             :         __isl_keep isl_ast_graft *graft);
      22             : 
      23             : #undef BASE
      24             : #define BASE ast_graft
      25             : 
      26             : #include <isl_list_templ.c>
      27             : 
      28             : #undef BASE
      29             : #define BASE ast_graft
      30             : #include <print_templ.c>
      31             : 
      32           0 : isl_ctx *isl_ast_graft_get_ctx(__isl_keep isl_ast_graft *graft)
      33             : {
      34           0 :         if (!graft)
      35           0 :                 return NULL;
      36           0 :         return isl_basic_set_get_ctx(graft->enforced);
      37             : }
      38             : 
      39           0 : __isl_give isl_ast_node *isl_ast_graft_get_node(
      40             :         __isl_keep isl_ast_graft *graft)
      41             : {
      42           0 :         return graft ? isl_ast_node_copy(graft->node) : NULL;
      43             : }
      44             : 
      45             : /* Create a graft for "node" with no guards and no enforced conditions.
      46             :  */
      47           0 : __isl_give isl_ast_graft *isl_ast_graft_alloc(
      48             :         __isl_take isl_ast_node *node, __isl_keep isl_ast_build *build)
      49             : {
      50             :         isl_ctx *ctx;
      51             :         isl_space *space;
      52             :         isl_ast_graft *graft;
      53             : 
      54           0 :         if (!node)
      55           0 :                 return NULL;
      56             : 
      57           0 :         ctx = isl_ast_node_get_ctx(node);
      58           0 :         graft = isl_calloc_type(ctx, isl_ast_graft);
      59           0 :         if (!graft)
      60           0 :                 goto error;
      61             : 
      62           0 :         space = isl_ast_build_get_space(build, 1);
      63             : 
      64           0 :         graft->ref = 1;
      65           0 :         graft->node = node;
      66           0 :         graft->guard = isl_set_universe(isl_space_copy(space));
      67           0 :         graft->enforced = isl_basic_set_universe(space);
      68             : 
      69           0 :         if (!graft->guard || !graft->enforced)
      70           0 :                 return isl_ast_graft_free(graft);
      71             : 
      72           0 :         return graft;
      73             : error:
      74           0 :         isl_ast_node_free(node);
      75           0 :         return NULL;
      76             : }
      77             : 
      78             : /* Create a graft with no guards and no enforced conditions
      79             :  * encapsulating a call to the domain element specified by "executed".
      80             :  * "executed" is assumed to be single-valued.
      81             :  */
      82           0 : __isl_give isl_ast_graft *isl_ast_graft_alloc_domain(
      83             :         __isl_take isl_map *executed, __isl_keep isl_ast_build *build)
      84             : {
      85             :         isl_ast_node *node;
      86             : 
      87           0 :         node = isl_ast_build_call_from_executed(build, executed);
      88             : 
      89           0 :         return isl_ast_graft_alloc(node, build);
      90             : }
      91             : 
      92           0 : static __isl_give isl_ast_graft *isl_ast_graft_copy(
      93             :         __isl_keep isl_ast_graft *graft)
      94             : {
      95           0 :         if (!graft)
      96           0 :                 return NULL;
      97             : 
      98           0 :         graft->ref++;
      99           0 :         return graft;
     100             : }
     101             : 
     102             : /* Do all the grafts in "list" have the same guard and is this guard
     103             :  * independent of the current depth?
     104             :  */
     105           0 : static int equal_independent_guards(__isl_keep isl_ast_graft_list *list,
     106             :         __isl_keep isl_ast_build *build)
     107             : {
     108             :         int i, n;
     109             :         int depth;
     110             :         isl_ast_graft *graft_0;
     111           0 :         int equal = 1;
     112             :         int skip;
     113             : 
     114           0 :         graft_0 = isl_ast_graft_list_get_ast_graft(list, 0);
     115           0 :         if (!graft_0)
     116           0 :                 return -1;
     117             : 
     118           0 :         depth = isl_ast_build_get_depth(build);
     119           0 :         if (isl_set_dim(graft_0->guard, isl_dim_set) <= depth)
     120           0 :                 skip = 0;
     121             :         else
     122           0 :                 skip = isl_set_involves_dims(graft_0->guard,
     123             :                                                 isl_dim_set, depth, 1);
     124           0 :         if (skip < 0 || skip) {
     125           0 :                 isl_ast_graft_free(graft_0);
     126           0 :                 return skip < 0 ? -1 : 0;
     127             :         }
     128             : 
     129           0 :         n = isl_ast_graft_list_n_ast_graft(list);
     130           0 :         for (i = 1; i < n; ++i) {
     131             :                 isl_ast_graft *graft;
     132           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
     133           0 :                 if (!graft)
     134           0 :                         equal = -1;
     135             :                 else
     136           0 :                         equal = isl_set_is_equal(graft_0->guard, graft->guard);
     137           0 :                 isl_ast_graft_free(graft);
     138           0 :                 if (equal < 0 || !equal)
     139             :                         break;
     140             :         }
     141             : 
     142           0 :         isl_ast_graft_free(graft_0);
     143             : 
     144           0 :         return equal;
     145             : }
     146             : 
     147             : /* Hoist "guard" out of the current level (given by "build").
     148             :  *
     149             :  * In particular, eliminate the dimension corresponding to the current depth.
     150             :  */
     151           0 : static __isl_give isl_set *hoist_guard(__isl_take isl_set *guard,
     152             :         __isl_keep isl_ast_build *build)
     153             : {
     154             :         int depth;
     155             : 
     156           0 :         depth = isl_ast_build_get_depth(build);
     157           0 :         if (depth < isl_set_dim(guard, isl_dim_set)) {
     158           0 :                 guard = isl_set_remove_divs_involving_dims(guard,
     159             :                                                 isl_dim_set, depth, 1);
     160           0 :                 guard = isl_set_eliminate(guard, isl_dim_set, depth, 1);
     161           0 :                 guard = isl_set_compute_divs(guard);
     162             :         }
     163             : 
     164           0 :         return guard;
     165             : }
     166             : 
     167             : /* Extract a common guard from the grafts in "list" that can be hoisted
     168             :  * out of the current level.  If no such guard can be found, then return
     169             :  * a universal set.
     170             :  *
     171             :  * If all the grafts in the list have the same guard and if this guard
     172             :  * is independent of the current level, then it can be hoisted out.
     173             :  * If there is only one graft in the list and if its guard
     174             :  * depends on the current level, then we eliminate this level and
     175             :  * return the result.
     176             :  *
     177             :  * Otherwise, we return the unshifted simple hull of the guards.
     178             :  * In order to be able to hoist as many constraints as possible,
     179             :  * but at the same time avoid hoisting constraints that did not
     180             :  * appear in the guards in the first place, we intersect the guards
     181             :  * with all the information that is available (i.e., the domain
     182             :  * from the build and the enforced constraints of the graft) and
     183             :  * compute the unshifted hull of the result using only constraints
     184             :  * from the original guards.
     185             :  * In particular, intersecting the guards with other known information
     186             :  * allows us to hoist guards that are only explicit is some of
     187             :  * the grafts and implicit in the others.
     188             :  *
     189             :  * The special case for equal guards is needed in case those guards
     190             :  * are non-convex.  Taking the simple hull would remove information
     191             :  * and would not allow for these guards to be hoisted completely.
     192             :  */
     193           0 : __isl_give isl_set *isl_ast_graft_list_extract_hoistable_guard(
     194             :         __isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build)
     195             : {
     196             :         int i, n;
     197             :         int equal;
     198             :         isl_ctx *ctx;
     199             :         isl_set *guard;
     200             :         isl_set_list *set_list;
     201             :         isl_basic_set *hull;
     202             : 
     203           0 :         if (!list || !build)
     204           0 :                 return NULL;
     205             : 
     206           0 :         n = isl_ast_graft_list_n_ast_graft(list);
     207           0 :         if (n == 0)
     208           0 :                 return isl_set_universe(isl_ast_build_get_space(build, 1));
     209             : 
     210           0 :         equal = equal_independent_guards(list, build);
     211           0 :         if (equal < 0)
     212           0 :                 return NULL;
     213             : 
     214           0 :         if (equal || n == 1) {
     215             :                 isl_ast_graft *graft_0;
     216             : 
     217           0 :                 graft_0 = isl_ast_graft_list_get_ast_graft(list, 0);
     218           0 :                 if (!graft_0)
     219           0 :                         return NULL;
     220           0 :                 guard = isl_set_copy(graft_0->guard);
     221           0 :                 if (!equal)
     222           0 :                         guard = hoist_guard(guard, build);
     223           0 :                 isl_ast_graft_free(graft_0);
     224           0 :                 return guard;
     225             :         }
     226             : 
     227           0 :         ctx = isl_ast_build_get_ctx(build);
     228           0 :         set_list = isl_set_list_alloc(ctx, n);
     229           0 :         guard = isl_set_empty(isl_ast_build_get_space(build, 1));
     230           0 :         for (i = 0; i < n; ++i) {
     231             :                 isl_ast_graft *graft;
     232             :                 isl_basic_set *enforced;
     233             :                 isl_set *guard_i;
     234             : 
     235           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
     236           0 :                 enforced = isl_ast_graft_get_enforced(graft);
     237           0 :                 guard_i = isl_set_copy(graft->guard);
     238           0 :                 isl_ast_graft_free(graft);
     239           0 :                 set_list = isl_set_list_add(set_list, isl_set_copy(guard_i));
     240           0 :                 guard_i = isl_set_intersect(guard_i,
     241             :                                             isl_set_from_basic_set(enforced));
     242           0 :                 guard_i = isl_set_intersect(guard_i,
     243             :                                             isl_ast_build_get_domain(build));
     244           0 :                 guard = isl_set_union(guard, guard_i);
     245             :         }
     246           0 :         hull = isl_set_unshifted_simple_hull_from_set_list(guard, set_list);
     247           0 :         guard = isl_set_from_basic_set(hull);
     248           0 :         return hoist_guard(guard, build);
     249             : }
     250             : 
     251             : /* Internal data structure used inside insert_if.
     252             :  *
     253             :  * list is the list of guarded nodes created by each call to insert_if.
     254             :  * node is the original node that is guarded by insert_if.
     255             :  * build is the build in which the AST is constructed.
     256             :  */
     257             : struct isl_insert_if_data {
     258             :         isl_ast_node_list *list;
     259             :         isl_ast_node *node;
     260             :         isl_ast_build *build;
     261             : };
     262             : 
     263             : static isl_stat insert_if(__isl_take isl_basic_set *bset, void *user);
     264             : 
     265             : /* Insert an if node around "node" testing the condition encoded
     266             :  * in guard "guard".
     267             :  *
     268             :  * If the user does not want any disjunctions in the if conditions
     269             :  * and if "guard" does involve a disjunction, then we make the different
     270             :  * disjuncts disjoint and insert an if node corresponding to each disjunct
     271             :  * around a copy of "node".  The result is then a block node containing
     272             :  * this sequence of guarded copies of "node".
     273             :  */
     274           0 : static __isl_give isl_ast_node *ast_node_insert_if(
     275             :         __isl_take isl_ast_node *node, __isl_take isl_set *guard,
     276             :         __isl_keep isl_ast_build *build)
     277             : {
     278             :         struct isl_insert_if_data data;
     279             :         isl_ctx *ctx;
     280             : 
     281           0 :         ctx = isl_ast_build_get_ctx(build);
     282           0 :         if (isl_options_get_ast_build_allow_or(ctx) ||
     283           0 :             isl_set_n_basic_set(guard) <= 1) {
     284             :                 isl_ast_node *if_node;
     285             :                 isl_ast_expr *expr;
     286             : 
     287           0 :                 expr = isl_ast_build_expr_from_set_internal(build, guard);
     288             : 
     289           0 :                 if_node = isl_ast_node_alloc_if(expr);
     290           0 :                 return isl_ast_node_if_set_then(if_node, node);
     291             :         }
     292             : 
     293           0 :         guard = isl_set_make_disjoint(guard);
     294             : 
     295           0 :         data.list = isl_ast_node_list_alloc(ctx, 0);
     296           0 :         data.node = node;
     297           0 :         data.build = build;
     298           0 :         if (isl_set_foreach_basic_set(guard, &insert_if, &data) < 0)
     299           0 :                 data.list = isl_ast_node_list_free(data.list);
     300             : 
     301           0 :         isl_set_free(guard);
     302           0 :         isl_ast_node_free(data.node);
     303           0 :         return isl_ast_node_alloc_block(data.list);
     304             : }
     305             : 
     306             : /* Insert an if node around a copy of "data->node" testing the condition
     307             :  * encoded in guard "bset" and add the result to data->list.
     308             :  */
     309           0 : static isl_stat insert_if(__isl_take isl_basic_set *bset, void *user)
     310             : {
     311           0 :         struct isl_insert_if_data *data = user;
     312             :         isl_ast_node *node;
     313             :         isl_set *set;
     314             : 
     315           0 :         set = isl_set_from_basic_set(bset);
     316           0 :         node = isl_ast_node_copy(data->node);
     317           0 :         node = ast_node_insert_if(node, set, data->build);
     318           0 :         data->list = isl_ast_node_list_add(data->list, node);
     319             : 
     320           0 :         return isl_stat_ok;
     321             : }
     322             : 
     323             : /* Insert an if node around graft->node testing the condition encoded
     324             :  * in guard "guard", assuming guard involves any conditions.
     325             :  */
     326           0 : static __isl_give isl_ast_graft *insert_if_node(
     327             :         __isl_take isl_ast_graft *graft, __isl_take isl_set *guard,
     328             :         __isl_keep isl_ast_build *build)
     329             : {
     330             :         int univ;
     331             : 
     332           0 :         if (!graft)
     333           0 :                 goto error;
     334             : 
     335           0 :         univ = isl_set_plain_is_universe(guard);
     336           0 :         if (univ < 0)
     337           0 :                 goto error;
     338           0 :         if (univ) {
     339           0 :                 isl_set_free(guard);
     340           0 :                 return graft;
     341             :         }
     342             : 
     343           0 :         build = isl_ast_build_copy(build);
     344           0 :         graft->node = ast_node_insert_if(graft->node, guard, build);
     345           0 :         isl_ast_build_free(build);
     346             : 
     347           0 :         if (!graft->node)
     348           0 :                 return isl_ast_graft_free(graft);
     349             : 
     350           0 :         return graft;
     351             : error:
     352           0 :         isl_set_free(guard);
     353           0 :         return isl_ast_graft_free(graft);
     354             : }
     355             : 
     356             : /* Insert an if node around graft->node testing the condition encoded
     357             :  * in graft->guard, assuming graft->guard involves any conditions.
     358             :  */
     359           0 : static __isl_give isl_ast_graft *insert_pending_guard_node(
     360             :         __isl_take isl_ast_graft *graft, __isl_keep isl_ast_build *build)
     361             : {
     362           0 :         if (!graft)
     363           0 :                 return NULL;
     364             : 
     365           0 :         return insert_if_node(graft, isl_set_copy(graft->guard), build);
     366             : }
     367             : 
     368             : /* Replace graft->enforced by "enforced".
     369             :  */
     370           0 : __isl_give isl_ast_graft *isl_ast_graft_set_enforced(
     371             :         __isl_take isl_ast_graft *graft, __isl_take isl_basic_set *enforced)
     372             : {
     373           0 :         if (!graft || !enforced)
     374             :                 goto error;
     375             : 
     376           0 :         isl_basic_set_free(graft->enforced);
     377           0 :         graft->enforced = enforced;
     378             : 
     379           0 :         return graft;
     380             : error:
     381           0 :         isl_basic_set_free(enforced);
     382           0 :         return isl_ast_graft_free(graft);
     383             : }
     384             : 
     385             : /* Update "enforced" such that it only involves constraints that are
     386             :  * also enforced by "graft".
     387             :  */
     388           0 : static __isl_give isl_basic_set *update_enforced(
     389             :         __isl_take isl_basic_set *enforced, __isl_keep isl_ast_graft *graft,
     390             :         int depth)
     391             : {
     392             :         isl_basic_set *enforced_g;
     393             : 
     394           0 :         enforced_g = isl_ast_graft_get_enforced(graft);
     395           0 :         if (depth < isl_basic_set_dim(enforced_g, isl_dim_set))
     396           0 :                 enforced_g = isl_basic_set_eliminate(enforced_g,
     397             :                                                         isl_dim_set, depth, 1);
     398           0 :         enforced_g = isl_basic_set_remove_unknown_divs(enforced_g);
     399           0 :         enforced_g = isl_basic_set_align_params(enforced_g,
     400             :                                 isl_basic_set_get_space(enforced));
     401           0 :         enforced = isl_basic_set_align_params(enforced,
     402             :                                 isl_basic_set_get_space(enforced_g));
     403           0 :         enforced = isl_set_simple_hull(isl_basic_set_union(enforced,
     404             :                                                 enforced_g));
     405             : 
     406           0 :         return enforced;
     407             : }
     408             : 
     409             : /* Extend the node at *body with node.
     410             :  *
     411             :  * If body points to the else branch, then *body may still be NULL.
     412             :  * If so, we simply attach node to this else branch.
     413             :  * Otherwise, we attach a list containing the statements already
     414             :  * attached at *body followed by node.
     415             :  */
     416           0 : static void extend_body(__isl_keep isl_ast_node **body,
     417             :         __isl_take isl_ast_node *node)
     418             : {
     419             :         isl_ast_node_list *list;
     420             : 
     421           0 :         if  (!*body) {
     422           0 :                 *body = node;
     423           0 :                 return;
     424             :         }
     425             : 
     426           0 :         if ((*body)->type == isl_ast_node_block) {
     427           0 :                 list = isl_ast_node_block_get_children(*body);
     428           0 :                 isl_ast_node_free(*body);
     429             :         } else
     430           0 :                 list = isl_ast_node_list_from_ast_node(*body);
     431           0 :         list = isl_ast_node_list_add(list, node);
     432           0 :         *body = isl_ast_node_alloc_block(list);
     433             : }
     434             : 
     435             : /* Merge "graft" into the last graft of "list".
     436             :  * body points to the then or else branch of an if node in that last graft.
     437             :  *
     438             :  * We attach graft->node to this branch and update the enforced
     439             :  * set of the last graft of "list" to take into account the enforced
     440             :  * set of "graft".
     441             :  */
     442           0 : static __isl_give isl_ast_graft_list *graft_extend_body(
     443             :         __isl_take isl_ast_graft_list *list,
     444             :         __isl_keep isl_ast_node **body, __isl_take isl_ast_graft *graft,
     445             :         __isl_keep isl_ast_build *build)
     446             : {
     447             :         int n;
     448             :         int depth;
     449             :         isl_ast_graft *last;
     450             :         isl_space *space;
     451             :         isl_basic_set *enforced;
     452             : 
     453           0 :         if (!list || !graft)
     454             :                 goto error;
     455           0 :         extend_body(body, isl_ast_node_copy(graft->node));
     456           0 :         if (!*body)
     457           0 :                 goto error;
     458             : 
     459           0 :         n = isl_ast_graft_list_n_ast_graft(list);
     460           0 :         last = isl_ast_graft_list_get_ast_graft(list, n - 1);
     461             : 
     462           0 :         depth = isl_ast_build_get_depth(build);
     463           0 :         space = isl_ast_build_get_space(build, 1);
     464           0 :         enforced = isl_basic_set_empty(space);
     465           0 :         enforced = update_enforced(enforced, last, depth);
     466           0 :         enforced = update_enforced(enforced, graft, depth);
     467           0 :         last = isl_ast_graft_set_enforced(last, enforced);
     468             : 
     469           0 :         list = isl_ast_graft_list_set_ast_graft(list, n - 1, last);
     470           0 :         isl_ast_graft_free(graft);
     471           0 :         return list;
     472             : error:
     473           0 :         isl_ast_graft_free(graft);
     474           0 :         return isl_ast_graft_list_free(list);
     475             : }
     476             : 
     477             : /* Merge "graft" into the last graft of "list", attaching graft->node
     478             :  * to the then branch of "last_if".
     479             :  */
     480           0 : static __isl_give isl_ast_graft_list *extend_then(
     481             :         __isl_take isl_ast_graft_list *list,
     482             :         __isl_keep isl_ast_node *last_if, __isl_take isl_ast_graft *graft,
     483             :         __isl_keep isl_ast_build *build)
     484             : {
     485           0 :         return graft_extend_body(list, &last_if->u.i.then, graft, build);
     486             : }
     487             : 
     488             : /* Merge "graft" into the last graft of "list", attaching graft->node
     489             :  * to the else branch of "last_if".
     490             :  */
     491           0 : static __isl_give isl_ast_graft_list *extend_else(
     492             :         __isl_take isl_ast_graft_list *list,
     493             :         __isl_keep isl_ast_node *last_if, __isl_take isl_ast_graft *graft,
     494             :         __isl_keep isl_ast_build *build)
     495             : {
     496           0 :         return graft_extend_body(list, &last_if->u.i.else_node, graft, build);
     497             : }
     498             : 
     499             : /* This data structure keeps track of an if node.
     500             :  *
     501             :  * "node" is the actual if-node
     502             :  * "guard" is the original, non-simplified guard of the node
     503             :  * "complement" is the complement of "guard" in the context of outer if nodes
     504             :  */
     505             : struct isl_if_node {
     506             :         isl_ast_node *node;
     507             :         isl_set *guard;
     508             :         isl_set *complement;
     509             : };
     510             : 
     511             : /* Given a list of "n" if nodes, clear those starting at "first"
     512             :  * and return "first" (i.e., the updated size of the array).
     513             :  */
     514           0 : static int clear_if_nodes(struct isl_if_node *if_node, int first, int n)
     515             : {
     516             :         int i;
     517             : 
     518           0 :         for (i = first; i < n; ++i) {
     519           0 :                 isl_set_free(if_node[i].guard);
     520           0 :                 isl_set_free(if_node[i].complement);
     521             :         }
     522             : 
     523           0 :         return first;
     524             : }
     525             : 
     526             : /* For each graft in "list",
     527             :  * insert an if node around graft->node testing the condition encoded
     528             :  * in graft->guard, assuming graft->guard involves any conditions.
     529             :  *
     530             :  * We keep track of a list of generated if nodes that can be extended
     531             :  * without changing the order of the elements in "list".
     532             :  * If the guard of a graft is a subset of either the guard or its complement
     533             :  * of one of those if nodes, then the node
     534             :  * of the new graft is inserted into the then or else branch of the last graft
     535             :  * and the current graft is discarded.
     536             :  * The guard of the node is then simplified based on the conditions
     537             :  * enforced at that then or else branch.
     538             :  * Otherwise, the current graft is appended to the list.
     539             :  *
     540             :  * We only construct else branches if allowed by the user.
     541             :  */
     542           0 : static __isl_give isl_ast_graft_list *insert_pending_guard_nodes(
     543             :         __isl_take isl_ast_graft_list *list,
     544             :         __isl_keep isl_ast_build *build)
     545             : {
     546             :         int i, j, n, n_if;
     547             :         int allow_else;
     548             :         isl_ctx *ctx;
     549             :         isl_ast_graft_list *res;
     550           0 :         struct isl_if_node *if_node = NULL;
     551             : 
     552           0 :         if (!build || !list)
     553           0 :                 return isl_ast_graft_list_free(list);
     554             : 
     555           0 :         ctx = isl_ast_build_get_ctx(build);
     556           0 :         n = isl_ast_graft_list_n_ast_graft(list);
     557             : 
     558           0 :         allow_else = isl_options_get_ast_build_allow_else(ctx);
     559             : 
     560           0 :         n_if = 0;
     561           0 :         if (n > 1) {
     562           0 :                 if_node = isl_alloc_array(ctx, struct isl_if_node, n - 1);
     563           0 :                 if (!if_node)
     564           0 :                         return isl_ast_graft_list_free(list);
     565             :         }
     566             : 
     567           0 :         res = isl_ast_graft_list_alloc(ctx, n);
     568             : 
     569           0 :         for (i = 0; i < n; ++i) {
     570             :                 isl_set *guard;
     571             :                 isl_ast_graft *graft;
     572             :                 int subset, found_then, found_else;
     573             :                 isl_ast_node *node;
     574             : 
     575           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
     576           0 :                 if (!graft)
     577           0 :                         break;
     578           0 :                 subset = 0;
     579           0 :                 found_then = found_else = -1;
     580           0 :                 if (n_if > 0) {
     581             :                         isl_set *test;
     582           0 :                         test = isl_set_copy(graft->guard);
     583           0 :                         test = isl_set_intersect(test,
     584             :                                                 isl_set_copy(build->domain));
     585           0 :                         for (j = n_if - 1; j >= 0; --j) {
     586           0 :                                 subset = isl_set_is_subset(test,
     587           0 :                                                         if_node[j].guard);
     588           0 :                                 if (subset < 0 || subset) {
     589           0 :                                         found_then = j;
     590           0 :                                         break;
     591             :                                 }
     592           0 :                                 if (!allow_else)
     593           0 :                                         continue;
     594           0 :                                 subset = isl_set_is_subset(test,
     595           0 :                                                         if_node[j].complement);
     596           0 :                                 if (subset < 0 || subset) {
     597           0 :                                         found_else = j;
     598           0 :                                         break;
     599             :                                 }
     600             :                         }
     601           0 :                         n_if = clear_if_nodes(if_node, j + 1, n_if);
     602           0 :                         isl_set_free(test);
     603             :                 }
     604           0 :                 if (subset < 0) {
     605           0 :                         graft = isl_ast_graft_free(graft);
     606           0 :                         break;
     607             :                 }
     608             : 
     609           0 :                 guard = isl_set_copy(graft->guard);
     610           0 :                 if (found_then >= 0)
     611           0 :                         graft->guard = isl_set_gist(graft->guard,
     612           0 :                                 isl_set_copy(if_node[found_then].guard));
     613           0 :                 else if (found_else >= 0)
     614           0 :                         graft->guard = isl_set_gist(graft->guard,
     615           0 :                                 isl_set_copy(if_node[found_else].complement));
     616             : 
     617           0 :                 node = graft->node;
     618           0 :                 if (!graft->guard)
     619           0 :                         graft = isl_ast_graft_free(graft);
     620           0 :                 graft = insert_pending_guard_node(graft, build);
     621           0 :                 if (graft && graft->node != node && i != n - 1) {
     622             :                         isl_set *set;
     623           0 :                         if_node[n_if].node = graft->node;
     624           0 :                         if_node[n_if].guard = guard;
     625           0 :                         if (found_then >= 0)
     626           0 :                                 set = if_node[found_then].guard;
     627           0 :                         else if (found_else >= 0)
     628           0 :                                 set = if_node[found_else].complement;
     629             :                         else
     630           0 :                                 set = build->domain;
     631           0 :                         set = isl_set_copy(set);
     632           0 :                         set = isl_set_subtract(set, isl_set_copy(guard));
     633           0 :                         if_node[n_if].complement = set;
     634           0 :                         n_if++;
     635             :                 } else
     636           0 :                         isl_set_free(guard);
     637           0 :                 if (!graft)
     638           0 :                         break;
     639             : 
     640           0 :                 if (found_then >= 0)
     641           0 :                         res = extend_then(res, if_node[found_then].node,
     642             :                                                 graft, build);
     643           0 :                 else if (found_else >= 0)
     644           0 :                         res = extend_else(res, if_node[found_else].node,
     645             :                                                 graft, build);
     646             :                 else
     647           0 :                         res = isl_ast_graft_list_add(res, graft);
     648             :         }
     649           0 :         if (i < n)
     650           0 :                 res = isl_ast_graft_list_free(res);
     651             : 
     652           0 :         isl_ast_graft_list_free(list);
     653           0 :         clear_if_nodes(if_node, 0, n_if);
     654           0 :         free(if_node);
     655           0 :         return res;
     656             : }
     657             : 
     658             : /* For each graft in "list",
     659             :  * insert an if node around graft->node testing the condition encoded
     660             :  * in graft->guard, assuming graft->guard involves any conditions.
     661             :  * Subsequently remove the guards from the grafts.
     662             :  */
     663           0 : __isl_give isl_ast_graft_list *isl_ast_graft_list_insert_pending_guard_nodes(
     664             :         __isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build)
     665             : {
     666             :         int i, n;
     667             :         isl_set *universe;
     668             : 
     669           0 :         list = insert_pending_guard_nodes(list, build);
     670           0 :         if (!list)
     671           0 :                 return NULL;
     672             : 
     673           0 :         universe = isl_set_universe(isl_ast_build_get_space(build, 1));
     674           0 :         n = isl_ast_graft_list_n_ast_graft(list);
     675           0 :         for (i = 0; i < n; ++i) {
     676             :                 isl_ast_graft *graft;
     677             : 
     678           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
     679           0 :                 if (!graft)
     680           0 :                         break;
     681           0 :                 isl_set_free(graft->guard);
     682           0 :                 graft->guard = isl_set_copy(universe);
     683           0 :                 if (!graft->guard)
     684           0 :                         graft = isl_ast_graft_free(graft);
     685           0 :                 list = isl_ast_graft_list_set_ast_graft(list, i, graft);
     686             :         }
     687           0 :         isl_set_free(universe);
     688           0 :         if (i < n)
     689           0 :                 return isl_ast_graft_list_free(list);
     690             : 
     691           0 :         return list;
     692             : }
     693             : 
     694             : /* Collect the nodes contained in the grafts in "list" in a node list.
     695             :  */
     696           0 : static __isl_give isl_ast_node_list *extract_node_list(
     697             :         __isl_keep isl_ast_graft_list *list)
     698             : {
     699             :         int i, n;
     700             :         isl_ctx *ctx;
     701             :         isl_ast_node_list *node_list;
     702             : 
     703           0 :         if (!list)
     704           0 :                 return NULL;
     705           0 :         ctx = isl_ast_graft_list_get_ctx(list);
     706           0 :         n = isl_ast_graft_list_n_ast_graft(list);
     707           0 :         node_list = isl_ast_node_list_alloc(ctx, n);
     708           0 :         for (i = 0; i < n; ++i) {
     709             :                 isl_ast_node *node;
     710             :                 isl_ast_graft *graft;
     711             : 
     712           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
     713           0 :                 node = isl_ast_graft_get_node(graft);
     714           0 :                 node_list = isl_ast_node_list_add(node_list, node);
     715           0 :                 isl_ast_graft_free(graft);
     716             :         }
     717             : 
     718           0 :         return node_list;
     719             : }
     720             : 
     721             : /* Look for shared enforced constraints by all the elements in "list"
     722             :  * on outer loops (with respect to the current depth) and return the result.
     723             :  *
     724             :  * If there are no elements in "list", then return the empty set.
     725             :  */
     726           0 : __isl_give isl_basic_set *isl_ast_graft_list_extract_shared_enforced(
     727             :         __isl_keep isl_ast_graft_list *list,
     728             :         __isl_keep isl_ast_build *build)
     729             : {
     730             :         int i, n;
     731             :         int depth;
     732             :         isl_space *space;
     733             :         isl_basic_set *enforced;
     734             : 
     735           0 :         if (!list)
     736           0 :                 return NULL;
     737             : 
     738           0 :         space = isl_ast_build_get_space(build, 1);
     739           0 :         enforced = isl_basic_set_empty(space);
     740             : 
     741           0 :         depth = isl_ast_build_get_depth(build);
     742           0 :         n = isl_ast_graft_list_n_ast_graft(list);
     743           0 :         for (i = 0; i < n; ++i) {
     744             :                 isl_ast_graft *graft;
     745             : 
     746           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
     747           0 :                 enforced = update_enforced(enforced, graft, depth);
     748           0 :                 isl_ast_graft_free(graft);
     749             :         }
     750             : 
     751           0 :         return enforced;
     752             : }
     753             : 
     754             : /* Record "guard" in "graft" so that it will be enforced somewhere
     755             :  * up the tree.  If the graft already has a guard, then it may be partially
     756             :  * redundant in combination with the new guard and in the context
     757             :  * the generated constraints of "build".  In fact, the new guard
     758             :  * may in itself have some redundant constraints.
     759             :  * We therefore (re)compute the gist of the intersection
     760             :  * and coalesce the result.
     761             :  */
     762           0 : static __isl_give isl_ast_graft *store_guard(__isl_take isl_ast_graft *graft,
     763             :         __isl_take isl_set *guard, __isl_keep isl_ast_build *build)
     764             : {
     765             :         int is_universe;
     766             : 
     767           0 :         if (!graft)
     768           0 :                 goto error;
     769             : 
     770           0 :         is_universe = isl_set_plain_is_universe(guard);
     771           0 :         if (is_universe < 0)
     772           0 :                 goto error;
     773           0 :         if (is_universe) {
     774           0 :                 isl_set_free(guard);
     775           0 :                 return graft;
     776             :         }
     777             : 
     778           0 :         graft->guard = isl_set_intersect(graft->guard, guard);
     779           0 :         graft->guard = isl_set_gist(graft->guard,
     780             :                                     isl_ast_build_get_generated(build));
     781           0 :         graft->guard = isl_set_coalesce(graft->guard);
     782           0 :         if (!graft->guard)
     783           0 :                 return isl_ast_graft_free(graft);
     784             : 
     785           0 :         return graft;
     786             : error:
     787           0 :         isl_set_free(guard);
     788           0 :         return isl_ast_graft_free(graft);
     789             : }
     790             : 
     791             : /* For each graft in "list", replace its guard with the gist with
     792             :  * respect to "context".
     793             :  */
     794           0 : static __isl_give isl_ast_graft_list *gist_guards(
     795             :         __isl_take isl_ast_graft_list *list, __isl_keep isl_set *context)
     796             : {
     797             :         int i, n;
     798             : 
     799           0 :         if (!list)
     800           0 :                 return NULL;
     801             : 
     802           0 :         n = isl_ast_graft_list_n_ast_graft(list);
     803           0 :         for (i = 0; i < n; ++i) {
     804             :                 isl_ast_graft *graft;
     805             : 
     806           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
     807           0 :                 if (!graft)
     808           0 :                         break;
     809           0 :                 graft->guard = isl_set_gist(graft->guard,
     810             :                                                 isl_set_copy(context));
     811           0 :                 if (!graft->guard)
     812           0 :                         graft = isl_ast_graft_free(graft);
     813           0 :                 list = isl_ast_graft_list_set_ast_graft(list, i, graft);
     814             :         }
     815           0 :         if (i < n)
     816           0 :                 return isl_ast_graft_list_free(list);
     817             : 
     818           0 :         return list;
     819             : }
     820             : 
     821             : /* For each graft in "list", replace its guard with the gist with
     822             :  * respect to "context".
     823             :  */
     824           0 : __isl_give isl_ast_graft_list *isl_ast_graft_list_gist_guards(
     825             :         __isl_take isl_ast_graft_list *list, __isl_take isl_set *context)
     826             : {
     827           0 :         list = gist_guards(list, context);
     828           0 :         isl_set_free(context);
     829             : 
     830           0 :         return list;
     831             : }
     832             : 
     833             : /* Allocate a graft in "build" based on the list of grafts in "sub_build".
     834             :  * "guard" and "enforced" are the guard and enforced constraints
     835             :  * of the allocated graft.  The guard is used to simplify the guards
     836             :  * of the elements in "list".
     837             :  *
     838             :  * The node is initialized to either a block containing the nodes of "children"
     839             :  * or, if there is only a single child, the node of that child.
     840             :  * If the current level requires a for node, it should be inserted by
     841             :  * a subsequent call to isl_ast_graft_insert_for.
     842             :  */
     843           0 : __isl_give isl_ast_graft *isl_ast_graft_alloc_from_children(
     844             :         __isl_take isl_ast_graft_list *list, __isl_take isl_set *guard,
     845             :         __isl_take isl_basic_set *enforced, __isl_keep isl_ast_build *build,
     846             :         __isl_keep isl_ast_build *sub_build)
     847             : {
     848             :         isl_ast_build *guard_build;
     849             :         isl_ast_node *node;
     850             :         isl_ast_node_list *node_list;
     851             :         isl_ast_graft *graft;
     852             : 
     853           0 :         guard_build = isl_ast_build_copy(sub_build);
     854           0 :         guard_build = isl_ast_build_replace_pending_by_guard(guard_build,
     855             :                                                 isl_set_copy(guard));
     856           0 :         list = gist_guards(list, guard);
     857           0 :         list = insert_pending_guard_nodes(list, guard_build);
     858           0 :         isl_ast_build_free(guard_build);
     859             : 
     860           0 :         node_list = extract_node_list(list);
     861           0 :         node = isl_ast_node_from_ast_node_list(node_list);
     862           0 :         isl_ast_graft_list_free(list);
     863             : 
     864           0 :         graft = isl_ast_graft_alloc(node, build);
     865           0 :         graft = store_guard(graft, guard, build);
     866           0 :         graft = isl_ast_graft_enforce(graft, enforced);
     867             : 
     868           0 :         return graft;
     869             : }
     870             : 
     871             : /* Combine the grafts in the list into a single graft.
     872             :  *
     873             :  * The guard is initialized to the shared guard of the list elements (if any),
     874             :  * provided it does not depend on the current dimension.
     875             :  * The guards in the elements are then simplified with respect to the
     876             :  * hoisted guard and materialized as if nodes around the contained AST nodes
     877             :  * in the context of "sub_build".
     878             :  *
     879             :  * The enforced set is initialized to the simple hull of the enforced sets
     880             :  * of the elements, provided the ast_build_exploit_nested_bounds option is set
     881             :  * or the new graft will be used at the same level.
     882             :  *
     883             :  * The node is initialized to either a block containing the nodes of "list"
     884             :  * or, if there is only a single element, the node of that element.
     885             :  */
     886           0 : static __isl_give isl_ast_graft *ast_graft_list_fuse(
     887             :         __isl_take isl_ast_graft_list *list, __isl_keep isl_ast_build *build)
     888             : {
     889             :         isl_ast_graft *graft;
     890             :         isl_basic_set *enforced;
     891             :         isl_set *guard;
     892             : 
     893           0 :         if (!list)
     894           0 :                 return NULL;
     895             : 
     896           0 :         enforced = isl_ast_graft_list_extract_shared_enforced(list, build);
     897           0 :         guard = isl_ast_graft_list_extract_hoistable_guard(list, build);
     898           0 :         graft = isl_ast_graft_alloc_from_children(list, guard, enforced,
     899             :                                                     build, build);
     900             : 
     901           0 :         return graft;
     902             : }
     903             : 
     904             : /* Combine the grafts in the list into a single graft.
     905             :  * Return a list containing this single graft.
     906             :  * If the original list is empty, then return an empty list.
     907             :  */
     908           0 : __isl_give isl_ast_graft_list *isl_ast_graft_list_fuse(
     909             :         __isl_take isl_ast_graft_list *list,
     910             :         __isl_keep isl_ast_build *build)
     911             : {
     912             :         isl_ast_graft *graft;
     913             : 
     914           0 :         if (!list)
     915           0 :                 return NULL;
     916           0 :         if (isl_ast_graft_list_n_ast_graft(list) <= 1)
     917           0 :                 return list;
     918           0 :         graft = ast_graft_list_fuse(list, build);
     919           0 :         return isl_ast_graft_list_from_ast_graft(graft);
     920             : }
     921             : 
     922             : /* Combine the two grafts into a single graft.
     923             :  * Return a list containing this single graft.
     924             :  */
     925           0 : static __isl_give isl_ast_graft *isl_ast_graft_fuse(
     926             :         __isl_take isl_ast_graft *graft1, __isl_take isl_ast_graft *graft2,
     927             :         __isl_keep isl_ast_build *build)
     928             : {
     929             :         isl_ctx *ctx;
     930             :         isl_ast_graft_list *list;
     931             : 
     932           0 :         ctx = isl_ast_build_get_ctx(build);
     933             : 
     934           0 :         list = isl_ast_graft_list_alloc(ctx, 2);
     935           0 :         list = isl_ast_graft_list_add(list, graft1);
     936           0 :         list = isl_ast_graft_list_add(list, graft2);
     937             : 
     938           0 :         return ast_graft_list_fuse(list, build);
     939             : }
     940             : 
     941             : /* Insert a for node enclosing the current graft->node.
     942             :  */
     943           0 : __isl_give isl_ast_graft *isl_ast_graft_insert_for(
     944             :         __isl_take isl_ast_graft *graft, __isl_take isl_ast_node *node)
     945             : {
     946           0 :         if (!graft)
     947           0 :                 goto error;
     948             : 
     949           0 :         graft->node = isl_ast_node_for_set_body(node, graft->node);
     950           0 :         if (!graft->node)
     951           0 :                 return isl_ast_graft_free(graft);
     952             : 
     953           0 :         return graft;
     954             : error:
     955           0 :         isl_ast_node_free(node);
     956           0 :         isl_ast_graft_free(graft);
     957           0 :         return NULL;
     958             : }
     959             : 
     960             : /* Insert a mark governing the current graft->node.
     961             :  */
     962           0 : __isl_give isl_ast_graft *isl_ast_graft_insert_mark(
     963             :         __isl_take isl_ast_graft *graft, __isl_take isl_id *mark)
     964             : {
     965           0 :         if (!graft)
     966           0 :                 goto error;
     967             : 
     968           0 :         graft->node = isl_ast_node_alloc_mark(mark, graft->node);
     969           0 :         if (!graft->node)
     970           0 :                 return isl_ast_graft_free(graft);
     971             : 
     972           0 :         return graft;
     973             : error:
     974           0 :         isl_id_free(mark);
     975           0 :         isl_ast_graft_free(graft);
     976           0 :         return NULL;
     977             : }
     978             : 
     979             : /* Represent the graft list as an AST node.
     980             :  * This operation drops the information about guards in the grafts, so
     981             :  * if there are any pending guards, then they are materialized as if nodes.
     982             :  */
     983           0 : __isl_give isl_ast_node *isl_ast_node_from_graft_list(
     984             :         __isl_take isl_ast_graft_list *list,
     985             :         __isl_keep isl_ast_build *build)
     986             : {
     987             :         isl_ast_node_list *node_list;
     988             : 
     989           0 :         list = insert_pending_guard_nodes(list, build);
     990           0 :         node_list = extract_node_list(list);
     991           0 :         isl_ast_graft_list_free(list);
     992             : 
     993           0 :         return isl_ast_node_from_ast_node_list(node_list);
     994             : }
     995             : 
     996           0 : __isl_null isl_ast_graft *isl_ast_graft_free(__isl_take isl_ast_graft *graft)
     997             : {
     998           0 :         if (!graft)
     999           0 :                 return NULL;
    1000             : 
    1001           0 :         if (--graft->ref > 0)
    1002           0 :                 return NULL;
    1003             : 
    1004           0 :         isl_ast_node_free(graft->node);
    1005           0 :         isl_set_free(graft->guard);
    1006           0 :         isl_basic_set_free(graft->enforced);
    1007           0 :         free(graft);
    1008             : 
    1009           0 :         return NULL;
    1010             : }
    1011             : 
    1012             : /* Record that the grafted tree enforces
    1013             :  * "enforced" by intersecting graft->enforced with "enforced".
    1014             :  */
    1015           0 : __isl_give isl_ast_graft *isl_ast_graft_enforce(
    1016             :         __isl_take isl_ast_graft *graft, __isl_take isl_basic_set *enforced)
    1017             : {
    1018           0 :         if (!graft || !enforced)
    1019             :                 goto error;
    1020             : 
    1021           0 :         enforced = isl_basic_set_align_params(enforced,
    1022             :                                 isl_basic_set_get_space(graft->enforced));
    1023           0 :         graft->enforced = isl_basic_set_align_params(graft->enforced,
    1024             :                                 isl_basic_set_get_space(enforced));
    1025           0 :         graft->enforced = isl_basic_set_intersect(graft->enforced, enforced);
    1026           0 :         if (!graft->enforced)
    1027           0 :                 return isl_ast_graft_free(graft);
    1028             : 
    1029           0 :         return graft;
    1030             : error:
    1031           0 :         isl_basic_set_free(enforced);
    1032           0 :         return isl_ast_graft_free(graft);
    1033             : }
    1034             : 
    1035           0 : __isl_give isl_basic_set *isl_ast_graft_get_enforced(
    1036             :         __isl_keep isl_ast_graft *graft)
    1037             : {
    1038           0 :         return graft ? isl_basic_set_copy(graft->enforced) : NULL;
    1039             : }
    1040             : 
    1041           0 : __isl_give isl_set *isl_ast_graft_get_guard(__isl_keep isl_ast_graft *graft)
    1042             : {
    1043           0 :         return graft ? isl_set_copy(graft->guard) : NULL;
    1044             : }
    1045             : 
    1046             : /* Record that "guard" needs to be inserted in "graft".
    1047             :  */
    1048           0 : __isl_give isl_ast_graft *isl_ast_graft_add_guard(
    1049             :         __isl_take isl_ast_graft *graft,
    1050             :         __isl_take isl_set *guard, __isl_keep isl_ast_build *build)
    1051             : {
    1052           0 :         return store_guard(graft, guard, build);
    1053             : }
    1054             : 
    1055             : /* Reformulate the "graft", which was generated in the context
    1056             :  * of an inner code generation, in terms of the outer code generation
    1057             :  * AST build.
    1058             :  *
    1059             :  * If "product" is set, then the domain of the inner code generation build is
    1060             :  *
    1061             :  *      [O -> S]
    1062             :  *
    1063             :  * with O the domain of the outer code generation build.
    1064             :  * We essentially need to project out S.
    1065             :  *
    1066             :  * If "product" is not set, then we need to project the domains onto
    1067             :  * their parameter spaces.
    1068             :  */
    1069           0 : __isl_give isl_ast_graft *isl_ast_graft_unembed(__isl_take isl_ast_graft *graft,
    1070             :         int product)
    1071             : {
    1072             :         isl_basic_set *enforced;
    1073             : 
    1074           0 :         if (!graft)
    1075           0 :                 return NULL;
    1076             : 
    1077           0 :         if (product) {
    1078           0 :                 enforced = graft->enforced;
    1079           0 :                 enforced = isl_basic_map_domain(isl_basic_set_unwrap(enforced));
    1080           0 :                 graft->enforced = enforced;
    1081           0 :                 graft->guard = isl_map_domain(isl_set_unwrap(graft->guard));
    1082             :         } else {
    1083           0 :                 graft->enforced = isl_basic_set_params(graft->enforced);
    1084           0 :                 graft->guard = isl_set_params(graft->guard);
    1085             :         }
    1086           0 :         graft->guard = isl_set_compute_divs(graft->guard);
    1087             : 
    1088           0 :         if (!graft->enforced || !graft->guard)
    1089           0 :                 return isl_ast_graft_free(graft);
    1090             : 
    1091           0 :         return graft;
    1092             : }
    1093             : 
    1094             : /* Reformulate the grafts in "list", which were generated in the context
    1095             :  * of an inner code generation, in terms of the outer code generation
    1096             :  * AST build.
    1097             :  */
    1098           0 : __isl_give isl_ast_graft_list *isl_ast_graft_list_unembed(
    1099             :         __isl_take isl_ast_graft_list *list, int product)
    1100             : {
    1101             :         int i, n;
    1102             : 
    1103           0 :         n = isl_ast_graft_list_n_ast_graft(list);
    1104           0 :         for (i = 0; i < n; ++i) {
    1105             :                 isl_ast_graft *graft;
    1106             : 
    1107           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
    1108           0 :                 graft = isl_ast_graft_unembed(graft, product);
    1109           0 :                 list = isl_ast_graft_list_set_ast_graft(list, i, graft);
    1110             :         }
    1111             : 
    1112           0 :         return list;
    1113             : }
    1114             : 
    1115             : /* Compute the preimage of "graft" under the function represented by "ma".
    1116             :  * In other words, plug in "ma" in "enforced" and "guard" fields of "graft".
    1117             :  */
    1118           0 : __isl_give isl_ast_graft *isl_ast_graft_preimage_multi_aff(
    1119             :         __isl_take isl_ast_graft *graft, __isl_take isl_multi_aff *ma)
    1120             : {
    1121             :         isl_basic_set *enforced;
    1122             : 
    1123           0 :         if (!graft)
    1124           0 :                 return NULL;
    1125             : 
    1126           0 :         enforced = graft->enforced;
    1127           0 :         graft->enforced = isl_basic_set_preimage_multi_aff(enforced,
    1128             :                                                 isl_multi_aff_copy(ma));
    1129           0 :         graft->guard = isl_set_preimage_multi_aff(graft->guard, ma);
    1130             : 
    1131           0 :         if (!graft->enforced || !graft->guard)
    1132           0 :                 return isl_ast_graft_free(graft);
    1133             : 
    1134           0 :         return graft;
    1135             : }
    1136             : 
    1137             : /* Compute the preimage of all the grafts in "list" under
    1138             :  * the function represented by "ma".
    1139             :  */
    1140           0 : __isl_give isl_ast_graft_list *isl_ast_graft_list_preimage_multi_aff(
    1141             :         __isl_take isl_ast_graft_list *list, __isl_take isl_multi_aff *ma)
    1142             : {
    1143             :         int i, n;
    1144             : 
    1145           0 :         n = isl_ast_graft_list_n_ast_graft(list);
    1146           0 :         for (i = 0; i < n; ++i) {
    1147             :                 isl_ast_graft *graft;
    1148             : 
    1149           0 :                 graft = isl_ast_graft_list_get_ast_graft(list, i);
    1150           0 :                 graft = isl_ast_graft_preimage_multi_aff(graft,
    1151             :                                                     isl_multi_aff_copy(ma));
    1152           0 :                 list = isl_ast_graft_list_set_ast_graft(list, i, graft);
    1153             :         }
    1154             : 
    1155           0 :         isl_multi_aff_free(ma);
    1156           0 :         return list;
    1157             : }
    1158             : 
    1159             : /* Compare two grafts based on their guards.
    1160             :  */
    1161           0 : static int cmp_graft(__isl_keep isl_ast_graft *a, __isl_keep isl_ast_graft *b,
    1162             :         void *user)
    1163             : {
    1164           0 :         return isl_set_plain_cmp(a->guard, b->guard);
    1165             : }
    1166             : 
    1167             : /* Order the elements in "list" based on their guards.
    1168             :  */
    1169           0 : __isl_give isl_ast_graft_list *isl_ast_graft_list_sort_guard(
    1170             :         __isl_take isl_ast_graft_list *list)
    1171             : {
    1172           0 :         return isl_ast_graft_list_sort(list, &cmp_graft, NULL);
    1173             : }
    1174             : 
    1175             : /* Merge the given two lists into a single list of grafts,
    1176             :  * merging grafts with the same guard into a single graft.
    1177             :  *
    1178             :  * "list2" has been sorted using isl_ast_graft_list_sort.
    1179             :  * "list1" may be the result of a previous call to isl_ast_graft_list_merge
    1180             :  * and may therefore not be completely sorted.
    1181             :  *
    1182             :  * The elements in "list2" need to be executed after those in "list1",
    1183             :  * but if the guard of a graft in "list2" is disjoint from the guards
    1184             :  * of some final elements in "list1", then it can be moved up to before
    1185             :  * those final elements.
    1186             :  *
    1187             :  * In particular, we look at each element g of "list2" in turn
    1188             :  * and move it up beyond elements of "list1" that would be sorted
    1189             :  * after g as long as each of these elements has a guard that is disjoint
    1190             :  * from that of g.
    1191             :  *
    1192             :  * We do not allow the second or any later element of "list2" to be moved
    1193             :  * before a previous elements of "list2" even if the reason that
    1194             :  * that element didn't move up further was that its guard was not disjoint
    1195             :  * from that of the previous element in "list1".
    1196             :  */
    1197           0 : __isl_give isl_ast_graft_list *isl_ast_graft_list_merge(
    1198             :         __isl_take isl_ast_graft_list *list1,
    1199             :         __isl_take isl_ast_graft_list *list2,
    1200             :         __isl_keep isl_ast_build *build)
    1201             : {
    1202             :         int i, j, first;
    1203             : 
    1204           0 :         if (!list1 || !list2 || !build)
    1205             :                 goto error;
    1206           0 :         if (list2->n == 0) {
    1207           0 :                 isl_ast_graft_list_free(list2);
    1208           0 :                 return list1;
    1209             :         }
    1210           0 :         if (list1->n == 0) {
    1211           0 :                 isl_ast_graft_list_free(list1);
    1212           0 :                 return list2;
    1213             :         }
    1214             : 
    1215           0 :         first = 0;
    1216           0 :         for (i = 0; i < list2->n; ++i) {
    1217             :                 isl_ast_graft *graft;
    1218           0 :                 graft = isl_ast_graft_list_get_ast_graft(list2, i);
    1219           0 :                 if (!graft)
    1220           0 :                         break;
    1221             : 
    1222           0 :                 for (j = list1->n; j >= 0; --j) {
    1223             :                         int cmp, disjoint;
    1224             :                         isl_ast_graft *graft_j;
    1225             : 
    1226           0 :                         if (j == first)
    1227           0 :                                 cmp = -1;
    1228             :                         else
    1229           0 :                                 cmp = isl_set_plain_cmp(list1->p[j - 1]->guard,
    1230             :                                                         graft->guard);
    1231           0 :                         if (cmp > 0) {
    1232           0 :                                 disjoint = isl_set_is_disjoint(graft->guard,
    1233           0 :                                                         list1->p[j - 1]->guard);
    1234           0 :                                 if (disjoint < 0) {
    1235           0 :                                         isl_ast_graft_free(graft);
    1236           0 :                                         list1 = isl_ast_graft_list_free(list1);
    1237           0 :                                         break;
    1238             :                                 }
    1239           0 :                                 if (!disjoint)
    1240           0 :                                         cmp = -1;
    1241             :                         }
    1242           0 :                         if (cmp > 0)
    1243           0 :                                 continue;
    1244           0 :                         if (cmp < 0) {
    1245           0 :                                 list1 = isl_ast_graft_list_insert(list1, j,
    1246             :                                                                 graft);
    1247           0 :                                 break;
    1248             :                         }
    1249             : 
    1250           0 :                         --j;
    1251             : 
    1252           0 :                         graft_j = isl_ast_graft_list_get_ast_graft(list1, j);
    1253           0 :                         graft_j = isl_ast_graft_fuse(graft_j, graft, build);
    1254           0 :                         list1 = isl_ast_graft_list_set_ast_graft(list1, j,
    1255             :                                                                 graft_j);
    1256           0 :                         break;
    1257             :                 }
    1258             : 
    1259           0 :                 if (j < 0) {
    1260           0 :                         isl_ast_graft_free(graft);
    1261           0 :                         isl_die(isl_ast_build_get_ctx(build),
    1262             :                                 isl_error_internal,
    1263             :                                 "element failed to get inserted", break);
    1264             :                 }
    1265             : 
    1266           0 :                 first = j + 1;
    1267           0 :                 if (!list1)
    1268           0 :                         break;
    1269             :         }
    1270           0 :         if (i < list2->n)
    1271           0 :                 list1 = isl_ast_graft_list_free(list1);
    1272           0 :         isl_ast_graft_list_free(list2);
    1273             : 
    1274           0 :         return list1;
    1275             : error:
    1276           0 :         isl_ast_graft_list_free(list1);
    1277           0 :         isl_ast_graft_list_free(list2);
    1278           0 :         return NULL;
    1279             : }
    1280             : 
    1281           0 : __isl_give isl_printer *isl_printer_print_ast_graft(__isl_take isl_printer *p,
    1282             :         __isl_keep isl_ast_graft *graft)
    1283             : {
    1284           0 :         if (!p)
    1285           0 :                 return NULL;
    1286           0 :         if (!graft)
    1287           0 :                 return isl_printer_free(p);
    1288             : 
    1289           0 :         p = isl_printer_print_str(p, "(");
    1290           0 :         p = isl_printer_print_str(p, "guard: ");
    1291           0 :         p = isl_printer_print_set(p, graft->guard);
    1292           0 :         p = isl_printer_print_str(p, ", ");
    1293           0 :         p = isl_printer_print_str(p, "enforced: ");
    1294           0 :         p = isl_printer_print_basic_set(p, graft->enforced);
    1295           0 :         p = isl_printer_print_str(p, ", ");
    1296           0 :         p = isl_printer_print_str(p, "node: ");
    1297           0 :         p = isl_printer_print_ast_node(p, graft->node);
    1298           0 :         p = isl_printer_print_str(p, ")");
    1299             : 
    1300           0 :         return p;
    1301             : }

Generated by: LCOV version 1.12