llvm-project/polly/lib/External/isl/isl_pw_templ.c

2238 lines
48 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2010-2011 INRIA Saclay
* Copyright 2011 Sven Verdoolaege
* Copyright 2012-2014 Ecole Normale Superieure
*
* Use of this software is governed by the MIT 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 dUlm, 75230 Paris, France
*/
#include <isl/id.h>
#include <isl/aff.h>
#include <isl_sort.h>
#include <isl_val_private.h>
#include <isl_pw_macro.h>
#ifdef HAS_TYPE
__isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim,
enum isl_fold type, int n)
#else
__isl_give PW *FN(PW,alloc_size)(__isl_take isl_space *dim, int n)
#endif
{
isl_ctx *ctx;
struct PW *pw;
if (!dim)
return NULL;
ctx = isl_space_get_ctx(dim);
isl_assert(ctx, n >= 0, goto error);
pw = isl_alloc(ctx, struct PW,
sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
if (!pw)
goto error;
pw->ref = 1;
#ifdef HAS_TYPE
pw->type = type;
#endif
pw->size = n;
pw->n = 0;
pw->dim = dim;
return pw;
error:
isl_space_free(dim);
return NULL;
}
#ifdef HAS_TYPE
__isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim, enum isl_fold type)
{
return FN(PW,alloc_size)(dim, type, 0);
}
#else
__isl_give PW *FN(PW,ZERO)(__isl_take isl_space *dim)
{
return FN(PW,alloc_size)(dim, 0);
}
#endif
__isl_give PW *FN(PW,add_piece)(__isl_take PW *pw,
__isl_take isl_set *set, __isl_take EL *el)
{
isl_ctx *ctx;
isl_space *el_dim = NULL;
if (!pw || !set || !el)
goto error;
if (isl_set_plain_is_empty(set) || FN(EL,EL_IS_ZERO)(el)) {
isl_set_free(set);
FN(EL,free)(el);
return pw;
}
ctx = isl_set_get_ctx(set);
#ifdef HAS_TYPE
if (pw->type != el->type)
isl_die(ctx, isl_error_invalid, "fold types don't match",
goto error);
#endif
el_dim = FN(EL,get_space(el));
isl_assert(ctx, isl_space_is_equal(pw->dim, el_dim), goto error);
isl_assert(ctx, pw->n < pw->size, goto error);
pw->p[pw->n].set = set;
pw->p[pw->n].FIELD = el;
pw->n++;
isl_space_free(el_dim);
return pw;
error:
isl_space_free(el_dim);
FN(PW,free)(pw);
isl_set_free(set);
FN(EL,free)(el);
return NULL;
}
/* Does the space of "set" correspond to that of the domain of "el".
*/
static isl_bool FN(PW,compatible_domain)(__isl_keep EL *el,
__isl_keep isl_set *set)
{
isl_bool ok;
isl_space *el_space, *set_space;
if (!set || !el)
return isl_bool_error;
set_space = isl_set_get_space(set);
el_space = FN(EL,get_space)(el);
ok = isl_space_is_domain_internal(set_space, el_space);
isl_space_free(el_space);
isl_space_free(set_space);
return ok;
}
/* Check that the space of "set" corresponds to that of the domain of "el".
*/
static isl_stat FN(PW,check_compatible_domain)(__isl_keep EL *el,
__isl_keep isl_set *set)
{
isl_bool ok;
ok = FN(PW,compatible_domain)(el, set);
if (ok < 0)
return isl_stat_error;
if (!ok)
isl_die(isl_set_get_ctx(set), isl_error_invalid,
"incompatible spaces", return isl_stat_error);
return isl_stat_ok;
}
#ifdef HAS_TYPE
__isl_give PW *FN(PW,alloc)(enum isl_fold type,
__isl_take isl_set *set, __isl_take EL *el)
#else
__isl_give PW *FN(PW,alloc)(__isl_take isl_set *set, __isl_take EL *el)
#endif
{
PW *pw;
if (FN(PW,check_compatible_domain)(el, set) < 0)
goto error;
#ifdef HAS_TYPE
pw = FN(PW,alloc_size)(FN(EL,get_space)(el), type, 1);
#else
pw = FN(PW,alloc_size)(FN(EL,get_space)(el), 1);
#endif
return FN(PW,add_piece)(pw, set, el);
error:
isl_set_free(set);
FN(EL,free)(el);
return NULL;
}
__isl_give PW *FN(PW,dup)(__isl_keep PW *pw)
{
int i;
PW *dup;
if (!pw)
return NULL;
#ifdef HAS_TYPE
dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, pw->n);
#else
dup = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->n);
#endif
if (!dup)
return NULL;
for (i = 0; i < pw->n; ++i)
dup = FN(PW,add_piece)(dup, isl_set_copy(pw->p[i].set),
FN(EL,copy)(pw->p[i].FIELD));
return dup;
}
__isl_give PW *FN(PW,cow)(__isl_take PW *pw)
{
if (!pw)
return NULL;
if (pw->ref == 1)
return pw;
pw->ref--;
return FN(PW,dup)(pw);
}
__isl_give PW *FN(PW,copy)(__isl_keep PW *pw)
{
if (!pw)
return NULL;
pw->ref++;
return pw;
}
__isl_null PW *FN(PW,free)(__isl_take PW *pw)
{
int i;
if (!pw)
return NULL;
if (--pw->ref > 0)
return NULL;
for (i = 0; i < pw->n; ++i) {
isl_set_free(pw->p[i].set);
FN(EL,free)(pw->p[i].FIELD);
}
isl_space_free(pw->dim);
free(pw);
return NULL;
}
const char *FN(PW,get_dim_name)(__isl_keep PW *pw, enum isl_dim_type type,
unsigned pos)
{
return pw ? isl_space_get_dim_name(pw->dim, type, pos) : NULL;
}
isl_bool FN(PW,has_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
unsigned pos)
{
return pw ? isl_space_has_dim_id(pw->dim, type, pos) : isl_bool_error;
}
__isl_give isl_id *FN(PW,get_dim_id)(__isl_keep PW *pw, enum isl_dim_type type,
unsigned pos)
{
return pw ? isl_space_get_dim_id(pw->dim, type, pos) : NULL;
}
isl_bool FN(PW,has_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
{
return pw ? isl_space_has_tuple_name(pw->dim, type) : isl_bool_error;
}
const char *FN(PW,get_tuple_name)(__isl_keep PW *pw, enum isl_dim_type type)
{
return pw ? isl_space_get_tuple_name(pw->dim, type) : NULL;
}
isl_bool FN(PW,has_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
{
return pw ? isl_space_has_tuple_id(pw->dim, type) : isl_bool_error;
}
__isl_give isl_id *FN(PW,get_tuple_id)(__isl_keep PW *pw, enum isl_dim_type type)
{
return pw ? isl_space_get_tuple_id(pw->dim, type) : NULL;
}
isl_bool FN(PW,IS_ZERO)(__isl_keep PW *pw)
{
if (!pw)
return isl_bool_error;
return pw->n == 0;
}
#ifndef NO_REALIGN
__isl_give PW *FN(PW,realign_domain)(__isl_take PW *pw,
__isl_take isl_reordering *exp)
{
int i;
pw = FN(PW,cow)(pw);
if (!pw || !exp)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_realign(pw->p[i].set,
isl_reordering_copy(exp));
if (!pw->p[i].set)
goto error;
pw->p[i].FIELD = FN(EL,realign_domain)(pw->p[i].FIELD,
isl_reordering_copy(exp));
if (!pw->p[i].FIELD)
goto error;
}
pw = FN(PW,reset_domain_space)(pw, isl_reordering_get_space(exp));
isl_reordering_free(exp);
return pw;
error:
isl_reordering_free(exp);
FN(PW,free)(pw);
return NULL;
}
/* Check that "pw" has only named parameters, reporting an error
* if it does not.
*/
isl_stat FN(PW,check_named_params)(__isl_keep PW *pw)
{
return isl_space_check_named_params(FN(PW,peek_space)(pw));
}
/* Align the parameters of "pw" to those of "model".
*/
__isl_give PW *FN(PW,align_params)(__isl_take PW *pw, __isl_take isl_space *model)
{
isl_ctx *ctx;
isl_bool equal_params;
if (!pw || !model)
goto error;
ctx = isl_space_get_ctx(model);
if (!isl_space_has_named_params(model))
isl_die(ctx, isl_error_invalid,
"model has unnamed parameters", goto error);
if (FN(PW,check_named_params)(pw) < 0)
goto error;
equal_params = isl_space_has_equal_params(pw->dim, model);
if (equal_params < 0)
goto error;
if (!equal_params) {
isl_reordering *exp;
exp = isl_parameter_alignment_reordering(pw->dim, model);
exp = isl_reordering_extend_space(exp,
FN(PW,get_domain_space)(pw));
pw = FN(PW,realign_domain)(pw, exp);
}
isl_space_free(model);
return pw;
error:
isl_space_free(model);
FN(PW,free)(pw);
return NULL;
}
static __isl_give PW *FN(PW,align_params_pw_pw_and)(__isl_take PW *pw1,
__isl_take PW *pw2,
__isl_give PW *(*fn)(__isl_take PW *pw1, __isl_take PW *pw2))
{
isl_bool equal_params;
if (!pw1 || !pw2)
goto error;
equal_params = isl_space_has_equal_params(pw1->dim, pw2->dim);
if (equal_params < 0)
goto error;
if (equal_params)
return fn(pw1, pw2);
if (FN(PW,check_named_params)(pw1) < 0 ||
FN(PW,check_named_params)(pw2) < 0)
goto error;
pw1 = FN(PW,align_params)(pw1, FN(PW,get_space)(pw2));
pw2 = FN(PW,align_params)(pw2, FN(PW,get_space)(pw1));
return fn(pw1, pw2);
error:
FN(PW,free)(pw1);
FN(PW,free)(pw2);
return NULL;
}
static __isl_give PW *FN(PW,align_params_pw_set_and)(__isl_take PW *pw,
__isl_take isl_set *set,
__isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_set *set))
{
isl_ctx *ctx;
isl_bool aligned;
if (!pw || !set)
goto error;
aligned = isl_set_space_has_equal_params(set, pw->dim);
if (aligned < 0)
goto error;
if (aligned)
return fn(pw, set);
ctx = FN(PW,get_ctx)(pw);
if (FN(PW,check_named_params)(pw) < 0)
goto error;
if (!isl_space_has_named_params(set->dim))
isl_die(ctx, isl_error_invalid,
"unaligned unnamed parameters", goto error);
pw = FN(PW,align_params)(pw, isl_set_get_space(set));
set = isl_set_align_params(set, FN(PW,get_space)(pw));
return fn(pw, set);
error:
FN(PW,free)(pw);
isl_set_free(set);
return NULL;
}
#endif
static __isl_give PW *FN(PW,union_add_aligned)(__isl_take PW *pw1,
__isl_take PW *pw2)
{
int i, j, n;
struct PW *res;
isl_ctx *ctx;
isl_set *set;
if (!pw1 || !pw2)
goto error;
ctx = isl_space_get_ctx(pw1->dim);
#ifdef HAS_TYPE
if (pw1->type != pw2->type)
isl_die(ctx, isl_error_invalid,
"fold types don't match", goto error);
#endif
isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
if (FN(PW,IS_ZERO)(pw1)) {
FN(PW,free)(pw1);
return pw2;
}
if (FN(PW,IS_ZERO)(pw2)) {
FN(PW,free)(pw2);
return pw1;
}
n = (pw1->n + 1) * (pw2->n + 1);
#ifdef HAS_TYPE
res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), pw1->type, n);
#else
res = FN(PW,alloc_size)(isl_space_copy(pw1->dim), n);
#endif
for (i = 0; i < pw1->n; ++i) {
set = isl_set_copy(pw1->p[i].set);
for (j = 0; j < pw2->n; ++j) {
struct isl_set *common;
EL *sum;
common = isl_set_intersect(isl_set_copy(pw1->p[i].set),
isl_set_copy(pw2->p[j].set));
if (isl_set_plain_is_empty(common)) {
isl_set_free(common);
continue;
}
set = isl_set_subtract(set,
isl_set_copy(pw2->p[j].set));
sum = FN(EL,add_on_domain)(common,
FN(EL,copy)(pw1->p[i].FIELD),
FN(EL,copy)(pw2->p[j].FIELD));
res = FN(PW,add_piece)(res, common, sum);
}
res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw1->p[i].FIELD));
}
for (j = 0; j < pw2->n; ++j) {
set = isl_set_copy(pw2->p[j].set);
for (i = 0; i < pw1->n; ++i)
set = isl_set_subtract(set,
isl_set_copy(pw1->p[i].set));
res = FN(PW,add_piece)(res, set, FN(EL,copy)(pw2->p[j].FIELD));
}
FN(PW,free)(pw1);
FN(PW,free)(pw2);
return res;
error:
FN(PW,free)(pw1);
FN(PW,free)(pw2);
return NULL;
}
/* Private version of "union_add". For isl_pw_qpolynomial and
* isl_pw_qpolynomial_fold, we prefer to simply call it "add".
*/
static __isl_give PW *FN(PW,union_add_)(__isl_take PW *pw1, __isl_take PW *pw2)
{
return FN(PW,align_params_pw_pw_and)(pw1, pw2,
&FN(PW,union_add_aligned));
}
/* Make sure "pw" has room for at least "n" more pieces.
*
* If there is only one reference to pw, we extend it in place.
* Otherwise, we create a new PW and copy the pieces.
*/
static __isl_give PW *FN(PW,grow)(__isl_take PW *pw, int n)
{
int i;
isl_ctx *ctx;
PW *res;
if (!pw)
return NULL;
if (pw->n + n <= pw->size)
return pw;
ctx = FN(PW,get_ctx)(pw);
n += pw->n;
if (pw->ref == 1) {
res = isl_realloc(ctx, pw, struct PW,
sizeof(struct PW) + (n - 1) * sizeof(S(PW,piece)));
if (!res)
return FN(PW,free)(pw);
res->size = n;
return res;
}
#ifdef HAS_TYPE
res = FN(PW,alloc_size)(isl_space_copy(pw->dim), pw->type, n);
#else
res = FN(PW,alloc_size)(isl_space_copy(pw->dim), n);
#endif
if (!res)
return FN(PW,free)(pw);
for (i = 0; i < pw->n; ++i)
res = FN(PW,add_piece)(res, isl_set_copy(pw->p[i].set),
FN(EL,copy)(pw->p[i].FIELD));
FN(PW,free)(pw);
return res;
}
static __isl_give PW *FN(PW,add_disjoint_aligned)(__isl_take PW *pw1,
__isl_take PW *pw2)
{
int i;
isl_ctx *ctx;
if (!pw1 || !pw2)
goto error;
if (pw1->size < pw1->n + pw2->n && pw1->n < pw2->n)
return FN(PW,add_disjoint_aligned)(pw2, pw1);
ctx = isl_space_get_ctx(pw1->dim);
#ifdef HAS_TYPE
if (pw1->type != pw2->type)
isl_die(ctx, isl_error_invalid,
"fold types don't match", goto error);
#endif
isl_assert(ctx, isl_space_is_equal(pw1->dim, pw2->dim), goto error);
if (FN(PW,IS_ZERO)(pw1)) {
FN(PW,free)(pw1);
return pw2;
}
if (FN(PW,IS_ZERO)(pw2)) {
FN(PW,free)(pw2);
return pw1;
}
pw1 = FN(PW,grow)(pw1, pw2->n);
if (!pw1)
goto error;
for (i = 0; i < pw2->n; ++i)
pw1 = FN(PW,add_piece)(pw1,
isl_set_copy(pw2->p[i].set),
FN(EL,copy)(pw2->p[i].FIELD));
FN(PW,free)(pw2);
return pw1;
error:
FN(PW,free)(pw1);
FN(PW,free)(pw2);
return NULL;
}
__isl_give PW *FN(PW,add_disjoint)(__isl_take PW *pw1, __isl_take PW *pw2)
{
return FN(PW,align_params_pw_pw_and)(pw1, pw2,
&FN(PW,add_disjoint_aligned));
}
/* This function is currently only used from isl_aff.c
*/
static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
__isl_take PW *pw2, __isl_take isl_space *space,
__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
__attribute__ ((unused));
/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
* The result of "fn" (and therefore also of this function) lives in "space".
*/
static __isl_give PW *FN(PW,on_shared_domain_in)(__isl_take PW *pw1,
__isl_take PW *pw2, __isl_take isl_space *space,
__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
{
int i, j, n;
PW *res = NULL;
if (!pw1 || !pw2)
goto error;
n = pw1->n * pw2->n;
#ifdef HAS_TYPE
res = FN(PW,alloc_size)(isl_space_copy(space), pw1->type, n);
#else
res = FN(PW,alloc_size)(isl_space_copy(space), n);
#endif
for (i = 0; i < pw1->n; ++i) {
for (j = 0; j < pw2->n; ++j) {
isl_set *common;
EL *res_ij;
int empty;
common = isl_set_intersect(
isl_set_copy(pw1->p[i].set),
isl_set_copy(pw2->p[j].set));
empty = isl_set_plain_is_empty(common);
if (empty < 0 || empty) {
isl_set_free(common);
if (empty < 0)
goto error;
continue;
}
res_ij = fn(FN(EL,copy)(pw1->p[i].FIELD),
FN(EL,copy)(pw2->p[j].FIELD));
res_ij = FN(EL,gist)(res_ij, isl_set_copy(common));
res = FN(PW,add_piece)(res, common, res_ij);
}
}
isl_space_free(space);
FN(PW,free)(pw1);
FN(PW,free)(pw2);
return res;
error:
isl_space_free(space);
FN(PW,free)(pw1);
FN(PW,free)(pw2);
FN(PW,free)(res);
return NULL;
}
/* This function is currently only used from isl_aff.c
*/
static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
__isl_take PW *pw2,
__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
__attribute__ ((unused));
/* Apply "fn" to pairs of elements from pw1 and pw2 on shared domains.
* The result of "fn" is assumed to live in the same space as "pw1" and "pw2".
*/
static __isl_give PW *FN(PW,on_shared_domain)(__isl_take PW *pw1,
__isl_take PW *pw2,
__isl_give EL *(*fn)(__isl_take EL *el1, __isl_take EL *el2))
{
isl_space *space;
if (!pw1 || !pw2)
goto error;
space = isl_space_copy(pw1->dim);
return FN(PW,on_shared_domain_in)(pw1, pw2, space, fn);
error:
FN(PW,free)(pw1);
FN(PW,free)(pw2);
return NULL;
}
#ifndef NO_NEG
__isl_give PW *FN(PW,neg)(__isl_take PW *pw)
{
int i;
if (!pw)
return NULL;
if (FN(PW,IS_ZERO)(pw))
return pw;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
for (i = 0; i < pw->n; ++i) {
pw->p[i].FIELD = FN(EL,neg)(pw->p[i].FIELD);
if (!pw->p[i].FIELD)
return FN(PW,free)(pw);
}
return pw;
}
#endif
#ifndef NO_SUB
__isl_give PW *FN(PW,sub)(__isl_take PW *pw1, __isl_take PW *pw2)
{
return FN(PW,add)(pw1, FN(PW,neg)(pw2));
}
#endif
/* Return the parameter domain of "pw".
*/
__isl_give isl_set *FN(PW,params)(__isl_take PW *pw)
{
return isl_set_params(FN(PW,domain)(pw));
}
__isl_give isl_set *FN(PW,domain)(__isl_take PW *pw)
{
int i;
isl_set *dom;
if (!pw)
return NULL;
dom = isl_set_empty(FN(PW,get_domain_space)(pw));
for (i = 0; i < pw->n; ++i)
dom = isl_set_union_disjoint(dom, isl_set_copy(pw->p[i].set));
FN(PW,free)(pw);
return dom;
}
/* Exploit the equalities in the domain of piece "i" of "pw"
* to simplify the associated function.
* If the domain of piece "i" is empty, then remove it entirely,
* replacing it with the final piece.
*/
static int FN(PW,exploit_equalities_and_remove_if_empty)(__isl_keep PW *pw,
int i)
{
isl_basic_set *aff;
int empty = isl_set_plain_is_empty(pw->p[i].set);
if (empty < 0)
return -1;
if (empty) {
isl_set_free(pw->p[i].set);
FN(EL,free)(pw->p[i].FIELD);
if (i != pw->n - 1)
pw->p[i] = pw->p[pw->n - 1];
pw->n--;
return 0;
}
aff = isl_set_affine_hull(isl_set_copy(pw->p[i].set));
pw->p[i].FIELD = FN(EL,substitute_equalities)(pw->p[i].FIELD, aff);
if (!pw->p[i].FIELD)
return -1;
return 0;
}
/* Convert a piecewise expression defined over a parameter domain
* into one that is defined over a zero-dimensional set.
*/
__isl_give PW *FN(PW,from_range)(__isl_take PW *pw)
{
isl_space *space;
if (!pw)
return NULL;
if (!isl_space_is_set(pw->dim))
isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
"not living in a set space", return FN(PW,free)(pw));
space = FN(PW,get_space)(pw);
space = isl_space_from_range(space);
pw = FN(PW,reset_space)(pw, space);
return pw;
}
/* Fix the value of the given parameter or domain dimension of "pw"
* to be equal to "value".
*/
__isl_give PW *FN(PW,fix_si)(__isl_take PW *pw, enum isl_dim_type type,
unsigned pos, int value)
{
int i;
if (!pw)
return NULL;
if (type == isl_dim_out)
isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
"cannot fix output dimension", return FN(PW,free)(pw));
if (pw->n == 0)
return pw;
if (type == isl_dim_in)
type = isl_dim_set;
pw = FN(PW,cow)(pw);
if (!pw)
return FN(PW,free)(pw);
for (i = pw->n - 1; i >= 0; --i) {
pw->p[i].set = isl_set_fix_si(pw->p[i].set, type, pos, value);
if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
return FN(PW,free)(pw);
}
return pw;
}
/* Restrict the domain of "pw" by combining each cell
* with "set" through a call to "fn", where "fn" may be
* isl_set_intersect, isl_set_intersect_params or isl_set_subtract.
*/
static __isl_give PW *FN(PW,restrict_domain_aligned)(__isl_take PW *pw,
__isl_take isl_set *set,
__isl_give isl_set *(*fn)(__isl_take isl_set *set1,
__isl_take isl_set *set2))
{
int i;
if (!pw || !set)
goto error;
if (pw->n == 0) {
isl_set_free(set);
return pw;
}
pw = FN(PW,cow)(pw);
if (!pw)
goto error;
for (i = pw->n - 1; i >= 0; --i) {
pw->p[i].set = fn(pw->p[i].set, isl_set_copy(set));
if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
goto error;
}
isl_set_free(set);
return pw;
error:
isl_set_free(set);
FN(PW,free)(pw);
return NULL;
}
static __isl_give PW *FN(PW,intersect_domain_aligned)(__isl_take PW *pw,
__isl_take isl_set *set)
{
return FN(PW,restrict_domain_aligned)(pw, set, &isl_set_intersect);
}
__isl_give PW *FN(PW,intersect_domain)(__isl_take PW *pw,
__isl_take isl_set *context)
{
return FN(PW,align_params_pw_set_and)(pw, context,
&FN(PW,intersect_domain_aligned));
}
static __isl_give PW *FN(PW,intersect_params_aligned)(__isl_take PW *pw,
__isl_take isl_set *set)
{
return FN(PW,restrict_domain_aligned)(pw, set,
&isl_set_intersect_params);
}
/* Intersect the domain of "pw" with the parameter domain "context".
*/
__isl_give PW *FN(PW,intersect_params)(__isl_take PW *pw,
__isl_take isl_set *context)
{
return FN(PW,align_params_pw_set_and)(pw, context,
&FN(PW,intersect_params_aligned));
}
/* Subtract "domain' from the domain of "pw", assuming their
* parameters have been aligned.
*/
static __isl_give PW *FN(PW,subtract_domain_aligned)(__isl_take PW *pw,
__isl_take isl_set *domain)
{
return FN(PW,restrict_domain_aligned)(pw, domain, &isl_set_subtract);
}
/* Subtract "domain' from the domain of "pw".
*/
__isl_give PW *FN(PW,subtract_domain)(__isl_take PW *pw,
__isl_take isl_set *domain)
{
return FN(PW,align_params_pw_set_and)(pw, domain,
&FN(PW,subtract_domain_aligned));
}
/* Compute the gist of "pw" with respect to the domain constraints
* of "context" for the case where the domain of the last element
* of "pw" is equal to "context".
* Call "fn_el" to compute the gist of this element, replace
* its domain by the universe and drop all other elements
* as their domains are necessarily disjoint from "context".
*/
static __isl_give PW *FN(PW,gist_last)(__isl_take PW *pw,
__isl_take isl_set *context,
__isl_give EL *(*fn_el)(__isl_take EL *el, __isl_take isl_set *set))
{
int i;
isl_space *space;
for (i = 0; i < pw->n - 1; ++i) {
isl_set_free(pw->p[i].set);
FN(EL,free)(pw->p[i].FIELD);
}
pw->p[0].FIELD = pw->p[pw->n - 1].FIELD;
pw->p[0].set = pw->p[pw->n - 1].set;
pw->n = 1;
space = isl_set_get_space(context);
pw->p[0].FIELD = fn_el(pw->p[0].FIELD, context);
context = isl_set_universe(space);
isl_set_free(pw->p[0].set);
pw->p[0].set = context;
if (!pw->p[0].FIELD || !pw->p[0].set)
return FN(PW,free)(pw);
return pw;
}
/* Compute the gist of "pw" with respect to the domain constraints
* of "context". Call "fn_el" to compute the gist of the elements
* and "fn_dom" to compute the gist of the domains.
*
* If the piecewise expression is empty or the context is the universe,
* then nothing can be simplified.
*/
static __isl_give PW *FN(PW,gist_aligned)(__isl_take PW *pw,
__isl_take isl_set *context,
__isl_give EL *(*fn_el)(__isl_take EL *el,
__isl_take isl_set *set),
__isl_give isl_set *(*fn_dom)(__isl_take isl_set *set,
__isl_take isl_basic_set *bset))
{
int i;
int is_universe;
isl_bool aligned;
isl_basic_set *hull = NULL;
if (!pw || !context)
goto error;
if (pw->n == 0) {
isl_set_free(context);
return pw;
}
is_universe = isl_set_plain_is_universe(context);
if (is_universe < 0)
goto error;
if (is_universe) {
isl_set_free(context);
return pw;
}
aligned = isl_set_space_has_equal_params(context, pw->dim);
if (aligned < 0)
goto error;
if (!aligned) {
pw = FN(PW,align_params)(pw, isl_set_get_space(context));
context = isl_set_align_params(context, FN(PW,get_space)(pw));
}
pw = FN(PW,cow)(pw);
if (!pw)
goto error;
if (pw->n == 1) {
int equal;
equal = isl_set_plain_is_equal(pw->p[0].set, context);
if (equal < 0)
goto error;
if (equal)
return FN(PW,gist_last)(pw, context, fn_el);
}
context = isl_set_compute_divs(context);
hull = isl_set_simple_hull(isl_set_copy(context));
for (i = pw->n - 1; i >= 0; --i) {
isl_set *set_i;
int empty;
if (i == pw->n - 1) {
int equal;
equal = isl_set_plain_is_equal(pw->p[i].set, context);
if (equal < 0)
goto error;
if (equal) {
isl_basic_set_free(hull);
return FN(PW,gist_last)(pw, context, fn_el);
}
}
set_i = isl_set_intersect(isl_set_copy(pw->p[i].set),
isl_set_copy(context));
empty = isl_set_plain_is_empty(set_i);
pw->p[i].FIELD = fn_el(pw->p[i].FIELD, set_i);
pw->p[i].set = fn_dom(pw->p[i].set, isl_basic_set_copy(hull));
if (empty < 0 || !pw->p[i].FIELD || !pw->p[i].set)
goto error;
if (empty) {
isl_set_free(pw->p[i].set);
FN(EL,free)(pw->p[i].FIELD);
if (i != pw->n - 1)
pw->p[i] = pw->p[pw->n - 1];
pw->n--;
}
}
isl_basic_set_free(hull);
isl_set_free(context);
return pw;
error:
FN(PW,free)(pw);
isl_basic_set_free(hull);
isl_set_free(context);
return NULL;
}
static __isl_give PW *FN(PW,gist_domain_aligned)(__isl_take PW *pw,
__isl_take isl_set *set)
{
return FN(PW,gist_aligned)(pw, set, &FN(EL,gist),
&isl_set_gist_basic_set);
}
__isl_give PW *FN(PW,gist)(__isl_take PW *pw, __isl_take isl_set *context)
{
return FN(PW,align_params_pw_set_and)(pw, context,
&FN(PW,gist_domain_aligned));
}
static __isl_give PW *FN(PW,gist_params_aligned)(__isl_take PW *pw,
__isl_take isl_set *set)
{
return FN(PW,gist_aligned)(pw, set, &FN(EL,gist_params),
&isl_set_gist_params_basic_set);
}
__isl_give PW *FN(PW,gist_params)(__isl_take PW *pw,
__isl_take isl_set *context)
{
return FN(PW,align_params_pw_set_and)(pw, context,
&FN(PW,gist_params_aligned));
}
/* Return -1 if the piece "p1" should be sorted before "p2"
* and 1 if it should be sorted after "p2".
* Return 0 if they do not need to be sorted in a specific order.
*
* The two pieces are compared on the basis of their function value expressions.
*/
static int FN(PW,sort_field_cmp)(const void *p1, const void *p2, void *arg)
{
struct FN(PW,piece) const *pc1 = p1;
struct FN(PW,piece) const *pc2 = p2;
return FN(EL,plain_cmp)(pc1->FIELD, pc2->FIELD);
}
/* Sort the pieces of "pw" according to their function value
* expressions and then combine pairs of adjacent pieces with
* the same such expression.
*
* The sorting is performed in place because it does not
* change the meaning of "pw", but care needs to be
* taken not to change any possible other copies of "pw"
* in case anything goes wrong.
*/
__isl_give PW *FN(PW,sort)(__isl_take PW *pw)
{
int i, j;
isl_set *set;
if (!pw)
return NULL;
if (pw->n <= 1)
return pw;
if (isl_sort(pw->p, pw->n, sizeof(pw->p[0]),
&FN(PW,sort_field_cmp), NULL) < 0)
return FN(PW,free)(pw);
for (i = pw->n - 1; i >= 1; --i) {
if (!FN(EL,plain_is_equal)(pw->p[i - 1].FIELD, pw->p[i].FIELD))
continue;
set = isl_set_union(isl_set_copy(pw->p[i - 1].set),
isl_set_copy(pw->p[i].set));
if (!set)
return FN(PW,free)(pw);
isl_set_free(pw->p[i].set);
FN(EL,free)(pw->p[i].FIELD);
isl_set_free(pw->p[i - 1].set);
pw->p[i - 1].set = set;
for (j = i + 1; j < pw->n; ++j)
pw->p[j - 1] = pw->p[j];
pw->n--;
}
return pw;
}
/* Coalesce the domains of "pw".
*
* Prior to the actual coalescing, first sort the pieces such that
* pieces with the same function value expression are combined
* into a single piece, the combined domain of which can then
* be coalesced.
*/
__isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
{
int i;
pw = FN(PW,sort)(pw);
if (!pw)
return NULL;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_coalesce(pw->p[i].set);
if (!pw->p[i].set)
goto error;
}
return pw;
error:
FN(PW,free)(pw);
return NULL;
}
isl_ctx *FN(PW,get_ctx)(__isl_keep PW *pw)
{
return pw ? isl_space_get_ctx(pw->dim) : NULL;
}
isl_bool FN(PW,involves_dims)(__isl_keep PW *pw, enum isl_dim_type type,
unsigned first, unsigned n)
{
int i;
enum isl_dim_type set_type;
if (!pw)
return isl_bool_error;
if (pw->n == 0 || n == 0)
return isl_bool_false;
set_type = type == isl_dim_in ? isl_dim_set : type;
for (i = 0; i < pw->n; ++i) {
isl_bool involves = FN(EL,involves_dims)(pw->p[i].FIELD,
type, first, n);
if (involves < 0 || involves)
return involves;
involves = isl_set_involves_dims(pw->p[i].set,
set_type, first, n);
if (involves < 0 || involves)
return involves;
}
return isl_bool_false;
}
__isl_give PW *FN(PW,set_dim_name)(__isl_take PW *pw,
enum isl_dim_type type, unsigned pos, const char *s)
{
int i;
enum isl_dim_type set_type;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
set_type = type == isl_dim_in ? isl_dim_set : type;
pw->dim = isl_space_set_dim_name(pw->dim, type, pos, s);
if (!pw->dim)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_set_dim_name(pw->p[i].set,
set_type, pos, s);
if (!pw->p[i].set)
goto error;
pw->p[i].FIELD = FN(EL,set_dim_name)(pw->p[i].FIELD, type, pos, s);
if (!pw->p[i].FIELD)
goto error;
}
return pw;
error:
FN(PW,free)(pw);
return NULL;
}
__isl_give PW *FN(PW,drop_dims)(__isl_take PW *pw,
enum isl_dim_type type, unsigned first, unsigned n)
{
int i;
enum isl_dim_type set_type;
if (!pw)
return NULL;
if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
return pw;
set_type = type == isl_dim_in ? isl_dim_set : type;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
if (!pw->dim)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
if (!pw->p[i].FIELD)
goto error;
if (type == isl_dim_out)
continue;
pw->p[i].set = isl_set_drop(pw->p[i].set, set_type, first, n);
if (!pw->p[i].set)
goto error;
}
return pw;
error:
FN(PW,free)(pw);
return NULL;
}
/* This function is very similar to drop_dims.
* The only difference is that the cells may still involve
* the specified dimensions. They are removed using
* isl_set_project_out instead of isl_set_drop.
*/
__isl_give PW *FN(PW,project_out)(__isl_take PW *pw,
enum isl_dim_type type, unsigned first, unsigned n)
{
int i;
enum isl_dim_type set_type;
if (!pw)
return NULL;
if (n == 0 && !isl_space_get_tuple_name(pw->dim, type))
return pw;
set_type = type == isl_dim_in ? isl_dim_set : type;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
pw->dim = isl_space_drop_dims(pw->dim, type, first, n);
if (!pw->dim)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_project_out(pw->p[i].set,
set_type, first, n);
if (!pw->p[i].set)
goto error;
pw->p[i].FIELD = FN(EL,drop_dims)(pw->p[i].FIELD, type, first, n);
if (!pw->p[i].FIELD)
goto error;
}
return pw;
error:
FN(PW,free)(pw);
return NULL;
}
/* Project the domain of pw onto its parameter space.
*/
__isl_give PW *FN(PW,project_domain_on_params)(__isl_take PW *pw)
{
isl_space *space;
unsigned n;
n = FN(PW,dim)(pw, isl_dim_in);
pw = FN(PW,project_out)(pw, isl_dim_in, 0, n);
space = FN(PW,get_domain_space)(pw);
space = isl_space_params(space);
pw = FN(PW,reset_domain_space)(pw, space);
return pw;
}
/* Drop all parameters not referenced by "pw".
*/
__isl_give PW *FN(PW,drop_unused_params)(__isl_take PW *pw)
{
int i;
if (FN(PW,check_named_params)(pw) < 0)
return FN(PW,free)(pw);
for (i = FN(PW,dim)(pw, isl_dim_param) - 1; i >= 0; i--) {
isl_bool involves;
involves = FN(PW,involves_dims)(pw, isl_dim_param, i, 1);
if (involves < 0)
return FN(PW,free)(pw);
if (!involves)
pw = FN(PW,drop_dims)(pw, isl_dim_param, i, 1);
}
return pw;
}
#ifndef NO_INSERT_DIMS
__isl_give PW *FN(PW,insert_dims)(__isl_take PW *pw, enum isl_dim_type type,
unsigned first, unsigned n)
{
int i;
enum isl_dim_type set_type;
if (!pw)
return NULL;
if (n == 0 && !isl_space_is_named_or_nested(pw->dim, type))
return pw;
set_type = type == isl_dim_in ? isl_dim_set : type;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
pw->dim = isl_space_insert_dims(pw->dim, type, first, n);
if (!pw->dim)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_insert_dims(pw->p[i].set,
set_type, first, n);
if (!pw->p[i].set)
goto error;
pw->p[i].FIELD = FN(EL,insert_dims)(pw->p[i].FIELD,
type, first, n);
if (!pw->p[i].FIELD)
goto error;
}
return pw;
error:
FN(PW,free)(pw);
return NULL;
}
#endif
__isl_give PW *FN(PW,fix_dim)(__isl_take PW *pw,
enum isl_dim_type type, unsigned pos, isl_int v)
{
int i;
if (!pw)
return NULL;
if (type == isl_dim_in)
type = isl_dim_set;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_fix(pw->p[i].set, type, pos, v);
if (FN(PW,exploit_equalities_and_remove_if_empty)(pw, i) < 0)
return FN(PW,free)(pw);
}
return pw;
}
/* Fix the value of the variable at position "pos" of type "type" of "pw"
* to be equal to "v".
*/
__isl_give PW *FN(PW,fix_val)(__isl_take PW *pw,
enum isl_dim_type type, unsigned pos, __isl_take isl_val *v)
{
if (!v)
return FN(PW,free)(pw);
if (!isl_val_is_int(v))
isl_die(FN(PW,get_ctx)(pw), isl_error_invalid,
"expecting integer value", goto error);
pw = FN(PW,fix_dim)(pw, type, pos, v->n);
isl_val_free(v);
return pw;
error:
isl_val_free(v);
return FN(PW,free)(pw);
}
unsigned FN(PW,dim)(__isl_keep PW *pw, enum isl_dim_type type)
{
return pw ? isl_space_dim(pw->dim, type) : 0;
}
__isl_give PW *FN(PW,split_dims)(__isl_take PW *pw,
enum isl_dim_type type, unsigned first, unsigned n)
{
int i;
if (!pw)
return NULL;
if (n == 0)
return pw;
if (type == isl_dim_in)
type = isl_dim_set;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
if (!pw->dim)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_split_dims(pw->p[i].set, type, first, n);
if (!pw->p[i].set)
goto error;
}
return pw;
error:
FN(PW,free)(pw);
return NULL;
}
#ifndef NO_OPT
/* Compute the maximal value attained by the piecewise quasipolynomial
* on its domain or zero if the domain is empty.
* In the worst case, the domain is scanned completely,
* so the domain is assumed to be bounded.
*/
__isl_give isl_val *FN(PW,opt)(__isl_take PW *pw, int max)
{
int i;
isl_val *opt;
if (!pw)
return NULL;
if (pw->n == 0) {
opt = isl_val_zero(FN(PW,get_ctx)(pw));
FN(PW,free)(pw);
return opt;
}
opt = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[0].FIELD),
isl_set_copy(pw->p[0].set), max);
for (i = 1; i < pw->n; ++i) {
isl_val *opt_i;
opt_i = FN(EL,opt_on_domain)(FN(EL,copy)(pw->p[i].FIELD),
isl_set_copy(pw->p[i].set), max);
if (max)
opt = isl_val_max(opt, opt_i);
else
opt = isl_val_min(opt, opt_i);
}
FN(PW,free)(pw);
return opt;
}
__isl_give isl_val *FN(PW,max)(__isl_take PW *pw)
{
return FN(PW,opt)(pw, 1);
}
__isl_give isl_val *FN(PW,min)(__isl_take PW *pw)
{
return FN(PW,opt)(pw, 0);
}
#endif
/* Return the space of "pw".
*/
__isl_keep isl_space *FN(PW,peek_space)(__isl_keep PW *pw)
{
return pw ? pw->dim : NULL;
}
__isl_give isl_space *FN(PW,get_space)(__isl_keep PW *pw)
{
return isl_space_copy(FN(PW,peek_space)(pw));
}
__isl_give isl_space *FN(PW,get_domain_space)(__isl_keep PW *pw)
{
return pw ? isl_space_domain(isl_space_copy(pw->dim)) : NULL;
}
/* Return the position of the dimension of the given type and name
* in "pw".
* Return -1 if no such dimension can be found.
*/
int FN(PW,find_dim_by_name)(__isl_keep PW *pw,
enum isl_dim_type type, const char *name)
{
if (!pw)
return -1;
return isl_space_find_dim_by_name(pw->dim, type, name);
}
#ifndef NO_RESET_DIM
/* Reset the space of "pw". Since we don't know if the elements
* represent the spaces themselves or their domains, we pass along
* both when we call their reset_space_and_domain.
*/
static __isl_give PW *FN(PW,reset_space_and_domain)(__isl_take PW *pw,
__isl_take isl_space *space, __isl_take isl_space *domain)
{
int i;
pw = FN(PW,cow)(pw);
if (!pw || !space || !domain)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_reset_space(pw->p[i].set,
isl_space_copy(domain));
if (!pw->p[i].set)
goto error;
pw->p[i].FIELD = FN(EL,reset_space_and_domain)(pw->p[i].FIELD,
isl_space_copy(space), isl_space_copy(domain));
if (!pw->p[i].FIELD)
goto error;
}
isl_space_free(domain);
isl_space_free(pw->dim);
pw->dim = space;
return pw;
error:
isl_space_free(domain);
isl_space_free(space);
FN(PW,free)(pw);
return NULL;
}
__isl_give PW *FN(PW,reset_domain_space)(__isl_take PW *pw,
__isl_take isl_space *domain)
{
isl_space *space;
space = isl_space_extend_domain_with_range(isl_space_copy(domain),
FN(PW,get_space)(pw));
return FN(PW,reset_space_and_domain)(pw, space, domain);
}
__isl_give PW *FN(PW,reset_space)(__isl_take PW *pw, __isl_take isl_space *dim)
{
isl_space *domain;
domain = isl_space_domain(isl_space_copy(dim));
return FN(PW,reset_space_and_domain)(pw, dim, domain);
}
__isl_give PW *FN(PW,set_tuple_id)(__isl_take PW *pw, enum isl_dim_type type,
__isl_take isl_id *id)
{
isl_space *space;
pw = FN(PW,cow)(pw);
if (!pw)
goto error;
space = FN(PW,get_space)(pw);
space = isl_space_set_tuple_id(space, type, id);
return FN(PW,reset_space)(pw, space);
error:
isl_id_free(id);
return FN(PW,free)(pw);
}
/* Drop the id on the specified tuple.
*/
__isl_give PW *FN(PW,reset_tuple_id)(__isl_take PW *pw, enum isl_dim_type type)
{
isl_space *space;
if (!pw)
return NULL;
if (!FN(PW,has_tuple_id)(pw, type))
return pw;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
space = FN(PW,get_space)(pw);
space = isl_space_reset_tuple_id(space, type);
return FN(PW,reset_space)(pw, space);
}
__isl_give PW *FN(PW,set_dim_id)(__isl_take PW *pw,
enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
{
pw = FN(PW,cow)(pw);
if (!pw)
goto error;
pw->dim = isl_space_set_dim_id(pw->dim, type, pos, id);
return FN(PW,reset_space)(pw, isl_space_copy(pw->dim));
error:
isl_id_free(id);
return FN(PW,free)(pw);
}
#endif
/* Reset the user pointer on all identifiers of parameters and tuples
* of the space of "pw".
*/
__isl_give PW *FN(PW,reset_user)(__isl_take PW *pw)
{
isl_space *space;
space = FN(PW,get_space)(pw);
space = isl_space_reset_user(space);
return FN(PW,reset_space)(pw, space);
}
isl_bool FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2)
{
if (!pw1 || !pw2)
return isl_bool_error;
return isl_space_is_equal(pw1->dim, pw2->dim);
}
#ifndef NO_MORPH
__isl_give PW *FN(PW,morph_domain)(__isl_take PW *pw,
__isl_take isl_morph *morph)
{
int i;
isl_ctx *ctx;
if (!pw || !morph)
goto error;
ctx = isl_space_get_ctx(pw->dim);
isl_assert(ctx, isl_space_is_domain_internal(morph->dom->dim, pw->dim),
goto error);
pw = FN(PW,cow)(pw);
if (!pw)
goto error;
pw->dim = isl_space_extend_domain_with_range(
isl_space_copy(morph->ran->dim), pw->dim);
if (!pw->dim)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_morph_set(isl_morph_copy(morph), pw->p[i].set);
if (!pw->p[i].set)
goto error;
pw->p[i].FIELD = FN(EL,morph_domain)(pw->p[i].FIELD,
isl_morph_copy(morph));
if (!pw->p[i].FIELD)
goto error;
}
isl_morph_free(morph);
return pw;
error:
FN(PW,free)(pw);
isl_morph_free(morph);
return NULL;
}
#endif
int FN(PW,n_piece)(__isl_keep PW *pw)
{
return pw ? pw->n : 0;
}
isl_stat FN(PW,foreach_piece)(__isl_keep PW *pw,
isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el, void *user),
void *user)
{
int i;
if (!pw)
return isl_stat_error;
for (i = 0; i < pw->n; ++i)
if (fn(isl_set_copy(pw->p[i].set),
FN(EL,copy)(pw->p[i].FIELD), user) < 0)
return isl_stat_error;
return isl_stat_ok;
}
#ifndef NO_LIFT
static isl_bool any_divs(__isl_keep isl_set *set)
{
int i;
if (!set)
return isl_bool_error;
for (i = 0; i < set->n; ++i)
if (set->p[i]->n_div > 0)
return isl_bool_true;
return isl_bool_false;
}
static isl_stat foreach_lifted_subset(__isl_take isl_set *set,
__isl_take EL *el,
isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
void *user), void *user)
{
int i;
if (!set || !el)
goto error;
for (i = 0; i < set->n; ++i) {
isl_set *lift;
EL *copy;
lift = isl_set_from_basic_set(isl_basic_set_copy(set->p[i]));
lift = isl_set_lift(lift);
copy = FN(EL,copy)(el);
copy = FN(EL,lift)(copy, isl_set_get_space(lift));
if (fn(lift, copy, user) < 0)
goto error;
}
isl_set_free(set);
FN(EL,free)(el);
return isl_stat_ok;
error:
isl_set_free(set);
FN(EL,free)(el);
return isl_stat_error;
}
isl_stat FN(PW,foreach_lifted_piece)(__isl_keep PW *pw,
isl_stat (*fn)(__isl_take isl_set *set, __isl_take EL *el,
void *user), void *user)
{
int i;
if (!pw)
return isl_stat_error;
for (i = 0; i < pw->n; ++i) {
isl_bool any;
isl_set *set;
EL *el;
any = any_divs(pw->p[i].set);
if (any < 0)
return isl_stat_error;
set = isl_set_copy(pw->p[i].set);
el = FN(EL,copy)(pw->p[i].FIELD);
if (!any) {
if (fn(set, el, user) < 0)
return isl_stat_error;
continue;
}
if (foreach_lifted_subset(set, el, fn, user) < 0)
return isl_stat_error;
}
return isl_stat_ok;
}
#endif
#ifndef NO_MOVE_DIMS
__isl_give PW *FN(PW,move_dims)(__isl_take PW *pw,
enum isl_dim_type dst_type, unsigned dst_pos,
enum isl_dim_type src_type, unsigned src_pos, unsigned n)
{
int i;
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
pw->dim = isl_space_move_dims(pw->dim, dst_type, dst_pos, src_type, src_pos, n);
if (!pw->dim)
goto error;
for (i = 0; i < pw->n; ++i) {
pw->p[i].FIELD = FN(EL,move_dims)(pw->p[i].FIELD,
dst_type, dst_pos, src_type, src_pos, n);
if (!pw->p[i].FIELD)
goto error;
}
if (dst_type == isl_dim_in)
dst_type = isl_dim_set;
if (src_type == isl_dim_in)
src_type = isl_dim_set;
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_move_dims(pw->p[i].set,
dst_type, dst_pos,
src_type, src_pos, n);
if (!pw->p[i].set)
goto error;
}
return pw;
error:
FN(PW,free)(pw);
return NULL;
}
#endif
__isl_give PW *FN(PW,mul_isl_int)(__isl_take PW *pw, isl_int v)
{
int i;
if (isl_int_is_one(v))
return pw;
if (pw && DEFAULT_IS_ZERO && isl_int_is_zero(v)) {
PW *zero;
isl_space *dim = FN(PW,get_space)(pw);
#ifdef HAS_TYPE
zero = FN(PW,ZERO)(dim, pw->type);
#else
zero = FN(PW,ZERO)(dim);
#endif
FN(PW,free)(pw);
return zero;
}
pw = FN(PW,cow)(pw);
if (!pw)
return NULL;
if (pw->n == 0)
return pw;
#ifdef HAS_TYPE
if (isl_int_is_neg(v))
pw->type = isl_fold_type_negate(pw->type);
#endif
for (i = 0; i < pw->n; ++i) {
pw->p[i].FIELD = FN(EL,scale)(pw->p[i].FIELD, v);
if (!pw->p[i].FIELD)
goto error;
}
return pw;
error:
FN(PW,free)(pw);
return NULL;
}
/* Multiply the pieces of "pw" by "v" and return the result.
*/
__isl_give PW *FN(PW,scale_val)(__isl_take PW *pw, __isl_take isl_val *v)
{
int i;
if (!pw || !v)
goto error;
if (isl_val_is_one(v)) {
isl_val_free(v);
return pw;
}
if (pw && DEFAULT_IS_ZERO && isl_val_is_zero(v)) {
PW *zero;
isl_space *space = FN(PW,get_space)(pw);
#ifdef HAS_TYPE
zero = FN(PW,ZERO)(space, pw->type);
#else
zero = FN(PW,ZERO)(space);
#endif
FN(PW,free)(pw);
isl_val_free(v);
return zero;
}
if (pw->n == 0) {
isl_val_free(v);
return pw;
}
pw = FN(PW,cow)(pw);
if (!pw)
goto error;
#ifdef HAS_TYPE
if (isl_val_is_neg(v))
pw->type = isl_fold_type_negate(pw->type);
#endif
for (i = 0; i < pw->n; ++i) {
pw->p[i].FIELD = FN(EL,scale_val)(pw->p[i].FIELD,
isl_val_copy(v));
if (!pw->p[i].FIELD)
goto error;
}
isl_val_free(v);
return pw;
error:
isl_val_free(v);
FN(PW,free)(pw);
return NULL;
}
/* Divide the pieces of "pw" by "v" and return the result.
*/
__isl_give PW *FN(PW,scale_down_val)(__isl_take PW *pw, __isl_take isl_val *v)
{
int i;
if (!pw || !v)
goto error;
if (isl_val_is_one(v)) {
isl_val_free(v);
return pw;
}
if (!isl_val_is_rat(v))
isl_die(isl_val_get_ctx(v), isl_error_invalid,
"expecting rational factor", goto error);
if (isl_val_is_zero(v))
isl_die(isl_val_get_ctx(v), isl_error_invalid,
"cannot scale down by zero", goto error);
if (pw->n == 0) {
isl_val_free(v);
return pw;
}
pw = FN(PW,cow)(pw);
if (!pw)
goto error;
#ifdef HAS_TYPE
if (isl_val_is_neg(v))
pw->type = isl_fold_type_negate(pw->type);
#endif
for (i = 0; i < pw->n; ++i) {
pw->p[i].FIELD = FN(EL,scale_down_val)(pw->p[i].FIELD,
isl_val_copy(v));
if (!pw->p[i].FIELD)
goto error;
}
isl_val_free(v);
return pw;
error:
isl_val_free(v);
FN(PW,free)(pw);
return NULL;
}
__isl_give PW *FN(PW,scale)(__isl_take PW *pw, isl_int v)
{
return FN(PW,mul_isl_int)(pw, v);
}
/* Apply some normalization to "pw".
* In particular, sort the pieces according to their function value
* expressions, combining pairs of adjacent pieces with
* the same such expression, and then normalize the domains of the pieces.
*
* We normalize in place, but if anything goes wrong we need
* to return NULL, so we need to make sure we don't change the
* meaning of any possible other copies of "pw".
*/
__isl_give PW *FN(PW,normalize)(__isl_take PW *pw)
{
int i;
isl_set *set;
pw = FN(PW,sort)(pw);
if (!pw)
return NULL;
for (i = 0; i < pw->n; ++i) {
set = isl_set_normalize(isl_set_copy(pw->p[i].set));
if (!set)
return FN(PW,free)(pw);
isl_set_free(pw->p[i].set);
pw->p[i].set = set;
}
return pw;
}
/* Is pw1 obviously equal to pw2?
* That is, do they have obviously identical cells and obviously identical
* elements on each cell?
*
* If "pw1" or "pw2" contain any NaNs, then they are considered
* not to be the same. A NaN is not equal to anything, not even
* to another NaN.
*/
isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
{
int i;
isl_bool equal, has_nan;
if (!pw1 || !pw2)
return isl_bool_error;
has_nan = FN(PW,involves_nan)(pw1);
if (has_nan >= 0 && !has_nan)
has_nan = FN(PW,involves_nan)(pw2);
if (has_nan < 0 || has_nan)
return isl_bool_not(has_nan);
if (pw1 == pw2)
return isl_bool_true;
if (!isl_space_is_equal(pw1->dim, pw2->dim))
return isl_bool_false;
pw1 = FN(PW,copy)(pw1);
pw2 = FN(PW,copy)(pw2);
pw1 = FN(PW,normalize)(pw1);
pw2 = FN(PW,normalize)(pw2);
if (!pw1 || !pw2)
goto error;
equal = pw1->n == pw2->n;
for (i = 0; equal && i < pw1->n; ++i) {
equal = isl_set_plain_is_equal(pw1->p[i].set, pw2->p[i].set);
if (equal < 0)
goto error;
if (!equal)
break;
equal = FN(EL,plain_is_equal)(pw1->p[i].FIELD, pw2->p[i].FIELD);
if (equal < 0)
goto error;
}
FN(PW,free)(pw1);
FN(PW,free)(pw2);
return equal;
error:
FN(PW,free)(pw1);
FN(PW,free)(pw2);
return isl_bool_error;
}
/* Does "pw" involve any NaNs?
*/
isl_bool FN(PW,involves_nan)(__isl_keep PW *pw)
{
int i;
if (!pw)
return isl_bool_error;
if (pw->n == 0)
return isl_bool_false;
for (i = 0; i < pw->n; ++i) {
isl_bool has_nan = FN(EL,involves_nan)(pw->p[i].FIELD);
if (has_nan < 0 || has_nan)
return has_nan;
}
return isl_bool_false;
}
#ifndef NO_PULLBACK
static __isl_give PW *FN(PW,align_params_pw_multi_aff_and)(__isl_take PW *pw,
__isl_take isl_multi_aff *ma,
__isl_give PW *(*fn)(__isl_take PW *pw, __isl_take isl_multi_aff *ma))
{
isl_ctx *ctx;
isl_bool equal_params;
isl_space *ma_space;
ma_space = isl_multi_aff_get_space(ma);
if (!pw || !ma || !ma_space)
goto error;
equal_params = isl_space_has_equal_params(pw->dim, ma_space);
if (equal_params < 0)
goto error;
if (equal_params) {
isl_space_free(ma_space);
return fn(pw, ma);
}
ctx = FN(PW,get_ctx)(pw);
if (FN(PW,check_named_params)(pw) < 0)
goto error;
if (!isl_space_has_named_params(ma_space))
isl_die(ctx, isl_error_invalid,
"unaligned unnamed parameters", goto error);
pw = FN(PW,align_params)(pw, ma_space);
ma = isl_multi_aff_align_params(ma, FN(PW,get_space)(pw));
return fn(pw, ma);
error:
isl_space_free(ma_space);
FN(PW,free)(pw);
isl_multi_aff_free(ma);
return NULL;
}
static __isl_give PW *FN(PW,align_params_pw_pw_multi_aff_and)(__isl_take PW *pw,
__isl_take isl_pw_multi_aff *pma,
__isl_give PW *(*fn)(__isl_take PW *pw,
__isl_take isl_pw_multi_aff *ma))
{
isl_bool equal_params;
isl_space *pma_space;
pma_space = isl_pw_multi_aff_get_space(pma);
if (!pw || !pma || !pma_space)
goto error;
equal_params = isl_space_has_equal_params(pw->dim, pma_space);
if (equal_params < 0)
goto error;
if (equal_params) {
isl_space_free(pma_space);
return fn(pw, pma);
}
if (FN(PW,check_named_params)(pw) < 0 ||
isl_pw_multi_aff_check_named_params(pma) < 0)
goto error;
pw = FN(PW,align_params)(pw, pma_space);
pma = isl_pw_multi_aff_align_params(pma, FN(PW,get_space)(pw));
return fn(pw, pma);
error:
isl_space_free(pma_space);
FN(PW,free)(pw);
isl_pw_multi_aff_free(pma);
return NULL;
}
/* Compute the pullback of "pw" by the function represented by "ma".
* In other words, plug in "ma" in "pw".
*/
static __isl_give PW *FN(PW,pullback_multi_aff_aligned)(__isl_take PW *pw,
__isl_take isl_multi_aff *ma)
{
int i;
isl_space *space = NULL;
ma = isl_multi_aff_align_divs(ma);
pw = FN(PW,cow)(pw);
if (!pw || !ma)
goto error;
space = isl_space_join(isl_multi_aff_get_space(ma),
FN(PW,get_space)(pw));
for (i = 0; i < pw->n; ++i) {
pw->p[i].set = isl_set_preimage_multi_aff(pw->p[i].set,
isl_multi_aff_copy(ma));
if (!pw->p[i].set)
goto error;
pw->p[i].FIELD = FN(EL,pullback_multi_aff)(pw->p[i].FIELD,
isl_multi_aff_copy(ma));
if (!pw->p[i].FIELD)
goto error;
}
pw = FN(PW,reset_space)(pw, space);
isl_multi_aff_free(ma);
return pw;
error:
isl_space_free(space);
isl_multi_aff_free(ma);
FN(PW,free)(pw);
return NULL;
}
__isl_give PW *FN(PW,pullback_multi_aff)(__isl_take PW *pw,
__isl_take isl_multi_aff *ma)
{
return FN(PW,align_params_pw_multi_aff_and)(pw, ma,
&FN(PW,pullback_multi_aff_aligned));
}
/* Compute the pullback of "pw" by the function represented by "pma".
* In other words, plug in "pma" in "pw".
*/
static __isl_give PW *FN(PW,pullback_pw_multi_aff_aligned)(__isl_take PW *pw,
__isl_take isl_pw_multi_aff *pma)
{
int i;
PW *res;
if (!pma)
goto error;
if (pma->n == 0) {
isl_space *space;
space = isl_space_join(isl_pw_multi_aff_get_space(pma),
FN(PW,get_space)(pw));
isl_pw_multi_aff_free(pma);
res = FN(PW,empty)(space);
FN(PW,free)(pw);
return res;
}
res = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
isl_multi_aff_copy(pma->p[0].maff));
res = FN(PW,intersect_domain)(res, isl_set_copy(pma->p[0].set));
for (i = 1; i < pma->n; ++i) {
PW *res_i;
res_i = FN(PW,pullback_multi_aff)(FN(PW,copy)(pw),
isl_multi_aff_copy(pma->p[i].maff));
res_i = FN(PW,intersect_domain)(res_i,
isl_set_copy(pma->p[i].set));
res = FN(PW,add_disjoint)(res, res_i);
}
isl_pw_multi_aff_free(pma);
FN(PW,free)(pw);
return res;
error:
isl_pw_multi_aff_free(pma);
FN(PW,free)(pw);
return NULL;
}
__isl_give PW *FN(PW,pullback_pw_multi_aff)(__isl_take PW *pw,
__isl_take isl_pw_multi_aff *pma)
{
return FN(PW,align_params_pw_pw_multi_aff_and)(pw, pma,
&FN(PW,pullback_pw_multi_aff_aligned));
}
#endif