From: Takayuki 'January June' Suwa Date: Sat, 10 May 2025 19:51:11 +0000 (+0900) Subject: xtensa: Fix up unwanted spills of SFmode hard registers holding function arguments... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6d73d75a7c04caf3457297400372f87765b9a653;p=thirdparty%2Fgcc.git 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 --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