[PATCH] Use get_range_info during number of iterations analysis
Jakub Jelinek
jakub@redhat.com
Wed Nov 6 17:32:00 GMT 2013
On Wed, Nov 06, 2013 at 06:13:42PM +0100, Jakub Jelinek wrote:
> I've looked at the above testcase to see why we aren't able to determine
> the number of iterations upper bound properly here.
And here is a patch that uses get_range_info during # of iterations
analysis, so that for your testcase we can actually find out that it has
at most 2 latch executions and at most 3 header executions.
On that testcase, bound_difference is actually called with n_5(D) + 0xffffffff
and 0 and we don't have range info for n_5(D), because we had better range
info only for the SSA_NAMEs temporarily created for the assertions.
But with the previously posted patch, we have reasonable range info on the
PHI of the IV at loop->header, and as that PHI has n_5(D) as one of its
arguments (the one from preheader edge), we can still use that range info
when inside of the loop for # of iters purposes, even when it might be
wider range than strictly necessary (but not in this case).
So, the patch looks at both get_range_info of var itself and of all the
results of PHIs on loop->header that have var as PHI arg from the preheader
edge, and ands all the ranges together.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2013-11-06 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.
--- gcc/tree-ssa-loop-niter.c.jj 2013-10-24 10:19:21.000000000 +0200
+++ gcc/tree-ssa-loop-niter.c 2013-11-06 14:37:47.445220588 +0100
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.
#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
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 v
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, tre
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);
Jakub
More information about the Gcc-patches
mailing list