LCOV - code coverage report
Current view: top level - metalib_isl - isl_local_space.c (source / functions) Hit Total Coverage
Test: 2018-10-31_point_maint_greina16.lcov Lines: 7 760 0.9 %
Date: 2018-11-01 11:27:00 Functions: 2 74 2.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2011      INRIA Saclay
       3             :  * Copyright 2012-2014 Ecole Normale Superieure
       4             :  *
       5             :  * Use of this software is governed by the MIT license
       6             :  *
       7             :  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
       8             :  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
       9             :  * 91893 Orsay, France
      10             :  * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
      11             :  */
      12             : 
      13             : #include <isl_ctx_private.h>
      14             : #include <isl/id.h>
      15             : #include <isl_map_private.h>
      16             : #include <isl_local_space_private.h>
      17             : #include <isl_space_private.h>
      18             : #include <isl_mat_private.h>
      19             : #include <isl_aff_private.h>
      20             : #include <isl_vec_private.h>
      21             : #include <isl_point_private.h>
      22             : #include <isl_seq.h>
      23             : #include <isl_local.h>
      24             : 
      25           0 : isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
      26             : {
      27           0 :         return ls ? ls->dim->ctx : NULL;
      28             : }
      29             : 
      30             : /* Return a hash value that digests "ls".
      31             :  */
      32           0 : uint32_t isl_local_space_get_hash(__isl_keep isl_local_space *ls)
      33             : {
      34             :         uint32_t hash, space_hash, div_hash;
      35             : 
      36           0 :         if (!ls)
      37           0 :                 return 0;
      38             : 
      39           0 :         hash = isl_hash_init();
      40           0 :         space_hash = isl_space_get_hash(ls->dim);
      41           0 :         isl_hash_hash(hash, space_hash);
      42           0 :         div_hash = isl_mat_get_hash(ls->div);
      43           0 :         isl_hash_hash(hash, div_hash);
      44             : 
      45           0 :         return hash;
      46             : }
      47             : 
      48           0 : __isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
      49             :         __isl_take isl_mat *div)
      50             : {
      51             :         isl_ctx *ctx;
      52           0 :         isl_local_space *ls = NULL;
      53             : 
      54           0 :         if (!dim || !div)
      55             :                 goto error;
      56             : 
      57           0 :         ctx = isl_space_get_ctx(dim);
      58           0 :         ls = isl_calloc_type(ctx, struct isl_local_space);
      59           0 :         if (!ls)
      60           0 :                 goto error;
      61             : 
      62           0 :         ls->ref = 1;
      63           0 :         ls->dim = dim;
      64           0 :         ls->div = div;
      65             : 
      66           0 :         return ls;
      67             : error:
      68           0 :         isl_mat_free(div);
      69           0 :         isl_space_free(dim);
      70           0 :         isl_local_space_free(ls);
      71           0 :         return NULL;
      72             : }
      73             : 
      74           0 : __isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
      75             :         unsigned n_div)
      76             : {
      77             :         isl_ctx *ctx;
      78             :         isl_mat *div;
      79             :         unsigned total;
      80             : 
      81           0 :         if (!dim)
      82           0 :                 return NULL;
      83             : 
      84           0 :         total = isl_space_dim(dim, isl_dim_all);
      85             : 
      86           0 :         ctx = isl_space_get_ctx(dim);
      87           0 :         div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
      88           0 :         return isl_local_space_alloc_div(dim, div);
      89             : }
      90             : 
      91           0 : __isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim)
      92             : {
      93           0 :         return isl_local_space_alloc(dim, 0);
      94             : }
      95             : 
      96           0 : __isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
      97             : {
      98           0 :         if (!ls)
      99           0 :                 return NULL;
     100             : 
     101           0 :         ls->ref++;
     102           0 :         return ls;
     103             : }
     104             : 
     105           0 : __isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
     106             : {
     107           0 :         if (!ls)
     108           0 :                 return NULL;
     109             : 
     110           0 :         return isl_local_space_alloc_div(isl_space_copy(ls->dim),
     111             :                                          isl_mat_copy(ls->div));
     112             : 
     113             : }
     114             : 
     115           0 : __isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
     116             : {
     117           0 :         if (!ls)
     118           0 :                 return NULL;
     119             : 
     120           0 :         if (ls->ref == 1)
     121           0 :                 return ls;
     122           0 :         ls->ref--;
     123           0 :         return isl_local_space_dup(ls);
     124             : }
     125             : 
     126           0 : __isl_null isl_local_space *isl_local_space_free(
     127             :         __isl_take isl_local_space *ls)
     128             : {
     129           0 :         if (!ls)
     130           0 :                 return NULL;
     131             : 
     132           0 :         if (--ls->ref > 0)
     133           0 :                 return NULL;
     134             : 
     135           0 :         isl_space_free(ls->dim);
     136           0 :         isl_mat_free(ls->div);
     137             : 
     138           0 :         free(ls);
     139             : 
     140           0 :         return NULL;
     141             : }
     142             : 
     143             : /* Is the local space that of a parameter domain?
     144             :  */
     145           0 : isl_bool isl_local_space_is_params(__isl_keep isl_local_space *ls)
     146             : {
     147           0 :         if (!ls)
     148           0 :                 return isl_bool_error;
     149           0 :         return isl_space_is_params(ls->dim);
     150             : }
     151             : 
     152             : /* Is the local space that of a set?
     153             :  */
     154           0 : isl_bool isl_local_space_is_set(__isl_keep isl_local_space *ls)
     155             : {
     156           0 :         return ls ? isl_space_is_set(ls->dim) : isl_bool_error;
     157             : }
     158             : 
     159             : /* Do "ls1" and "ls2" have the same space?
     160             :  */
     161           0 : isl_bool isl_local_space_has_equal_space(__isl_keep isl_local_space *ls1,
     162             :         __isl_keep isl_local_space *ls2)
     163             : {
     164           0 :         if (!ls1 || !ls2)
     165           0 :                 return isl_bool_error;
     166             : 
     167           0 :         return isl_space_is_equal(ls1->dim, ls2->dim);
     168             : }
     169             : 
     170             : /* Is the space of "ls" equal to "space"?
     171             :  */
     172           0 : isl_bool isl_local_space_has_space(__isl_keep isl_local_space *ls,
     173             :         __isl_keep isl_space *space)
     174             : {
     175           0 :         return isl_space_is_equal(isl_local_space_peek_space(ls), space);
     176             : }
     177             : 
     178             : /* Check that the space of "ls" is equal to "space".
     179             :  */
     180           0 : static isl_stat isl_local_space_check_has_space(__isl_keep isl_local_space *ls,
     181             :         __isl_keep isl_space *space)
     182             : {
     183             :         isl_bool ok;
     184             : 
     185           0 :         ok = isl_local_space_has_space(ls, space);
     186           0 :         if (ok < 0)
     187           0 :                 return isl_stat_error;
     188           0 :         if (!ok)
     189           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
     190             :                         "spaces don't match", return isl_stat_error);
     191           0 :         return isl_stat_ok;
     192             : }
     193             : 
     194             : /* Return true if the two local spaces are identical, with identical
     195             :  * expressions for the integer divisions.
     196             :  */
     197           0 : isl_bool isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
     198             :         __isl_keep isl_local_space *ls2)
     199             : {
     200             :         isl_bool equal;
     201             : 
     202           0 :         equal = isl_local_space_has_equal_space(ls1, ls2);
     203           0 :         if (equal < 0 || !equal)
     204           0 :                 return equal;
     205             : 
     206           0 :         if (!isl_local_space_divs_known(ls1))
     207           0 :                 return isl_bool_false;
     208           0 :         if (!isl_local_space_divs_known(ls2))
     209           0 :                 return isl_bool_false;
     210             : 
     211           0 :         return isl_mat_is_equal(ls1->div, ls2->div);
     212             : }
     213             : 
     214             : /* Compare two isl_local_spaces.
     215             :  *
     216             :  * Return -1 if "ls1" is "smaller" than "ls2", 1 if "ls1" is "greater"
     217             :  * than "ls2" and 0 if they are equal.
     218             :  */
     219           0 : int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
     220             :         __isl_keep isl_local_space *ls2)
     221             : {
     222             :         int cmp;
     223             : 
     224           0 :         if (ls1 == ls2)
     225           0 :                 return 0;
     226           0 :         if (!ls1)
     227           0 :                 return -1;
     228           0 :         if (!ls2)
     229           0 :                 return 1;
     230             : 
     231           0 :         cmp = isl_space_cmp(ls1->dim, ls2->dim);
     232           0 :         if (cmp != 0)
     233           0 :                 return cmp;
     234             : 
     235           0 :         return isl_local_cmp(ls1->div, ls2->div);
     236             : }
     237             : 
     238           0 : int isl_local_space_dim(__isl_keep isl_local_space *ls,
     239             :         enum isl_dim_type type)
     240             : {
     241           0 :         if (!ls)
     242           0 :                 return 0;
     243           0 :         if (type == isl_dim_div)
     244           0 :                 return ls->div->n_row;
     245           0 :         if (type == isl_dim_all)
     246           0 :                 return isl_space_dim(ls->dim, isl_dim_all) + ls->div->n_row;
     247           0 :         return isl_space_dim(ls->dim, type);
     248             : }
     249             : 
     250           0 : unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
     251             :         enum isl_dim_type type)
     252             : {
     253             :         isl_space *dim;
     254             : 
     255           0 :         if (!ls)
     256           0 :                 return 0;
     257             : 
     258           0 :         dim = ls->dim;
     259           0 :         switch (type) {
     260           0 :         case isl_dim_cst:       return 0;
     261           0 :         case isl_dim_param:     return 1;
     262           0 :         case isl_dim_in:        return 1 + dim->nparam;
     263           0 :         case isl_dim_out:       return 1 + dim->nparam + dim->n_in;
     264           0 :         case isl_dim_div:       return 1 + dim->nparam + dim->n_in + dim->n_out;
     265           0 :         default:                return 0;
     266             :         }
     267             : }
     268             : 
     269             : /* Return the position of the dimension of the given type and name
     270             :  * in "ls".
     271             :  * Return -1 if no such dimension can be found.
     272             :  */
     273           0 : int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls,
     274             :         enum isl_dim_type type, const char *name)
     275             : {
     276           0 :         if (!ls)
     277           0 :                 return -1;
     278           0 :         if (type == isl_dim_div)
     279           0 :                 return -1;
     280           0 :         return isl_space_find_dim_by_name(ls->dim, type, name);
     281             : }
     282             : 
     283             : /* Does the given dimension have a name?
     284             :  */
     285           0 : isl_bool isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
     286             :         enum isl_dim_type type, unsigned pos)
     287             : {
     288           0 :         return ls ? isl_space_has_dim_name(ls->dim, type, pos) : isl_bool_error;
     289             : }
     290             : 
     291           0 : const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
     292             :         enum isl_dim_type type, unsigned pos)
     293             : {
     294           0 :         return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
     295             : }
     296             : 
     297           0 : isl_bool isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
     298             :         enum isl_dim_type type, unsigned pos)
     299             : {
     300           0 :         return ls ? isl_space_has_dim_id(ls->dim, type, pos) : isl_bool_error;
     301             : }
     302             : 
     303           0 : __isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
     304             :         enum isl_dim_type type, unsigned pos)
     305             : {
     306           0 :         return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL;
     307             : }
     308             : 
     309             : /* Return the argument of the integer division at position "pos" in "ls".
     310             :  * All local variables in "ls" are known to have a (complete) explicit
     311             :  * representation.
     312             :  */
     313           0 : static __isl_give isl_aff *extract_div(__isl_keep isl_local_space *ls, int pos)
     314             : {
     315             :         isl_aff *aff;
     316             : 
     317           0 :         aff = isl_aff_alloc(isl_local_space_copy(ls));
     318           0 :         if (!aff)
     319           0 :                 return NULL;
     320           0 :         isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size);
     321           0 :         return aff;
     322             : }
     323             : 
     324             : /* Return the argument of the integer division at position "pos" in "ls".
     325             :  * The integer division at that position is known to have a complete
     326             :  * explicit representation, but some of the others do not.
     327             :  * Remove them first because the domain of an isl_aff
     328             :  * is not allowed to have unknown local variables.
     329             :  */
     330           0 : static __isl_give isl_aff *drop_unknown_divs_and_extract_div(
     331             :         __isl_keep isl_local_space *ls, int pos)
     332             : {
     333             :         int i, n;
     334             :         isl_bool unknown;
     335             :         isl_aff *aff;
     336             : 
     337           0 :         ls = isl_local_space_copy(ls);
     338           0 :         n = isl_local_space_dim(ls, isl_dim_div);
     339           0 :         for (i = n - 1; i >= 0; --i) {
     340           0 :                 unknown = isl_local_space_div_is_marked_unknown(ls, i);
     341           0 :                 if (unknown < 0)
     342           0 :                         ls = isl_local_space_free(ls);
     343           0 :                 else if (!unknown)
     344           0 :                         continue;
     345           0 :                 ls = isl_local_space_drop_dims(ls, isl_dim_div, i, 1);
     346           0 :                 if (pos > i)
     347           0 :                         --pos;
     348             :         }
     349           0 :         aff = extract_div(ls, pos);
     350           0 :         isl_local_space_free(ls);
     351           0 :         return aff;
     352             : }
     353             : 
     354             : /* Return the argument of the integer division at position "pos" in "ls".
     355             :  * The integer division is assumed to have a complete explicit
     356             :  * representation.  If some of the other integer divisions
     357             :  * do not have an explicit representation, then they need
     358             :  * to be removed first because the domain of an isl_aff
     359             :  * is not allowed to have unknown local variables.
     360             :  */
     361           0 : __isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
     362             :         int pos)
     363             : {
     364             :         isl_bool known;
     365             : 
     366           0 :         if (!ls)
     367           0 :                 return NULL;
     368             : 
     369           0 :         if (pos < 0 || pos >= ls->div->n_row)
     370           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
     371             :                         "index out of bounds", return NULL);
     372             : 
     373           0 :         known = isl_local_space_div_is_known(ls, pos);
     374           0 :         if (known < 0)
     375           0 :                 return NULL;
     376           0 :         if (!known)
     377           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
     378             :                         "expression of div unknown", return NULL);
     379           0 :         if (!isl_local_space_is_set(ls))
     380           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
     381             :                         "cannot represent divs of map spaces", return NULL);
     382             : 
     383           0 :         known = isl_local_space_divs_known(ls);
     384           0 :         if (known < 0)
     385           0 :                 return NULL;
     386           0 :         if (known)
     387           0 :                 return extract_div(ls, pos);
     388             :         else
     389           0 :                 return drop_unknown_divs_and_extract_div(ls, pos);
     390             : }
     391             : 
     392             : /* Return the space of "ls".
     393             :  */
     394           0 : __isl_keep isl_space *isl_local_space_peek_space(__isl_keep isl_local_space *ls)
     395             : {
     396           0 :         if (!ls)
     397           0 :                 return NULL;
     398             : 
     399           0 :         return ls->dim;
     400             : }
     401             : 
     402           0 : __isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
     403             : {
     404           0 :         return isl_space_copy(isl_local_space_peek_space(ls));
     405             : }
     406             : 
     407             : /* Return the space of "ls".
     408             :  * This may be either a copy or the space itself
     409             :  * if there is only one reference to "ls".
     410             :  * This allows the space to be modified inplace
     411             :  * if both the local space and its space have only a single reference.
     412             :  * The caller is not allowed to modify "ls" between this call and
     413             :  * a subsequent call to isl_local_space_restore_space.
     414             :  * The only exception is that isl_local_space_free can be called instead.
     415             :  */
     416           0 : __isl_give isl_space *isl_local_space_take_space(__isl_keep isl_local_space *ls)
     417             : {
     418             :         isl_space *space;
     419             : 
     420           0 :         if (!ls)
     421           0 :                 return NULL;
     422           0 :         if (ls->ref != 1)
     423           0 :                 return isl_local_space_get_space(ls);
     424           0 :         space = ls->dim;
     425           0 :         ls->dim = NULL;
     426           0 :         return space;
     427             : }
     428             : 
     429             : /* Set the space of "ls" to "space", where the space of "ls" may be missing
     430             :  * due to a preceding call to isl_local_space_take_space.
     431             :  * However, in this case, "ls" only has a single reference and
     432             :  * then the call to isl_local_space_cow has no effect.
     433             :  */
     434           0 : __isl_give isl_local_space *isl_local_space_restore_space(
     435             :         __isl_take isl_local_space *ls, __isl_take isl_space *space)
     436             : {
     437           0 :         if (!ls || !space)
     438             :                 goto error;
     439             : 
     440           0 :         if (ls->dim == space) {
     441           0 :                 isl_space_free(space);
     442           0 :                 return ls;
     443             :         }
     444             : 
     445           0 :         ls = isl_local_space_cow(ls);
     446           0 :         if (!ls)
     447           0 :                 goto error;
     448           0 :         isl_space_free(ls->dim);
     449           0 :         ls->dim = space;
     450             : 
     451           0 :         return ls;
     452             : error:
     453           0 :         isl_local_space_free(ls);
     454           0 :         isl_space_free(space);
     455           0 :         return NULL;
     456             : }
     457             : 
     458             : /* Return the local variables of "ls".
     459             :  */
     460           0 : __isl_keep isl_local *isl_local_space_peek_local(__isl_keep isl_local_space *ls)
     461             : {
     462           0 :         return ls ? ls->div : NULL;
     463             : }
     464             : 
     465             : /* Replace the identifier of the tuple of type "type" by "id".
     466             :  */
     467           0 : __isl_give isl_local_space *isl_local_space_set_tuple_id(
     468             :         __isl_take isl_local_space *ls,
     469             :         enum isl_dim_type type, __isl_take isl_id *id)
     470             : {
     471           0 :         ls = isl_local_space_cow(ls);
     472           0 :         if (!ls)
     473           0 :                 goto error;
     474           0 :         ls->dim = isl_space_set_tuple_id(ls->dim, type, id);
     475           0 :         if (!ls->dim)
     476           0 :                 return isl_local_space_free(ls);
     477           0 :         return ls;
     478             : error:
     479           0 :         isl_id_free(id);
     480           0 :         return NULL;
     481             : }
     482             : 
     483           0 : __isl_give isl_local_space *isl_local_space_set_dim_name(
     484             :         __isl_take isl_local_space *ls,
     485             :         enum isl_dim_type type, unsigned pos, const char *s)
     486             : {
     487           0 :         ls = isl_local_space_cow(ls);
     488           0 :         if (!ls)
     489           0 :                 return NULL;
     490           0 :         ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s);
     491           0 :         if (!ls->dim)
     492           0 :                 return isl_local_space_free(ls);
     493             : 
     494           0 :         return ls;
     495             : }
     496             : 
     497           0 : __isl_give isl_local_space *isl_local_space_set_dim_id(
     498             :         __isl_take isl_local_space *ls,
     499             :         enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
     500             : {
     501           0 :         ls = isl_local_space_cow(ls);
     502           0 :         if (!ls)
     503           0 :                 goto error;
     504           0 :         ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id);
     505           0 :         if (!ls->dim)
     506           0 :                 return isl_local_space_free(ls);
     507             : 
     508           0 :         return ls;
     509             : error:
     510           0 :         isl_id_free(id);
     511           0 :         return NULL;
     512             : }
     513             : 
     514             : /* Construct a zero-dimensional local space with the given parameter domain.
     515             :  */
     516           0 : __isl_give isl_local_space *isl_local_space_set_from_params(
     517             :         __isl_take isl_local_space *ls)
     518             : {
     519             :         isl_space *space;
     520             : 
     521           0 :         space = isl_local_space_take_space(ls);
     522           0 :         space = isl_space_set_from_params(space);
     523           0 :         ls = isl_local_space_restore_space(ls, space);
     524             : 
     525           0 :         return ls;
     526             : }
     527             : 
     528           0 : __isl_give isl_local_space *isl_local_space_reset_space(
     529             :         __isl_take isl_local_space *ls, __isl_take isl_space *dim)
     530             : {
     531           0 :         ls = isl_local_space_cow(ls);
     532           0 :         if (!ls || !dim)
     533             :                 goto error;
     534             : 
     535           0 :         isl_space_free(ls->dim);
     536           0 :         ls->dim = dim;
     537             : 
     538           0 :         return ls;
     539             : error:
     540           0 :         isl_local_space_free(ls);
     541           0 :         isl_space_free(dim);
     542           0 :         return NULL;
     543             : }
     544             : 
     545             : /* Reorder the dimensions of "ls" according to the given reordering.
     546             :  * The reordering r is assumed to have been extended with the local
     547             :  * variables, leaving them in the same order.
     548             :  */
     549           0 : __isl_give isl_local_space *isl_local_space_realign(
     550             :         __isl_take isl_local_space *ls, __isl_take isl_reordering *r)
     551             : {
     552           0 :         ls = isl_local_space_cow(ls);
     553           0 :         if (!ls || !r)
     554             :                 goto error;
     555             : 
     556           0 :         ls->div = isl_local_reorder(ls->div, isl_reordering_copy(r));
     557           0 :         if (!ls->div)
     558           0 :                 goto error;
     559             : 
     560           0 :         ls = isl_local_space_reset_space(ls, isl_reordering_get_space(r));
     561             : 
     562           0 :         isl_reordering_free(r);
     563           0 :         return ls;
     564             : error:
     565           0 :         isl_local_space_free(ls);
     566           0 :         isl_reordering_free(r);
     567           0 :         return NULL;
     568             : }
     569             : 
     570           0 : __isl_give isl_local_space *isl_local_space_add_div(
     571             :         __isl_take isl_local_space *ls, __isl_take isl_vec *div)
     572             : {
     573           0 :         ls = isl_local_space_cow(ls);
     574           0 :         if (!ls || !div)
     575             :                 goto error;
     576             : 
     577           0 :         if (ls->div->n_col != div->size)
     578           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
     579             :                         "incompatible dimensions", goto error);
     580             : 
     581           0 :         ls->div = isl_mat_add_zero_cols(ls->div, 1);
     582           0 :         ls->div = isl_mat_add_rows(ls->div, 1);
     583           0 :         if (!ls->div)
     584           0 :                 goto error;
     585             : 
     586           0 :         isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
     587           0 :         isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
     588             : 
     589           0 :         isl_vec_free(div);
     590           0 :         return ls;
     591             : error:
     592           0 :         isl_local_space_free(ls);
     593           0 :         isl_vec_free(div);
     594           0 :         return NULL;
     595             : }
     596             : 
     597           0 : __isl_give isl_local_space *isl_local_space_replace_divs(
     598             :         __isl_take isl_local_space *ls, __isl_take isl_mat *div)
     599             : {
     600           0 :         ls = isl_local_space_cow(ls);
     601             : 
     602           0 :         if (!ls || !div)
     603             :                 goto error;
     604             : 
     605           0 :         isl_mat_free(ls->div);
     606           0 :         ls->div = div;
     607           0 :         return ls;
     608             : error:
     609           0 :         isl_mat_free(div);
     610           0 :         isl_local_space_free(ls);
     611           0 :         return NULL;
     612             : }
     613             : 
     614             : /* Copy row "s" of "src" to row "d" of "dst", applying the expansion
     615             :  * defined by "exp".
     616             :  */
     617           0 : static void expand_row(__isl_keep isl_mat *dst, int d,
     618             :         __isl_keep isl_mat *src, int s, int *exp)
     619             : {
     620             :         int i;
     621           0 :         unsigned c = src->n_col - src->n_row;
     622             : 
     623           0 :         isl_seq_cpy(dst->row[d], src->row[s], c);
     624           0 :         isl_seq_clr(dst->row[d] + c, dst->n_col - c);
     625             : 
     626           0 :         for (i = 0; i < s; ++i)
     627           0 :                 isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
     628           0 : }
     629             : 
     630             : /* Compare (known) divs.
     631             :  * Return non-zero if at least one of the two divs is unknown.
     632             :  * In particular, if both divs are unknown, we respect their
     633             :  * current order.  Otherwise, we sort the known div after the unknown
     634             :  * div only if the known div depends on the unknown div.
     635             :  */
     636           0 : static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j,
     637             :         unsigned n_row, unsigned n_col)
     638             : {
     639             :         int li, lj;
     640             :         int unknown_i, unknown_j;
     641             : 
     642           0 :         unknown_i = isl_int_is_zero(row_i[0]);
     643           0 :         unknown_j = isl_int_is_zero(row_j[0]);
     644             : 
     645           0 :         if (unknown_i && unknown_j)
     646           0 :                 return i - j;
     647             : 
     648           0 :         if (unknown_i)
     649           0 :                 li = n_col - n_row + i;
     650             :         else
     651           0 :                 li = isl_seq_last_non_zero(row_i, n_col);
     652           0 :         if (unknown_j)
     653           0 :                 lj = n_col - n_row + j;
     654             :         else
     655           0 :                 lj = isl_seq_last_non_zero(row_j, n_col);
     656             : 
     657           0 :         if (li != lj)
     658           0 :                 return li - lj;
     659             : 
     660           0 :         return isl_seq_cmp(row_i, row_j, n_col);
     661             : }
     662             : 
     663             : /* Call cmp_row for divs in a matrix.
     664             :  */
     665           0 : int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j)
     666             : {
     667           0 :         return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col);
     668             : }
     669             : 
     670             : /* Call cmp_row for divs in a basic map.
     671             :  */
     672           0 : static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j,
     673             :         unsigned total)
     674             : {
     675           0 :         return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total);
     676             : }
     677             : 
     678             : /* Sort the divs in "bmap".
     679             :  *
     680             :  * We first make sure divs are placed after divs on which they depend.
     681             :  * Then we perform a simple insertion sort based on the same ordering
     682             :  * that is used in isl_merge_divs.
     683             :  */
     684  2898854974 : __isl_give isl_basic_map *isl_basic_map_sort_divs(
     685             :         __isl_take isl_basic_map *bmap)
     686             : {
     687             :         int i, j;
     688             :         unsigned total;
     689             : 
     690  2898854974 :         bmap = isl_basic_map_order_divs(bmap);
     691  2898854974 :         if (!bmap)
     692           0 :                 return NULL;
     693  2898854974 :         if (bmap->n_div <= 1)
     694  2898854974 :                 return bmap;
     695             : 
     696           0 :         total = 2 + isl_basic_map_total_dim(bmap);
     697           0 :         for (i = 1; i < bmap->n_div; ++i) {
     698           0 :                 for (j = i - 1; j >= 0; --j) {
     699           0 :                         if (bmap_cmp_row(bmap, j, j + 1, total) <= 0)
     700           0 :                                 break;
     701           0 :                         isl_basic_map_swap_div(bmap, j, j + 1);
     702             :                 }
     703             :         }
     704             : 
     705           0 :         return bmap;
     706             : }
     707             : 
     708             : /* Sort the divs in the basic maps of "map".
     709             :  */
     710  1208312287 : __isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map)
     711             : {
     712  1208312287 :         return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs);
     713             : }
     714             : 
     715             : /* Combine the two lists of divs into a single list.
     716             :  * For each row i in div1, exp1[i] is set to the position of the corresponding
     717             :  * row in the result.  Similarly for div2 and exp2.
     718             :  * This function guarantees
     719             :  *      exp1[i] >= i
     720             :  *      exp1[i+1] > exp1[i]
     721             :  * For optimal merging, the two input list should have been sorted.
     722             :  */
     723           0 : __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
     724             :         __isl_keep isl_mat *div2, int *exp1, int *exp2)
     725             : {
     726             :         int i, j, k;
     727           0 :         isl_mat *div = NULL;
     728             :         unsigned d;
     729             : 
     730           0 :         if (!div1 || !div2)
     731           0 :                 return NULL;
     732             : 
     733           0 :         d = div1->n_col - div1->n_row;
     734           0 :         div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
     735           0 :                                 d + div1->n_row + div2->n_row);
     736           0 :         if (!div)
     737           0 :                 return NULL;
     738             : 
     739           0 :         for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
     740             :                 int cmp;
     741             : 
     742           0 :                 expand_row(div, k, div1, i, exp1);
     743           0 :                 expand_row(div, k + 1, div2, j, exp2);
     744             : 
     745           0 :                 cmp = isl_mat_cmp_div(div, k, k + 1);
     746           0 :                 if (cmp == 0) {
     747           0 :                         exp1[i++] = k;
     748           0 :                         exp2[j++] = k;
     749           0 :                 } else if (cmp < 0) {
     750           0 :                         exp1[i++] = k;
     751             :                 } else {
     752           0 :                         exp2[j++] = k;
     753           0 :                         isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
     754             :                 }
     755             :         }
     756           0 :         for (; i < div1->n_row; ++i, ++k) {
     757           0 :                 expand_row(div, k, div1, i, exp1);
     758           0 :                 exp1[i] = k;
     759             :         }
     760           0 :         for (; j < div2->n_row; ++j, ++k) {
     761           0 :                 expand_row(div, k, div2, j, exp2);
     762           0 :                 exp2[j] = k;
     763             :         }
     764             : 
     765           0 :         div->n_row = k;
     766           0 :         div->n_col = d + k;
     767             : 
     768           0 :         return div;
     769             : }
     770             : 
     771             : /* Swap divs "a" and "b" in "ls".
     772             :  */
     773           0 : __isl_give isl_local_space *isl_local_space_swap_div(
     774             :         __isl_take isl_local_space *ls, int a, int b)
     775             : {
     776             :         int offset;
     777             : 
     778           0 :         ls = isl_local_space_cow(ls);
     779           0 :         if (!ls)
     780           0 :                 return NULL;
     781           0 :         if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row)
     782           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
     783             :                         "index out of bounds", return isl_local_space_free(ls));
     784           0 :         offset = ls->div->n_col - ls->div->n_row;
     785           0 :         ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b);
     786           0 :         ls->div = isl_mat_swap_rows(ls->div, a, b);
     787           0 :         if (!ls->div)
     788           0 :                 return isl_local_space_free(ls);
     789           0 :         return ls;
     790             : }
     791             : 
     792             : /* Construct a local space that contains all the divs in either
     793             :  * "ls1" or "ls2".
     794             :  */
     795           0 : __isl_give isl_local_space *isl_local_space_intersect(
     796             :         __isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2)
     797             : {
     798             :         isl_ctx *ctx;
     799           0 :         int *exp1 = NULL;
     800           0 :         int *exp2 = NULL;
     801           0 :         isl_mat *div = NULL;
     802             :         isl_bool equal;
     803             : 
     804           0 :         if (!ls1 || !ls2)
     805             :                 goto error;
     806             : 
     807           0 :         ctx = isl_local_space_get_ctx(ls1);
     808           0 :         if (!isl_space_is_equal(ls1->dim, ls2->dim))
     809           0 :                 isl_die(ctx, isl_error_invalid,
     810             :                         "spaces should be identical", goto error);
     811             : 
     812           0 :         if (ls2->div->n_row == 0) {
     813           0 :                 isl_local_space_free(ls2);
     814           0 :                 return ls1;
     815             :         }
     816             : 
     817           0 :         if (ls1->div->n_row == 0) {
     818           0 :                 isl_local_space_free(ls1);
     819           0 :                 return ls2;
     820             :         }
     821             : 
     822           0 :         exp1 = isl_alloc_array(ctx, int, ls1->div->n_row);
     823           0 :         exp2 = isl_alloc_array(ctx, int, ls2->div->n_row);
     824           0 :         if (!exp1 || !exp2)
     825             :                 goto error;
     826             : 
     827           0 :         div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2);
     828           0 :         if (!div)
     829           0 :                 goto error;
     830             : 
     831           0 :         equal = isl_mat_is_equal(ls1->div, div);
     832           0 :         if (equal < 0)
     833           0 :                 goto error;
     834           0 :         if (!equal)
     835           0 :                 ls1 = isl_local_space_cow(ls1);
     836           0 :         if (!ls1)
     837           0 :                 goto error;
     838             : 
     839           0 :         free(exp1);
     840           0 :         free(exp2);
     841           0 :         isl_local_space_free(ls2);
     842           0 :         isl_mat_free(ls1->div);
     843           0 :         ls1->div = div;
     844             : 
     845           0 :         return ls1;
     846             : error:
     847           0 :         free(exp1);
     848           0 :         free(exp2);
     849           0 :         isl_mat_free(div);
     850           0 :         isl_local_space_free(ls1);
     851           0 :         isl_local_space_free(ls2);
     852           0 :         return NULL;
     853             : }
     854             : 
     855             : /* Is the local variable "div" of "ls" marked as not having
     856             :  * an explicit representation?
     857             :  * Note that even if this variable is not marked in this way and therefore
     858             :  * does have an explicit representation, this representation may still
     859             :  * depend (indirectly) on other local variables that do not
     860             :  * have an explicit representation.
     861             :  */
     862           0 : isl_bool isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space *ls,
     863             :         int div)
     864             : {
     865           0 :         if (!ls)
     866           0 :                 return isl_bool_error;
     867           0 :         return isl_local_div_is_marked_unknown(ls->div, div);
     868             : }
     869             : 
     870             : /* Does "ls" have a complete explicit representation for div "div"?
     871             :  */
     872           0 : isl_bool isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div)
     873             : {
     874           0 :         if (!ls)
     875           0 :                 return isl_bool_error;
     876           0 :         return isl_local_div_is_known(ls->div, div);
     877             : }
     878             : 
     879             : /* Does "ls" have an explicit representation for all local variables?
     880             :  */
     881           0 : isl_bool isl_local_space_divs_known(__isl_keep isl_local_space *ls)
     882             : {
     883           0 :         if (!ls)
     884           0 :                 return isl_bool_error;
     885           0 :         return isl_local_divs_known(ls->div);
     886             : }
     887             : 
     888           0 : __isl_give isl_local_space *isl_local_space_domain(
     889             :         __isl_take isl_local_space *ls)
     890             : {
     891           0 :         ls = isl_local_space_drop_dims(ls, isl_dim_out,
     892           0 :                                         0, isl_local_space_dim(ls, isl_dim_out));
     893           0 :         ls = isl_local_space_cow(ls);
     894           0 :         if (!ls)
     895           0 :                 return NULL;
     896           0 :         ls->dim = isl_space_domain(ls->dim);
     897           0 :         if (!ls->dim)
     898           0 :                 return isl_local_space_free(ls);
     899           0 :         return ls;
     900             : }
     901             : 
     902           0 : __isl_give isl_local_space *isl_local_space_range(
     903             :         __isl_take isl_local_space *ls)
     904             : {
     905           0 :         ls = isl_local_space_drop_dims(ls, isl_dim_in,
     906           0 :                                         0, isl_local_space_dim(ls, isl_dim_in));
     907           0 :         ls = isl_local_space_cow(ls);
     908           0 :         if (!ls)
     909           0 :                 return NULL;
     910             : 
     911           0 :         ls->dim = isl_space_range(ls->dim);
     912           0 :         if (!ls->dim)
     913           0 :                 return isl_local_space_free(ls);
     914           0 :         return ls;
     915             : }
     916             : 
     917             : /* Construct a local space for a map that has the given local
     918             :  * space as domain and that has a zero-dimensional range.
     919             :  */
     920           0 : __isl_give isl_local_space *isl_local_space_from_domain(
     921             :         __isl_take isl_local_space *ls)
     922             : {
     923           0 :         ls = isl_local_space_cow(ls);
     924           0 :         if (!ls)
     925           0 :                 return NULL;
     926           0 :         ls->dim = isl_space_from_domain(ls->dim);
     927           0 :         if (!ls->dim)
     928           0 :                 return isl_local_space_free(ls);
     929           0 :         return ls;
     930             : }
     931             : 
     932           0 : __isl_give isl_local_space *isl_local_space_add_dims(
     933             :         __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
     934             : {
     935             :         int pos;
     936             : 
     937           0 :         if (!ls)
     938           0 :                 return NULL;
     939           0 :         pos = isl_local_space_dim(ls, type);
     940           0 :         return isl_local_space_insert_dims(ls, type, pos, n);
     941             : }
     942             : 
     943             : /* Remove common factor of non-constant terms and denominator.
     944             :  */
     945           0 : static void normalize_div(__isl_keep isl_local_space *ls, int div)
     946             : {
     947           0 :         isl_ctx *ctx = ls->div->ctx;
     948           0 :         unsigned total = ls->div->n_col - 2;
     949             : 
     950           0 :         isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd);
     951           0 :         isl_int_gcd(ctx->normalize_gcd,
     952             :                     ctx->normalize_gcd, ls->div->row[div][0]);
     953           0 :         if (isl_int_is_one(ctx->normalize_gcd))
     954           0 :                 return;
     955             : 
     956           0 :         isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2,
     957           0 :                             ctx->normalize_gcd, total);
     958           0 :         isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0],
     959             :                             ctx->normalize_gcd);
     960           0 :         isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1],
     961             :                             ctx->normalize_gcd);
     962             : }
     963             : 
     964             : /* Exploit the equalities in "eq" to simplify the expressions of
     965             :  * the integer divisions in "ls".
     966             :  * The integer divisions in "ls" are assumed to appear as regular
     967             :  * dimensions in "eq".
     968             :  */
     969           0 : __isl_give isl_local_space *isl_local_space_substitute_equalities(
     970             :         __isl_take isl_local_space *ls, __isl_take isl_basic_set *eq)
     971             : {
     972             :         int i, j, k;
     973             :         unsigned total;
     974             :         unsigned n_div;
     975             : 
     976           0 :         if (!ls || !eq)
     977             :                 goto error;
     978             : 
     979           0 :         total = isl_space_dim(eq->dim, isl_dim_all);
     980           0 :         if (isl_local_space_dim(ls, isl_dim_all) != total)
     981           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
     982             :                         "spaces don't match", goto error);
     983           0 :         total++;
     984           0 :         n_div = eq->n_div;
     985           0 :         for (i = 0; i < eq->n_eq; ++i) {
     986           0 :                 j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
     987           0 :                 if (j < 0 || j == 0 || j >= total)
     988           0 :                         continue;
     989             : 
     990           0 :                 for (k = 0; k < ls->div->n_row; ++k) {
     991           0 :                         if (isl_int_is_zero(ls->div->row[k][1 + j]))
     992           0 :                                 continue;
     993           0 :                         ls = isl_local_space_cow(ls);
     994           0 :                         if (!ls)
     995           0 :                                 goto error;
     996           0 :                         ls->div = isl_mat_cow(ls->div);
     997           0 :                         if (!ls->div)
     998           0 :                                 goto error;
     999           0 :                         isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total,
    1000           0 :                                         &ls->div->row[k][0]);
    1001           0 :                         normalize_div(ls, k);
    1002             :                 }
    1003             :         }
    1004             : 
    1005           0 :         isl_basic_set_free(eq);
    1006           0 :         return ls;
    1007             : error:
    1008           0 :         isl_basic_set_free(eq);
    1009           0 :         isl_local_space_free(ls);
    1010           0 :         return NULL;
    1011             : }
    1012             : 
    1013             : /* Plug in the affine expressions "subs" of length "subs_len" (including
    1014             :  * the denominator and the constant term) into the variable at position "pos"
    1015             :  * of the "n" div expressions starting at "first".
    1016             :  *
    1017             :  * Let i be the dimension to replace and let "subs" be of the form
    1018             :  *
    1019             :  *      f/d
    1020             :  *
    1021             :  * Any integer division starting at "first" with a non-zero coefficient for i,
    1022             :  *
    1023             :  *      floor((a i + g)/m)
    1024             :  *
    1025             :  * is replaced by
    1026             :  *
    1027             :  *      floor((a f + d g)/(m d))
    1028             :  */
    1029           0 : __isl_give isl_local_space *isl_local_space_substitute_seq(
    1030             :         __isl_take isl_local_space *ls,
    1031             :         enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
    1032             :         int first, int n)
    1033             : {
    1034             :         int i;
    1035             :         isl_int v;
    1036             : 
    1037           0 :         if (n == 0)
    1038           0 :                 return ls;
    1039           0 :         ls = isl_local_space_cow(ls);
    1040           0 :         if (!ls)
    1041           0 :                 return NULL;
    1042           0 :         ls->div = isl_mat_cow(ls->div);
    1043           0 :         if (!ls->div)
    1044           0 :                 return isl_local_space_free(ls);
    1045             : 
    1046           0 :         if (first + n > ls->div->n_row)
    1047           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
    1048             :                         "index out of bounds", return isl_local_space_free(ls));
    1049             : 
    1050           0 :         pos += isl_local_space_offset(ls, type);
    1051             : 
    1052           0 :         isl_int_init(v);
    1053           0 :         for (i = first; i < first + n; ++i) {
    1054           0 :                 if (isl_int_is_zero(ls->div->row[i][1 + pos]))
    1055           0 :                         continue;
    1056           0 :                 isl_seq_substitute(ls->div->row[i], pos, subs,
    1057           0 :                         ls->div->n_col, subs_len, v);
    1058           0 :                 normalize_div(ls, i);
    1059             :         }
    1060           0 :         isl_int_clear(v);
    1061             : 
    1062           0 :         return ls;
    1063             : }
    1064             : 
    1065             : /* Plug in "subs" for dimension "type", "pos" in the integer divisions
    1066             :  * of "ls".
    1067             :  *
    1068             :  * Let i be the dimension to replace and let "subs" be of the form
    1069             :  *
    1070             :  *      f/d
    1071             :  *
    1072             :  * Any integer division with a non-zero coefficient for i,
    1073             :  *
    1074             :  *      floor((a i + g)/m)
    1075             :  *
    1076             :  * is replaced by
    1077             :  *
    1078             :  *      floor((a f + d g)/(m d))
    1079             :  */
    1080           0 : __isl_give isl_local_space *isl_local_space_substitute(
    1081             :         __isl_take isl_local_space *ls,
    1082             :         enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
    1083             : {
    1084           0 :         ls = isl_local_space_cow(ls);
    1085           0 :         if (!ls || !subs)
    1086           0 :                 return isl_local_space_free(ls);
    1087             : 
    1088           0 :         if (!isl_space_is_equal(ls->dim, subs->ls->dim))
    1089           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
    1090             :                         "spaces don't match", return isl_local_space_free(ls));
    1091           0 :         if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
    1092           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
    1093             :                         "cannot handle divs yet",
    1094             :                         return isl_local_space_free(ls));
    1095             : 
    1096           0 :         return isl_local_space_substitute_seq(ls, type, pos, subs->v->el,
    1097           0 :                                             subs->v->size, 0, ls->div->n_row);
    1098             : }
    1099             : 
    1100           0 : isl_bool isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
    1101             :         enum isl_dim_type type)
    1102             : {
    1103           0 :         if (!ls)
    1104           0 :                 return isl_bool_error;
    1105           0 :         return isl_space_is_named_or_nested(ls->dim, type);
    1106             : }
    1107             : 
    1108           0 : __isl_give isl_local_space *isl_local_space_drop_dims(
    1109             :         __isl_take isl_local_space *ls,
    1110             :         enum isl_dim_type type, unsigned first, unsigned n)
    1111             : {
    1112             :         isl_ctx *ctx;
    1113             : 
    1114           0 :         if (!ls)
    1115           0 :                 return NULL;
    1116           0 :         if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
    1117           0 :                 return ls;
    1118             : 
    1119           0 :         ctx = isl_local_space_get_ctx(ls);
    1120           0 :         if (first + n > isl_local_space_dim(ls, type))
    1121           0 :                 isl_die(ctx, isl_error_invalid, "range out of bounds",
    1122             :                         return isl_local_space_free(ls));
    1123             : 
    1124           0 :         ls = isl_local_space_cow(ls);
    1125           0 :         if (!ls)
    1126           0 :                 return NULL;
    1127             : 
    1128           0 :         if (type == isl_dim_div) {
    1129           0 :                 ls->div = isl_mat_drop_rows(ls->div, first, n);
    1130             :         } else {
    1131           0 :                 ls->dim = isl_space_drop_dims(ls->dim, type, first, n);
    1132           0 :                 if (!ls->dim)
    1133           0 :                         return isl_local_space_free(ls);
    1134             :         }
    1135             : 
    1136           0 :         first += 1 + isl_local_space_offset(ls, type);
    1137           0 :         ls->div = isl_mat_drop_cols(ls->div, first, n);
    1138           0 :         if (!ls->div)
    1139           0 :                 return isl_local_space_free(ls);
    1140             : 
    1141           0 :         return ls;
    1142             : }
    1143             : 
    1144           0 : __isl_give isl_local_space *isl_local_space_insert_dims(
    1145             :         __isl_take isl_local_space *ls,
    1146             :         enum isl_dim_type type, unsigned first, unsigned n)
    1147             : {
    1148             :         isl_ctx *ctx;
    1149             : 
    1150           0 :         if (!ls)
    1151           0 :                 return NULL;
    1152           0 :         if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
    1153           0 :                 return ls;
    1154             : 
    1155           0 :         ctx = isl_local_space_get_ctx(ls);
    1156           0 :         if (first > isl_local_space_dim(ls, type))
    1157           0 :                 isl_die(ctx, isl_error_invalid, "position out of bounds",
    1158             :                         return isl_local_space_free(ls));
    1159             : 
    1160           0 :         ls = isl_local_space_cow(ls);
    1161           0 :         if (!ls)
    1162           0 :                 return NULL;
    1163             : 
    1164           0 :         if (type == isl_dim_div) {
    1165           0 :                 ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
    1166             :         } else {
    1167           0 :                 ls->dim = isl_space_insert_dims(ls->dim, type, first, n);
    1168           0 :                 if (!ls->dim)
    1169           0 :                         return isl_local_space_free(ls);
    1170             :         }
    1171             : 
    1172           0 :         first += 1 + isl_local_space_offset(ls, type);
    1173           0 :         ls->div = isl_mat_insert_zero_cols(ls->div, first, n);
    1174           0 :         if (!ls->div)
    1175           0 :                 return isl_local_space_free(ls);
    1176             : 
    1177           0 :         return ls;
    1178             : }
    1179             : 
    1180             : /* Does the linear part of "constraint" correspond to
    1181             :  * integer division "div" in "ls"?
    1182             :  *
    1183             :  * That is, given div = floor((c + f)/m), is the constraint of the form
    1184             :  *
    1185             :  *              f - m d + c' >= 0            [sign = 1]
    1186             :  * or
    1187             :  *              -f + m d + c'' >= 0          [sign = -1]
    1188             :  * ?
    1189             :  * If so, set *sign to the corresponding value.
    1190             :  */
    1191           0 : static isl_bool is_linear_div_constraint(__isl_keep isl_local_space *ls,
    1192             :         isl_int *constraint, unsigned div, int *sign)
    1193             : {
    1194             :         isl_bool unknown;
    1195             :         unsigned pos;
    1196             : 
    1197           0 :         unknown = isl_local_space_div_is_marked_unknown(ls, div);
    1198           0 :         if (unknown < 0)
    1199           0 :                 return isl_bool_error;
    1200           0 :         if (unknown)
    1201           0 :                 return isl_bool_false;
    1202             : 
    1203           0 :         pos = isl_local_space_offset(ls, isl_dim_div) + div;
    1204             : 
    1205           0 :         if (isl_int_eq(constraint[pos], ls->div->row[div][0])) {
    1206           0 :                 *sign = -1;
    1207           0 :                 if (!isl_seq_is_neg(constraint + 1,
    1208           0 :                                     ls->div->row[div] + 2, pos - 1))
    1209           0 :                         return isl_bool_false;
    1210           0 :         } else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) {
    1211           0 :                 *sign = 1;
    1212           0 :                 if (!isl_seq_eq(constraint + 1, ls->div->row[div] + 2, pos - 1))
    1213           0 :                         return isl_bool_false;
    1214             :         } else {
    1215           0 :                 return isl_bool_false;
    1216             :         }
    1217           0 :         if (isl_seq_first_non_zero(constraint + pos + 1,
    1218           0 :                                     ls->div->n_row - div - 1) != -1)
    1219           0 :                 return isl_bool_false;
    1220           0 :         return isl_bool_true;
    1221             : }
    1222             : 
    1223             : /* Check if the constraints pointed to by "constraint" is a div
    1224             :  * constraint corresponding to div "div" in "ls".
    1225             :  *
    1226             :  * That is, if div = floor(f/m), then check if the constraint is
    1227             :  *
    1228             :  *              f - m d >= 0
    1229             :  * or
    1230             :  *              -(f-(m-1)) + m d >= 0
    1231             :  *
    1232             :  * First check if the linear part is of the right form and
    1233             :  * then check the constant term.
    1234             :  */
    1235           0 : isl_bool isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
    1236             :         isl_int *constraint, unsigned div)
    1237             : {
    1238             :         int sign;
    1239             :         isl_bool linear;
    1240             : 
    1241           0 :         linear = is_linear_div_constraint(ls, constraint, div, &sign);
    1242           0 :         if (linear < 0 || !linear)
    1243           0 :                 return linear;
    1244             : 
    1245           0 :         if (sign < 0) {
    1246             :                 int neg;
    1247           0 :                 isl_int_sub(ls->div->row[div][1],
    1248             :                                 ls->div->row[div][1], ls->div->row[div][0]);
    1249           0 :                 isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
    1250           0 :                 neg = isl_seq_is_neg(constraint, ls->div->row[div] + 1, 1);
    1251           0 :                 isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
    1252           0 :                 isl_int_add(ls->div->row[div][1],
    1253             :                                 ls->div->row[div][1], ls->div->row[div][0]);
    1254           0 :                 if (!neg)
    1255           0 :                         return isl_bool_false;
    1256             :         } else {
    1257           0 :                 if (!isl_int_eq(constraint[0], ls->div->row[div][1]))
    1258           0 :                         return isl_bool_false;
    1259             :         }
    1260             : 
    1261           0 :         return isl_bool_true;
    1262             : }
    1263             : 
    1264             : /* Is the constraint pointed to by "constraint" one
    1265             :  * of an equality that corresponds to integer division "div" in "ls"?
    1266             :  *
    1267             :  * That is, given an integer division of the form
    1268             :  *
    1269             :  *      a = floor((f + c)/m)
    1270             :  *
    1271             :  * is the equality of the form
    1272             :  *
    1273             :  *              -f + m d + c' = 0
    1274             :  * ?
    1275             :  * Note that the constant term is not checked explicitly, but given
    1276             :  * that this is a valid equality constraint, the constant c' necessarily
    1277             :  * has a value close to -c.
    1278             :  */
    1279           0 : isl_bool isl_local_space_is_div_equality(__isl_keep isl_local_space *ls,
    1280             :         isl_int *constraint, unsigned div)
    1281             : {
    1282             :         int sign;
    1283             :         isl_bool linear;
    1284             : 
    1285           0 :         linear = is_linear_div_constraint(ls, constraint, div, &sign);
    1286           0 :         if (linear < 0 || !linear)
    1287           0 :                 return linear;
    1288             : 
    1289           0 :         return sign < 0;
    1290             : }
    1291             : 
    1292             : /*
    1293             :  * Set active[i] to 1 if the dimension at position i is involved
    1294             :  * in the linear expression l.
    1295             :  */
    1296           0 : int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l)
    1297             : {
    1298             :         int i, j;
    1299             :         isl_ctx *ctx;
    1300           0 :         int *active = NULL;
    1301             :         unsigned total;
    1302             :         unsigned offset;
    1303             : 
    1304           0 :         ctx = isl_local_space_get_ctx(ls);
    1305           0 :         total = isl_local_space_dim(ls, isl_dim_all);
    1306           0 :         active = isl_calloc_array(ctx, int, total);
    1307           0 :         if (total && !active)
    1308           0 :                 return NULL;
    1309             : 
    1310           0 :         for (i = 0; i < total; ++i)
    1311           0 :                 active[i] = !isl_int_is_zero(l[i]);
    1312             : 
    1313           0 :         offset = isl_local_space_offset(ls, isl_dim_div) - 1;
    1314           0 :         for (i = ls->div->n_row - 1; i >= 0; --i) {
    1315           0 :                 if (!active[offset + i])
    1316           0 :                         continue;
    1317           0 :                 for (j = 0; j < total; ++j)
    1318           0 :                         active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]);
    1319             :         }
    1320             : 
    1321           0 :         return active;
    1322             : }
    1323             : 
    1324             : /* Given a local space "ls" of a set, create a local space
    1325             :  * for the lift of the set.  In particular, the result
    1326             :  * is of the form [dim -> local[..]], with ls->div->n_row variables in the
    1327             :  * range of the wrapped map.
    1328             :  */
    1329           0 : __isl_give isl_local_space *isl_local_space_lift(
    1330             :         __isl_take isl_local_space *ls)
    1331             : {
    1332           0 :         ls = isl_local_space_cow(ls);
    1333           0 :         if (!ls)
    1334           0 :                 return NULL;
    1335             : 
    1336           0 :         ls->dim = isl_space_lift(ls->dim, ls->div->n_row);
    1337           0 :         ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row);
    1338           0 :         if (!ls->dim || !ls->div)
    1339           0 :                 return isl_local_space_free(ls);
    1340             : 
    1341           0 :         return ls;
    1342             : }
    1343             : 
    1344             : /* Construct a basic map that maps a set living in local space "ls"
    1345             :  * to the corresponding lifted local space.
    1346             :  */
    1347           0 : __isl_give isl_basic_map *isl_local_space_lifting(
    1348             :         __isl_take isl_local_space *ls)
    1349             : {
    1350             :         isl_basic_map *lifting;
    1351             :         isl_basic_set *bset;
    1352             : 
    1353           0 :         if (!ls)
    1354           0 :                 return NULL;
    1355           0 :         if (!isl_local_space_is_set(ls))
    1356           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
    1357             :                         "lifting only defined on set spaces", goto error);
    1358             : 
    1359           0 :         bset = isl_basic_set_from_local_space(ls);
    1360           0 :         lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset));
    1361           0 :         lifting = isl_basic_map_domain_map(lifting);
    1362           0 :         lifting = isl_basic_map_reverse(lifting);
    1363             : 
    1364           0 :         return lifting;
    1365             : error:
    1366           0 :         isl_local_space_free(ls);
    1367           0 :         return NULL;
    1368             : }
    1369             : 
    1370             : /* Compute the preimage of "ls" under the function represented by "ma".
    1371             :  * In other words, plug in "ma" in "ls".  The result is a local space
    1372             :  * that is part of the domain space of "ma".
    1373             :  *
    1374             :  * If the divs in "ls" are represented as
    1375             :  *
    1376             :  *      floor((a_i(p) + b_i x + c_i(divs))/n_i)
    1377             :  *
    1378             :  * and ma is represented by
    1379             :  *
    1380             :  *      x = D(p) + F(y) + G(divs')
    1381             :  *
    1382             :  * then the resulting divs are
    1383             :  *
    1384             :  *      floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
    1385             :  *
    1386             :  * We first copy over the divs from "ma" and then
    1387             :  * we add the modified divs from "ls".
    1388             :  */
    1389           0 : __isl_give isl_local_space *isl_local_space_preimage_multi_aff(
    1390             :         __isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma)
    1391             : {
    1392             :         int i;
    1393             :         isl_space *space;
    1394           0 :         isl_local_space *res = NULL;
    1395             :         int n_div_ls, n_div_ma;
    1396             :         isl_int f, c1, c2, g;
    1397             : 
    1398           0 :         ma = isl_multi_aff_align_divs(ma);
    1399           0 :         if (!ls || !ma)
    1400             :                 goto error;
    1401           0 :         if (!isl_space_is_range_internal(ls->dim, ma->space))
    1402           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
    1403             :                         "spaces don't match", goto error);
    1404             : 
    1405           0 :         n_div_ls = isl_local_space_dim(ls, isl_dim_div);
    1406           0 :         n_div_ma = ma->n ? isl_aff_dim(ma->u.p[0], isl_dim_div) : 0;
    1407             : 
    1408           0 :         space = isl_space_domain(isl_multi_aff_get_space(ma));
    1409           0 :         res = isl_local_space_alloc(space, n_div_ma + n_div_ls);
    1410           0 :         if (!res)
    1411           0 :                 goto error;
    1412             : 
    1413           0 :         if (n_div_ma) {
    1414           0 :                 isl_mat_free(res->div);
    1415           0 :                 res->div = isl_mat_copy(ma->u.p[0]->ls->div);
    1416           0 :                 res->div = isl_mat_add_zero_cols(res->div, n_div_ls);
    1417           0 :                 res->div = isl_mat_add_rows(res->div, n_div_ls);
    1418           0 :                 if (!res->div)
    1419           0 :                         goto error;
    1420             :         }
    1421             : 
    1422           0 :         isl_int_init(f);
    1423           0 :         isl_int_init(c1);
    1424           0 :         isl_int_init(c2);
    1425           0 :         isl_int_init(g);
    1426             : 
    1427           0 :         for (i = 0; i < ls->div->n_row; ++i) {
    1428           0 :                 if (isl_int_is_zero(ls->div->row[i][0])) {
    1429           0 :                         isl_int_set_si(res->div->row[n_div_ma + i][0], 0);
    1430           0 :                         continue;
    1431             :                 }
    1432           0 :                 isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i],
    1433             :                                 ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1);
    1434           0 :                 normalize_div(res, n_div_ma + i);
    1435             :         }
    1436             : 
    1437           0 :         isl_int_clear(f);
    1438           0 :         isl_int_clear(c1);
    1439           0 :         isl_int_clear(c2);
    1440           0 :         isl_int_clear(g);
    1441             : 
    1442           0 :         isl_local_space_free(ls);
    1443           0 :         isl_multi_aff_free(ma);
    1444           0 :         return res;
    1445             : error:
    1446           0 :         isl_local_space_free(ls);
    1447           0 :         isl_multi_aff_free(ma);
    1448           0 :         isl_local_space_free(res);
    1449           0 :         return NULL;
    1450             : }
    1451             : 
    1452             : /* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls"
    1453             :  * to dimensions of "dst_type" at "dst_pos".
    1454             :  *
    1455             :  * Moving to/from local dimensions is not allowed.
    1456             :  * We currently assume that the dimension type changes.
    1457             :  */
    1458           0 : __isl_give isl_local_space *isl_local_space_move_dims(
    1459             :         __isl_take isl_local_space *ls,
    1460             :         enum isl_dim_type dst_type, unsigned dst_pos,
    1461             :         enum isl_dim_type src_type, unsigned src_pos, unsigned n)
    1462             : {
    1463             :         unsigned g_dst_pos;
    1464             :         unsigned g_src_pos;
    1465             : 
    1466           0 :         if (!ls)
    1467           0 :                 return NULL;
    1468           0 :         if (n == 0 &&
    1469           0 :             !isl_local_space_is_named_or_nested(ls, src_type) &&
    1470           0 :             !isl_local_space_is_named_or_nested(ls, dst_type))
    1471           0 :                 return ls;
    1472             : 
    1473           0 :         if (src_pos + n > isl_local_space_dim(ls, src_type))
    1474           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
    1475             :                         "range out of bounds", return isl_local_space_free(ls));
    1476           0 :         if (dst_pos > isl_local_space_dim(ls, dst_type))
    1477           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
    1478             :                         "position out of bounds",
    1479             :                         return isl_local_space_free(ls));
    1480           0 :         if (src_type == isl_dim_div)
    1481           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
    1482             :                         "cannot move divs", return isl_local_space_free(ls));
    1483           0 :         if (dst_type == isl_dim_div)
    1484           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
    1485             :                         "cannot move to divs", return isl_local_space_free(ls));
    1486           0 :         if (dst_type == src_type && dst_pos == src_pos)
    1487           0 :                 return ls;
    1488           0 :         if (dst_type == src_type)
    1489           0 :                 isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
    1490             :                         "moving dims within the same type not supported",
    1491             :                         return isl_local_space_free(ls));
    1492             : 
    1493           0 :         ls = isl_local_space_cow(ls);
    1494           0 :         if (!ls)
    1495           0 :                 return NULL;
    1496             : 
    1497           0 :         g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos;
    1498           0 :         g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos;
    1499           0 :         if (dst_type > src_type)
    1500           0 :                 g_dst_pos -= n;
    1501           0 :         ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n);
    1502           0 :         if (!ls->div)
    1503           0 :                 return isl_local_space_free(ls);
    1504           0 :         ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos,
    1505             :                                         src_type, src_pos, n);
    1506           0 :         if (!ls->dim)
    1507           0 :                 return isl_local_space_free(ls);
    1508             : 
    1509           0 :         return ls;
    1510             : }
    1511             : 
    1512             : /* Remove any internal structure of the domain of "ls".
    1513             :  * If there is any such internal structure in the input,
    1514             :  * then the name of the corresponding space is also removed.
    1515             :  */
    1516           0 : __isl_give isl_local_space *isl_local_space_flatten_domain(
    1517             :         __isl_take isl_local_space *ls)
    1518             : {
    1519           0 :         if (!ls)
    1520           0 :                 return NULL;
    1521             : 
    1522           0 :         if (!ls->dim->nested[0])
    1523           0 :                 return ls;
    1524             : 
    1525           0 :         ls = isl_local_space_cow(ls);
    1526           0 :         if (!ls)
    1527           0 :                 return NULL;
    1528             : 
    1529           0 :         ls->dim = isl_space_flatten_domain(ls->dim);
    1530           0 :         if (!ls->dim)
    1531           0 :                 return isl_local_space_free(ls);
    1532             : 
    1533           0 :         return ls;
    1534             : }
    1535             : 
    1536             : /* Remove any internal structure of the range of "ls".
    1537             :  * If there is any such internal structure in the input,
    1538             :  * then the name of the corresponding space is also removed.
    1539             :  */
    1540           0 : __isl_give isl_local_space *isl_local_space_flatten_range(
    1541             :         __isl_take isl_local_space *ls)
    1542             : {
    1543           0 :         if (!ls)
    1544           0 :                 return NULL;
    1545             : 
    1546           0 :         if (!ls->dim->nested[1])
    1547           0 :                 return ls;
    1548             : 
    1549           0 :         ls = isl_local_space_cow(ls);
    1550           0 :         if (!ls)
    1551           0 :                 return NULL;
    1552             : 
    1553           0 :         ls->dim = isl_space_flatten_range(ls->dim);
    1554           0 :         if (!ls->dim)
    1555           0 :                 return isl_local_space_free(ls);
    1556             : 
    1557           0 :         return ls;
    1558             : }
    1559             : 
    1560             : /* Given the local space "ls" of a map, return the local space of a set
    1561             :  * that lives in a space that wraps the space of "ls" and that has
    1562             :  * the same divs.
    1563             :  */
    1564           0 : __isl_give isl_local_space *isl_local_space_wrap(__isl_take isl_local_space *ls)
    1565             : {
    1566           0 :         ls = isl_local_space_cow(ls);
    1567           0 :         if (!ls)
    1568           0 :                 return NULL;
    1569             : 
    1570           0 :         ls->dim = isl_space_wrap(ls->dim);
    1571           0 :         if (!ls->dim)
    1572           0 :                 return isl_local_space_free(ls);
    1573             : 
    1574           0 :         return ls;
    1575             : }
    1576             : 
    1577             : /* Lift the point "pnt", living in the space of "ls"
    1578             :  * to live in a space with extra coordinates corresponding
    1579             :  * to the local variables of "ls".
    1580             :  */
    1581           0 : __isl_give isl_point *isl_local_space_lift_point(__isl_take isl_local_space *ls,
    1582             :         __isl_take isl_point *pnt)
    1583             : {
    1584             :         unsigned n_local;
    1585             :         isl_space *space;
    1586             :         isl_local *local;
    1587             :         isl_vec *vec;
    1588             : 
    1589           0 :         if (isl_local_space_check_has_space(ls, isl_point_peek_space(pnt)) < 0)
    1590           0 :                 goto error;
    1591             : 
    1592           0 :         local = isl_local_space_peek_local(ls);
    1593           0 :         n_local = isl_local_space_dim(ls, isl_dim_div);
    1594             : 
    1595           0 :         space = isl_point_take_space(pnt);
    1596           0 :         vec = isl_point_take_vec(pnt);
    1597             : 
    1598           0 :         space = isl_space_lift(space, n_local);
    1599           0 :         vec = isl_local_extend_point_vec(local, vec);
    1600             : 
    1601           0 :         pnt = isl_point_restore_vec(pnt, vec);
    1602           0 :         pnt = isl_point_restore_space(pnt, space);
    1603             : 
    1604           0 :         isl_local_space_free(ls);
    1605             : 
    1606           0 :         return pnt;
    1607             : error:
    1608           0 :         isl_local_space_free(ls);
    1609           0 :         isl_point_free(pnt);
    1610           0 :         return NULL;
    1611             : }

Generated by: LCOV version 1.12