summaryrefslogtreecommitdiff
path: root/polly/lib/External/isl/isl_ast_build_expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'polly/lib/External/isl/isl_ast_build_expr.c')
-rw-r--r--polly/lib/External/isl/isl_ast_build_expr.c663
1 files changed, 412 insertions, 251 deletions
diff --git a/polly/lib/External/isl/isl_ast_build_expr.c b/polly/lib/External/isl/isl_ast_build_expr.c
index 3e35416f7255..590fa6f5e5a5 100644
--- a/polly/lib/External/isl/isl_ast_build_expr.c
+++ b/polly/lib/External/isl/isl_ast_build_expr.c
@@ -40,6 +40,8 @@ static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *aff,
/* Internal data structure used inside isl_ast_expr_add_term.
* The domain of "build" is used to simplify the expressions.
* "build" needs to be set by the caller of isl_ast_expr_add_term.
+ * "ls" is the domain local space of the affine expression
+ * of which a term is being added.
* "cst" is the constant term of the expression in which the added term
* appears. It may be modified by isl_ast_expr_add_term.
*
@@ -48,6 +50,7 @@ static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *aff,
*/
struct isl_ast_add_term_data {
isl_ast_build *build;
+ isl_local_space *ls;
isl_val *cst;
isl_val *v;
};
@@ -72,23 +75,23 @@ struct isl_ast_add_term_data {
* Similarly, if floor(cst/v) is zero, then there is no point in
* checking again.
*/
-static int is_non_neg_after_stealing(__isl_keep isl_aff *aff,
+static isl_bool is_non_neg_after_stealing(__isl_keep isl_aff *aff,
__isl_keep isl_val *d, struct isl_ast_add_term_data *data)
{
isl_aff *shifted;
isl_val *shift;
- int is_zero;
- int non_neg;
+ isl_bool is_zero;
+ isl_bool non_neg;
if (isl_val_sgn(data->cst) != isl_val_sgn(data->v))
- return 0;
+ return isl_bool_false;
shift = isl_val_div(isl_val_copy(data->cst), isl_val_copy(data->v));
shift = isl_val_floor(shift);
is_zero = isl_val_is_zero(shift);
if (is_zero < 0 || is_zero) {
isl_val_free(shift);
- return is_zero < 0 ? -1 : 0;
+ return isl_bool_not(is_zero);
}
shift = isl_val_mul(shift, isl_val_copy(d));
shifted = isl_aff_copy(aff);
@@ -99,7 +102,7 @@ static int is_non_neg_after_stealing(__isl_keep isl_aff *aff,
return non_neg;
}
-/* Given the numerator "aff' of the argument of an integer division
+/* Given the numerator "aff" of the argument of an integer division
* with denominator "d", steal part of the constant term of
* the expression in which the integer division appears to make it
* non-negative over data->build->domain.
@@ -115,7 +118,7 @@ static int is_non_neg_after_stealing(__isl_keep isl_aff *aff,
* That is, compute the minimal value "m" of "aff" over
* data->build->domain and take
*
- * s = ceil(m/d)
+ * s = ceil(-m/d)
*
* such that
*
@@ -147,11 +150,26 @@ static __isl_give isl_aff *steal_from_cst(__isl_take isl_aff *aff,
return isl_aff_add_constant_val(aff, shift);
}
-/* Create an isl_ast_expr evaluating the div at position "pos" in "ls".
+/* Construct an expression representing the binary operation "type"
+ * (some division or modulo) applied to the expressions
+ * constructed from "aff" and "v".
+ */
+static __isl_give isl_ast_expr *div_mod(enum isl_ast_expr_op_type type,
+ __isl_take isl_aff *aff, __isl_take isl_val *v,
+ __isl_keep isl_ast_build *build)
+{
+ isl_ast_expr *expr1, *expr2;
+
+ expr1 = isl_ast_expr_from_aff(aff, build);
+ expr2 = isl_ast_expr_from_val(v);
+ return isl_ast_expr_alloc_binary(type, expr1, expr2);
+}
+
+/* Create an isl_ast_expr evaluating the div at position "pos" in data->ls.
* The result is simplified in terms of data->build->domain.
* This function may change (the sign of) data->v.
*
- * "ls" is known to be non-NULL.
+ * data->ls is known to be non-NULL.
*
* Let the div be of the form floor(e/d).
* If the ast_build_prefer_pdiv option is set then we check if "e"
@@ -182,22 +200,21 @@ static __isl_give isl_aff *steal_from_cst(__isl_take isl_aff *aff,
* with s the minimal shift that makes the argument non-negative.
*/
static __isl_give isl_ast_expr *var_div(struct isl_ast_add_term_data *data,
- __isl_keep isl_local_space *ls, int pos)
+ int pos)
{
- isl_ctx *ctx = isl_local_space_get_ctx(ls);
+ isl_ctx *ctx = isl_local_space_get_ctx(data->ls);
isl_aff *aff;
- isl_ast_expr *num, *den;
isl_val *d;
enum isl_ast_expr_op_type type;
- aff = isl_local_space_get_div(ls, pos);
+ aff = isl_local_space_get_div(data->ls, pos);
d = isl_aff_get_denominator_val(aff);
aff = isl_aff_scale_val(aff, isl_val_copy(d));
- den = isl_ast_expr_from_val(isl_val_copy(d));
type = isl_ast_expr_op_fdiv_q;
if (isl_options_get_ast_build_prefer_pdiv(ctx)) {
- int non_neg = isl_ast_build_aff_is_nonneg(data->build, aff);
+ isl_bool non_neg;
+ non_neg = isl_ast_build_aff_is_nonneg(data->build, aff);
if (non_neg >= 0 && !non_neg) {
isl_aff *opp = oppose_div_arg(isl_aff_copy(aff),
isl_val_copy(d));
@@ -220,49 +237,47 @@ static __isl_give isl_ast_expr *var_div(struct isl_ast_add_term_data *data,
type = isl_ast_expr_op_pdiv_q;
}
- isl_val_free(d);
- num = isl_ast_expr_from_aff(aff, data->build);
- return isl_ast_expr_alloc_binary(type, num, den);
+ return div_mod(type, aff, d, data->build);
}
-/* Create an isl_ast_expr evaluating the specified dimension of "ls".
+/* Create an isl_ast_expr evaluating the specified dimension of data->ls.
* The result is simplified in terms of data->build->domain.
* This function may change (the sign of) data->v.
*
* The isl_ast_expr is constructed based on the type of the dimension.
* - divs are constructed by var_div
* - set variables are constructed from the iterator isl_ids in data->build
- * - parameters are constructed from the isl_ids in "ls"
+ * - parameters are constructed from the isl_ids in data->ls
*/
static __isl_give isl_ast_expr *var(struct isl_ast_add_term_data *data,
- __isl_keep isl_local_space *ls, enum isl_dim_type type, int pos)
+ enum isl_dim_type type, int pos)
{
- isl_ctx *ctx = isl_local_space_get_ctx(ls);
+ isl_ctx *ctx = isl_local_space_get_ctx(data->ls);
isl_id *id;
if (type == isl_dim_div)
- return var_div(data, ls, pos);
+ return var_div(data, pos);
if (type == isl_dim_set) {
id = isl_ast_build_get_iterator_id(data->build, pos);
return isl_ast_expr_from_id(id);
}
- if (!isl_local_space_has_dim_id(ls, type, pos))
+ if (!isl_local_space_has_dim_id(data->ls, type, pos))
isl_die(ctx, isl_error_internal, "unnamed dimension",
return NULL);
- id = isl_local_space_get_dim_id(ls, type, pos);
+ id = isl_local_space_get_dim_id(data->ls, type, pos);
return isl_ast_expr_from_id(id);
}
/* Does "expr" represent the zero integer?
*/
-static int ast_expr_is_zero(__isl_keep isl_ast_expr *expr)
+static isl_bool ast_expr_is_zero(__isl_keep isl_ast_expr *expr)
{
if (!expr)
- return -1;
+ return isl_bool_error;
if (expr->type != isl_ast_expr_int)
- return 0;
+ return isl_bool_false;
return isl_val_is_zero(expr->u.v);
}
@@ -343,10 +358,8 @@ static __isl_give isl_ast_expr *isl_ast_expr_mod(__isl_keep isl_val *v,
if (!aff)
return NULL;
- expr = isl_ast_expr_from_aff(isl_aff_copy(aff), build);
-
- c = isl_ast_expr_from_val(isl_val_copy(d));
- expr = isl_ast_expr_alloc_binary(isl_ast_expr_op_pdiv_r, expr, c);
+ expr = div_mod(isl_ast_expr_op_pdiv_r,
+ isl_aff_copy(aff), isl_val_copy(d), build);
if (!isl_val_is_one(v)) {
c = isl_ast_expr_from_val(isl_val_copy(v));
@@ -394,7 +407,7 @@ error:
return NULL;
}
-/* Add an expression for "*v" times the specified dimension of "ls"
+/* Add an expression for "*v" times the specified dimension of data->ls
* to expr.
* If the dimension is an integer division, then this function
* may modify data->cst in order to make the numerator non-negative.
@@ -418,8 +431,7 @@ error:
*
*/
static __isl_give isl_ast_expr *isl_ast_expr_add_term(
- __isl_take isl_ast_expr *expr,
- __isl_keep isl_local_space *ls, enum isl_dim_type type, int pos,
+ __isl_take isl_ast_expr *expr, enum isl_dim_type type, int pos,
__isl_take isl_val *v, struct isl_ast_add_term_data *data)
{
isl_ast_expr *term;
@@ -428,7 +440,7 @@ static __isl_give isl_ast_expr *isl_ast_expr_add_term(
return NULL;
data->v = v;
- term = var(data, ls, type, pos);
+ term = var(data, type, pos);
v = data->v;
if (isl_val_is_neg(v) && !ast_expr_is_zero(expr)) {
@@ -569,7 +581,7 @@ static isl_bool is_even_test(struct isl_extract_mod_data *data,
*
* Also, if "lin - 1" is non-negative, then "lin" is non-negative too.
*/
-static int extract_term_and_mod(struct isl_extract_mod_data *data,
+static isl_stat extract_term_and_mod(struct isl_extract_mod_data *data,
__isl_take isl_aff *term, __isl_take isl_aff *arg)
{
isl_bool even;
@@ -605,9 +617,9 @@ static int extract_term_and_mod(struct isl_extract_mod_data *data,
else
data->add = isl_aff_add(data->add, term);
if (!data->add)
- return -1;
+ return isl_stat_error;
- return 0;
+ return isl_stat_ok;
}
/* Given that data->v * div_i in data->aff is of the form
@@ -628,7 +640,7 @@ static int extract_term_and_mod(struct isl_extract_mod_data *data,
*
* to data->neg or data->pos depending on the sign of -f.
*/
-static int extract_mod(struct isl_extract_mod_data *data)
+static isl_stat extract_mod(struct isl_extract_mod_data *data)
{
return extract_term_and_mod(data, isl_aff_copy(data->div),
isl_aff_copy(data->div));
@@ -652,9 +664,9 @@ static int extract_mod(struct isl_extract_mod_data *data)
*
* This function may modify data->div.
*/
-static int extract_nonneg_mod(struct isl_extract_mod_data *data)
+static isl_stat extract_nonneg_mod(struct isl_extract_mod_data *data)
{
- int mod;
+ isl_bool mod;
mod = isl_ast_build_aff_is_nonneg(data->build, data->div);
if (mod < 0)
@@ -671,10 +683,10 @@ static int extract_nonneg_mod(struct isl_extract_mod_data *data)
return extract_mod(data);
}
- return 0;
+ return isl_stat_ok;
error:
data->aff = isl_aff_free(data->aff);
- return -1;
+ return isl_stat_error;
}
/* Is the affine expression of constraint "c" "simpler" than data->nonneg
@@ -735,19 +747,21 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c,
enum isl_dim_type a_type[2] = { isl_dim_param, isl_dim_in };
int i, t;
isl_size n[2];
- int parallel = 1, opposite = 1;
+ isl_bool parallel = isl_bool_true, opposite = isl_bool_true;
for (t = 0; t < 2; ++t) {
n[t] = isl_constraint_dim(c, c_type[t]);
if (n[t] < 0)
- return isl_stat_error;
+ goto error;
for (i = 0; i < n[t]; ++i) {
- int a, b;
+ isl_bool a, b;
a = isl_constraint_involves_dims(c, c_type[t], i, 1);
b = isl_aff_involves_dims(data->div, a_type[t], i, 1);
+ if (a < 0 || b < 0)
+ goto error;
if (a != b)
- parallel = opposite = 0;
+ parallel = opposite = isl_bool_false;
}
}
@@ -756,7 +770,7 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c,
v = isl_val_abs(isl_constraint_get_constant_val(c));
if (isl_val_cmp_si(v, 1 << 15) > 0)
- parallel = opposite = 0;
+ parallel = opposite = isl_bool_false;
isl_val_free(v);
}
@@ -781,6 +795,8 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c,
}
isl_val_free(v1);
isl_val_free(v2);
+ if (parallel < 0 || opposite < 0)
+ goto error;
}
}
@@ -796,6 +812,9 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c,
return isl_stat_error;
return isl_stat_ok;
+error:
+ isl_constraint_free(c);
+ return isl_stat_error;
}
/* Given that data->v * div_i in data->aff is of the form
@@ -854,7 +873,7 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c,
* multiple of d to make it positive.
*
*
- * Note that the above is a only a very simple heuristic for finding an
+ * Note that the above is only a very simple heuristic for finding an
* appropriate expression. We could try a bit harder by also considering
* sums of constraints that involve disjoint sets of variables or
* we could consider arbitrary linear combinations of constraints,
@@ -877,7 +896,7 @@ static isl_stat check_parallel_or_opposite(__isl_take isl_constraint *c,
* Alternatively, we could first compute the dual of the domain
* and plug in the constraints on the coefficients.
*/
-static int try_extract_mod(struct isl_extract_mod_data *data)
+static isl_stat try_extract_mod(struct isl_extract_mod_data *data)
{
isl_basic_set *hull;
isl_val *v1, *v2;
@@ -937,7 +956,7 @@ static int try_extract_mod(struct isl_extract_mod_data *data)
isl_aff_copy(data->div), data->nonneg);
error:
data->aff = isl_aff_free(data->aff);
- return -1;
+ return isl_stat_error;
}
/* Check if "data->aff" involves any (implicit) modulo computations based
@@ -1051,6 +1070,81 @@ static __isl_give isl_aff *extract_modulos(__isl_take isl_aff *aff,
return data.aff;
}
+/* Call "fn" on every non-zero coefficient of "aff",
+ * passing it in the type of dimension (in terms of the domain),
+ * the position and the value, as long as "fn" returns isl_bool_true.
+ * If "reverse" is set, then the coefficients are considered in reverse order
+ * within each type.
+ */
+static isl_bool every_non_zero_coefficient(__isl_keep isl_aff *aff,
+ int reverse,
+ isl_bool (*fn)(enum isl_dim_type type, int pos, __isl_take isl_val *v,
+ void *user),
+ void *user)
+{
+ int i, j;
+ enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div };
+ enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div };
+ isl_val *v;
+
+ for (i = 0; i < 3; ++i) {
+ isl_size n;
+
+ n = isl_aff_dim(aff, t[i]);
+ if (n < 0)
+ return isl_bool_error;
+ for (j = 0; j < n; ++j) {
+ isl_bool ok;
+ int pos;
+
+ pos = reverse ? n - 1 - j : j;
+ v = isl_aff_get_coefficient_val(aff, t[i], pos);
+ ok = isl_val_is_zero(v);
+ if (ok >= 0 && !ok)
+ ok = fn(l[i], pos, v, user);
+ else
+ isl_val_free(v);
+ if (ok < 0 || !ok)
+ return ok;
+ }
+ }
+
+ return isl_bool_true;
+}
+
+/* Internal data structure for extract_rational.
+ *
+ * "d" is the denominator of the original affine expression.
+ * "ls" is its domain local space.
+ * "rat" collects the rational part.
+ */
+struct isl_ast_extract_rational_data {
+ isl_val *d;
+ isl_local_space *ls;
+
+ isl_aff *rat;
+};
+
+/* Given a non-zero term in an affine expression equal to "v" times
+ * the variable of type "type" at position "pos",
+ * add it to data->rat if "v" is not a multiple of data->d.
+ */
+static isl_bool add_rational(enum isl_dim_type type, int pos,
+ __isl_take isl_val *v, void *user)
+{
+ struct isl_ast_extract_rational_data *data = user;
+ isl_aff *rat;
+
+ if (isl_val_is_divisible_by(v, data->d)) {
+ isl_val_free(v);
+ return isl_bool_true;
+ }
+ rat = isl_aff_var_on_domain(isl_local_space_copy(data->ls), type, pos);
+ rat = isl_aff_scale_val(rat, v);
+ data->rat = isl_aff_add(data->rat, rat);
+ return isl_bool_true;
+}
+
/* Check if aff involves any non-integer coefficients.
* If so, split aff into
*
@@ -1062,80 +1156,95 @@ static __isl_give isl_aff *extract_modulos(__isl_take isl_aff *aff,
static __isl_give isl_aff *extract_rational(__isl_take isl_aff *aff,
__isl_keep isl_ast_expr **expr, __isl_keep isl_ast_build *build)
{
- int i, j;
- isl_size n;
- isl_aff *rat = NULL;
- isl_local_space *ls = NULL;
+ struct isl_ast_extract_rational_data data = { NULL };
isl_ast_expr *rat_expr;
- isl_val *v, *d;
- enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div };
- enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div };
+ isl_val *v;
if (!aff)
return NULL;
- d = isl_aff_get_denominator_val(aff);
- if (!d)
+ data.d = isl_aff_get_denominator_val(aff);
+ if (!data.d)
goto error;
- if (isl_val_is_one(d)) {
- isl_val_free(d);
+ if (isl_val_is_one(data.d)) {
+ isl_val_free(data.d);
return aff;
}
- aff = isl_aff_scale_val(aff, isl_val_copy(d));
+ aff = isl_aff_scale_val(aff, isl_val_copy(data.d));
- ls = isl_aff_get_domain_local_space(aff);
- rat = isl_aff_zero_on_domain(isl_local_space_copy(ls));
+ data.ls = isl_aff_get_domain_local_space(aff);
+ data.rat = isl_aff_zero_on_domain(isl_local_space_copy(data.ls));
- for (i = 0; i < 3; ++i) {
- n = isl_aff_dim(aff, t[i]);
- if (n < 0)
- goto error;
- for (j = 0; j < n; ++j) {
- isl_aff *rat_j;
-
- v = isl_aff_get_coefficient_val(aff, t[i], j);
- if (!v)
- goto error;
- if (isl_val_is_divisible_by(v, d)) {
- isl_val_free(v);
- continue;
- }
- rat_j = isl_aff_var_on_domain(isl_local_space_copy(ls),
- l[i], j);
- rat_j = isl_aff_scale_val(rat_j, v);
- rat = isl_aff_add(rat, rat_j);
- }
- }
+ if (every_non_zero_coefficient(aff, 0, &add_rational, &data) < 0)
+ goto error;
v = isl_aff_get_constant_val(aff);
- if (isl_val_is_divisible_by(v, d)) {
+ if (isl_val_is_divisible_by(v, data.d)) {
isl_val_free(v);
} else {
isl_aff *rat_0;
- rat_0 = isl_aff_val_on_domain(isl_local_space_copy(ls), v);
- rat = isl_aff_add(rat, rat_0);
+ rat_0 = isl_aff_val_on_domain(isl_local_space_copy(data.ls), v);
+ data.rat = isl_aff_add(data.rat, rat_0);
}
- isl_local_space_free(ls);
+ isl_local_space_free(data.ls);
- aff = isl_aff_sub(aff, isl_aff_copy(rat));
- aff = isl_aff_scale_down_val(aff, isl_val_copy(d));
+ aff = isl_aff_sub(aff, isl_aff_copy(data.rat));
+ aff = isl_aff_scale_down_val(aff, isl_val_copy(data.d));
- rat_expr = isl_ast_expr_from_aff(rat, build);
- rat_expr = isl_ast_expr_div(rat_expr, isl_ast_expr_from_val(d));
+ rat_expr = div_mod(isl_ast_expr_op_div, data.rat, data.d, build);
*expr = ast_expr_add(*expr, rat_expr);
return aff;
error:
- isl_aff_free(rat);
- isl_local_space_free(ls);
+ isl_aff_free(data.rat);
+ isl_local_space_free(data.ls);
isl_aff_free(aff);
- isl_val_free(d);
+ isl_val_free(data.d);
return NULL;
}
-/* Construct an isl_ast_expr that evaluates the affine expression "aff",
+/* Internal data structure for isl_ast_expr_from_aff.
+ *
+ * "term" contains the information for adding a term.
+ * "expr" collects the results.
+ */
+struct isl_ast_add_terms_data {
+ struct isl_ast_add_term_data *term;
+ isl_ast_expr *expr;
+};
+
+/* Given a non-zero term in an affine expression equal to "v" times
+ * the variable of type "type" at position "pos",
+ * add the corresponding AST expression to data->expr.
+ */
+static isl_bool add_term(enum isl_dim_type type, int pos,
+ __isl_take isl_val *v, void *user)
+{
+ struct isl_ast_add_terms_data *data = user;
+
+ data->expr =
+ isl_ast_expr_add_term(data->expr, type, pos, v, data->term);
+
+ return isl_bool_true;
+}
+
+/* Add terms to "expr" for each variable in "aff".
+ * The result is simplified in terms of data->build->domain.
+ */
+static __isl_give isl_ast_expr *add_terms(__isl_take isl_ast_expr *expr,
+ __isl_keep isl_aff *aff, struct isl_ast_add_term_data *data)
+{
+ struct isl_ast_add_terms_data terms_data = { data, expr };
+
+ if (every_non_zero_coefficient(aff, 0, &add_term, &terms_data) < 0)
+ return isl_ast_expr_free(terms_data.expr);
+
+ return terms_data.expr;
+}
+
+/* Construct an isl_ast_expr that evaluates the affine expression "aff".
* The result is simplified in terms of build->domain.
*
* We first extract hidden modulo computations from the affine expression
@@ -1146,15 +1255,9 @@ error:
__isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff,
__isl_keep isl_ast_build *build)
{
- int i, j;
- isl_size n;
- isl_val *v;
isl_ctx *ctx = isl_aff_get_ctx(aff);
isl_ast_expr *expr, *expr_neg;
- enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div };
- enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div };
- isl_local_space *ls;
- struct isl_ast_add_term_data data;
+ struct isl_ast_add_term_data term_data;
if (!aff)
return NULL;
@@ -1167,68 +1270,70 @@ __isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff,
aff = extract_modulos(aff, &expr, &expr_neg, build);
expr = ast_expr_sub(expr, expr_neg);
- ls = isl_aff_get_domain_local_space(aff);
+ term_data.build = build;
+ term_data.ls = isl_aff_get_domain_local_space(aff);
+ term_data.cst = isl_aff_get_constant_val(aff);
+ expr = add_terms(expr, aff, &term_data);
- data.build = build;
- data.cst = isl_aff_get_constant_val(aff);
- for (i = 0; i < 3; ++i) {
- n = isl_aff_dim(aff, t[i]);
- if (n < 0)
- expr = isl_ast_expr_free(expr);
- for (j = 0; j < n; ++j) {
- v = isl_aff_get_coefficient_val(aff, t[i], j);
- if (!v)
- expr = isl_ast_expr_free(expr);
- if (isl_val_is_zero(v)) {
- isl_val_free(v);
- continue;
- }
- expr = isl_ast_expr_add_term(expr,
- ls, l[i], j, v, &data);
- }
- }
-
- expr = isl_ast_expr_add_int(expr, data.cst);
+ expr = isl_ast_expr_add_int(expr, term_data.cst);
+ isl_local_space_free(term_data.ls);
- isl_local_space_free(ls);
isl_aff_free(aff);
return expr;
}
-/* Add terms to "expr" for each variable in "aff" with a coefficient
- * with sign equal to "sign".
- * The result is simplified in terms of data->build->domain.
+/* Internal data structure for coefficients_of_sign.
+ *
+ * "sign" is the sign of the coefficients that should be retained.
+ * "aff" is the affine expression of which some coefficients are zeroed out.
*/
-static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr,
- __isl_keep isl_aff *aff, int sign, struct isl_ast_add_term_data *data)
+struct isl_ast_coefficients_of_sign_data {
+ int sign;
+ isl_aff *aff;
+};
+
+/* Clear the specified coefficient of data->aff if the value "v"
+ * does not have the required sign.
+ */
+static isl_bool clear_opposite_sign(enum isl_dim_type type, int pos,
+ __isl_take isl_val *v, void *user)
{
- int i, j;
- isl_val *v;
- enum isl_dim_type t[] = { isl_dim_param, isl_dim_in, isl_dim_div };
- enum isl_dim_type l[] = { isl_dim_param, isl_dim_set, isl_dim_div };
- isl_local_space *ls;
+ struct isl_ast_coefficients_of_sign_data *data = user;
- ls = isl_aff_get_domain_local_space(aff);
+ if (type == isl_dim_set)
+ type = isl_dim_in;
+ if (data->sign * isl_val_sgn(v) < 0)
+ data->aff = isl_aff_set_coefficient_si(data->aff, type, pos, 0);
+ isl_val_free(v);
- for (i = 0; i < 3; ++i) {
- isl_size n = isl_aff_dim(aff, t[i]);
- if (n < 0)
- expr = isl_ast_expr_free(expr);
- for (j = 0; j < n; ++j) {
- v = isl_aff_get_coefficient_val(aff, t[i], j);
- if (sign * isl_val_sgn(v) <= 0) {
- isl_val_free(v);
- continue;
- }
- v = isl_val_abs(v);
- expr = isl_ast_expr_add_term(expr,
- ls, l[i], j, v, data);
- }
- }
+ return isl_bool_true;
+}
- isl_local_space_free(ls);
+/* Extract the coefficients of "aff" (excluding the constant term)
+ * that have the given sign.
+ *
+ * Take a copy of "aff" and clear the coefficients that do not have
+ * the required sign.
+ * Consider the coefficients in reverse order since clearing
+ * the coefficient of an integer division in data.aff
+ * could result in the removal of that integer division from data.aff,
+ * changing the positions of all subsequent integer divisions of data.aff,
+ * while those of "aff" remain the same.
+ */
+static __isl_give isl_aff *coefficients_of_sign(__isl_take isl_aff *aff,
+ int sign)
+{
+ struct isl_ast_coefficients_of_sign_data data;
- return expr;
+ data.sign = sign;
+ data.aff = isl_aff_copy(aff);
+ if (every_non_zero_coefficient(aff, 1, &clear_opposite_sign, &data) < 0)
+ data.aff = isl_aff_free(data.aff);
+ isl_aff_free(aff);
+
+ data.aff = isl_aff_set_constant_si(data.aff, 0);
+
+ return data.aff;
}
/* Should the constant term "v" be considered positive?
@@ -1240,13 +1345,17 @@ static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr,
* This results in slightly shorter expressions and may reduce the risk
* of overflows.
*/
-static int constant_is_considered_positive(__isl_keep isl_val *v,
+static isl_bool constant_is_considered_positive(__isl_keep isl_val *v,
__isl_keep isl_ast_expr *pos, __isl_keep isl_ast_expr *neg)
{
- if (ast_expr_is_zero(pos))
- return 1;
- if (ast_expr_is_zero(neg))
- return 0;
+ isl_bool zero;
+
+ zero = ast_expr_is_zero(pos);
+ if (zero < 0 || zero)
+ return zero;
+ zero = ast_expr_is_zero(neg);
+ if (zero < 0 || zero)
+ return isl_bool_not(zero);
return isl_val_is_pos(v);
}
@@ -1276,11 +1385,11 @@ static int constant_is_considered_positive(__isl_keep isl_val *v,
*
* where e and e' differ by a constant.
*/
-static int is_stride_constraint(__isl_keep isl_aff *aff, int pos)
+static isl_bool is_stride_constraint(__isl_keep isl_aff *aff, int pos)
{
isl_aff *div;
isl_val *c, *d;
- int eq;
+ isl_bool eq;
div = isl_aff_get_div(aff, pos);
c = isl_aff_get_coefficient_val(aff, isl_dim_div, pos);
@@ -1379,28 +1488,44 @@ static __isl_give isl_ast_expr *extract_stride_constraint(
return expr;
}
-/* Construct an isl_ast_expr that evaluates the condition "constraint",
- * The result is simplified in terms of build->domain.
- *
- * We first check if the constraint is an equality of the form
+/* Construct an isl_ast_expr evaluating
*
- * e - d floor(e/d) = 0
- *
- * i.e.,
- *
- * e mod d = 0
+ * "expr_pos" == "expr_neg", if "eq" is set, or
+ * "expr_pos" >= "expr_neg", if "eq" is not set
*
- * If so, we convert it to
- *
- * (isl_ast_expr_op_eq,
- * (isl_ast_expr_op_zdiv_r, expr(e), expr(d)), expr(0))
+ * However, if "expr_pos" is an integer constant (and "expr_neg" is not),
+ * then the two expressions are interchanged. This ensures that,
+ * e.g., "i <= 5" is constructed rather than "5 >= i".
+ */
+static __isl_give isl_ast_expr *construct_constraint_expr(int eq,
+ __isl_take isl_ast_expr *expr_pos, __isl_take isl_ast_expr *expr_neg)
+{
+ isl_ast_expr *expr;
+ enum isl_ast_expr_op_type type;
+ int pos_is_cst, neg_is_cst;
+
+ pos_is_cst = isl_ast_expr_get_type(expr_pos) == isl_ast_expr_int;
+ neg_is_cst = isl_ast_expr_get_type(expr_neg) == isl_ast_expr_int;
+ if (pos_is_cst && !neg_is_cst) {
+ type = eq ? isl_ast_expr_op_eq : isl_ast_expr_op_le;
+ expr = isl_ast_expr_alloc_binary(type, expr_neg, expr_pos);
+ } else {
+ type = eq ? isl_ast_expr_op_eq : isl_ast_expr_op_ge;
+ expr = isl_ast_expr_alloc_binary(type, expr_pos, expr_neg);
+ }
+
+ return expr;
+}
+
+/* Construct an isl_ast_expr that evaluates the condition "aff" == 0
+ * (if "eq" is set) or "aff" >= 0 (otherwise).
+ * The result is simplified in terms of build->domain.
*
- * Otherwise, let the constraint by either "a >= 0" or "a == 0".
- * We first extract hidden modulo computations from "a"
+ * We first extract hidden modulo computations from "aff"
* and then collect all the terms with a positive coefficient in cons_pos
* and the terms with a negative coefficient in cons_neg.
*
- * The result is then of the form
+ * The result is then essentially of the form
*
* (isl_ast_expr_op_ge, expr(pos), expr(-neg)))
*
@@ -1408,48 +1533,20 @@ static __isl_give isl_ast_expr *extract_stride_constraint(
*
* (isl_ast_expr_op_eq, expr(pos), expr(-neg)))
*
- * However, if the first expression is an integer constant (and the second
- * is not), then we swap the two expressions. This ensures that we construct,
- * e.g., "i <= 5" rather than "5 >= i".
- *
- * Furthermore, is there are no terms with positive coefficients (or no terms
+ * However, if there are no terms with positive coefficients (or no terms
* with negative coefficients), then the constant term is added to "pos"
* (or "neg"), ignoring the sign of the constant term.
*/
-static __isl_give isl_ast_expr *isl_ast_expr_from_constraint(
- __isl_take isl_constraint *constraint, __isl_keep isl_ast_build *build)
+static __isl_give isl_ast_expr *isl_ast_expr_from_constraint_no_stride(
+ int eq, __isl_take isl_aff *aff, __isl_keep isl_ast_build *build)
{
- int i;
- isl_size n;
+ isl_bool cst_is_pos;
isl_ctx *ctx;
isl_ast_expr *expr_pos;
isl_ast_expr *expr_neg;
- isl_ast_expr *expr;
- isl_aff *aff;
- int eq;
- enum isl_ast_expr_op_type type;
+ isl_aff *aff_pos, *aff_neg;
struct isl_ast_add_term_data data;
- if (!constraint)
- return NULL;
-
- aff = isl_constraint_get_aff(constraint);
- eq = isl_constraint_is_equality(constraint);
- isl_constraint_free(constraint);
-
- n = isl_aff_dim(aff, isl_dim_div);
- if (n < 0)
- aff = isl_aff_free(aff);
- if (eq && n > 0)
- for (i = 0; i < n; ++i) {
- int is_stride;
- is_stride = is_stride_constraint(aff, i);
- if (is_stride < 0)
- goto error;
- if (is_stride)
- return extract_stride_constraint(aff, i, build);
- }
-
ctx = isl_aff_get_ctx(aff);
expr_pos = isl_ast_expr_alloc_int_si(ctx, 0);
expr_neg = isl_ast_expr_alloc_int_si(ctx, 0);
@@ -1457,30 +1554,79 @@ static __isl_give isl_ast_expr *isl_ast_expr_from_constraint(
aff = extract_modulos(aff, &expr_pos, &expr_neg, build);
data.build = build;
+ data.ls = isl_aff_get_domain_local_space(aff);
data.cst = isl_aff_get_constant_val(aff);
- expr_pos = add_signed_terms(expr_pos, aff, 1, &data);
+
+ aff_pos = coefficients_of_sign(isl_aff_copy(aff), 1);
+ aff_neg = isl_aff_neg(coefficients_of_sign(aff, -1));
+
+ expr_pos = add_terms(expr_pos, aff_pos, &data);
data.cst = isl_val_neg(data.cst);
- expr_neg = add_signed_terms(expr_neg, aff, -1, &data);
+ expr_neg = add_terms(expr_neg, aff_neg, &data);
data.cst = isl_val_neg(data.cst);
+ isl_local_space_free(data.ls);
+
+ cst_is_pos =
+ constant_is_considered_positive(data.cst, expr_pos, expr_neg);
+ if (cst_is_pos < 0)
+ expr_pos = isl_ast_expr_free(expr_pos);
- if (constant_is_considered_positive(data.cst, expr_pos, expr_neg)) {
+ if (cst_is_pos) {
expr_pos = isl_ast_expr_add_int(expr_pos, data.cst);
} else {
data.cst = isl_val_neg(data.cst);
expr_neg = isl_ast_expr_add_int(expr_neg, data.cst);
}
- if (isl_ast_expr_get_type(expr_pos) == isl_ast_expr_int &&
- isl_ast_expr_get_type(expr_neg) != isl_ast_expr_int) {
- type = eq ? isl_ast_expr_op_eq : isl_ast_expr_op_le;
- expr = isl_ast_expr_alloc_binary(type, expr_neg, expr_pos);
- } else {
- type = eq ? isl_ast_expr_op_eq : isl_ast_expr_op_ge;
- expr = isl_ast_expr_alloc_binary(type, expr_pos, expr_neg);
- }
+ isl_aff_free(aff_pos);
+ isl_aff_free(aff_neg);
+ return construct_constraint_expr(eq, expr_pos, expr_neg);
+}
- isl_aff_free(aff);
- return expr;
+/* Construct an isl_ast_expr that evaluates the condition "constraint".
+ * The result is simplified in terms of build->domain.
+ *
+ * We first check if the constraint is an equality of the form
+ *
+ * e - d floor(e/d) = 0
+ *
+ * i.e.,
+ *
+ * e mod d = 0
+ *
+ * If so, we convert it to
+ *
+ * (isl_ast_expr_op_eq,
+ * (isl_ast_expr_op_zdiv_r, expr(e), expr(d)), expr(0))
+ */
+static __isl_give isl_ast_expr *isl_ast_expr_from_constraint(
+ __isl_take isl_constraint *constraint, __isl_keep isl_ast_build *build)
+{
+ int i;
+ isl_size n;
+ isl_aff *aff;
+ isl_bool eq;
+
+ aff = isl_constraint_get_aff(constraint);
+ eq = isl_constraint_is_equality(constraint);
+ isl_constraint_free(constraint);
+ if (eq < 0)
+ goto error;
+
+ n = isl_aff_dim(aff, isl_dim_div);
+ if (n < 0)
+ aff = isl_aff_free(aff);
+ if (eq && n > 0)
+ for (i = 0; i < n; ++i) {
+ isl_bool is_stride;
+ is_stride = is_stride_constraint(aff, i);
+ if (is_stride < 0)
+ goto error;
+ if (is_stride)
+ return extract_stride_constraint(aff, i, build);
+ }
+
+ return isl_ast_expr_from_constraint_no_stride(eq, aff, build);
error:
isl_aff_free(aff);
return NULL;
@@ -1878,17 +2024,13 @@ static __isl_give isl_ast_expr *ast_expr_from_aff_list(
op_type = state == isl_state_min ? isl_ast_expr_op_min
: isl_ast_expr_op_max;
expr = isl_ast_expr_alloc_op(isl_ast_build_get_ctx(build), op_type, n);
- if (!expr)
- goto error;
for (i = 0; i < n; ++i) {
isl_ast_expr *expr_i;
aff = isl_aff_list_get_aff(list, i);
expr_i = isl_ast_expr_from_aff(aff, build);
- if (!expr_i)
- goto error;
- expr->u.op.args[i] = expr_i;
+ expr = isl_ast_expr_op_add_arg(expr, expr_i);
}
isl_aff_list_free(list);
@@ -1899,21 +2041,22 @@ error:
return NULL;
}
-/* Extend the expression in "next" to take into account
+/* Extend the list of expressions in "next" to take into account
* the piece at position "pos" in "data", allowing for a further extension
* for the next piece(s).
- * In particular, "next" is set to a select operation that selects
+ * In particular, "next" is extended with a select operation that selects
* an isl_ast_expr corresponding to data->aff_list on data->set and
* to an expression that will be filled in by later calls.
- * Return a pointer to this location.
+ * Return a pointer to the arguments of this select operation.
* Afterwards, the state of "data" is set to isl_state_none.
*
* The constraints of data->set are added to the generated
* constraints of the build such that they can be exploited to simplify
* the AST expression constructed from data->aff_list.
*/
-static isl_ast_expr **add_intermediate_piece(struct isl_from_pw_aff_data *data,
- int pos, isl_ast_expr **next)
+static isl_ast_expr_list **add_intermediate_piece(
+ struct isl_from_pw_aff_data *data,
+ int pos, isl_ast_expr_list **next)
{
isl_ctx *ctx;
isl_ast_build *build;
@@ -1926,26 +2069,26 @@ static isl_ast_expr **add_intermediate_piece(struct isl_from_pw_aff_data *data,
ternary = isl_ast_expr_alloc_op(ctx, isl_ast_expr_op_select, 3);
gist = isl_set_gist(isl_set_copy(set), isl_set_copy(data->dom));
arg = isl_ast_build_expr_from_set_internal(data->build, gist);
- ternary = isl_ast_expr_set_op_arg(ternary, 0, arg);
+ ternary = isl_ast_expr_op_add_arg(ternary, arg);
build = isl_ast_build_copy(data->build);
build = isl_ast_build_restrict_generated(build, set);
arg = ast_expr_from_aff_list(data->p[pos].aff_list,
data->p[pos].state, build);
data->p[pos].aff_list = NULL;
isl_ast_build_free(build);
- ternary = isl_ast_expr_set_op_arg(ternary, 1, arg);
+ ternary = isl_ast_expr_op_add_arg(ternary, arg);
data->p[pos].state = isl_state_none;
if (!ternary)
return NULL;
- *next = ternary;
- return &ternary->u.op.args[2];
+ *next = isl_ast_expr_list_add(*next, ternary);
+ return &ternary->u.op.args;
}
-/* Extend the expression in "next" to take into account
+/* Extend the list of expressions in "next" to take into account
* the final piece, located at position "pos" in "data".
- * In particular, "next" is set to evaluate data->aff_list
- * and the domain is ignored.
+ * In particular, "next" is extended with an expression
+ * to evaluate data->aff_list and the domain is ignored.
* Return isl_stat_ok on success and isl_stat_error on failure.
*
* The constraints of data->set are however added to the generated
@@ -1953,9 +2096,10 @@ static isl_ast_expr **add_intermediate_piece(struct isl_from_pw_aff_data *data,
* the AST expression constructed from data->aff_list.
*/
static isl_stat add_last_piece(struct isl_from_pw_aff_data *data,
- int pos, isl_ast_expr **next)
+ int pos, isl_ast_expr_list **next)
{
isl_ast_build *build;
+ isl_ast_expr *last;
if (data->p[pos].state == isl_state_none)
isl_die(isl_ast_build_get_ctx(data->build), isl_error_invalid,
@@ -1964,8 +2108,9 @@ static isl_stat add_last_piece(struct isl_from_pw_aff_data *data,
build = isl_ast_build_copy(data->build);
build = isl_ast_build_restrict_generated(build, data->p[pos].set);
data->p[pos].set = NULL;
- *next = ast_expr_from_aff_list(data->p[pos].aff_list,
+ last = ast_expr_from_aff_list(data->p[pos].aff_list,
data->p[pos].state, build);
+ *next = isl_ast_expr_list_add(*next, last);
data->p[pos].aff_list = NULL;
isl_ast_build_free(build);
data->p[pos].state = isl_state_none;
@@ -2006,17 +2151,25 @@ static int sort_pieces_cmp(const void *p1, const void *p2, void *arg)
*
* Construct intermediate AST expressions for the initial pieces and
* finish off with the final pieces.
+ *
+ * Any piece that is not the very first is added to the list of arguments
+ * of the previously constructed piece.
+ * In order not to have to special case the first piece,
+ * an extra list is created to hold the final result.
*/
static isl_ast_expr *build_pieces(struct isl_from_pw_aff_data *data)
{
int i;
- isl_ast_expr *res = NULL;
- isl_ast_expr **next = &res;
+ isl_ctx *ctx;
+ isl_ast_expr_list *res_list;
+ isl_ast_expr_list **next = &res_list;
+ isl_ast_expr *res;
if (data->p[data->n].state != isl_state_none)
data->n++;
+ ctx = isl_ast_build_get_ctx(data->build);
if (data->n == 0)
- isl_die(isl_ast_build_get_ctx(data->build), isl_error_invalid,
+ isl_die(ctx, isl_error_invalid,
"cannot handle void expression", return NULL);
for (i = 0; i < data->n; ++i) {
@@ -2028,18 +2181,26 @@ static isl_ast_expr *build_pieces(struct isl_from_pw_aff_data *data)
if (isl_sort(data->p, data->n, sizeof(data->p[0]),
&sort_pieces_cmp, NULL) < 0)
- return isl_ast_expr_free(res);
+ return NULL;
+ res_list = isl_ast_expr_list_alloc(ctx, 1);
+ if (!res_list)
+ return NULL;
for (i = 0; i + 1 < data->n; ++i) {
next = add_intermediate_piece(data, i, next);
if (!next)
- return isl_ast_expr_free(res);
+ goto error;
}
if (add_last_piece(data, data->n - 1, next) < 0)
- return isl_ast_expr_free(res);
+ goto error;
+ res = isl_ast_expr_list_get_at(res_list, 0);
+ isl_ast_expr_list_free(res_list);
return res;
+error:
+ isl_ast_expr_list_free(res_list);
+ return NULL;
}
/* Is the domain of the current entry of "data", which is assumed
@@ -2364,14 +2525,14 @@ static __isl_give isl_ast_expr *isl_ast_build_with_arguments(
n = isl_multi_pw_aff_dim(mpa, isl_dim_out);
expr = n >= 0 ? isl_ast_expr_alloc_op(ctx, type, 1 + n) : NULL;
- expr = isl_ast_expr_set_op_arg(expr, 0, arg0);
+ expr = isl_ast_expr_op_add_arg(expr, arg0);
for (i = 0; i < n; ++i) {
isl_pw_aff *pa;
isl_ast_expr *arg;
pa = isl_multi_pw_aff_get_pw_aff(mpa, i);
arg = isl_ast_build_expr_from_pw_aff_internal(build, pa);
- expr = isl_ast_expr_set_op_arg(expr, 1 + i, arg);
+ expr = isl_ast_expr_op_add_arg(expr, arg);
}
isl_multi_pw_aff_free(mpa);