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" } } */