diff options
author | Jakub Jelinek <jakub@redhat.com> | 2013-11-07 15:31:00 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2013-11-07 15:31:00 +0100 |
commit | 7190fdc1906cfdfee00dc32197bee568d8174b71 (patch) | |
tree | 34f58737caa85eb5c8e9db1492758091f6afb58e | |
parent | d23c0a32ab98d6c170970bb1ee319c6fc967852d (diff) | |
download | gcc-7190fdc1906cfdfee00dc32197bee568d8174b71.zip gcc-7190fdc1906cfdfee00dc32197bee568d8174b71.tar.gz gcc-7190fdc1906cfdfee00dc32197bee568d8174b71.tar.bz2 |
tree-ssa-loop-niter.c: Include tree-ssanames.h.
* tree-ssa-loop-niter.c: Include tree-ssanames.h.
(determine_value_range): Add loop argument. Use get_range_info to
improve range.
(bound_difference): Adjust caller.
* gcc.dg/tree-ssa/loop-39.c: New test.
From-SVN: r204516
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/loop-39.c | 26 | ||||
-rw-r--r-- | gcc/tree-ssa-loop-niter.c | 76 |
4 files changed, 107 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2dbbfef..a4bb664 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2013-11-07 Jakub Jelinek <jakub@redhat.com> + + * tree-ssa-loop-niter.c: Include tree-ssanames.h. + (determine_value_range): Add loop argument. Use get_range_info to + improve range. + (bound_difference): Adjust caller. + 2013-11-07 Richard Biener <rguenther@suse.de> Jakub Jelinek <jakub@redhat.com> diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 643d156..e28fce6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,7 @@ 2013-11-07 Jakub Jelinek <jakub@redhat.com> + * gcc.dg/tree-ssa/loop-39.c: New test. + * gcc.dg/unroll_1.c: Add -fno-tree-vrp to dg-options. * gcc.dg/unroll_2.c: Likewise. * gcc.dg/unroll_3.c: Likewise. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-39.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-39.c new file mode 100644 index 0000000..1f6bba4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-39.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-sccp-details" } */ + +int +foo (unsigned int n) +{ + int i, r = 1; + if (n > 0) + { + asm (""); + if (n < 10) + { + asm (""); + do + { + --n; + r *= 2; + } + while (n > 0); + } + } + return r + n; +} + +/* { dg-final { scan-tree-dump "# of iterations \[^\n\r]*, bounded by 8" "sccp" } } */ +/* { dg-final { cleanup-tree-dump "sccp" } } */ diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c index c3e0ef2..3014faa 100644 --- a/gcc/tree-ssa-loop-niter.c +++ b/gcc/tree-ssa-loop-niter.c @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "tree-inline.h" #include "tree-pass.h" +#include "tree-ssanames.h" #define SWAP(X, Y) do { affine_iv *tmp = (X); (X) = (Y); (Y) = tmp; } while (0) @@ -119,9 +120,12 @@ split_to_var_and_offset (tree expr, tree *var, mpz_t offset) in TYPE to MIN and MAX. */ static void -determine_value_range (tree type, tree var, mpz_t off, +determine_value_range (struct loop *loop, tree type, tree var, mpz_t off, mpz_t min, mpz_t max) { + double_int minv, maxv; + enum value_range_type rtype = VR_VARYING; + /* If the expression is a constant, we know its value exactly. */ if (integer_zerop (var)) { @@ -130,9 +134,73 @@ determine_value_range (tree type, tree var, mpz_t off, return; } + get_type_static_bounds (type, min, max); + + /* See if we have some range info from VRP. */ + if (TREE_CODE (var) == SSA_NAME && INTEGRAL_TYPE_P (type)) + { + edge e = loop_preheader_edge (loop); + gimple_stmt_iterator gsi; + + /* Either for VAR itself... */ + rtype = get_range_info (var, &minv, &maxv); + /* Or for PHI results in loop->header where VAR is used as + PHI argument from the loop preheader edge. */ + for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple phi = gsi_stmt (gsi); + double_int minc, maxc; + if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var + && (get_range_info (gimple_phi_result (phi), &minc, &maxc) + == VR_RANGE)) + { + if (rtype != VR_RANGE) + { + rtype = VR_RANGE; + minv = minc; + maxv = maxc; + } + else + { + minv = minv.max (minc, TYPE_UNSIGNED (type)); + maxv = maxv.min (maxc, TYPE_UNSIGNED (type)); + gcc_assert (minv.cmp (maxv, TYPE_UNSIGNED (type)) <= 0); + } + } + } + if (rtype == VR_RANGE) + { + mpz_t minm, maxm; + gcc_assert (minv.cmp (maxv, TYPE_UNSIGNED (type)) <= 0); + mpz_init (minm); + mpz_init (maxm); + mpz_set_double_int (minm, minv, TYPE_UNSIGNED (type)); + mpz_set_double_int (maxm, maxv, TYPE_UNSIGNED (type)); + mpz_add (minm, minm, off); + mpz_add (maxm, maxm, off); + /* If the computation may not wrap or off is zero, then this + is always fine. If off is negative and minv + off isn't + smaller than type's minimum, or off is positive and + maxv + off isn't bigger than type's maximum, use the more + precise range too. */ + if (nowrap_type_p (type) + || mpz_sgn (off) == 0 + || (mpz_sgn (off) < 0 && mpz_cmp (minm, min) >= 0) + || (mpz_sgn (off) > 0 && mpz_cmp (maxm, max) <= 0)) + { + mpz_set (min, minm); + mpz_set (max, maxm); + mpz_clear (minm); + mpz_clear (maxm); + return; + } + mpz_clear (minm); + mpz_clear (maxm); + } + } + /* If the computation may wrap, we know nothing about the value, except for the range of the type. */ - get_type_static_bounds (type, min, max); if (!nowrap_type_p (type)) return; @@ -405,8 +473,8 @@ bound_difference (struct loop *loop, tree x, tree y, bounds *bnds) mpz_init (maxx); mpz_init (miny); mpz_init (maxy); - determine_value_range (type, varx, offx, minx, maxx); - determine_value_range (type, vary, offy, miny, maxy); + determine_value_range (loop, type, varx, offx, minx, maxx); + determine_value_range (loop, type, vary, offy, miny, maxy); mpz_sub (bnds->below, minx, maxy); mpz_sub (bnds->up, maxx, miny); |