tree-vrp.c (adjust_range_with_scev): Use number of iteration estimate.
2010-09-01 Richard Guenther <rguenther@suse.de> * tree-vrp.c (adjust_range_with_scev): Use number of iteration estimate. (vrp_visit_phi_node): Delay using SCEV till we balloon the range. (execute_vrp): Compute number of iteration estimates. * cfgloop.h (estimate_numbers_of_iterations_loop): Adjust prototype. * tree-flow.h (estimate_numbers_of_iterations): Likewise. * tree-data-ref.c (estimated_loop_iterations): Adjust. * tree-ssa-loop-niter.c (estimate_numbers_of_iterations_loop): Infer loop bounds from undefined behavior based on a new parameter. (estimate_numbers_of_iterations): Likewise. (scev_probably_wraps_p): Adjust. * tree-ssa-loop.c (tree_ssa_loop_bounds): Likewise. * gcc.dg/vect/vect-outer-fir.c: Adjust. * gcc.dg/tree-ssa/vrp54.c: New testcase. * gcc.c-torture/execute/20100827-1.c: Likewise. From-SVN: r163724
This commit is contained in:
parent
eacbdaaac1
commit
e34882831e
11 changed files with 199 additions and 96 deletions
|
@ -1,3 +1,20 @@
|
|||
2010-09-01 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
* tree-vrp.c (adjust_range_with_scev): Use number of iteration
|
||||
estimate.
|
||||
(vrp_visit_phi_node): Delay using SCEV till we balloon the
|
||||
range.
|
||||
(execute_vrp): Compute number of iteration estimates.
|
||||
* cfgloop.h (estimate_numbers_of_iterations_loop): Adjust prototype.
|
||||
* tree-flow.h (estimate_numbers_of_iterations): Likewise.
|
||||
* tree-data-ref.c (estimated_loop_iterations): Adjust.
|
||||
* tree-ssa-loop-niter.c (estimate_numbers_of_iterations_loop):
|
||||
Infer loop bounds from undefined behavior based on a new
|
||||
parameter.
|
||||
(estimate_numbers_of_iterations): Likewise.
|
||||
(scev_probably_wraps_p): Adjust.
|
||||
* tree-ssa-loop.c (tree_ssa_loop_bounds): Likewise.
|
||||
|
||||
2010-09-01 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* config/stormy16/stormy16.c: Use REG_P, MEM_P and CONST_INT_P
|
||||
|
|
|
@ -276,7 +276,7 @@ gcov_type expected_loop_iterations_unbounded (const struct loop *);
|
|||
extern unsigned expected_loop_iterations (const struct loop *);
|
||||
extern rtx doloop_condition_get (rtx);
|
||||
|
||||
void estimate_numbers_of_iterations_loop (struct loop *);
|
||||
void estimate_numbers_of_iterations_loop (struct loop *, bool);
|
||||
HOST_WIDE_INT estimated_loop_iterations_int (struct loop *, bool);
|
||||
bool estimated_loop_iterations (struct loop *, bool, double_int *);
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2010-09-01 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
* gcc.dg/vect/vect-outer-fir.c: Adjust.
|
||||
* gcc.dg/tree-ssa/vrp54.c: New testcase.
|
||||
* gcc.c-torture/execute/20100827-1.c: Likewise.
|
||||
|
||||
2010-09-01 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
|
||||
|
||||
* gfortran.dg/execute_command_line_1.f90: New test.
|
||||
|
|
23
gcc/testsuite/gcc.c-torture/execute/20100827-1.c
Normal file
23
gcc/testsuite/gcc.c-torture/execute/20100827-1.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
extern void abort (void);
|
||||
int __attribute__((noinline,noclone))
|
||||
foo (char *p)
|
||||
{
|
||||
int h = 0;
|
||||
do
|
||||
{
|
||||
if (*p == '\0')
|
||||
break;
|
||||
++h;
|
||||
if (p == 0)
|
||||
abort ();
|
||||
++p;
|
||||
}
|
||||
while (1);
|
||||
return h;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
if (foo("a") != 1)
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
34
gcc/testsuite/gcc.dg/tree-ssa/vrp54.c
Normal file
34
gcc/testsuite/gcc.dg/tree-ssa/vrp54.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp1" } */
|
||||
|
||||
extern void link_error (void);
|
||||
void foo (void)
|
||||
{
|
||||
int j = 256;
|
||||
do
|
||||
{
|
||||
if (j < 0 || j > 256)
|
||||
link_error ();
|
||||
j--;
|
||||
}
|
||||
while (j >= 0);
|
||||
if (j != -1)
|
||||
link_error ();
|
||||
}
|
||||
extern void link_error (void);
|
||||
void bar (void)
|
||||
{
|
||||
int j = 0;
|
||||
do
|
||||
{
|
||||
if (j < 0 || j > 256)
|
||||
link_error ();
|
||||
j++;
|
||||
}
|
||||
while (j <= 256);
|
||||
if (j != 257)
|
||||
link_error ();
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-not "link_error" "vrp1" } } */
|
||||
/* { dg-final { cleanup-tree-dump "vrp1" } } */
|
|
@ -11,10 +11,6 @@ float out[N];
|
|||
float fir_out[N];
|
||||
|
||||
/* Should be vectorized. Fixed misaligment in the inner-loop. */
|
||||
/* Currently not vectorized because we get too many BBs in the inner-loop,
|
||||
because the compiler doesn't realize that the inner-loop executes at
|
||||
least once (cause k<4), and so there's no need to create a guard code
|
||||
to skip the inner-loop in case it doesn't execute. */
|
||||
__attribute__ ((noinline))
|
||||
void foo (){
|
||||
int i,j,k;
|
||||
|
@ -74,6 +70,5 @@ int main (void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 2 "vect" { xfail *-*-* } } } */
|
||||
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail vect_no_align } } } */
|
||||
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 2 "vect" { xfail vect_no_align } } } */
|
||||
/* { dg-final { cleanup-tree-dump "vect" } } */
|
||||
|
|
|
@ -1716,7 +1716,7 @@ bool
|
|||
estimated_loop_iterations (struct loop *loop, bool conservative,
|
||||
double_int *nit)
|
||||
{
|
||||
estimate_numbers_of_iterations_loop (loop);
|
||||
estimate_numbers_of_iterations_loop (loop, true);
|
||||
if (conservative)
|
||||
{
|
||||
if (!loop->any_upper_bound)
|
||||
|
|
|
@ -684,7 +684,7 @@ bool number_of_iterations_exit (struct loop *, edge,
|
|||
tree find_loop_niter (struct loop *, edge *);
|
||||
tree loop_niter_by_eval (struct loop *, edge);
|
||||
tree find_loop_niter_by_eval (struct loop *, edge *);
|
||||
void estimate_numbers_of_iterations (void);
|
||||
void estimate_numbers_of_iterations (bool);
|
||||
bool array_at_struct_end_p (tree);
|
||||
bool scev_probably_wraps_p (tree, tree, gimple, struct loop *, bool);
|
||||
bool convert_affine_scev (struct loop *, tree, tree *, tree *, gimple, bool);
|
||||
|
|
|
@ -2933,10 +2933,11 @@ gcov_type_to_double_int (gcov_type val)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Records estimates on numbers of iterations of LOOP. */
|
||||
/* Records estimates on numbers of iterations of LOOP. If USE_UNDEFINED_P
|
||||
is true also use estimates derived from undefined behavior. */
|
||||
|
||||
void
|
||||
estimate_numbers_of_iterations_loop (struct loop *loop)
|
||||
estimate_numbers_of_iterations_loop (struct loop *loop, bool use_undefined_p)
|
||||
{
|
||||
VEC (edge, heap) *exits;
|
||||
tree niter, type;
|
||||
|
@ -2970,7 +2971,8 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
|
|||
}
|
||||
VEC_free (edge, heap, exits);
|
||||
|
||||
infer_loop_bounds_from_undefined (loop);
|
||||
if (use_undefined_p)
|
||||
infer_loop_bounds_from_undefined (loop);
|
||||
|
||||
/* If we have a measured profile, use it to estimate the number of
|
||||
iterations. */
|
||||
|
@ -2993,7 +2995,7 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
|
|||
/* Records estimates on numbers of iterations of loops. */
|
||||
|
||||
void
|
||||
estimate_numbers_of_iterations (void)
|
||||
estimate_numbers_of_iterations (bool use_undefined_p)
|
||||
{
|
||||
loop_iterator li;
|
||||
struct loop *loop;
|
||||
|
@ -3004,7 +3006,7 @@ estimate_numbers_of_iterations (void)
|
|||
|
||||
FOR_EACH_LOOP (li, loop, 0)
|
||||
{
|
||||
estimate_numbers_of_iterations_loop (loop);
|
||||
estimate_numbers_of_iterations_loop (loop, use_undefined_p);
|
||||
}
|
||||
|
||||
fold_undefer_and_ignore_overflow_warnings ();
|
||||
|
@ -3200,7 +3202,7 @@ scev_probably_wraps_p (tree base, tree step,
|
|||
|
||||
valid_niter = fold_build2 (FLOOR_DIV_EXPR, unsigned_type, delta, step_abs);
|
||||
|
||||
estimate_numbers_of_iterations_loop (loop);
|
||||
estimate_numbers_of_iterations_loop (loop, true);
|
||||
for (bound = loop->bounds; bound; bound = bound->next)
|
||||
{
|
||||
if (n_of_executions_at_most (at_stmt, bound, valid_niter))
|
||||
|
|
|
@ -458,7 +458,7 @@ tree_ssa_loop_bounds (void)
|
|||
if (number_of_loops () <= 1)
|
||||
return 0;
|
||||
|
||||
estimate_numbers_of_iterations ();
|
||||
estimate_numbers_of_iterations (true);
|
||||
scev_reset ();
|
||||
return 0;
|
||||
}
|
||||
|
|
186
gcc/tree-vrp.c
186
gcc/tree-vrp.c
|
@ -3382,6 +3382,38 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop,
|
|||
else
|
||||
tmax = TYPE_MAX_VALUE (type);
|
||||
|
||||
/* Try to use estimated number of iterations for the loop to constrain the
|
||||
final value in the evolution.
|
||||
We are interested in the number of executions of the latch, while
|
||||
nb_iterations_upper_bound includes the last execution of the exit test. */
|
||||
if (TREE_CODE (step) == INTEGER_CST
|
||||
&& loop->any_upper_bound
|
||||
&& !double_int_zero_p (loop->nb_iterations_upper_bound)
|
||||
&& is_gimple_val (init)
|
||||
&& (TREE_CODE (init) != SSA_NAME
|
||||
|| get_value_range (init)->type == VR_RANGE))
|
||||
{
|
||||
value_range_t maxvr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
|
||||
double_int dtmp;
|
||||
dtmp = double_int_mul (tree_to_double_int (step),
|
||||
double_int_sub (loop->nb_iterations_upper_bound,
|
||||
double_int_one));
|
||||
tem = double_int_to_tree (TREE_TYPE (init), dtmp);
|
||||
/* If the multiplication overflowed we can't do a meaningful
|
||||
adjustment. */
|
||||
if (double_int_equal_p (dtmp, tree_to_double_int (tem)))
|
||||
{
|
||||
extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
|
||||
TREE_TYPE (init), init, tem);
|
||||
/* Likewise if the addition did. */
|
||||
if (maxvr.type == VR_RANGE)
|
||||
{
|
||||
tmin = maxvr.min;
|
||||
tmax = maxvr.max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
|
||||
{
|
||||
min = tmin;
|
||||
|
@ -3414,40 +3446,35 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop,
|
|||
/* INIT is the maximum value. If INIT is lower than VR->MAX
|
||||
but no smaller than VR->MIN, set VR->MAX to INIT. */
|
||||
if (compare_values (init, max) == -1)
|
||||
{
|
||||
max = init;
|
||||
|
||||
/* If we just created an invalid range with the minimum
|
||||
greater than the maximum, we fail conservatively.
|
||||
This should happen only in unreachable
|
||||
parts of code, or for invalid programs. */
|
||||
if (compare_values (min, max) == 1)
|
||||
return;
|
||||
}
|
||||
max = init;
|
||||
|
||||
/* According to the loop information, the variable does not
|
||||
overflow. If we think it does, probably because of an
|
||||
overflow due to arithmetic on a different INF value,
|
||||
reset now. */
|
||||
if (is_negative_overflow_infinity (min))
|
||||
if (is_negative_overflow_infinity (min)
|
||||
|| compare_values (min, tmin) == -1)
|
||||
min = tmin;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If INIT is bigger than VR->MIN, set VR->MIN to INIT. */
|
||||
if (compare_values (init, min) == 1)
|
||||
{
|
||||
min = init;
|
||||
min = init;
|
||||
|
||||
/* Again, avoid creating invalid range by failing. */
|
||||
if (compare_values (min, max) == 1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_positive_overflow_infinity (max))
|
||||
if (is_positive_overflow_infinity (max)
|
||||
|| compare_values (tmax, max) == -1)
|
||||
max = tmax;
|
||||
}
|
||||
|
||||
/* If we just created an invalid range with the minimum
|
||||
greater than the maximum, we fail conservatively.
|
||||
This should happen only in unreachable
|
||||
parts of code, or for invalid programs. */
|
||||
if (compare_values (min, max) == 1)
|
||||
return;
|
||||
|
||||
set_value_range (vr, VR_RANGE, min, max, vr->equiv);
|
||||
}
|
||||
}
|
||||
|
@ -6509,8 +6536,6 @@ vrp_visit_phi_node (gimple phi)
|
|||
int edges, old_edges;
|
||||
struct loop *l;
|
||||
|
||||
copy_value_range (&vr_result, lhs_vr);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "\nVisiting PHI node: ");
|
||||
|
@ -6571,13 +6596,6 @@ vrp_visit_phi_node (gimple phi)
|
|||
}
|
||||
}
|
||||
|
||||
/* If this is a loop PHI node SCEV may known more about its
|
||||
value-range. */
|
||||
if (current_loops
|
||||
&& (l = loop_containing_stmt (phi))
|
||||
&& l->header == gimple_bb (phi))
|
||||
adjust_range_with_scev (&vr_result, l, phi, lhs);
|
||||
|
||||
if (vr_result.type == VR_VARYING)
|
||||
goto varying;
|
||||
|
||||
|
@ -6589,61 +6607,63 @@ vrp_visit_phi_node (gimple phi)
|
|||
previous one. We don't do this if we have seen a new executable
|
||||
edge; this helps us avoid an overflow infinity for conditionals
|
||||
which are not in a loop. */
|
||||
if (lhs_vr->type == VR_RANGE && vr_result.type == VR_RANGE
|
||||
&& edges <= old_edges)
|
||||
if (edges > 0
|
||||
&& edges == old_edges)
|
||||
{
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (lhs)))
|
||||
int cmp_min = compare_values (lhs_vr->min, vr_result.min);
|
||||
int cmp_max = compare_values (lhs_vr->max, vr_result.max);
|
||||
|
||||
/* For non VR_RANGE or for pointers fall back to varying if
|
||||
the range changed. */
|
||||
if ((lhs_vr->type != VR_RANGE || vr_result.type != VR_RANGE
|
||||
|| POINTER_TYPE_P (TREE_TYPE (lhs)))
|
||||
&& (cmp_min != 0 || cmp_max != 0))
|
||||
goto varying;
|
||||
|
||||
/* If the new minimum is smaller or larger than the previous
|
||||
one, go all the way to -INF. In the first case, to avoid
|
||||
iterating millions of times to reach -INF, and in the
|
||||
other case to avoid infinite bouncing between different
|
||||
minimums. */
|
||||
if (cmp_min > 0 || cmp_min < 0)
|
||||
{
|
||||
int cmp_min = compare_values (lhs_vr->min, vr_result.min);
|
||||
int cmp_max = compare_values (lhs_vr->max, vr_result.max);
|
||||
|
||||
/* If the new minimum is smaller or larger than the previous
|
||||
one, go all the way to -INF. In the first case, to avoid
|
||||
iterating millions of times to reach -INF, and in the
|
||||
other case to avoid infinite bouncing between different
|
||||
minimums. */
|
||||
if (cmp_min > 0 || cmp_min < 0)
|
||||
{
|
||||
/* If we will end up with a (-INF, +INF) range, set it to
|
||||
VARYING. Same if the previous max value was invalid for
|
||||
the type and we'd end up with vr_result.min > vr_result.max. */
|
||||
if (vrp_val_is_max (vr_result.max)
|
||||
|| compare_values (TYPE_MIN_VALUE (TREE_TYPE (vr_result.min)),
|
||||
vr_result.max) > 0)
|
||||
goto varying;
|
||||
|
||||
if (!needs_overflow_infinity (TREE_TYPE (vr_result.min))
|
||||
|| !vrp_var_may_overflow (lhs, phi))
|
||||
vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min));
|
||||
else if (supports_overflow_infinity (TREE_TYPE (vr_result.min)))
|
||||
vr_result.min =
|
||||
negative_overflow_infinity (TREE_TYPE (vr_result.min));
|
||||
else
|
||||
goto varying;
|
||||
}
|
||||
|
||||
/* Similarly, if the new maximum is smaller or larger than
|
||||
the previous one, go all the way to +INF. */
|
||||
if (cmp_max < 0 || cmp_max > 0)
|
||||
{
|
||||
/* If we will end up with a (-INF, +INF) range, set it to
|
||||
VARYING. Same if the previous min value was invalid for
|
||||
the type and we'd end up with vr_result.max < vr_result.min. */
|
||||
if (vrp_val_is_min (vr_result.min)
|
||||
|| compare_values (TYPE_MAX_VALUE (TREE_TYPE (vr_result.max)),
|
||||
vr_result.min) < 0)
|
||||
goto varying;
|
||||
|
||||
if (!needs_overflow_infinity (TREE_TYPE (vr_result.max))
|
||||
|| !vrp_var_may_overflow (lhs, phi))
|
||||
vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max));
|
||||
else if (supports_overflow_infinity (TREE_TYPE (vr_result.max)))
|
||||
vr_result.max =
|
||||
positive_overflow_infinity (TREE_TYPE (vr_result.max));
|
||||
else
|
||||
goto varying;
|
||||
}
|
||||
if (!needs_overflow_infinity (TREE_TYPE (vr_result.min))
|
||||
|| !vrp_var_may_overflow (lhs, phi))
|
||||
vr_result.min = TYPE_MIN_VALUE (TREE_TYPE (vr_result.min));
|
||||
else if (supports_overflow_infinity (TREE_TYPE (vr_result.min)))
|
||||
vr_result.min =
|
||||
negative_overflow_infinity (TREE_TYPE (vr_result.min));
|
||||
}
|
||||
|
||||
/* Similarly, if the new maximum is smaller or larger than
|
||||
the previous one, go all the way to +INF. */
|
||||
if (cmp_max < 0 || cmp_max > 0)
|
||||
{
|
||||
if (!needs_overflow_infinity (TREE_TYPE (vr_result.max))
|
||||
|| !vrp_var_may_overflow (lhs, phi))
|
||||
vr_result.max = TYPE_MAX_VALUE (TREE_TYPE (vr_result.max));
|
||||
else if (supports_overflow_infinity (TREE_TYPE (vr_result.max)))
|
||||
vr_result.max =
|
||||
positive_overflow_infinity (TREE_TYPE (vr_result.max));
|
||||
}
|
||||
|
||||
/* If we dropped either bound to +-INF then if this is a loop
|
||||
PHI node SCEV may known more about its value-range. */
|
||||
if ((cmp_min > 0 || cmp_min < 0
|
||||
|| cmp_max < 0 || cmp_max > 0)
|
||||
&& current_loops
|
||||
&& (l = loop_containing_stmt (phi))
|
||||
&& l->header == gimple_bb (phi))
|
||||
adjust_range_with_scev (&vr_result, l, phi, lhs);
|
||||
|
||||
/* If we will end up with a (-INF, +INF) range, set it to
|
||||
VARYING. Same if the previous max value was invalid for
|
||||
the type and we end up with vr_result.min > vr_result.max. */
|
||||
if ((vrp_val_is_max (vr_result.max)
|
||||
&& vrp_val_is_min (vr_result.min))
|
||||
|| compare_values (vr_result.min,
|
||||
vr_result.max) > 0)
|
||||
goto varying;
|
||||
}
|
||||
|
||||
/* If the new range is different than the previous value, keep
|
||||
|
@ -7650,6 +7670,12 @@ execute_vrp (void)
|
|||
rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
|
||||
scev_initialize ();
|
||||
|
||||
/* Estimate number of iterations - but do not use undefined behavior
|
||||
for this. We can't do this lazily as other functions may compute
|
||||
this using undefined behavior. */
|
||||
free_numbers_of_iterations_estimates ();
|
||||
estimate_numbers_of_iterations (false);
|
||||
|
||||
insert_range_assertions ();
|
||||
|
||||
to_remove_edges = VEC_alloc (edge, heap, 10);
|
||||
|
|
Loading…
Add table
Reference in a new issue