https://gcc.gnu.org/g:cf791f625f246add50d178e8a466408d17595efc

commit r17-5767-gcf791f625f246add50d178e8a466408d17595efc
Author: Vladimir N. Makarov <[email protected]>
Date:   Fri Oct 30 16:32:57 2026 -0400

    [PR 128251][LRA]: Spill (plus (reg) (const)) for memory constraint
    
    In the PR test case the operand (argp) can be only in memory for given
    insn.  Register elimination transforms (argp) into (plus (reg)
    (const)) and LRA has no code to spill it (LRA can spill only reg).
    The patch implements this code.
    
    gcc/ChangeLog:
    
            PR rtl-optimization/128251
            * lra-constraints.cc (reg_plus_const_p): New function.
            (process_alt_operands): Use it.
            (process_address_1): Use reg_plus_const_p.
            (curr_insn_transform): Spill (plus (reg) (const)) for memory
            constraint.
    
    gcc/testsuite/ChangeLog:
    
            PR rtl-optimization/128251
            * gcc.target/i386/pr128251.c: New.

Diff:
---
 gcc/lra-constraints.cc                   | 46 ++++++++++++++++++++++++++++----
 gcc/testsuite/gcc.target/i386/pr128251.c | 16 +++++++++++
 2 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index 40bdd26b3763..3d5731a77064 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -2140,6 +2140,14 @@ spilled_pseudo_p (rtx op)
          && REGNO (op) >= FIRST_PSEUDO_REGISTER && in_mem_p (REGNO (op)));
 }
 
+/* Return true if OP is (plus (reg) (const)).  */
+static inline bool
+reg_plus_const_p (rtx op)
+{
+  return (GET_CODE (op) == PLUS && REG_P (XEXP (op, 0))
+         && CONSTANT_P (XEXP (op, 1)));
+}
+
 /* Return true if X is a general constant.  */
 static inline bool
 general_constant_p (rtx x)
@@ -2964,7 +2972,11 @@ process_alt_operands (int only_alternative)
                          || MEM_P (op) || REG_P (op)
                          /* We can restore the equiv insn by a
                             reload.  */
-                         || equiv_substition_p[nop])
+                         || equiv_substition_p[nop]
+                         /* It can be a sum produced by elimination of a
+                            register. We can materialized into a register and
+                            then spill into memory.  */
+                         || reg_plus_const_p (op))
                        badop = false;
                      constmemok = true;
                      offmemok = true;
@@ -4429,9 +4441,7 @@ process_address_1 (int nop, bool check_only_p,
       if (REG_P (new_reg)
          && last_insn != insns
          && (set = single_set (last_insn)) != NULL_RTX
-         && GET_CODE (SET_SRC (set)) == PLUS
-         && REG_P (XEXP (SET_SRC (set), 0))
-         && CONSTANT_P (XEXP (SET_SRC (set), 1)))
+         && reg_plus_const_p (SET_SRC (set)))
        {
          *ad.inner = SET_SRC (set);
          if (valid_address_p (op, &ad, cn))
@@ -5301,12 +5311,38 @@ curr_insn_transform (bool check_only_p)
 
              lra_emit_move (new_reg, addr);
              if (align_p)
-               emit_move_insn (new_reg, gen_rtx_AND (GET_MODE (new_reg), 
new_reg, XEXP (*loc, 1)));
+               emit_move_insn (new_reg, gen_rtx_AND (GET_MODE (new_reg),
+                                                     new_reg, XEXP (*loc, 1)));
            }
          before = end_sequence ();
          *loc = new_reg;
          lra_update_dup (curr_id, i);
        }
+      else if (goal_alt_matched[i][0] == -1 && goal_alt_offmemok[i]
+              && reg_plus_const_p (op))
+       {
+         /* Materialize the sum probably produced by elimination of a register
+            and then spill it into memory to satisfy the memory constraint.  */
+         machine_mode mode = curr_operand_mode[i];
+         enum reg_class rclass
+           = base_reg_class (mode, ADDR_SPACE_GENERIC, PLUS, SCRATCH, op,
+                             curr_insn);
+         rtx mem_pseudo;
+
+         if (get_reload_reg (curr_static_id->operand[i].type, mode, op,
+                             rclass, NULL, false, false, "elimination sum",
+                             &new_reg))
+           {
+             push_to_sequence (before);
+             lra_emit_move (new_reg, op);
+             mem_pseudo = lra_create_new_reg (mode, NULL_RTX, NO_REGS,
+                                              NULL, "elimination sum mem");
+             emit_insn (emit_spill_move (true, mem_pseudo, new_reg));
+             before = end_sequence ();
+             *curr_id->operand_loc[i] = mem_pseudo;
+             lra_update_dup (curr_id, i);
+           }
+       }
       else if (goal_alt_matched[i][0] == -1)
        {
          machine_mode mode;
diff --git a/gcc/testsuite/gcc.target/i386/pr128251.c 
b/gcc/testsuite/gcc.target/i386/pr128251.c
new file mode 100644
index 000000000000..d7a1ecdfa782
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr128251.c
@@ -0,0 +1,16 @@
+/* PR rtl-optimization/128251 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern long double rsp;
+struct __attribute__((aligned(32))) m256_2_struct {
+    int x1, x2;
+};
+void check_struct_passing2(struct m256_2_struct ms
+                           __attribute__((__unused__))) {
+
+    if (!((unsigned long)&ms.x1 == rsp + 8))
+        __builtin_abort();
+    if (!((unsigned long)&ms.x2 == rsp + 40))
+        __builtin_abort();
+}

Reply via email to