From 6d73d75a7c04caf3457297400372f87765b9a653 Mon Sep 17 00:00:00 2001 From: Takayuki 'January June' Suwa Date: Sun, 11 May 2025 04:51:11 +0900 Subject: [PATCH] xtensa: Fix up unwanted spills of SFmode hard registers holding function arguments/returns MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 | 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 -- 2.47.2