]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
avoid-store-forwarding: Re-apply extension after bit insert sequence [PR124713]
authorKonstantinos Eleftheriou <konstantinos.eleftheriou@vrull.eu>
Tue, 31 Mar 2026 12:12:33 +0000 (05:12 -0700)
committerPhilipp Tomsich <philipp.tomsich@vrull.eu>
Fri, 5 Jun 2026 15:27:29 +0000 (17:27 +0200)
The avoid-store-forwarding pass loses SIGN_EXTEND/ZERO_EXTEND
semantics when the forwarding target is an extending load that is
not fully eliminated.  The bit-field insert operates on the
full-width destination register, but does not re-apply the
extension, leaving stale upper bits from the original load.

Fix by emitting the corresponding extension after the bit insert
sequence for non-eliminated extending loads, mirroring what the
load-elimination path already does.

PR rtl-optimization/124713

gcc/ChangeLog:

* avoid-store-forwarding.cc (process_store_forwarding): Re-apply
SIGN_EXTEND/ZERO_EXTEND after bit insert sequence when the load is
not eliminated.

gcc/testsuite/ChangeLog:

* gcc.target/aarch64/pr124713.c: New test.

gcc/avoid-store-forwarding.cc
gcc/testsuite/gcc.target/aarch64/pr124713.c [new file with mode: 0644]

index bb015681c4588a56ba4c1ad085a1b0129d32e54c..67abd2e37bd64ac1ce73ba2f7ce486a67491dcca 100644 (file)
@@ -420,20 +420,34 @@ process_store_forwarding (vec<store_fwd_info> &stores, rtx_insn *load_insn,
       stores.ordered_remove (move_to_front);
     }
 
-  if (load_elim)
+  machine_mode outer_mode = GET_MODE (SET_DEST (load));
+  if (load_elim || outer_mode != load_mem_mode)
     {
-      machine_mode outer_mode = GET_MODE (SET_DEST (load));
-      rtx load_move;
-      rtx load_value = dest;
+      /* If the load is being eliminated, emit a move (with extension if
+        needed) from the temp register to the original load destination.
+        Otherwise, if the load has SIGN_EXTEND or ZERO_EXTEND wrapping
+        the MEM, the bit insert sequence may have modified bits that
+        affect the extension (e.g. the sign bit), so re-apply it.  */
+      rtx move_src;
       if (outer_mode != load_mem_mode)
        {
-         load_value = simplify_gen_unary (GET_CODE (SET_SRC (load)),
-                                          outer_mode, dest, load_mem_mode);
+         rtx ext_op = dest;
+         if (!load_elim)
+           {
+             ext_op = lowpart_subreg (load_mem_mode, dest, outer_mode);
+             if (!ext_op)
+               return false;
+           }
+         move_src = simplify_gen_unary (GET_CODE (SET_SRC (load)),
+                                        outer_mode, ext_op, load_mem_mode);
        }
-      load_move = gen_rtx_SET (SET_DEST (load), load_value);
+      else
+       move_src = dest;
+
+      rtx move = gen_rtx_SET (SET_DEST (load), move_src);
 
       start_sequence ();
-      rtx_insn *insn = emit_insn (load_move);
+      rtx_insn *insn = emit_insn (move);
       rtx_insn *seq = end_sequence ();
 
       if (recog_memoized (insn) < 0)
diff --git a/gcc/testsuite/gcc.target/aarch64/pr124713.c b/gcc/testsuite/gcc.target/aarch64/pr124713.c
new file mode 100644 (file)
index 0000000..798cf1f
--- /dev/null
@@ -0,0 +1,24 @@
+/* PR rtl-optimization/124713 */
+/* { dg-do run } */
+/* { dg-require-effective-target aarch64_little_endian } */
+/* { dg-options "-Og -favoid-store-forwarding -fwrapv" } */
+
+int x;
+long y;
+
+__attribute__((noipa)) long
+foo (short m)
+{
+  short b = m * 13;
+  __builtin_memset (1 + (char *) &b, x, 1);
+  long c = *(long *) __builtin_memset (&y, x, 4);
+  return c + b;
+}
+
+int
+main ()
+{
+  long x = foo (3840);
+  if (x)
+    __builtin_abort ();
+}