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 ();
+}

Reply via email to