The multi-word narrowing path in store_integral_bit_field uses
simplify_gen_subreg followed by gcc_assert (op0).  The symmetric path
in extract_integral_bit_field was switched to force_subreg, but the
store side was deliberately left on simplify_gen_subreg because op0
is an lvalue.  When the subreg simplification fails (e.g. a vector
op0 punned through an int mode whose word-aligned subregs are rejected
by validate_subreg, as happens for V8SI on -mbig-endian aarch64),
the assert fires.

The avoid-store-forwarding pass (-favoid-store-forwarding) triggers
this: it routes such a vector op0 through store_integral_bit_field.

Replace the assert with a graceful fallback to store_split_bit_field,
mirroring the cross-word branch immediately above.  No change for
inputs where the narrowing succeeds.

Tested on AArch64, x86-64 and PowerPC BE.

        PR rtl-optimization/123754

gcc/ChangeLog:

        * expmed.cc (store_integral_bit_field): When the SUBREG
        narrowing fails, defer to store_split_bit_field instead of
        asserting.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/pr123754.c: New test.
        * gcc.target/aarch64/avoid-store-forwarding-be-2.c: New test.
---
 gcc/expmed.cc                                 | 18 ++++++--
 .../aarch64/avoid-store-forwarding-be-2.c     | 41 +++++++++++++++++++
 gcc/testsuite/gcc.target/aarch64/pr123754.c   | 15 +++++++
 3 files changed, 71 insertions(+), 3 deletions(-)
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/avoid-store-forwarding-be-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/pr123754.c

diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index e4433384c591..da1b5b632876 100644
--- a/gcc/expmed.cc
+++ b/gcc/expmed.cc
@@ -1064,9 +1064,21 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode 
op0_mode,
                                 value, value_mode, reverse);
          return true;
        }
-      op0 = simplify_gen_subreg (word_mode, op0, op0_mode.require (),
-                                bitnum / BITS_PER_WORD * UNITS_PER_WORD);
-      gcc_assert (op0);
+      rtx new_op0
+       = simplify_gen_subreg (word_mode, op0, op0_mode.require (),
+                              bitnum / BITS_PER_WORD * UNITS_PER_WORD);
+      if (!new_op0)
+       {
+         /* No valid word-mode SUBREG of op0 at this offset.  Defer to
+            store_split_bit_field, which addresses op0 a word at a time.  */
+         if (!fallback_p)
+           return false;
+         store_split_bit_field (op0, op0_mode, bitsize, bitnum,
+                                bitregion_start, bitregion_end,
+                                value, value_mode, reverse);
+         return true;
+       }
+      op0 = new_op0;
       op0_mode = word_mode;
       bitnum %= BITS_PER_WORD;
     }
diff --git a/gcc/testsuite/gcc.target/aarch64/avoid-store-forwarding-be-2.c 
b/gcc/testsuite/gcc.target/aarch64/avoid-store-forwarding-be-2.c
new file mode 100644
index 000000000000..f06099097747
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/avoid-store-forwarding-be-2.c
@@ -0,0 +1,41 @@
+/* PR rtl-optimization/123754 */
+/* { dg-do run } */
+/* { dg-require-effective-target aarch64_big_endian } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-O2 -favoid-store-forwarding" } */
+
+typedef unsigned __int128 u128;
+
+union u {
+  u128 v;
+  unsigned char b[16];
+};
+
+u128 __attribute__ ((noinline))
+foo (unsigned char x, unsigned char y, u128 init)
+{
+  union u u;
+  u.v = init;
+  u.b[0] = x;
+  u.b[15] = y;
+  return u.v;
+}
+
+int
+main (void)
+{
+  u128 init = ((u128) 0xfedcba9876543210ULL << 64) | 0x0123456789abcdefULL;
+  u128 r = foo (0xAA, 0xBB, init);
+
+  unsigned char *p = (unsigned char *) &r;
+  unsigned char *q = (unsigned char *) &init;
+
+  if (p[0] != 0xAA || p[15] != 0xBB)
+    __builtin_abort ();
+
+  for (int i = 1; i < 15; i++)
+    if (p[i] != q[i])
+      __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/pr123754.c 
b/gcc/testsuite/gcc.target/aarch64/pr123754.c
new file mode 100644
index 000000000000..4478413237ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr123754.c
@@ -0,0 +1,15 @@
+/* PR rtl-optimization/123754 */
+/* { dg-do compile } */
+/* { dg-require-effective-target aarch64_big_endian } */
+/* { dg-options "-O2 -favoid-store-forwarding" } */
+
+typedef __attribute__((__vector_size__(32))) int V;
+long long i;
+V g;
+
+void
+foo (V *v)
+{
+  __builtin_memcpy (v, &i, 5);
+  g *= *v;
+}
-- 
2.52.0

Reply via email to