https://gcc.gnu.org/g:2edb50a310896da72710dba7724a3b4a541a1cbb

commit r16-1065-g2edb50a310896da72710dba7724a3b4a541a1cbb
Author: Alexandre Oliva <ol...@adacore.com>
Date:   Mon Jun 2 20:21:45 2025 -0300

    [lra] force reg update after spilling to memory [PR120424]
    
    In the added C++ testcase, a stack slot at a negative sp offset is
    used to hold a value across a call.
    
    There are a couple of causes that directly lead to this outcome:
    
    - the -fstack-clash-protection and -fnon-call-exception options, that
    cause arm_frame_pointer_required to flip from false to true when the
    first pseudo gets spilled to memory;
    
    - when the affected pseudo is spilled to memory, we fail to update lra
    regno info, because the insns that reference it are already on the
    lra_constraint_insn_stack;
    
    There is another potentially-related issue:
    
    - when we notice that the frame pointer can no longer be eliminated to
    the stack pointer, we immediately clear can_eliminate, and also
    prev_can_eliminate, but update_reg_eliminate relied on the latter to
    tell that it needs to propagate a previous_offset to the
    newly-selected elimination, or restore the original offsets.
    
    This patch ensures that we update insn register info after spilling a
    pseudo to memory, and enables update_reg_eliminate to recognize the
    case in which a previously-preferred elimination is disabled
    regardless of prev_can_eliminate.
    
    
    for  gcc/ChangeLog
    
            PR rtl-optimization/120424
            PR middle-end/118939
            * lra-spills.cc (spill_pseudos): Update insn regno info.
            * lra-eliminations.cc (update_reg_eliminate): Recognize
            disabling of active elimination regardless of
            prev_can_eliminate.
    
    for  gcc/testsuite/ChangeLog
    
            PR rtl-optimization/120424
            PR middle-end/118939
            * g++.target/arm/pr120424.C: New.
            * gnat.dg/controlled9.adb: New.
            * gnat.dg/controlled9_pkg.ads: New.

Diff:
---
 gcc/lra-eliminations.cc                   |  2 +-
 gcc/lra-spills.cc                         |  2 +-
 gcc/testsuite/g++.target/arm/pr120424.C   | 34 +++++++++++++++++++++++++++++++
 gcc/testsuite/gnat.dg/controlled9.adb     | 10 +++++++++
 gcc/testsuite/gnat.dg/controlled9_pkg.ads |  5 +++++
 5 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc
index d84a7d1ee99f..bb708b007a4e 100644
--- a/gcc/lra-eliminations.cc
+++ b/gcc/lra-eliminations.cc
@@ -1185,7 +1185,7 @@ update_reg_eliminate (bitmap insns_with_changed_offsets)
          setup_can_eliminate (ep, false);
          continue;
        }
-      if (ep->can_eliminate != prev && elimination_map[ep->from] == ep)
+      if (!ep->can_eliminate && elimination_map[ep->from] == ep)
        {
          /* We cannot use this elimination anymore -- find another
             one.  */
diff --git a/gcc/lra-spills.cc b/gcc/lra-spills.cc
index fc912c43ce6e..4febc693d283 100644
--- a/gcc/lra-spills.cc
+++ b/gcc/lra-spills.cc
@@ -556,7 +556,7 @@ spill_pseudos (void)
                fprintf (lra_dump_file,
                         "Changing spilled pseudos to memory in insn #%u\n",
                         INSN_UID (insn));
-             lra_push_insn (insn);
+             lra_push_insn_and_update_insn_regno_info (insn);
              if (lra_reg_spill_p || targetm.different_addr_displacement_p ())
                lra_set_used_insn_alternative (insn, LRA_UNKNOWN_ALT);
            }
diff --git a/gcc/testsuite/g++.target/arm/pr120424.C 
b/gcc/testsuite/g++.target/arm/pr120424.C
new file mode 100644
index 000000000000..4d0e49013c04
--- /dev/null
+++ b/gcc/testsuite/g++.target/arm/pr120424.C
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=armv7 -O2 -fstack-clash-protection 
-fnon-call-exceptions" } */
+/* { dg-final { scan-assembler-not {#-8} } } */
+/* LRA register elimination gets confused when register spilling
+   causes arm_frame_pointer_required to switch from false to true, and
+   ends up using a stack slot below sp.  */
+
+void f() {
+  int i = 0, j = 0;
+  asm ("" : : "m" (i), "m" (j));
+}
+
+void g(void (*fn[])(), int i)
+{
+  auto fn0 = fn[i+0];
+  auto fn1 = fn[i+1];
+  auto fn2 = fn[i+2];
+  auto fn3 = fn[i+3];
+  fn0();
+  fn1();
+  if (!fn2)
+    throw i+2;
+  fn2();
+  fn3();
+  fn0();
+  fn1();
+}
+
+int
+main()
+{
+  void (*fn[4])() = { f, f, f, f };
+  g (fn, 0);
+}
diff --git a/gcc/testsuite/gnat.dg/controlled9.adb 
b/gcc/testsuite/gnat.dg/controlled9.adb
new file mode 100644
index 000000000000..fb7acce854e1
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/controlled9.adb
@@ -0,0 +1,10 @@
+--  { dg-do run }
+--  { dg-options "-O1 -fstack-check" }
+--  from PR middle-end/118939
+
+with Controlled9_Pkg;
+procedure Controlled9 is
+   S : constant Controlled9_Pkg.T_Access := new Controlled9_Pkg.T;
+begin
+   null;
+end Controlled9;       
diff --git a/gcc/testsuite/gnat.dg/controlled9_pkg.ads 
b/gcc/testsuite/gnat.dg/controlled9_pkg.ads
new file mode 100644
index 000000000000..d0e7c28273e9
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/controlled9_pkg.ads
@@ -0,0 +1,5 @@
+with Ada.Finalization;
+package Controlled9_Pkg is
+   type T is new Ada.Finalization.Controlled with null record;
+   type T_Access is access all T;
+end Controlled9_Pkg;

Reply via email to