X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=isl_ast_build_expr.c;h=81d8fbfae8f46b045f9f04376b950ad5b234c16d;hb=0be722b9c97458514c57b124fb09a0d3ba9f2ade;hp=51f33cebbf0e6ac80496692a63161556dedb444e;hpb=8d21eadb2ba515d655d5f742fd97383f83e86c00;p=platform%2Fupstream%2Fisl.git diff --git a/isl_ast_build_expr.c b/isl_ast_build_expr.c index 51f33ce..81d8fbf 100644 --- a/isl_ast_build_expr.c +++ b/isl_ast_build_expr.c @@ -12,33 +12,27 @@ #include #include -/* Compute the minimum of the integer affine expression "obj" over the points - * in build->domain and put the result in *opt. - */ -enum isl_lp_result isl_ast_build_min(__isl_keep isl_ast_build *build, - __isl_keep isl_aff *obj, isl_int *opt) -{ - if (!build) - return isl_lp_error; - - return isl_set_min(build->domain, obj, opt); -} - -/* Compute the maximum of the integer affine expression "obj" over the points - * in build->domain and put the result in *opt. +/* Compute the "opposite" of the (numerator of the) argument of a div + * with denonimator "d". + * + * In particular, compute + * + * -aff + (d - 1) */ -enum isl_lp_result isl_ast_build_max(__isl_keep isl_ast_build *build, - __isl_keep isl_aff *obj, isl_int *opt) +static __isl_give isl_aff *oppose_div_arg(__isl_take isl_aff *aff, isl_int d) { - if (!build) - return isl_lp_error; + aff = isl_aff_neg(aff); + aff = isl_aff_add_constant(aff, d); + aff = isl_aff_add_constant_si(aff, -1); - return isl_set_max(build->domain, obj, opt); + return aff; } /* Create an isl_ast_expr evaluating the div at position "pos" in "ls". * The result is simplified in terms of build->domain. * + * "v" points to the coefficient of the div in the expression where it + * appears and may be updated by this function. * "ls" is known to be non-NULL. * * Let the div be of the form floor(e/d). @@ -51,8 +45,16 @@ enum isl_lp_result isl_ast_build_max(__isl_keep isl_ast_build *build, * * (fdiv_q, expr(e), expr(d)) * + * If the ast_build_prefer_pdiv option is set and + * if "e" is not non-negative, then we check if "-e + d - 1" is non-negative. + * If so, we can rewrite + * + * floor(e/d) = -ceil(-e/d) = -floor((-e + d - 1)/d) + * + * and still use pdiv_q. */ -static __isl_give isl_ast_expr *var_div(__isl_keep isl_local_space *ls, +static __isl_give isl_ast_expr *var_div(isl_int *v, + __isl_keep isl_local_space *ls, int pos, __isl_keep isl_ast_build *build) { isl_ctx *ctx = isl_local_space_get_ctx(ls); @@ -66,17 +68,27 @@ static __isl_give isl_ast_expr *var_div(__isl_keep isl_local_space *ls, isl_aff_get_denominator(aff, &d); aff = isl_aff_scale(aff, d); den = isl_ast_expr_alloc_int(ctx, d); - isl_int_clear(d); type = isl_ast_op_fdiv_q; if (isl_options_get_ast_build_prefer_pdiv(ctx)) { int non_neg = isl_ast_build_aff_is_nonneg(build, aff); + if (non_neg >= 0 && !non_neg) { + isl_aff *opp = oppose_div_arg(isl_aff_copy(aff), d); + non_neg = isl_ast_build_aff_is_nonneg(build, opp); + if (non_neg >= 0 && non_neg) { + isl_int_neg(*v, *v); + isl_aff_free(aff); + aff = opp; + } else + isl_aff_free(opp); + } if (non_neg < 0) aff = isl_aff_free(aff); else if (non_neg) type = isl_ast_op_pdiv_q; } + isl_int_clear(d); num = isl_ast_expr_from_aff(aff, build); return isl_ast_expr_alloc_binary(type, num, den); } @@ -84,19 +96,22 @@ static __isl_give isl_ast_expr *var_div(__isl_keep isl_local_space *ls, /* Create an isl_ast_expr evaluating the specified dimension of "ls". * The result is simplified in terms of build->domain. * + * "v" points to the coefficient of the specified dimension + * in the expression where it appears and may be updated by this function. + * * 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 "build" * - parameters are constructed from the isl_ids in "ls" */ -static __isl_give isl_ast_expr *var(__isl_keep isl_local_space *ls, +static __isl_give isl_ast_expr *var(isl_int *v, __isl_keep isl_local_space *ls, enum isl_dim_type type, int pos, __isl_keep isl_ast_build *build) { isl_ctx *ctx = isl_local_space_get_ctx(ls); isl_id *id; if (type == isl_dim_div) - return var_div(ls, pos, build); + return var_div(v, ls, pos, build); if (type == isl_dim_set) { id = isl_ast_build_get_iterator_id(build, pos); @@ -212,50 +227,44 @@ static __isl_give isl_ast_expr *isl_ast_expr_mod(isl_int v, return expr; } -/* Create an isl_ast_expr evaluating "v" times the specified dimension of "ls". - * The result is simplified in terms of build->domain. +/* Create an isl_ast_expr that scales "expr" by "v". * - * Let e be the expression for the specified dimension. - * If v is 1, we simply return e. + * If v is 1, we simply return expr. * If v is -1, we return * - * (isl_ast_op_minus, e) + * (isl_ast_op_minus, expr) * * Otherwise, we return * - * (isl_ast_op_mul, expr(v), e) + * (isl_ast_op_mul, expr(v), expr) */ -static __isl_give isl_ast_expr *isl_ast_expr_term( - __isl_keep isl_local_space *ls, enum isl_dim_type type, int pos, - isl_int v, __isl_keep isl_ast_build *build) +static __isl_give isl_ast_expr *scale(__isl_take isl_ast_expr *expr, isl_int v) { isl_ctx *ctx; - isl_ast_expr *expr; isl_ast_expr *c; - if (!ls) + if (!expr) return NULL; + if (isl_int_is_one(v)) + return expr; - ctx = isl_local_space_get_ctx(ls); - expr = var(ls, type, pos, build); - - if (!isl_int_is_one(v)) { - if (isl_int_is_negone(v)) { - expr = isl_ast_expr_neg(expr); - } else { - c = isl_ast_expr_alloc_int(ctx, v); - expr = isl_ast_expr_mul(c, expr); - } + if (isl_int_is_negone(v)) { + expr = isl_ast_expr_neg(expr); + } else { + ctx = isl_ast_expr_get_ctx(expr); + c = isl_ast_expr_alloc_int(ctx, v); + expr = isl_ast_expr_mul(c, expr); } return expr; } -/* Add an expression for "v" times the specified dimension of "ls" +/* Add an expression for "*v" times the specified dimension of "ls" * to expr. * - * Let e be the expression for the specified dimension. - * If "v" is negative, we create + * Let e be the expression for the specified dimension, + * multiplied by the absolute value of "*v". + * If "*v" is negative, we create * * (isl_ast_op_sub, expr, e) * @@ -265,7 +274,7 @@ static __isl_give isl_ast_expr *isl_ast_expr_term( * * instead. * - * If "v" is positive, we simply create + * If "*v" is positive, we simply create * * (isl_ast_op_add, expr, e) * @@ -273,19 +282,21 @@ static __isl_give isl_ast_expr *isl_ast_expr_term( 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_int v, __isl_keep isl_ast_build *build) + isl_int *v, __isl_keep isl_ast_build *build) { isl_ast_expr *term; if (!expr) return NULL; - if (isl_int_is_neg(v) && !ast_expr_is_zero(expr)) { - isl_int_neg(v, v); - term = isl_ast_expr_term(ls, type, pos, v, build); + term = var(v, ls, type, pos, build); + + if (isl_int_is_neg(*v) && !ast_expr_is_zero(expr)) { + isl_int_neg(*v, *v); + term = scale(term, *v); return ast_expr_sub(expr, term); } else { - term = isl_ast_expr_term(ls, type, pos, v, build); + term = scale(term, *v); return ast_expr_add(expr, term); } } @@ -338,6 +349,12 @@ static __isl_give isl_ast_expr *isl_ast_expr_add_int( * (isl_ast_op_pdiv_r, a, m) * * we need to make sure that a is non-negative. + * If not, we check if "-a + m - 1" is non-negative. + * If so, we can rewrite + * + * floor(a/m) = -ceil(-a/m) = -floor((-a + m - 1)/m) + * + * and still extract a modulo. * * The caller is responsible for dividing *neg and/or *pos by d. */ @@ -355,8 +372,20 @@ static __isl_give isl_aff *extract_modulo(__isl_take isl_aff *aff, div = isl_aff_get_div(aff, j); isl_aff_get_denominator(div, &d); mod = isl_int_is_divisible_by(v, d); - if (mod) + if (mod) { + div = isl_aff_scale(div, d); mod = isl_ast_build_aff_is_nonneg(build, div); + if (mod >= 0 && !mod) { + isl_aff *opp = oppose_div_arg(isl_aff_copy(div), d); + mod = isl_ast_build_aff_is_nonneg(build, opp); + if (mod >= 0 && mod) { + isl_aff_free(div); + div = opp; + isl_int_neg(v, v); + } else + isl_aff_free(opp); + } + } if (mod < 0) { isl_aff_free(div); isl_int_clear(d); @@ -366,7 +395,6 @@ static __isl_give isl_aff *extract_modulo(__isl_take isl_aff *aff, isl_int_clear(d); return aff; } - div = isl_aff_scale(div, d); isl_int_divexact(v, v, d); s = isl_int_sgn(v); isl_int_abs(v, v); @@ -482,7 +510,7 @@ __isl_give isl_ast_expr *isl_ast_expr_from_aff(__isl_take isl_aff *aff, if (isl_int_is_zero(v)) continue; expr = isl_ast_expr_add_term(expr, - ls, l[i], j, v, build); + ls, l[i], j, &v, build); } } @@ -526,22 +554,35 @@ static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr, continue; isl_int_abs(v, v); expr = isl_ast_expr_add_term(expr, - ls, l[i], j, v, build); + ls, l[i], j, &v, build); } } - isl_aff_get_constant(aff, &v); - if (sign * isl_int_sgn(v) > 0) { - isl_int_abs(v, v); - expr = isl_ast_expr_add_int(expr, v); - } - isl_local_space_free(ls); isl_int_clear(v); return expr; } +/* Should the constant term "v" be considered positive? + * + * A positive constant will be added to "pos" by the caller, + * while a negative constant will be added to "neg". + * If either "pos" or "neg" is exactly zero, then we prefer + * to add the constant "v" to that side, irrespective of the sign of "v". + * This results in slightly shorter expressions and may reduce the risk + * of overflows. + */ +static int constant_is_considered_positive(isl_int 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; + return isl_int_is_pos(v); +} + /* Construct an isl_ast_expr that evaluates the condition "constraint", * The result is simplified in terms of build->domain. * @@ -561,6 +602,10 @@ static __isl_give isl_ast_expr *add_signed_terms(__isl_take isl_ast_expr *expr, * 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 + * 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) @@ -570,6 +615,7 @@ static __isl_give isl_ast_expr *isl_ast_expr_from_constraint( isl_ast_expr *expr_neg; isl_ast_expr *expr; isl_aff *aff; + isl_int v; int eq; enum isl_ast_op_type type; @@ -587,6 +633,16 @@ static __isl_give isl_ast_expr *isl_ast_expr_from_constraint( expr_pos = add_signed_terms(expr_pos, aff, 1, build); expr_neg = add_signed_terms(expr_neg, aff, -1, build); + isl_int_init(v); + isl_aff_get_constant(aff, &v); + if (constant_is_considered_positive(v, expr_pos, expr_neg)) { + expr_pos = isl_ast_expr_add_int(expr_pos, v); + } else { + isl_int_neg(v, v); + expr_neg = isl_ast_expr_add_int(expr_neg, v); + } + isl_int_clear(v); + eq = isl_constraint_is_equality(constraint); if (isl_ast_expr_get_type(expr_pos) == isl_ast_expr_int &&