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