* 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
+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>
* tree-ssa-loop-niter.c (number_of_iterations_lt_to_ne): Clean up
+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>
* gcc.dg/vect/vect-mask-store-move-1.c: XFAIL.
--- /dev/null
+/* { 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" } } */
/* 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
- evaluated. USE_OVERFLOW_SEMANTICS is true if this function should assume 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
- tests, but also to enforce that the result follows them. Returns true if the
- conversion succeeded, false otherwise. */
+ evaluated. USE_OVERFLOW_SEMANTICS is true if this function should assume
+ 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 tests, but also to enforce that the result follows them.
+ FROM is the source variable converted if it's not NULL. Returns true if
+ the conversion succeeded, false otherwise. */
bool
convert_affine_scev (struct loop *loop, tree type,
tree *base, tree *step, gimple *at_stmt,
- bool use_overflow_semantics)
+ bool use_overflow_semantics, tree from)
{
tree ct = TREE_TYPE (*step);
bool enforce_overflow_semantics;
must_check_rslt_overflow = false;
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))
return false;
if (must_check_rslt_overflow
/* 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. */
- && 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;
*base = new_base;
USE_OVERFLOW_SEMANTICS is true if this function should assume 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
- tests, but also to enforce that the result follows them. */
+ arithmetics in C does not overflow) -- i.e., to use them to avoid
+ unnecessary tests, but also to enforce that the result follows them.
+
+ FROM is the source variable converted if it's not NULL. */
static tree
chrec_convert_1 (tree type, tree chrec, gimple *at_stmt,
- bool use_overflow_semantics)
+ bool use_overflow_semantics, tree from)
{
tree ct, res;
tree base, step;
step = CHREC_RIGHT (chrec);
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);
/* If we cannot propagate the cast inside the chrec, just keep the cast. */
CHREC_LEFT (chrec)),
fold_convert (utype,
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
res = fold_convert (type, chrec);
USE_OVERFLOW_SEMANTICS is true if this function should assume 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
- tests, but also to enforce that the result follows them. */
+ arithmetics in C does not overflow) -- i.e., to use them to avoid
+ unnecessary tests, but also to enforce that the result follows them.
+
+ FROM is the source variable converted if it's not NULL. */
tree
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
extern tree chrec_fold_plus (tree, tree, tree);
extern tree chrec_fold_minus (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_aggressive (tree, tree, bool *);
extern tree chrec_merge (tree, tree);
extern void for_each_scev_op (tree *, bool (*) (tree *, void *), void *);
extern bool convert_affine_scev (struct loop *, tree, tree *, tree *, gimple *,
- bool);
+ bool, tree = NULL);
/* Observers. */
extern bool eq_evolutions_p (const_tree, const_tree);
}
else
chrec1 = analyze_scalar_evolution (loop, rhs1);
- res = chrec_convert (type, chrec1, at_stmt);
+ res = chrec_convert (type, chrec1, at_stmt, true, rhs1);
break;
case BIT_AND_EXPR:
/* If access is not executed on every iteration, we must ensure that overlow
may not make the access valid later. */
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))
upper = 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
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
USE_OVERFLOW_SEMANTICS is true if this function should assume that
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
-scev_probably_wraps_p (tree base, tree step,
+scev_probably_wraps_p (tree var, tree base, tree step,
gimple *at_stmt, struct loop *loop,
bool use_overflow_semantics)
{
if (TREE_CODE (step) != INTEGER_CST)
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))
return false;
extern void estimate_numbers_of_iterations (void);
extern bool stmt_dominates_stmt_p (gimple *, gimple *);
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_numbers_of_iterations_estimates_loop (struct loop *);
extern void free_numbers_of_iterations_estimates (function *);
or decreases, ... */
dir == EV_DIR_UNKNOWN
/* ... or if it may wrap. */
- || scev_probably_wraps_p (init, step, stmt, get_chrec_loop (chrec),
- true))
+ || scev_probably_wraps_p (NULL_TREE, init, step, stmt,
+ get_chrec_loop (chrec), true))
return;
/* We use TYPE_MIN_VALUE and TYPE_MAX_VALUE here instead of