X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=isl_aff.c;h=ccd2b426c20a23e58a223e2dead30d405266eaa0;hb=f068f30e43903b246ea5aad7a57a1138435daf0e;hp=722da3b561e53627f97192d44af49ca8abe67e9c;hpb=556d287f982d8cc1a6f1fd6a318e926c95dbebf4;p=platform%2Fupstream%2Fisl.git diff --git a/isl_aff.c b/isl_aff.c index 722da3b..ccd2b42 100644 --- a/isl_aff.c +++ b/isl_aff.c @@ -1,16 +1,20 @@ /* * Copyright 2011 INRIA Saclay * Copyright 2011 Sven Verdoolaege + * Copyright 2012 Ecole Normale Superieure * * Use of this software is governed by the GNU LGPLv2.1 license * * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, * 91893 Orsay, France + * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France */ #include +#define ISL_DIM_H #include +#include #include #include #include @@ -280,6 +284,34 @@ error: return NULL; } +__isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff, + __isl_take isl_space *model) +{ + if (!aff || !model) + goto error; + + if (!isl_space_match(aff->ls->dim, isl_dim_param, + model, isl_dim_param)) { + isl_reordering *exp; + + model = isl_space_drop_dims(model, isl_dim_in, + 0, isl_space_dim(model, isl_dim_in)); + model = isl_space_drop_dims(model, isl_dim_out, + 0, isl_space_dim(model, isl_dim_out)); + exp = isl_parameter_alignment_reordering(aff->ls->dim, model); + exp = isl_reordering_extend_space(exp, + isl_aff_get_domain_space(aff)); + aff = isl_aff_realign_domain(aff, exp); + } + + isl_space_free(model); + return aff; +error: + isl_space_free(model); + isl_aff_free(aff); + return NULL; +} + int isl_aff_plain_is_zero(__isl_keep isl_aff *aff) { if (!aff) @@ -544,6 +576,41 @@ __isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff) return aff; } +/* Remove divs from the local space that do not appear in the affine + * expression. + * We currently only remove divs at the end. + * Some intermediate divs may also not appear directly in the affine + * expression, but we would also need to check that no other divs are + * defined in terms of them. + */ +__isl_give isl_aff *isl_aff_remove_unused_divs( __isl_take isl_aff *aff) +{ + int pos; + int off; + int n; + + if (!aff) + return NULL; + + n = isl_local_space_dim(aff->ls, isl_dim_div); + off = isl_local_space_offset(aff->ls, isl_dim_div); + + pos = isl_seq_last_non_zero(aff->v->el + 1 + off, n) + 1; + if (pos == n) + return aff; + + aff = isl_aff_cow(aff); + if (!aff) + return NULL; + + aff->ls = isl_local_space_drop_dims(aff->ls, isl_dim_div, pos, n - pos); + aff->v = isl_vec_drop_els(aff->v, 1 + off + pos, n - pos); + if (!aff->ls || !aff->v) + return isl_aff_free(aff); + + return aff; +} + __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff) { if (!aff) @@ -551,6 +618,7 @@ __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff) aff->v = isl_vec_normalize(aff->v); if (!aff->v) return isl_aff_free(aff); + aff = isl_aff_remove_unused_divs(aff); return aff; } @@ -936,6 +1004,7 @@ static __isl_give isl_aff *isl_aff_substitute_equalities_lifted( } isl_basic_set_free(eq); + aff = isl_aff_normalize(aff); return aff; error: isl_basic_set_free(eq); @@ -1011,10 +1080,13 @@ __isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff, __isl_give isl_basic_set *isl_aff_nonneg_basic_set(__isl_take isl_aff *aff) { isl_constraint *ineq; + isl_basic_set *bset; ineq = isl_inequality_from_aff(aff); - return isl_basic_set_from_constraint(ineq); + bset = isl_basic_set_from_constraint(ineq); + bset = isl_basic_set_simplify(bset); + return bset; } /* Return a basic set containing those elements in the space @@ -1023,10 +1095,13 @@ __isl_give isl_basic_set *isl_aff_nonneg_basic_set(__isl_take isl_aff *aff) __isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff) { isl_constraint *ineq; + isl_basic_set *bset; ineq = isl_equality_from_aff(aff); - return isl_basic_set_from_constraint(ineq); + bset = isl_basic_set_from_constraint(ineq); + bset = isl_basic_set_simplify(bset); + return bset; } /* Return a basic set containing those elements in the shared space @@ -1144,6 +1219,30 @@ __isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff, return aff; } +/* Project the domain of the affine expression onto its parameter space. + * The affine expression may not involve any of the domain dimensions. + */ +__isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff) +{ + isl_space *space; + unsigned n; + int involves; + + n = isl_aff_dim(aff, isl_dim_in); + involves = isl_aff_involves_dims(aff, isl_dim_in, 0, n); + if (involves < 0) + return isl_aff_free(aff); + if (involves) + isl_die(isl_aff_get_ctx(aff), isl_error_invalid, + "affine expression involves some of the domain dimensions", + return isl_aff_free(aff)); + aff = isl_aff_drop_dims(aff, isl_dim_in, 0, n); + space = isl_aff_get_domain_space(aff); + space = isl_space_params(space); + aff = isl_aff_reset_domain_space(aff, space); + return aff; +} + __isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff, enum isl_dim_type type, unsigned first, unsigned n) { @@ -1472,9 +1571,11 @@ __isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff) } /* Return a set containing those elements in the domain - * of pwaff where it is zero. + * of pwaff where it is zero (if complement is 0) or not zero + * (if complement is 1). */ -__isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) +static __isl_give isl_set *pw_aff_zero_set(__isl_take isl_pw_aff *pwaff, + int complement) { int i; isl_set *set; @@ -1486,11 +1587,15 @@ __isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) for (i = 0; i < pwaff->n; ++i) { isl_basic_set *bset; - isl_set *set_i; + isl_set *set_i, *zero; bset = isl_aff_zero_basic_set(isl_aff_copy(pwaff->p[i].aff)); - set_i = isl_set_from_basic_set(bset); - set_i = isl_set_intersect(set_i, isl_set_copy(pwaff->p[i].set)); + zero = isl_set_from_basic_set(bset); + set_i = isl_set_copy(pwaff->p[i].set); + if (complement) + set_i = isl_set_subtract(set_i, zero); + else + set_i = isl_set_intersect(set_i, zero); set = isl_set_union_disjoint(set, set_i); } @@ -1500,11 +1605,19 @@ __isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) } /* Return a set containing those elements in the domain + * of pwaff where it is zero. + */ +__isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) +{ + return pw_aff_zero_set(pwaff, 0); +} + +/* Return a set containing those elements in the domain * of pwaff where it is not zero. */ __isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff) { - return isl_set_complement(isl_pw_aff_zero_set(pwaff)); + return pw_aff_zero_set(pwaff, 1); } /* Return a set containing those elements in the shared domain @@ -1768,20 +1881,34 @@ __isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff) return pwaff; } +/* Assuming that "cond1" and "cond2" are disjoint, + * return an affine expression that is equal to pwaff1 on cond1 + * and to pwaff2 on cond2. + */ +static __isl_give isl_pw_aff *isl_pw_aff_select( + __isl_take isl_set *cond1, __isl_take isl_pw_aff *pwaff1, + __isl_take isl_set *cond2, __isl_take isl_pw_aff *pwaff2) +{ + pwaff1 = isl_pw_aff_intersect_domain(pwaff1, cond1); + pwaff2 = isl_pw_aff_intersect_domain(pwaff2, cond2); + + return isl_pw_aff_add_disjoint(pwaff1, pwaff2); +} + /* Return an affine expression that is equal to pwaff_true for elements - * in "cond" and to pwaff_false for elements not in "cond". + * where "cond" is non-zero and to pwaff_false for elements where "cond" + * is zero. * That is, return cond ? pwaff_true : pwaff_false; */ -__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_set *cond, +__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond, __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false) { - isl_set *comp; - - comp = isl_set_complement(isl_set_copy(cond)); - pwaff_true = isl_pw_aff_intersect_domain(pwaff_true, cond); - pwaff_false = isl_pw_aff_intersect_domain(pwaff_false, comp); + isl_set *cond_true, *cond_false; - return isl_pw_aff_add_disjoint(pwaff_true, pwaff_false); + cond_true = isl_pw_aff_non_zero_set(isl_pw_aff_copy(cond)); + cond_false = isl_pw_aff_zero_set(cond); + return isl_pw_aff_select(cond_true, pwaff_true, + cond_false, pwaff_false); } int isl_aff_is_cst(__isl_keep isl_aff *aff) @@ -1870,10 +1997,14 @@ static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2) { isl_set *le; + isl_set *dom; + dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)), + isl_pw_aff_domain(isl_pw_aff_copy(pwaff2))); le = isl_pw_aff_le_set(isl_pw_aff_copy(pwaff1), isl_pw_aff_copy(pwaff2)); - return isl_pw_aff_cond(le, pwaff1, pwaff2); + dom = isl_set_subtract(dom, isl_set_copy(le)); + return isl_pw_aff_select(le, pwaff1, dom, pwaff2); } __isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1, @@ -1885,11 +2016,15 @@ __isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1, static __isl_give isl_pw_aff *pw_aff_max(__isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2) { - isl_set *le; + isl_set *ge; + isl_set *dom; - le = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1), + dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)), + isl_pw_aff_domain(isl_pw_aff_copy(pwaff2))); + ge = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1), isl_pw_aff_copy(pwaff2)); - return isl_pw_aff_cond(le, pwaff1, pwaff2); + dom = isl_set_subtract(dom, isl_set_copy(ge)); + return isl_pw_aff_select(ge, pwaff1, dom, pwaff2); } __isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1, @@ -1947,6 +2082,50 @@ __isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list) #include +/* Construct an isl_multi_aff in the given space with value zero in + * each of the output dimensions. + */ +__isl_give isl_multi_aff *isl_multi_aff_zero(__isl_take isl_space *space) +{ + int n; + isl_multi_aff *ma; + + if (!space) + return NULL; + + n = isl_space_dim(space , isl_dim_out); + ma = isl_multi_aff_alloc(isl_space_copy(space)); + + if (!n) + isl_space_free(space); + else { + int i; + isl_local_space *ls; + isl_aff *aff; + + space = isl_space_domain(space); + ls = isl_local_space_from_space(space); + aff = isl_aff_zero_on_domain(ls); + + for (i = 0; i < n; ++i) + ma = isl_multi_aff_set_aff(ma, i, isl_aff_copy(aff)); + + isl_aff_free(aff); + } + + return ma; +} + +/* Create an isl_pw_multi_aff with the given isl_multi_aff on a universe + * domain. + */ +__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff( + __isl_take isl_multi_aff *ma) +{ + isl_set *dom = isl_set_universe(isl_multi_aff_get_domain_space(ma)); + return isl_pw_multi_aff_alloc(dom, ma); +} + __isl_give isl_multi_aff *isl_multi_aff_add(__isl_take isl_multi_aff *maff1, __isl_take isl_multi_aff *maff2) { @@ -2094,6 +2273,16 @@ __isl_give isl_multi_aff *isl_multi_aff_drop_dims(__isl_take isl_multi_aff *maff maff->space = isl_space_drop_dims(maff->space, type, first, n); if (!maff->space) return isl_multi_aff_free(maff); + + if (type == isl_dim_out) { + for (i = 0; i < n; ++i) + isl_aff_free(maff->p[first + i]); + for (i = first; i + n < maff->n; ++i) + maff->p[i] = maff->p[i + n]; + maff->n -= n; + return maff; + } + for (i = 0; i < maff->n; ++i) { maff->p[i] = isl_aff_drop_dims(maff->p[i], type, first, n); if (!maff->p[i]) @@ -2129,6 +2318,18 @@ __isl_give isl_multi_aff *isl_multi_aff_drop_dims(__isl_take isl_multi_aff *maff #include +#undef UNION +#define UNION isl_union_pw_multi_aff +#undef PART +#define PART isl_pw_multi_aff +#undef PARTS +#define PARTS pw_multi_aff +#define ALIGN_DOMAIN + +#define NO_EVAL + +#include + static __isl_give isl_pw_multi_aff *pw_multi_aff_add( __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) { @@ -2190,22 +2391,145 @@ __isl_give isl_set *isl_set_from_pw_multi_aff(__isl_take isl_pw_multi_aff *pma) return isl_map_from_pw_multi_aff(pma); } +/* Given a basic map with a single output dimension that is defined + * in terms of the parameters and input dimensions using an equality, + * extract an isl_aff that expresses the output dimension in terms + * of the parameters and input dimensions. + * + * Since some applications expect the result of isl_pw_multi_aff_from_map + * to only contain integer affine expressions, we compute the floor + * of the expression before returning. + * + * This function shares some similarities with + * isl_basic_map_has_defining_equality and isl_constraint_get_bound. + */ +static __isl_give isl_aff *extract_isl_aff_from_basic_map( + __isl_take isl_basic_map *bmap) +{ + int i; + unsigned offset; + unsigned total; + isl_local_space *ls; + isl_aff *aff; + + if (!bmap) + return NULL; + if (isl_basic_map_dim(bmap, isl_dim_out) != 1) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "basic map should have a single output dimension", + goto error); + offset = isl_basic_map_offset(bmap, isl_dim_out); + total = isl_basic_map_total_dim(bmap); + for (i = 0; i < bmap->n_eq; ++i) { + if (isl_int_is_zero(bmap->eq[i][offset])) + continue; + if (isl_seq_first_non_zero(bmap->eq[i] + offset + 1, + 1 + total - (offset + 1)) != -1) + continue; + break; + } + if (i >= bmap->n_eq) + isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, + "unable to find suitable equality", goto error); + ls = isl_basic_map_get_local_space(bmap); + aff = isl_aff_alloc(isl_local_space_domain(ls)); + if (!aff) + goto error; + if (isl_int_is_neg(bmap->eq[i][offset])) + isl_seq_cpy(aff->v->el + 1, bmap->eq[i], offset); + else + isl_seq_neg(aff->v->el + 1, bmap->eq[i], offset); + isl_seq_clr(aff->v->el + 1 + offset, aff->v->size - (1 + offset)); + isl_int_abs(aff->v->el[0], bmap->eq[i][offset]); + isl_basic_map_free(bmap); + + aff = isl_aff_remove_unused_divs(aff); + aff = isl_aff_floor(aff); + return aff; +error: + isl_basic_map_free(bmap); + return NULL; +} + +/* Given a basic map where each output dimension is defined + * in terms of the parameters and input dimensions using an equality, + * extract an isl_multi_aff that expresses the output dimensions in terms + * of the parameters and input dimensions. + */ +static __isl_give isl_multi_aff *extract_isl_multi_aff_from_basic_map( + __isl_take isl_basic_map *bmap) +{ + int i; + unsigned n_out; + isl_multi_aff *ma; + + if (!bmap) + return NULL; + + ma = isl_multi_aff_alloc(isl_basic_map_get_space(bmap)); + n_out = isl_basic_map_dim(bmap, isl_dim_out); + + for (i = 0; i < n_out; ++i) { + isl_basic_map *bmap_i; + isl_aff *aff; + + bmap_i = isl_basic_map_copy(bmap); + bmap_i = isl_basic_map_project_out(bmap_i, isl_dim_out, + i + 1, n_out - (1 + i)); + bmap_i = isl_basic_map_project_out(bmap_i, isl_dim_out, 0, i); + aff = extract_isl_aff_from_basic_map(bmap_i); + ma = isl_multi_aff_set_aff(ma, i, aff); + } + + isl_basic_map_free(bmap); + + return ma; +} + +/* Create an isl_pw_multi_aff that is equivalent to + * isl_map_intersect_domain(isl_map_from_basic_map(bmap), domain). + * The given basic map is such that each output dimension is defined + * in terms of the parameters and input dimensions using an equality. + */ +static __isl_give isl_pw_multi_aff *plain_pw_multi_aff_from_map( + __isl_take isl_set *domain, __isl_take isl_basic_map *bmap) +{ + isl_multi_aff *ma; + + ma = extract_isl_multi_aff_from_basic_map(bmap); + return isl_pw_multi_aff_alloc(domain, ma); +} + /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. * This obivously only works if the input "map" is single-valued. * If so, we compute the lexicographic minimum of the image in the form * of an isl_pw_multi_aff. Since the image is unique, it is equal * to its lexicographic minimum. * If the input is not single-valued, we produce an error. + * + * As a special case, we first check if all output dimensions are uniquely + * defined in terms of the parameters and input dimensions over the entire + * domain. If so, we extract the desired isl_pw_multi_aff directly + * from the affine hull of "map" and its domain. */ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map) { int i; int sv; isl_pw_multi_aff *pma; + isl_basic_map *hull; if (!map) return NULL; + hull = isl_map_affine_hull(isl_map_copy(map)); + sv = isl_basic_map_plain_is_single_valued(hull); + if (sv >= 0 && sv) + return plain_pw_multi_aff_from_map(isl_map_domain(map), hull); + isl_basic_map_free(hull); + if (sv < 0) + goto error; + sv = isl_map_is_single_valued(map); if (sv < 0) goto error; @@ -2238,6 +2562,24 @@ __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set) return isl_pw_multi_aff_from_map(set); } +/* Return the piecewise affine expression "set ? 1 : 0". + */ +__isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set) +{ + isl_pw_aff *pa; + isl_space *space = isl_set_get_space(set); + isl_local_space *ls = isl_local_space_from_space(space); + isl_aff *zero = isl_aff_zero_on_domain(isl_local_space_copy(ls)); + isl_aff *one = isl_aff_zero_on_domain(ls); + + one = isl_aff_add_constant_si(one, 1); + pa = isl_pw_aff_alloc(isl_set_copy(set), one); + set = isl_set_complement(set); + pa = isl_pw_aff_add_disjoint(pa, isl_pw_aff_alloc(set, zero)); + + return pa; +} + /* Plug in "subs" for dimension "type", "pos" of "aff". * * Let i be the dimension to replace and let "subs" be of the form @@ -2516,3 +2858,37 @@ error: isl_local_space_free(*ls); return isl_multi_aff_free(maff); } + + +/* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma". + */ +__isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff( + __isl_keep isl_pw_multi_aff *pma, int pos) +{ + int i; + int n_out; + isl_space *space; + isl_pw_aff *pa; + + if (!pma) + return NULL; + + n_out = isl_pw_multi_aff_dim(pma, isl_dim_out); + if (pos < 0 || pos >= n_out) + isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, + "index out of bounds", return NULL); + + space = isl_pw_multi_aff_get_space(pma); + space = isl_space_drop_dims(space, isl_dim_out, + pos + 1, n_out - pos - 1); + space = isl_space_drop_dims(space, isl_dim_out, 0, pos); + + pa = isl_pw_aff_alloc_size(space, pma->n); + for (i = 0; i < pma->n; ++i) { + isl_aff *aff; + aff = isl_multi_aff_get_aff(pma->p[i].maff, pos); + pa = isl_pw_aff_add_piece(pa, isl_set_copy(pma->p[i].set), aff); + } + + return pa; +}