From: Konstantinos Eleftheriou Date: Fri, 22 May 2026 13:09:49 +0000 (+0200) Subject: store_integral_bit_field: Graceful fallback when SUBREG narrowing fails [PR123754] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=188731cde7a5b36df6aea08eec035ceece150ce9;p=thirdparty%2Fgcc.git store_integral_bit_field: Graceful fallback when SUBREG narrowing fails [PR123754] 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. --- diff --git a/gcc/expmed.cc b/gcc/expmed.cc index e4433384c59..da1b5b63287 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 00000000000..f0609909774 --- /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 00000000000..4478413237a --- /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; +}