]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-ssa-loop-niter.c: Include tree-ssanames.h.
authorJakub Jelinek <jakub@redhat.com>
Thu, 7 Nov 2013 14:31:00 +0000 (15:31 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 7 Nov 2013 14:31:00 +0000 (15:31 +0100)
* 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

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/loop-39.c [new file with mode: 0644]
gcc/tree-ssa-loop-niter.c

index 2dbbfefa792111cc66966bb7ada7f863c27ea55b..a4bb664c35e0e511f972a2d945221899cdf68385 100644 (file)
@@ -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>
 
index 643d1569b376d088feb60ee79ff4c332df562c86..e28fce632c6c6b160fde5ec435e7576fff204c2f 100644 (file)
@@ -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 (file)
index 0000000..1f6bba4
--- /dev/null
@@ -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" } } */
index c3e0ef26af7c1adbcd9573ce171dc33b14d960d0..3014faae7968d0bc6f3249e8dedc7b945c04c1b1 100644 (file)
@@ -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);