The following patch avoids keeping the inherited MEM_ATTRs when
set_mem_attributes_minus_bitpos is called with a variable ARRAY_REF.
The inherited ones may not reflect the correct offset.

We try to preserve the MEM_EXPR from the base object expansion
but we have to make sure to also preserve the corresponding MEM_ALIAS_SET
then since otherwise path-based disambiguation gets confused.
The other choice we'd have would be to drop the MEM_EXPR but keep
the alias-set from the full reference.  Or, of course "improve"
MEM_EXPR generation to not "fail" in case the ARRAY_REF offset is
variable (we keep variable ARRAY_REFs in the MEM_EXPR if there's
a COMPONENT_REF ontop of the ref for example).  I 
understand the "inheriting" be exactly useful in the
case we otherwise give up (I've added an assert that we're not
inheriting from sth when creating a stack slot).

The expand_assignment fix could be treated separately (in different
code paths we are already preserving MEM_ALIAS_SET this way).

As said the alternative fix for set_mem_attrs_minus_bitpos would
be to remove all the ARRAY_REF special-casing and do the same
as we do for MEM_REF.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

Any comments?

Thanks,
Richard.

2020-06-03  Richard Biener  <rguent...@suse.de>

        PR middle-end/95493
        * emit-rtl.c (set_mem_attrs_minus_bitpos): Clear
        offset-known when the ARRAY_REF is variable.  If we end up
        inherting the MEM_EXPR from the original MEM_ATTRS then also
        inherit the corresponding MEM_ALIAS_SET.  Avoid altering
        MEM_KEEP_ALIAS_SET_P in that case.
        * expr.c (expand_assignment): Preserve MEM_ALIAS_SET when emitting
        the store.

        * g++.dg/torture/pr95493.C: New testcase.
---
 gcc/emit-rtl.c                         | 59 ++++++++++++++----------
 gcc/expr.c                             |  6 ++-
 gcc/testsuite/g++.dg/torture/pr95493.C | 62 ++++++++++++++++++++++++++
 3 files changed, 103 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/torture/pr95493.C

diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 2b790636366..09521b6f85e 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1964,8 +1964,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int 
objectp,
   refattrs = MEM_ATTRS (ref);
   if (refattrs)
     {
-      /* ??? Can this ever happen?  Calling this routine on a MEM that
-        already carries memory attributes should probably be invalid.  */
+      gcc_assert (! TYPE_P (t));
+      /* We are calling this function with attributes set up from expanding
+        the base of a memory reference as returned by get_inner_referece.  */
       attrs.expr = refattrs->expr;
       attrs.offset_known_p = refattrs->offset_known_p;
       attrs.offset = refattrs->offset;
@@ -2052,11 +2053,6 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int 
objectp,
            as = TYPE_ADDR_SPACE (TREE_TYPE (base));
        }
 
-      /* If this expression uses it's parent's alias set, mark it such
-        that we won't change it.  */
-      if (component_uses_parent_alias_set_from (t) != NULL_TREE)
-       MEM_KEEP_ALIAS_SET_P (ref) = 1;
-
       /* If this is a decl, set the attributes of the MEM from it.  */
       if (DECL_P (t))
        {
@@ -2114,6 +2110,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int 
objectp,
            }
          while (TREE_CODE (t2) == ARRAY_REF);
 
+         attrs.offset_known_p = false;
+         attrs.offset = 0;
+         apply_bitpos = 0;
          if (DECL_P (t2)
              || (TREE_CODE (t2) == COMPONENT_REF
                  /* For trailing arrays t2 doesn't have a size that
@@ -2141,24 +2140,38 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int 
objectp,
          apply_bitpos = bitpos;
        }
 
-      /* If this is a reference based on a partitioned decl replace the
-        base with a MEM_REF of the pointer representative we created
-        during stack slot partitioning.  */
-      if (attrs.expr
-         && VAR_P (base)
-         && ! is_global_var (base)
-         && cfun->gimple_df->decls_to_pointers != NULL)
+      /* If we chose to keep the MEM_EXPR from the inner reference
+        expansion make sure to also keep the corresponding alias-set
+        since otherwise path-based disambiguation is confused.  */
+      if (refattrs
+         && attrs.expr == refattrs->expr)
+       attrs.alias = refattrs->alias;
+      else if (attrs.expr)
        {
-         tree *namep = cfun->gimple_df->decls_to_pointers->get (base);
-         if (namep)
+         /* If this expression uses it's parent's alias set, mark it such
+            that we won't change it.  */
+         if (component_uses_parent_alias_set_from (t) != NULL_TREE)
+           MEM_KEEP_ALIAS_SET_P (ref) = 1;
+
+         /* If this is a reference based on a partitioned decl replace the
+            base with a MEM_REF of the pointer representative we created
+            during stack slot partitioning.  */
+         if (attrs.expr
+             && VAR_P (base)
+             && ! is_global_var (base)
+             && cfun->gimple_df->decls_to_pointers != NULL)
            {
-             attrs.expr = unshare_expr (attrs.expr);
-             tree *orig_base = &attrs.expr;
-             while (handled_component_p (*orig_base))
-               orig_base = &TREE_OPERAND (*orig_base, 0);
-             tree aptrt = reference_alias_ptr_type (*orig_base);
-             *orig_base = build2 (MEM_REF, TREE_TYPE (*orig_base), *namep,
-                                  build_int_cst (aptrt, 0));
+             tree *namep = cfun->gimple_df->decls_to_pointers->get (base);
+             if (namep)
+               {
+                 attrs.expr = unshare_expr (attrs.expr);
+                 tree *orig_base = &attrs.expr;
+                 while (handled_component_p (*orig_base))
+                   orig_base = &TREE_OPERAND (*orig_base, 0);
+                 tree aptrt = reference_alias_ptr_type (*orig_base);
+                 *orig_base = build2 (MEM_REF, TREE_TYPE (*orig_base), *namep,
+                                      build_int_cst (aptrt, 0));
+               }
            }
        }
 
diff --git a/gcc/expr.c b/gcc/expr.c
index 6b75028e7f1..2357178fce4 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -5354,6 +5354,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
        }
       else
        {
+         alias_set_type alias_set;
          if (MEM_P (to_rtx))
            {
              /* If the field is at offset zero, we could have been given the
@@ -5362,7 +5363,10 @@ expand_assignment (tree to, tree from, bool nontemporal)
              set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos);
              if (volatilep)
                MEM_VOLATILE_P (to_rtx) = 1;
+             alias_set = MEM_ALIAS_SET (to_rtx);
            }
+         else
+           alias_set = get_alias_set (to);
 
          gcc_checking_assert (known_ge (bitpos, 0));
          if (optimize_bitfield_assignment_op (bitsize, bitpos,
@@ -5373,7 +5377,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
          else
            result = store_field (to_rtx, bitsize, bitpos,
                                  bitregion_start, bitregion_end,
-                                 mode1, from, get_alias_set (to),
+                                 mode1, from, alias_set,
                                  nontemporal, reversep);
        }
 
diff --git a/gcc/testsuite/g++.dg/torture/pr95493.C 
b/gcc/testsuite/g++.dg/torture/pr95493.C
new file mode 100644
index 00000000000..5e05056854d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr95493.C
@@ -0,0 +1,62 @@
+// { dg-do run }
+// { dg-additional-options "-std=c++17" }
+
+struct verify
+{
+  const bool m_failed = false;
+
+  [[gnu::noinline]] void print_hex(const void* x, int n) const
+  {
+    const auto* bytes = static_cast<const unsigned char*>(x);
+    for (int i = 0; i < n; ++i)
+      __builtin_printf((i && i % 4 == 0) ? "'%02x" : "%02x", bytes[i]);
+    __builtin_printf("\n");
+  }
+
+  template <typename... Ts>
+  verify(bool ok, const Ts&... extra_info) : m_failed(!ok)
+  {
+    if (m_failed)
+      (print_hex(&extra_info, sizeof(extra_info)), ...);
+  }
+
+  ~verify()
+  {
+    if (m_failed)
+      __builtin_abort();
+  }
+};
+
+using K [[gnu::vector_size(16)]] = int;
+
+int
+main()
+{
+  int count = 1;
+  asm("" : "+m"(count));
+  verify(count == 1, 0, "", 0);
+
+  {
+    struct SW
+    {
+      K d;
+    };
+    struct
+    {
+      SW d;
+    } xx;
+    SW& x = xx.d;
+    x = SW(); // [0, 0, 0, 0]
+    for (int i = 3; i >= 2; --i)
+      {
+        x.d[i] = -1; // [0, 0, 0, -1] ...
+        int a = [](K y) {
+          for (int j = 0; j < 4; ++j)
+            if (y[j] != 0)
+              return j;
+          return -1;
+        }(x.d);
+        verify(a == i, 0, 0, 0, 0, i, x);
+      }
+  }
+}
-- 
2.26.2

Reply via email to