https://gcc.gnu.org/g:6d73d75a7c04caf3457297400372f87765b9a653

commit r16-529-g6d73d75a7c04caf3457297400372f87765b9a653
Author: Takayuki 'January June' Suwa <jjsuwa_sys3...@yahoo.co.jp>
Date:   Sun May 11 04:51:11 2025 +0900

    xtensa: Fix up unwanted spills of SFmode hard registers holding function 
arguments/returns
    
    Until now (presumably after transition to LRA), hard registers storing
    function arguments or return values ​​were spilling undesirably when
    TARGET_HARD_FLOAT is enabled.
    
         /* example */
         float test0(float a, float b) {
           return a + b;
         }
         extern float foo(void);
         float test1(void) {
           return foo() * 3.14f;
         }
    
         ;; before
         test0:
            entry   sp, 48
            wfr     f0, a2
            wfr     f1, a3
            add.s   f0, f0, f1
            s32i.n  a2, sp, 0       ;; unwanted spilling-out
            s32i.n  a3, sp, 4       ;;
            rfr     a2, f0
            retw.n
            .literal .LC1, 1078523331
         test1:
            entry   sp, 48
            call8   foo
            l32r    a8, .LC1
            wfr     f0, a10
            wfr     f1, a8
            mul.s   f0, f0, f1
            s32i.n  a10, sp, 0      ;; unwanted spilling-out
            rfr     a2, f0
            retw.n
    
    Ultimately, that is because the costs of moving between integer and
    floating-point hard registers are undefined and the default (large value)
    is used.  This patch fixes this.
    
         ;; after
         test0:
            entry   sp, 32
            wfr     f1, a2
            wfr     f0, a3
            add.s   f0, f1, f0
            rfr     a2, f0
            retw.n
            .literal .LC1, 1078523331
         test1:
            entry   sp, 32
            call8   foo
            l32r    a8, .LC1
            wfr     f1, a10
            wfr     f0, a8
            mul.s   f0, f1, f0
            rfr     a2, f0
            retw.n
    
    gcc/ChangeLog:
    
            * config/xtensa/xtensa.cc (xtensa_register_move_cost):
            Add appropriate move costs between AR_REGS and FP_REGS.

Diff:
---
 gcc/config/xtensa/xtensa.cc | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index 53db06ec6f2c..621fb0aeb461 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -4430,17 +4430,27 @@ static int
 xtensa_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
                           reg_class_t from, reg_class_t to)
 {
-  if (from == to && from != BR_REGS && to != BR_REGS)
+  /* If both are equal (except for BR_REGS) or belong to AR_REGS,
+     the cost is 2 (the default value).  */
+  if ((from == to && from != BR_REGS && to != BR_REGS)
+      || (reg_class_subset_p (from, AR_REGS)
+         && reg_class_subset_p (to, AR_REGS)))
     return 2;
-  else if (reg_class_subset_p (from, AR_REGS)
-          && reg_class_subset_p (to, AR_REGS))
-    return 2;
-  else if (reg_class_subset_p (from, AR_REGS) && to == ACC_REG)
-    return 3;
-  else if (from == ACC_REG && reg_class_subset_p (to, AR_REGS))
+
+  /* The cost between AR_REGS and FR_REGS must be <= 8 (2x the default
+     MEMORY_MOVE_COST) to avoid unwanted spills, and > 4 (2x the above
+     case) to avoid excessive register-to-register moves.  */
+  if ((reg_class_subset_p (from, AR_REGS) && to == FP_REGS)
+      || (from == FP_REGS && reg_class_subset_p (to, AR_REGS)))
+    return 5;
+
+  if ((reg_class_subset_p (from, AR_REGS) && to == ACC_REG)
+      || (from == ACC_REG && reg_class_subset_p (to, AR_REGS)))
     return 3;
-  else
-    return 10;
+
+  /* Otherwise, spills to stack (because greater than 2x the default
+     MEMORY_MOVE_COST).  */
+  return 10;
 }
 
 /* Compute a (partial) cost for rtx X.  Return true if the complete

Reply via email to