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 <[email protected]>
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" } } */