]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
xtensa: Fix up unwanted spills of SFmode hard registers holding function arguments...
authorTakayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
Sat, 10 May 2025 19:51:11 +0000 (04:51 +0900)
committerMax Filippov <jcmvbkbc@gmail.com>
Sun, 11 May 2025 19:38:59 +0000 (12:38 -0700)
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.

gcc/config/xtensa/xtensa.cc

index 53db06ec6f2ccff5f97563783b5c337847700c5a..621fb0aeb461f35995dc3ae227995a012c2bd500 100644 (file)
@@ -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