tree-scalar-evolution.c (simple_iv_with_niters): New funcion.
* tree-scalar-evolution.c (simple_iv_with_niters): New funcion. (derive_simple_iv_with_niters): New function. (simple_iv): Rewrite using simple_iv_with_niters. * tree-scalar-evolution.h (simple_iv_with_niters): New decl. * tree-ssa-loop-niter.c (number_of_iterations_exit_assumptions): New function. (number_of_iterations_exit): Rewrite using above function. * tree-ssa-loop-niter.h (number_of_iterations_exit_assumptions): New Decl. gcc/testsuite * gcc.dg/tree-ssa/loop-41.c: New test. From-SVN: r238367
This commit is contained in:
parent
afc89e5849
commit
43aabfcfd4
|
@ -1,3 +1,15 @@
|
|||
2016-07-15 Bin Cheng <bin.cheng@arm.com>
|
||||
|
||||
* tree-scalar-evolution.c (simple_iv_with_niters): New funcion.
|
||||
(derive_simple_iv_with_niters): New function.
|
||||
(simple_iv): Rewrite using simple_iv_with_niters.
|
||||
* tree-scalar-evolution.h (simple_iv_with_niters): New decl.
|
||||
* tree-ssa-loop-niter.c (number_of_iterations_exit_assumptions): New
|
||||
function.
|
||||
(number_of_iterations_exit): Rewrite using above function.
|
||||
* tree-ssa-loop-niter.h (number_of_iterations_exit_assumptions): New
|
||||
Decl.
|
||||
|
||||
2016-07-15 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* config/i386/i386.c (ix86_builtin_vectorization_cost): Adjust
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2016-07-15 Bin Cheng <bin.cheng@arm.com>
|
||||
|
||||
* gcc.dg/tree-ssa/loop-41.c: New test.
|
||||
|
||||
2016-07-15 Bin Cheng <bin.cheng@arm.com>
|
||||
|
||||
PR tree-optimization/71347
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1 -ftree-vrp -fdump-tree-vrp-alias" } */
|
||||
|
||||
signed char arr[240];
|
||||
void foo (void)
|
||||
{
|
||||
|
||||
unsigned short i, length = 200;
|
||||
|
||||
for (i = 1; (int)i < (length - 1); i++)
|
||||
arr[i] = -1;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-not "RANGE \\\[0, 65535\\\]" "vrp1" } } */
|
|
@ -3393,6 +3393,55 @@ iv_can_overflow_p (struct loop *loop, tree type, tree base, tree step)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Given EV with form of "(type) {inner_base, inner_step}_loop", this
|
||||
function tries to derive condition under which it can be simplified
|
||||
into "{(type)inner_base, (type)inner_step}_loop". The condition is
|
||||
the maximum number that inner iv can iterate. */
|
||||
|
||||
static tree
|
||||
derive_simple_iv_with_niters (tree ev, tree *niters)
|
||||
{
|
||||
if (!CONVERT_EXPR_P (ev))
|
||||
return ev;
|
||||
|
||||
tree inner_ev = TREE_OPERAND (ev, 0);
|
||||
if (TREE_CODE (inner_ev) != POLYNOMIAL_CHREC)
|
||||
return ev;
|
||||
|
||||
tree init = CHREC_LEFT (inner_ev);
|
||||
tree step = CHREC_RIGHT (inner_ev);
|
||||
if (TREE_CODE (init) != INTEGER_CST
|
||||
|| TREE_CODE (step) != INTEGER_CST || integer_zerop (step))
|
||||
return ev;
|
||||
|
||||
tree type = TREE_TYPE (ev);
|
||||
tree inner_type = TREE_TYPE (inner_ev);
|
||||
if (TYPE_PRECISION (inner_type) >= TYPE_PRECISION (type))
|
||||
return ev;
|
||||
|
||||
/* Type conversion in "(type) {inner_base, inner_step}_loop" can be
|
||||
folded only if inner iv won't overflow. We compute the maximum
|
||||
number the inner iv can iterate before overflowing and return the
|
||||
simplified affine iv. */
|
||||
tree delta;
|
||||
init = fold_convert (type, init);
|
||||
step = fold_convert (type, step);
|
||||
ev = build_polynomial_chrec (CHREC_VARIABLE (inner_ev), init, step);
|
||||
if (tree_int_cst_sign_bit (step))
|
||||
{
|
||||
tree bound = lower_bound_in_type (inner_type, inner_type);
|
||||
delta = fold_build2 (MINUS_EXPR, type, init, fold_convert (type, bound));
|
||||
step = fold_build1 (NEGATE_EXPR, type, step);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree bound = upper_bound_in_type (inner_type, inner_type);
|
||||
delta = fold_build2 (MINUS_EXPR, type, fold_convert (type, bound), init);
|
||||
}
|
||||
*niters = fold_build2 (FLOOR_DIV_EXPR, type, delta, step);
|
||||
return ev;
|
||||
}
|
||||
|
||||
/* Checks whether use of OP in USE_LOOP behaves as a simple affine iv with
|
||||
respect to WRTO_LOOP and returns its base and step in IV if possible
|
||||
(see analyze_scalar_evolution_in_loop for more details on USE_LOOP
|
||||
|
@ -3410,13 +3459,29 @@ iv_can_overflow_p (struct loop *loop, tree type, tree base, tree step)
|
|||
not wrap by some other argument. Otherwise, this might introduce undefined
|
||||
behavior, and
|
||||
|
||||
for (i = iv->base; ; i = (type) ((unsigned type) i + (unsigned type) iv->step))
|
||||
i = iv->base;
|
||||
for (; ; i = (type) ((unsigned type) i + (unsigned type) iv->step))
|
||||
|
||||
must be used instead. */
|
||||
must be used instead.
|
||||
|
||||
When IV_NITERS is not NULL, this function also checks case in which OP
|
||||
is a conversion of an inner simple iv of below form:
|
||||
|
||||
(outer_type){inner_base, inner_step}_loop.
|
||||
|
||||
If type of inner iv has smaller precision than outer_type, it can't be
|
||||
folded into {(outer_type)inner_base, (outer_type)inner_step}_loop because
|
||||
the inner iv could overflow/wrap. In this case, we derive a condition
|
||||
under which the inner iv won't overflow/wrap and do the simplification.
|
||||
The derived condition normally is the maximum number the inner iv can
|
||||
iterate, and will be stored in IV_NITERS. This is useful in loop niter
|
||||
analysis, to derive break conditions when a loop must terminate, when is
|
||||
infinite. */
|
||||
|
||||
bool
|
||||
simple_iv (struct loop *wrto_loop, struct loop *use_loop, tree op,
|
||||
affine_iv *iv, bool allow_nonconstant_step)
|
||||
simple_iv_with_niters (struct loop *wrto_loop, struct loop *use_loop,
|
||||
tree op, affine_iv *iv, tree *iv_niters,
|
||||
bool allow_nonconstant_step)
|
||||
{
|
||||
enum tree_code code;
|
||||
tree type, ev, base, e, stop;
|
||||
|
@ -3446,8 +3511,14 @@ simple_iv (struct loop *wrto_loop, struct loop *use_loop, tree op,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (TREE_CODE (ev) != POLYNOMIAL_CHREC
|
||||
|| CHREC_VARIABLE (ev) != (unsigned) wrto_loop->num)
|
||||
/* If we can derive valid scalar evolution with assumptions. */
|
||||
if (iv_niters && TREE_CODE (ev) != POLYNOMIAL_CHREC)
|
||||
ev = derive_simple_iv_with_niters (ev, iv_niters);
|
||||
|
||||
if (TREE_CODE (ev) != POLYNOMIAL_CHREC)
|
||||
return false;
|
||||
|
||||
if (CHREC_VARIABLE (ev) != (unsigned) wrto_loop->num)
|
||||
return false;
|
||||
|
||||
iv->step = CHREC_RIGHT (ev);
|
||||
|
@ -3544,6 +3615,17 @@ simple_iv (struct loop *wrto_loop, struct loop *use_loop, tree op,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Like simple_iv_with_niters, but return TRUE when OP behaves as a simple
|
||||
affine iv unconditionally. */
|
||||
|
||||
bool
|
||||
simple_iv (struct loop *wrto_loop, struct loop *use_loop, tree op,
|
||||
affine_iv *iv, bool allow_nonconstant_step)
|
||||
{
|
||||
return simple_iv_with_niters (wrto_loop, use_loop, op, iv,
|
||||
NULL, allow_nonconstant_step);
|
||||
}
|
||||
|
||||
/* Finalize the scalar evolution analysis. */
|
||||
|
||||
void
|
||||
|
|
|
@ -36,6 +36,8 @@ extern void gather_stats_on_scev_database (void);
|
|||
extern void final_value_replacement_loop (struct loop *);
|
||||
extern unsigned int scev_const_prop (void);
|
||||
extern bool expression_expensive_p (tree);
|
||||
extern bool simple_iv_with_niters (struct loop *, struct loop *, tree,
|
||||
struct affine_iv *, tree *, bool);
|
||||
extern bool simple_iv (struct loop *, struct loop *, tree, struct affine_iv *,
|
||||
bool);
|
||||
extern bool iv_can_overflow_p (struct loop *, tree, tree, tree);
|
||||
|
|
|
@ -2176,20 +2176,17 @@ loop_only_exit_p (const struct loop *loop, const_edge exit)
|
|||
}
|
||||
|
||||
/* Stores description of number of iterations of LOOP derived from
|
||||
EXIT (an exit edge of the LOOP) in NITER. Returns true if some
|
||||
useful information could be derived (and fields of NITER has
|
||||
meaning described in comments at struct tree_niter_desc
|
||||
declaration), false otherwise. If WARN is true and
|
||||
-Wunsafe-loop-optimizations was given, warn if the optimizer is going to use
|
||||
potentially unsafe assumptions.
|
||||
EXIT (an exit edge of the LOOP) in NITER. Returns true if some useful
|
||||
information could be derived (and fields of NITER have meaning described
|
||||
in comments at struct tree_niter_desc declaration), false otherwise.
|
||||
When EVERY_ITERATION is true, only tests that are known to be executed
|
||||
every iteration are considered (i.e. only test that alone bounds the loop).
|
||||
every iteration are considered (i.e. only test that alone bounds the loop).
|
||||
*/
|
||||
|
||||
bool
|
||||
number_of_iterations_exit (struct loop *loop, edge exit,
|
||||
struct tree_niter_desc *niter,
|
||||
bool warn, bool every_iteration)
|
||||
number_of_iterations_exit_assumptions (struct loop *loop, edge exit,
|
||||
struct tree_niter_desc *niter,
|
||||
bool every_iteration)
|
||||
{
|
||||
gimple *last;
|
||||
gcond *stmt;
|
||||
|
@ -2241,9 +2238,16 @@ number_of_iterations_exit (struct loop *loop, edge exit,
|
|||
&& !POINTER_TYPE_P (type))
|
||||
return false;
|
||||
|
||||
if (!simple_iv (loop, loop_containing_stmt (stmt), op0, &iv0, false))
|
||||
tree iv0_niters = NULL_TREE;
|
||||
if (!simple_iv_with_niters (loop, loop_containing_stmt (stmt),
|
||||
op0, &iv0, &iv0_niters, false))
|
||||
return false;
|
||||
if (!simple_iv (loop, loop_containing_stmt (stmt), op1, &iv1, false))
|
||||
tree iv1_niters = NULL_TREE;
|
||||
if (!simple_iv_with_niters (loop, loop_containing_stmt (stmt),
|
||||
op1, &iv1, &iv1_niters, false))
|
||||
return false;
|
||||
/* Give up on complicated case. */
|
||||
if (iv0_niters && iv1_niters)
|
||||
return false;
|
||||
|
||||
/* We don't want to see undefined signed overflow warnings while
|
||||
|
@ -2259,6 +2263,24 @@ number_of_iterations_exit (struct loop *loop, edge exit,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Incorporate additional assumption implied by control iv. */
|
||||
tree iv_niters = iv0_niters ? iv0_niters : iv1_niters;
|
||||
if (iv_niters)
|
||||
{
|
||||
tree assumption = fold_build2 (LE_EXPR, boolean_type_node, niter->niter,
|
||||
fold_convert (TREE_TYPE (niter->niter),
|
||||
iv_niters));
|
||||
|
||||
if (!integer_nonzerop (assumption))
|
||||
niter->assumptions = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
|
||||
niter->assumptions, assumption);
|
||||
|
||||
/* Refine upper bound if possible. */
|
||||
if (TREE_CODE (iv_niters) == INTEGER_CST
|
||||
&& niter->max > wi::to_widest (iv_niters))
|
||||
niter->max = wi::to_widest (iv_niters);
|
||||
}
|
||||
|
||||
if (optimize >= 3)
|
||||
{
|
||||
niter->assumptions = simplify_using_outer_evolutions (loop,
|
||||
|
@ -2281,44 +2303,22 @@ number_of_iterations_exit (struct loop *loop, edge exit,
|
|||
if (TREE_CODE (niter->niter) == INTEGER_CST)
|
||||
niter->max = wi::to_widest (niter->niter);
|
||||
|
||||
if (integer_onep (niter->assumptions))
|
||||
return true;
|
||||
return (!integer_zerop (niter->assumptions));
|
||||
}
|
||||
|
||||
/* With -funsafe-loop-optimizations we assume that nothing bad can happen.
|
||||
But if we can prove that there is overflow or some other source of weird
|
||||
behavior, ignore the loop even with -funsafe-loop-optimizations. */
|
||||
if (integer_zerop (niter->assumptions) || !single_exit (loop))
|
||||
/* Like number_of_iterations_exit, but return TRUE only if the niter
|
||||
information holds unconditionally. */
|
||||
|
||||
bool
|
||||
number_of_iterations_exit (struct loop *loop, edge exit,
|
||||
struct tree_niter_desc *niter,
|
||||
bool, bool every_iteration)
|
||||
{
|
||||
if (!number_of_iterations_exit_assumptions (loop, exit, niter,
|
||||
every_iteration))
|
||||
return false;
|
||||
|
||||
if (flag_unsafe_loop_optimizations)
|
||||
niter->assumptions = boolean_true_node;
|
||||
|
||||
if (warn)
|
||||
{
|
||||
const char *wording;
|
||||
location_t loc = gimple_location (stmt);
|
||||
|
||||
/* We can provide a more specific warning if one of the operator is
|
||||
constant and the other advances by +1 or -1. */
|
||||
if (!integer_zerop (iv1.step)
|
||||
? (integer_zerop (iv0.step)
|
||||
&& (integer_onep (iv1.step) || integer_all_onesp (iv1.step)))
|
||||
: (integer_onep (iv0.step) || integer_all_onesp (iv0.step)))
|
||||
wording =
|
||||
flag_unsafe_loop_optimizations
|
||||
? N_("assuming that the loop is not infinite")
|
||||
: N_("cannot optimize possibly infinite loops");
|
||||
else
|
||||
wording =
|
||||
flag_unsafe_loop_optimizations
|
||||
? N_("assuming that the loop counter does not overflow")
|
||||
: N_("cannot optimize loop, the loop counter may overflow");
|
||||
|
||||
warning_at ((LOCATION_LINE (loc) > 0) ? loc : input_location,
|
||||
OPT_Wunsafe_loop_optimizations, "%s", gettext (wording));
|
||||
}
|
||||
|
||||
return flag_unsafe_loop_optimizations;
|
||||
return (integer_nonzerop (niter->assumptions));
|
||||
}
|
||||
|
||||
/* Try to determine the number of iterations of LOOP. If we succeed,
|
||||
|
|
|
@ -27,6 +27,9 @@ extern bool loop_only_exit_p (const struct loop *, const_edge);
|
|||
extern bool number_of_iterations_exit (struct loop *, edge,
|
||||
struct tree_niter_desc *niter, bool,
|
||||
bool every_iteration = true);
|
||||
extern bool number_of_iterations_exit_assumptions (struct loop *, edge,
|
||||
struct tree_niter_desc *,
|
||||
bool = true);
|
||||
extern tree find_loop_niter (struct loop *, edge *);
|
||||
extern bool finite_loop_p (struct loop *);
|
||||
extern tree loop_niter_by_eval (struct loop *, edge);
|
||||
|
|
Loading…
Reference in New Issue