mirror of git://gcc.gnu.org/git/gcc.git
tree-chrec.c (convert_affine_scev): New parameter.
* tree-chrec.c (convert_affine_scev): New parameter. Pass new arg. (chrec_convert_1, chrec_convert): Ditto. * tree-chrec.h (chrec_convert, convert_affine_scev): New parameter. * tree-scalar-evolution.c (interpret_rhs_expr): Pass new arg. * tree-vrp.c (adjust_range_with_scev): Ditto. * tree-ssa-loop-niter.c (idx_infer_loop_bounds): Ditto. (scev_var_range_cant_overflow): New function. (scev_probably_wraps_p): New parameter. Call above function. * tree-ssa-loop-niter.h (scev_probably_wraps_p): New parameter. gcc/testsuite * gcc.dg/tree-ssa/scev-15.c: New. From-SVN: r238586
This commit is contained in:
parent
106d07f8d2
commit
b24d942079
|
|
@ -1,3 +1,15 @@
|
||||||
|
2016-07-21 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
* tree-chrec.c (convert_affine_scev): New parameter. Pass new arg.
|
||||||
|
(chrec_convert_1, chrec_convert): Ditto.
|
||||||
|
* tree-chrec.h (chrec_convert, convert_affine_scev): New parameter.
|
||||||
|
* tree-scalar-evolution.c (interpret_rhs_expr): Pass new arg.
|
||||||
|
* tree-vrp.c (adjust_range_with_scev): Ditto.
|
||||||
|
* tree-ssa-loop-niter.c (idx_infer_loop_bounds): Ditto.
|
||||||
|
(scev_var_range_cant_overflow): New function.
|
||||||
|
(scev_probably_wraps_p): New parameter. Call above function.
|
||||||
|
* tree-ssa-loop-niter.h (scev_probably_wraps_p): New parameter.
|
||||||
|
|
||||||
2016-07-21 Bin Cheng <bin.cheng@arm.com>
|
2016-07-21 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
* tree-ssa-loop-niter.c (number_of_iterations_lt_to_ne): Clean up
|
* tree-ssa-loop-niter.c (number_of_iterations_lt_to_ne): Clean up
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
2016-07-21 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
* gcc.dg/tree-ssa/scev-15.c: New.
|
||||||
|
|
||||||
2016-07-21 Bin Cheng <bin.cheng@arm.com>
|
2016-07-21 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
* gcc.dg/vect/vect-mask-store-move-1.c: XFAIL.
|
* gcc.dg/vect/vect-mask-store-move-1.c: XFAIL.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-O3 -fdump-tree-ldist" } */
|
||||||
|
|
||||||
|
void
|
||||||
|
foo (int *p)
|
||||||
|
{
|
||||||
|
unsigned short i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
for (j = 1; j < 101; j++)
|
||||||
|
{
|
||||||
|
unsigned int index = 100 * i + j;
|
||||||
|
p[index-1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop can be transformed into builtin memset since &p[...] is SCEV. */
|
||||||
|
/* { dg-final { scan-tree-dump "builtin_memset" "ldist" } } */
|
||||||
|
|
@ -1162,16 +1162,17 @@ nb_vars_in_chrec (tree chrec)
|
||||||
|
|
||||||
/* Converts BASE and STEP of affine scev to TYPE. LOOP is the loop whose iv
|
/* Converts BASE and STEP of affine scev to TYPE. LOOP is the loop whose iv
|
||||||
the scev corresponds to. AT_STMT is the statement at that the scev is
|
the scev corresponds to. AT_STMT is the statement at that the scev is
|
||||||
evaluated. USE_OVERFLOW_SEMANTICS is true if this function should assume that
|
evaluated. USE_OVERFLOW_SEMANTICS is true if this function should assume
|
||||||
the rules for overflow of the given language apply (e.g., that signed
|
that the rules for overflow of the given language apply (e.g., that signed
|
||||||
arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
|
arithmetics in C does not overflow) -- i.e., to use them to avoid
|
||||||
tests, but also to enforce that the result follows them. Returns true if the
|
unnecessary tests, but also to enforce that the result follows them.
|
||||||
conversion succeeded, false otherwise. */
|
FROM is the source variable converted if it's not NULL. Returns true if
|
||||||
|
the conversion succeeded, false otherwise. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
convert_affine_scev (struct loop *loop, tree type,
|
convert_affine_scev (struct loop *loop, tree type,
|
||||||
tree *base, tree *step, gimple *at_stmt,
|
tree *base, tree *step, gimple *at_stmt,
|
||||||
bool use_overflow_semantics)
|
bool use_overflow_semantics, tree from)
|
||||||
{
|
{
|
||||||
tree ct = TREE_TYPE (*step);
|
tree ct = TREE_TYPE (*step);
|
||||||
bool enforce_overflow_semantics;
|
bool enforce_overflow_semantics;
|
||||||
|
|
@ -1230,7 +1231,7 @@ convert_affine_scev (struct loop *loop, tree type,
|
||||||
must_check_rslt_overflow = false;
|
must_check_rslt_overflow = false;
|
||||||
|
|
||||||
if (must_check_src_overflow
|
if (must_check_src_overflow
|
||||||
&& scev_probably_wraps_p (*base, *step, at_stmt, loop,
|
&& scev_probably_wraps_p (from, *base, *step, at_stmt, loop,
|
||||||
use_overflow_semantics))
|
use_overflow_semantics))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -1258,7 +1259,8 @@ convert_affine_scev (struct loop *loop, tree type,
|
||||||
if (must_check_rslt_overflow
|
if (must_check_rslt_overflow
|
||||||
/* Note that in this case we cannot use the fact that signed variables
|
/* Note that in this case we cannot use the fact that signed variables
|
||||||
do not overflow, as this is what we are verifying for the new iv. */
|
do not overflow, as this is what we are verifying for the new iv. */
|
||||||
&& scev_probably_wraps_p (new_base, new_step, at_stmt, loop, false))
|
&& scev_probably_wraps_p (NULL_TREE, new_base, new_step,
|
||||||
|
at_stmt, loop, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*base = new_base;
|
*base = new_base;
|
||||||
|
|
@ -1288,12 +1290,14 @@ chrec_convert_rhs (tree type, tree chrec, gimple *at_stmt)
|
||||||
|
|
||||||
USE_OVERFLOW_SEMANTICS is true if this function should assume that
|
USE_OVERFLOW_SEMANTICS is true if this function should assume that
|
||||||
the rules for overflow of the given language apply (e.g., that signed
|
the rules for overflow of the given language apply (e.g., that signed
|
||||||
arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
|
arithmetics in C does not overflow) -- i.e., to use them to avoid
|
||||||
tests, but also to enforce that the result follows them. */
|
unnecessary tests, but also to enforce that the result follows them.
|
||||||
|
|
||||||
|
FROM is the source variable converted if it's not NULL. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
chrec_convert_1 (tree type, tree chrec, gimple *at_stmt,
|
chrec_convert_1 (tree type, tree chrec, gimple *at_stmt,
|
||||||
bool use_overflow_semantics)
|
bool use_overflow_semantics, tree from)
|
||||||
{
|
{
|
||||||
tree ct, res;
|
tree ct, res;
|
||||||
tree base, step;
|
tree base, step;
|
||||||
|
|
@ -1314,7 +1318,7 @@ chrec_convert_1 (tree type, tree chrec, gimple *at_stmt,
|
||||||
step = CHREC_RIGHT (chrec);
|
step = CHREC_RIGHT (chrec);
|
||||||
|
|
||||||
if (convert_affine_scev (loop, type, &base, &step, at_stmt,
|
if (convert_affine_scev (loop, type, &base, &step, at_stmt,
|
||||||
use_overflow_semantics))
|
use_overflow_semantics, from))
|
||||||
return build_polynomial_chrec (loop->num, base, step);
|
return build_polynomial_chrec (loop->num, base, step);
|
||||||
|
|
||||||
/* If we cannot propagate the cast inside the chrec, just keep the cast. */
|
/* If we cannot propagate the cast inside the chrec, just keep the cast. */
|
||||||
|
|
@ -1347,7 +1351,7 @@ keep_cast:
|
||||||
CHREC_LEFT (chrec)),
|
CHREC_LEFT (chrec)),
|
||||||
fold_convert (utype,
|
fold_convert (utype,
|
||||||
CHREC_RIGHT (chrec)));
|
CHREC_RIGHT (chrec)));
|
||||||
res = chrec_convert_1 (type, res, at_stmt, use_overflow_semantics);
|
res = chrec_convert_1 (type, res, at_stmt, use_overflow_semantics, from);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
res = fold_convert (type, chrec);
|
res = fold_convert (type, chrec);
|
||||||
|
|
@ -1395,14 +1399,16 @@ keep_cast:
|
||||||
|
|
||||||
USE_OVERFLOW_SEMANTICS is true if this function should assume that
|
USE_OVERFLOW_SEMANTICS is true if this function should assume that
|
||||||
the rules for overflow of the given language apply (e.g., that signed
|
the rules for overflow of the given language apply (e.g., that signed
|
||||||
arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
|
arithmetics in C does not overflow) -- i.e., to use them to avoid
|
||||||
tests, but also to enforce that the result follows them. */
|
unnecessary tests, but also to enforce that the result follows them.
|
||||||
|
|
||||||
|
FROM is the source variable converted if it's not NULL. */
|
||||||
|
|
||||||
tree
|
tree
|
||||||
chrec_convert (tree type, tree chrec, gimple *at_stmt,
|
chrec_convert (tree type, tree chrec, gimple *at_stmt,
|
||||||
bool use_overflow_semantics)
|
bool use_overflow_semantics, tree from)
|
||||||
{
|
{
|
||||||
return chrec_convert_1 (type, chrec, at_stmt, use_overflow_semantics);
|
return chrec_convert_1 (type, chrec, at_stmt, use_overflow_semantics, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert CHREC to TYPE, without regard to signed overflows. Returns the new
|
/* Convert CHREC to TYPE, without regard to signed overflows. Returns the new
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ enum ev_direction scev_direction (const_tree);
|
||||||
extern tree chrec_fold_plus (tree, tree, tree);
|
extern tree chrec_fold_plus (tree, tree, tree);
|
||||||
extern tree chrec_fold_minus (tree, tree, tree);
|
extern tree chrec_fold_minus (tree, tree, tree);
|
||||||
extern tree chrec_fold_multiply (tree, tree, tree);
|
extern tree chrec_fold_multiply (tree, tree, tree);
|
||||||
extern tree chrec_convert (tree, tree, gimple *, bool = true);
|
extern tree chrec_convert (tree, tree, gimple *, bool = true, tree = NULL);
|
||||||
extern tree chrec_convert_rhs (tree, tree, gimple *);
|
extern tree chrec_convert_rhs (tree, tree, gimple *);
|
||||||
extern tree chrec_convert_aggressive (tree, tree, bool *);
|
extern tree chrec_convert_aggressive (tree, tree, bool *);
|
||||||
|
|
||||||
|
|
@ -75,7 +75,7 @@ extern tree reset_evolution_in_loop (unsigned, tree, tree);
|
||||||
extern tree chrec_merge (tree, tree);
|
extern tree chrec_merge (tree, tree);
|
||||||
extern void for_each_scev_op (tree *, bool (*) (tree *, void *), void *);
|
extern void for_each_scev_op (tree *, bool (*) (tree *, void *), void *);
|
||||||
extern bool convert_affine_scev (struct loop *, tree, tree *, tree *, gimple *,
|
extern bool convert_affine_scev (struct loop *, tree, tree *, tree *, gimple *,
|
||||||
bool);
|
bool, tree = NULL);
|
||||||
|
|
||||||
/* Observers. */
|
/* Observers. */
|
||||||
extern bool eq_evolutions_p (const_tree, const_tree);
|
extern bool eq_evolutions_p (const_tree, const_tree);
|
||||||
|
|
|
||||||
|
|
@ -1933,7 +1933,7 @@ interpret_rhs_expr (struct loop *loop, gimple *at_stmt,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
chrec1 = analyze_scalar_evolution (loop, rhs1);
|
chrec1 = analyze_scalar_evolution (loop, rhs1);
|
||||||
res = chrec_convert (type, chrec1, at_stmt);
|
res = chrec_convert (type, chrec1, at_stmt, true, rhs1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BIT_AND_EXPR:
|
case BIT_AND_EXPR:
|
||||||
|
|
|
||||||
|
|
@ -3128,7 +3128,8 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta)
|
||||||
/* If access is not executed on every iteration, we must ensure that overlow
|
/* If access is not executed on every iteration, we must ensure that overlow
|
||||||
may not make the access valid later. */
|
may not make the access valid later. */
|
||||||
if (!dominated_by_p (CDI_DOMINATORS, loop->latch, gimple_bb (data->stmt))
|
if (!dominated_by_p (CDI_DOMINATORS, loop->latch, gimple_bb (data->stmt))
|
||||||
&& scev_probably_wraps_p (initial_condition_in_loop_num (ev, loop->num),
|
&& scev_probably_wraps_p (NULL_TREE,
|
||||||
|
initial_condition_in_loop_num (ev, loop->num),
|
||||||
step, data->stmt, loop, true))
|
step, data->stmt, loop, true))
|
||||||
upper = false;
|
upper = false;
|
||||||
|
|
||||||
|
|
@ -4191,6 +4192,104 @@ loop_exits_before_overflow (tree base, tree step,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* VAR is scev variable whose evolution part is constant STEP, this function
|
||||||
|
proves that VAR can't overflow by using value range info. If VAR's value
|
||||||
|
range is [MIN, MAX], it can be proven by:
|
||||||
|
MAX + step doesn't overflow ; if step > 0
|
||||||
|
or
|
||||||
|
MIN + step doesn't underflow ; if step < 0.
|
||||||
|
|
||||||
|
We can only do this if var is computed in every loop iteration, i.e, var's
|
||||||
|
definition has to dominate loop latch. Consider below example:
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
<bb 3>:
|
||||||
|
|
||||||
|
<bb 4>:
|
||||||
|
# RANGE [0, 4294967294] NONZERO 65535
|
||||||
|
# i_21 = PHI <0(3), i_18(9)>
|
||||||
|
if (i_21 != 0)
|
||||||
|
goto <bb 6>;
|
||||||
|
else
|
||||||
|
goto <bb 8>;
|
||||||
|
|
||||||
|
<bb 6>:
|
||||||
|
# RANGE [0, 65533] NONZERO 65535
|
||||||
|
_6 = i_21 + 4294967295;
|
||||||
|
# RANGE [0, 65533] NONZERO 65535
|
||||||
|
_7 = (long unsigned int) _6;
|
||||||
|
# RANGE [0, 524264] NONZERO 524280
|
||||||
|
_8 = _7 * 8;
|
||||||
|
# PT = nonlocal escaped
|
||||||
|
_9 = a_14 + _8;
|
||||||
|
*_9 = 0;
|
||||||
|
|
||||||
|
<bb 8>:
|
||||||
|
# RANGE [1, 65535] NONZERO 65535
|
||||||
|
i_18 = i_21 + 1;
|
||||||
|
if (i_18 >= 65535)
|
||||||
|
goto <bb 10>;
|
||||||
|
else
|
||||||
|
goto <bb 9>;
|
||||||
|
|
||||||
|
<bb 9>:
|
||||||
|
goto <bb 4>;
|
||||||
|
|
||||||
|
<bb 10>:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VAR _6 doesn't overflow only with pre-condition (i_21 != 0), here we
|
||||||
|
can't use _6 to prove no-overlfow for _7. In fact, var _7 takes value
|
||||||
|
sequence (4294967295, 0, 1, ..., 65533) in loop life time, rather than
|
||||||
|
(4294967295, 4294967296, ...). */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
scev_var_range_cant_overflow (tree var, tree step, struct loop *loop)
|
||||||
|
{
|
||||||
|
tree type;
|
||||||
|
wide_int minv, maxv, diff, step_wi;
|
||||||
|
enum value_range_type rtype;
|
||||||
|
|
||||||
|
if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check if VAR evaluates in every loop iteration. It's not the case
|
||||||
|
if VAR is default definition or does not dominate loop's latch. */
|
||||||
|
basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (var));
|
||||||
|
if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rtype = get_range_info (var, &minv, &maxv);
|
||||||
|
if (rtype != VR_RANGE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* VAR is a scev whose evolution part is STEP and value range info
|
||||||
|
is [MIN, MAX], we can prove its no-overflowness by conditions:
|
||||||
|
|
||||||
|
type_MAX - MAX >= step ; if step > 0
|
||||||
|
MIN - type_MIN >= |step| ; if step < 0.
|
||||||
|
|
||||||
|
Or VAR must take value outside of value range, which is not true. */
|
||||||
|
step_wi = step;
|
||||||
|
type = TREE_TYPE (var);
|
||||||
|
if (tree_int_cst_sign_bit (step))
|
||||||
|
{
|
||||||
|
diff = lower_bound_in_type (type, type);
|
||||||
|
diff = minv - diff;
|
||||||
|
step_wi = - step_wi;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
diff = upper_bound_in_type (type, type);
|
||||||
|
diff = diff - maxv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (wi::geu_p (diff, step_wi));
|
||||||
|
}
|
||||||
|
|
||||||
/* Return false only when the induction variable BASE + STEP * I is
|
/* Return false only when the induction variable BASE + STEP * I is
|
||||||
known to not overflow: i.e. when the number of iterations is small
|
known to not overflow: i.e. when the number of iterations is small
|
||||||
enough with respect to the step and initial condition in order to
|
enough with respect to the step and initial condition in order to
|
||||||
|
|
@ -4199,10 +4298,13 @@ loop_exits_before_overflow (tree base, tree step,
|
||||||
|
|
||||||
USE_OVERFLOW_SEMANTICS is true if this function should assume that
|
USE_OVERFLOW_SEMANTICS is true if this function should assume that
|
||||||
the rules for overflow of the given language apply (e.g., that signed
|
the rules for overflow of the given language apply (e.g., that signed
|
||||||
arithmetics in C does not overflow). */
|
arithmetics in C does not overflow).
|
||||||
|
|
||||||
|
If VAR is a ssa variable, this function also returns false if VAR can
|
||||||
|
be proven not overflow with value range info. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
scev_probably_wraps_p (tree base, tree step,
|
scev_probably_wraps_p (tree var, tree base, tree step,
|
||||||
gimple *at_stmt, struct loop *loop,
|
gimple *at_stmt, struct loop *loop,
|
||||||
bool use_overflow_semantics)
|
bool use_overflow_semantics)
|
||||||
{
|
{
|
||||||
|
|
@ -4239,6 +4341,11 @@ scev_probably_wraps_p (tree base, tree step,
|
||||||
if (TREE_CODE (step) != INTEGER_CST)
|
if (TREE_CODE (step) != INTEGER_CST)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
/* Check if var can be proven not overflow with value range info. */
|
||||||
|
if (var && TREE_CODE (var) == SSA_NAME
|
||||||
|
&& scev_var_range_cant_overflow (var, step, loop))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (loop_exits_before_overflow (base, step, at_stmt, loop))
|
if (loop_exits_before_overflow (base, step, at_stmt, loop))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,8 @@ extern bool estimated_stmt_executions (struct loop *, widest_int *);
|
||||||
extern void estimate_numbers_of_iterations (void);
|
extern void estimate_numbers_of_iterations (void);
|
||||||
extern bool stmt_dominates_stmt_p (gimple *, gimple *);
|
extern bool stmt_dominates_stmt_p (gimple *, gimple *);
|
||||||
extern bool nowrap_type_p (tree);
|
extern bool nowrap_type_p (tree);
|
||||||
extern bool scev_probably_wraps_p (tree, tree, gimple *, struct loop *, bool);
|
extern bool scev_probably_wraps_p (tree, tree, tree, gimple *,
|
||||||
|
struct loop *, bool);
|
||||||
extern void free_loop_control_ivs (struct loop *);
|
extern void free_loop_control_ivs (struct loop *);
|
||||||
extern void free_numbers_of_iterations_estimates_loop (struct loop *);
|
extern void free_numbers_of_iterations_estimates_loop (struct loop *);
|
||||||
extern void free_numbers_of_iterations_estimates (function *);
|
extern void free_numbers_of_iterations_estimates (function *);
|
||||||
|
|
|
||||||
|
|
@ -4156,8 +4156,8 @@ adjust_range_with_scev (value_range *vr, struct loop *loop,
|
||||||
or decreases, ... */
|
or decreases, ... */
|
||||||
dir == EV_DIR_UNKNOWN
|
dir == EV_DIR_UNKNOWN
|
||||||
/* ... or if it may wrap. */
|
/* ... or if it may wrap. */
|
||||||
|| scev_probably_wraps_p (init, step, stmt, get_chrec_loop (chrec),
|
|| scev_probably_wraps_p (NULL_TREE, init, step, stmt,
|
||||||
true))
|
get_chrec_loop (chrec), true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* We use TYPE_MIN_VALUE and TYPE_MAX_VALUE here instead of
|
/* We use TYPE_MIN_VALUE and TYPE_MAX_VALUE here instead of
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue