This PR shows an issue in the must-alias oracle (stmt_kills_ref_p) which when determining must-alias by finding a common base in two reference trees doesn't handle trailing arrays correctly. The fix is to do array-at-struct-end detection on-the-fly by recording the innermost ARRAY_REF we drop when searching for the common base and not allow that to be an array_at_struct_end_p. Similar to trunk array_at_struct_end_p this doesn't allow sub-arrays to be flexible, for (*)[2'][3''] only ' is allowed to expand below the declared bound (the artificial case of ' having just one element and thus effectively not being an array and '' being a flexible array is not supported by GCC).
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Poking more holes appreciated ;) Richard. 2017-08-21 Richard Biener <rguent...@suse.de> PR middle-end/81884 * tree-ssa-alias.c (stmt_kills_ref_p): Handle array accesses at struct end conservatively when comparing common bases. * g++.dg/torture/pr81884.C: New testcase. Index: gcc/tree-ssa-alias.c =================================================================== --- gcc/tree-ssa-alias.c (revision 251103) +++ gcc/tree-ssa-alias.c (working copy) @@ -2415,6 +2415,7 @@ stmt_kills_ref_p (gimple *stmt, ao_ref * if (ref->ref) { tree base = ref->ref; + tree innermost_dropped_array_ref = NULL_TREE; if (handled_component_p (base)) { tree saved_lhs0 = NULL_TREE; @@ -2434,6 +2435,11 @@ stmt_kills_ref_p (gimple *stmt, ao_ref * TREE_OPERAND (base, 0) = saved_base0; if (res) break; + /* Remember if we drop an array-ref that we need to + double-check not being at struct end. */ + if (TREE_CODE (base) == ARRAY_REF + || TREE_CODE (base) == ARRAY_RANGE_REF) + innermost_dropped_array_ref = base; /* Otherwise drop handled components of the access. */ base = saved_base0; } @@ -2442,15 +2448,22 @@ stmt_kills_ref_p (gimple *stmt, ao_ref * TREE_OPERAND (lhs, 0) = saved_lhs0; } /* Finally check if the lhs has the same address and size as the - base candidate of the access. */ - if (lhs == base - || (((TYPE_SIZE (TREE_TYPE (lhs)) - == TYPE_SIZE (TREE_TYPE (base))) - || (TYPE_SIZE (TREE_TYPE (lhs)) - && TYPE_SIZE (TREE_TYPE (base)) - && operand_equal_p (TYPE_SIZE (TREE_TYPE (lhs)), - TYPE_SIZE (TREE_TYPE (base)), 0))) - && operand_equal_p (lhs, base, OEP_ADDRESS_OF))) + base candidate of the access. Watch out if we have dropped + an array-ref that was at struct end, this means ref->ref may + be outside of the TYPE_SIZE of its base. */ + if ((! innermost_dropped_array_ref + || ! array_at_struct_end_p (innermost_dropped_array_ref, false)) + && (lhs == base + || (((TYPE_SIZE (TREE_TYPE (lhs)) + == TYPE_SIZE (TREE_TYPE (base))) + || (TYPE_SIZE (TREE_TYPE (lhs)) + && TYPE_SIZE (TREE_TYPE (base)) + && operand_equal_p (TYPE_SIZE (TREE_TYPE (lhs)), + TYPE_SIZE (TREE_TYPE (base)), + 0))) + && operand_equal_p (lhs, base, + OEP_ADDRESS_OF + | OEP_MATCH_SIDE_EFFECTS)))) return true; } Index: gcc/testsuite/g++.dg/torture/pr81884.C =================================================================== --- gcc/testsuite/g++.dg/torture/pr81884.C (nonexistent) +++ gcc/testsuite/g++.dg/torture/pr81884.C (working copy) @@ -0,0 +1,39 @@ +/* { dg-do run } */ + +typedef unsigned long uint64_t; + +struct value_t { + uint64_t _count; + value_t(uint64_t c) : _count(c) {} +}; + +struct X { + value_t eventTime; + uint64_t arr[0]; +}; + +X* x; + +__attribute__((noclone, noinline)) +void initialize() +{ + x->arr[0] = 11; + x->arr[1] = 12; + x->eventTime = value_t(10); + x->arr[2] = 13; + x->arr[3] = 14; +} + +int main() +{ + char buffer[sizeof(X) + sizeof(uint64_t)*4]; + x = (X*)buffer; + x->eventTime = value_t(999); + x->arr[0] = 1; + x->arr[1] = 2; + x->arr[2] = 3; + x->arr[3] = 4; + initialize(); + if (x->arr[0] != 11 || x->arr[1] != 12 || x->arr[2] != 13 || x->arr[3] != 14) + __builtin_abort (); +}