When store forwarding is avoided without eliminating the load (the store
only partially covers it), the extension wrapping the load's MEM is
re-applied after the bit-insert sequence, reusing SET_DEST (load) as the
move destination. As the load insn is kept here, that rtx is now shared
between two insns. That is fine for a plain REG, but in the case that the
dest is a SUBREG, it must not be shared (verify_rtx_sharing ICEs).
Unshare the destination with copy_rtx when building the move.
Bootstrapped/regtested on AArch64, x86-64 and PowerPC.
PR rtl-optimization/126434
gcc/ChangeLog:
* avoid-store-forwarding.cc (process_store_forwarding): Unshare the
load destination when building the re-extension move.
gcc/testsuite/ChangeLog:
* gcc.dg/pr126434.c: New test.
---
gcc/avoid-store-forwarding.cc | 4 +++-
gcc/testsuite/gcc.dg/pr126434.c | 18 ++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.dg/pr126434.c
diff --git a/gcc/avoid-store-forwarding.cc b/gcc/avoid-store-forwarding.cc
index 67abd2e37bd6..141f96c3d848 100644
--- a/gcc/avoid-store-forwarding.cc
+++ b/gcc/avoid-store-forwarding.cc
@@ -444,7 +444,9 @@ process_store_forwarding (vec<store_fwd_info> &stores,
rtx_insn *load_insn,
else
move_src = dest;
- rtx move = gen_rtx_SET (SET_DEST (load), move_src);
+ /* In the non-elimination case the load insn is retained, so unshare
+ its destination to avoid sharing a SUBREG between two insns. */
+ rtx move = gen_rtx_SET (copy_rtx (SET_DEST (load)), move_src);
start_sequence ();
rtx_insn *insn = emit_insn (move);
diff --git a/gcc/testsuite/gcc.dg/pr126434.c b/gcc/testsuite/gcc.dg/pr126434.c
new file mode 100644
index 000000000000..b039ad0dfee6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126434.c
@@ -0,0 +1,18 @@
+/* PR rtl-optimization/126434 */
+/* { dg-do compile } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-O1 -favoid-store-forwarding
--param=store-forwarding-max-distance=146" } */
+
+/* The store partially covers the load, so the load is kept and its
+ zero-extension is re-applied over a SUBREG destination. */
+
+unsigned x;
+__int128 y;
+
+void
+foo ()
+{
+ __builtin_memset (&x, 0, 2);
+ y &= x;
+}
+
--
2.52.0