The following makes us infer loop bounds for loops like

 <bb 3>:
  # str_28 = PHI <"foo"(2), str_10(4)>
...
  str_10 = str_28 + 1;
  _4 = *str_10;
  if (_4 != 0)
    goto <bb 4>;
  else
    goto <bb 8>;

  <bb 4>:
  goto <bb 3>;

or

  <bb 3>:
  # p_15 = PHI <p_6(3), &a(2)>
  p_6 = p_15 + 1;
  *p_15 = 0;
...
  if (n.1_5 > i_8)
    goto <bb 3>;
  else
    goto <bb 4>;

Boostrap and regtest pending on x86_64-unknown-linux-gnu.

Honza - is there a symtab way of querying whether DECL_SIZE of
a decl is "correct"?  I know to better exclude extern decls
and commons, but for example C++ may have stronger rules.

Thanks,
Richard.

2014-10-16  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/63278
        * tree-ssa-loop-niter.c: Include tree-dfa.h.
        (struct ilb_data): Add pointer to outermost reference.
        (idx_infer_loop_bounds): Handle plain MEM_REFs of STRING_CSTs
        and DECLs.
        (infer_loop_bounds_from_ref): Adjust.

        * gcc.dg/tree-ssa/loop-41.c: New testcase.
        * gcc.dg/tree-ssa/loop-42.c: Likewise.

Index: gcc/tree-ssa-loop-niter.c
===================================================================
--- gcc/tree-ssa-loop-niter.c   (revision 216258)
+++ gcc/tree-ssa-loop-niter.c   (working copy)
@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3.
 #include "stringpool.h"
 #include "tree-ssanames.h"
 #include "wide-int-print.h"
+#include "tree-dfa.h"
 
 
 #define SWAP(X, Y) do { affine_iv *tmp = (X); (X) = (Y); (Y) = tmp; } while (0)
@@ -2775,6 +2776,7 @@ struct ilb_data
 {
   struct loop *loop;
   gimple stmt;
+  tree ref;
 };
 
 static bool
@@ -2787,7 +2789,10 @@ idx_infer_loop_bounds (tree base, tree *
   struct loop *loop = data->loop;
   bool reliable = true;
 
-  if (TREE_CODE (base) != ARRAY_REF)
+  if (TREE_CODE (base) != ARRAY_REF
+      && (TREE_CODE (base) != MEM_REF
+         || base != data->ref
+         || !integer_zerop (TREE_OPERAND (base, 1))))
     return true;
 
   /* For arrays at the end of the structure, we are not guaranteed that they
@@ -2816,8 +2821,46 @@ idx_infer_loop_bounds (tree base, tree *
       || chrec_contains_symbols_defined_in_loop (init, loop->num))
     return true;
 
-  low = array_ref_low_bound (base);
-  high = array_ref_up_bound (base);
+  if (TREE_CODE (base) == MEM_REF)
+    {
+      HOST_WIDE_INT offset;
+      tree decl;
+      if (TREE_CODE (init) != ADDR_EXPR)
+       return true;
+      decl = get_addr_base_and_unit_offset (TREE_OPERAND (init, 0), &offset);
+      if (!decl
+         || offset != 0)
+       return true;
+      /* If this is a bare MEM_REF with a pointer IV that starts at
+         offset zero of an object with known size we can easily compute
+        an upper bound for the pointer IV.  */
+      if (TREE_CODE (decl) == STRING_CST)
+       {
+         low = size_zero_node;
+         high = size_int (TREE_STRING_LENGTH (decl));
+       }
+      else if (DECL_P (decl)
+              && ((TREE_STATIC (decl) && !DECL_COMMON (decl))
+                  || auto_var_in_fn_p (decl, cfun->decl)))
+       {
+         low = size_zero_node;
+         if (TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST)
+           return true;
+         high = DECL_SIZE_UNIT (decl);
+       }
+      else
+       return true;
+      /* We only require an upper estimate for high.  So only
+        if we can, subtract the size of the access.  */
+      if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (base))) == INTEGER_CST)
+       high = size_binop (MINUS_EXPR,
+                          high, TYPE_SIZE_UNIT (TREE_TYPE (base)));
+    }
+  else
+    {
+      low = array_ref_low_bound (base);
+      high = array_ref_up_bound (base);
+    }
 
   /* The case of nonconstant bounds could be handled, but it would be
      complicated.  */
@@ -2879,6 +2922,7 @@ infer_loop_bounds_from_ref (struct loop
 
   data.loop = loop;
   data.stmt = stmt;
+  data.ref = ref;
   for_each_index (&ref, idx_infer_loop_bounds, &data);
 }
 
Index: gcc/testsuite/gcc.dg/tree-ssa/loop-42.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/loop-42.c     (revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/loop-42.c     (working copy)
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-cunroll-details" } */
+
+extern void abort (void);
+int a = -1;
+int n = sizeof (int);
+int main()
+{
+  char *p;
+  int i;
+  for (i = 0, p = (char *)&a; i < n; ++i)
+    *p++ = 0;
+  if (a != 0)
+    abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump "loop with 4 iterations completely unrolled" 
"cunroll" } } */
+/* { dg-final { cleanup-tree-dump "cunroll" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/loop-41.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/loop-41.c     (revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/loop-41.c     (working copy)
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fdump-tree-cunroll-details" } */
+
+extern void abort (void);
+
+static inline unsigned int hashString2(const char* str)
+{
+  unsigned int hash = 5381;
+  while (*str) {
+      hash += (hash << 5) + *str;
+      str++;
+  }
+  return hash;
+}
+
+int main()
+{
+  unsigned int hash = hashString2("foo");
+  if (hash != 193491849)
+    abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump "loop with 4 iterations completely unrolled" 
"cunroll" } } */
+/* { dg-final { cleanup-tree-dump "cunroll" } } */

Reply via email to