lra: emit caller-save register spills before call insn [PR116028]

LRA emits insns to save caller-save registers in the
inheritance/splitting pass. In this pass, LRA builds EBBs (Extended
Basic Block) and traverses the insns in the EBBs in reverse order from
the last insn to the first insn. When LRA sees a write to a pseudo (that
has been assigned a caller-save register), and there is a read following
the write, with an intervening call insn between the write and read,
then LRA generates a spill immediately after the write and a restore
immediately before the read. The spill is needed because the call insn
will clobber the caller-save register.

If there is a write insn and a call insn in two separate BBs but
belonging to the same EBB, the spill insn gets generated in the BB
containing the write insn. If the write insn is in the entry BB, then
the spill insn that is generated in the entry BB prevents shrink wrap
from happening. This is because the spill insn references the stack
pointer and hence the prolog gets generated in the entry BB itself.

This patch ensures that the spill insn is generated before the call insn
instead of after the write. This is also more efficient as the spill now
occurs only in the path containing the call.

2024-08-01  Surya Kumari Jangala  <jskum...@linux.ibm.com>

gcc/
        PR rtl-optimization/PR116028
        * lra-constraints.cc (split_reg): Spill register before call
        insn.
        (latest_call_insn): New variable.
        (inherit_in_ebb): Track the latest call insn.

gcc/testsuite/
        PR rtl-optimization/PR116028
        * gcc.dg/ira-shrinkwrap-prep-1.c: Remove xfail for powerpc.
        * gcc.dg/pr10474.c: Remove xfail for powerpc.
---

diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index 92b343fa99a..34f2461f791 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -143,6 +143,7 @@ static int bb_reload_num;
    (NULL otherwise), its data (basic block, the insn data, the insn
    static data, and the mode of each operand).  */
 static rtx_insn *curr_insn;
+static rtx_insn *latest_call_insn;
 static rtx curr_insn_set;
 static basic_block curr_bb;
 static lra_insn_recog_data_t curr_id;
@@ -6286,10 +6287,14 @@ split_reg (bool before_p, int original_regno, rtx_insn 
*insn,
                         after_p ? restore : NULL,
                         call_save_p
                         ?  "Add reg<-save" : "Add reg<-split");
-  lra_process_new_insns (insn, before_p ? save : NULL,
-                        before_p ? NULL : save,
-                        call_save_p
-                        ?  "Add save<-reg" : "Add split<-reg");
+  if (call_save_p)
+    lra_process_new_insns (PREV_INSN (latest_call_insn), NULL, save,
+                          "Add save<-reg");
+  else
+    lra_process_new_insns (insn, before_p ? save : NULL,
+                          before_p ? NULL : save,
+                          call_save_p
+                          ?  "Add save<-reg" : "Add split<-reg");
   if (nregs > 1 || original_regno < FIRST_PSEUDO_REGISTER)
     /* If we are trying to split multi-register.  We should check
        conflicts on the next assignment sub-pass.  IRA can allocate on
@@ -6773,6 +6778,7 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail)
   last_processed_bb = NULL;
   CLEAR_HARD_REG_SET (potential_reload_hard_regs);
   live_hard_regs = eliminable_regset | lra_no_alloc_regs;
+  latest_call_insn = NULL;
   /* We don't process new insns generated in the loop. */
   for (curr_insn = tail; curr_insn != PREV_INSN (head); curr_insn = prev_insn)
     {
@@ -6985,6 +6991,7 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail)
              last_call_for_abi[callee_abi.id ()] = calls_num;
              full_and_partial_call_clobbers
                |= callee_abi.full_and_partial_reg_clobbers ();
+             latest_call_insn = curr_insn;
              if ((cheap = find_reg_note (curr_insn,
                                          REG_RETURNED, NULL_RTX)) != NULL_RTX
                  && ((cheap = XEXP (cheap, 0)), true)
diff --git a/gcc/testsuite/gcc.dg/ira-shrinkwrap-prep-1.c 
b/gcc/testsuite/gcc.dg/ira-shrinkwrap-prep-1.c
index a95637abbe5..8c150972f95 100644
--- a/gcc/testsuite/gcc.dg/ira-shrinkwrap-prep-1.c
+++ b/gcc/testsuite/gcc.dg/ira-shrinkwrap-prep-1.c
@@ -26,4 +26,4 @@ bar (long a)
 
 /* { dg-final { scan-rtl-dump "Will split live ranges of parameters" "ira" } } 
*/
 /* { dg-final { scan-rtl-dump "Split live-range of register" "ira" { xfail { ! 
aarch64*-*-* } } } } */
-/* { dg-final { scan-rtl-dump "Performing shrink-wrapping" "pro_and_epilogue" 
{ xfail powerpc*-*-* } } } */
+/* { dg-final { scan-rtl-dump "Performing shrink-wrapping" "pro_and_epilogue" 
} } */
diff --git a/gcc/testsuite/gcc.dg/pr10474.c b/gcc/testsuite/gcc.dg/pr10474.c
index a4af536ec28..b5393d5b6e3 100644
--- a/gcc/testsuite/gcc.dg/pr10474.c
+++ b/gcc/testsuite/gcc.dg/pr10474.c
@@ -13,4 +13,4 @@ void f(int *i)
 }
 
 /* XFAIL due to PR70681.  */ 
-/* { dg-final { scan-rtl-dump "Performing shrink-wrapping" "pro_and_epilogue"  
{ xfail arm*-*-* powerpc*-*-* } } } */
+/* { dg-final { scan-rtl-dump "Performing shrink-wrapping" "pro_and_epilogue"  
{ xfail arm*-*-* } } } */

Reply via email to