From c38d04a10c6457a719d2fad692d84bd216190b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Sep 2026 15:14:20 -0600 Subject: [PATCH] RISC-V/LoongArch IR: Get vrot's sine and cosine from one call Like arm64 and x64, call vfpu_sincos_packed and split the double it returns. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/MIPS/LoongArch64/LoongArch64CompFPU.cpp | 27 ++++++++++++-------- Core/MIPS/RiscV/RiscVCompFPU.cpp | 27 ++++++++++++-------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/Core/MIPS/LoongArch64/LoongArch64CompFPU.cpp b/Core/MIPS/LoongArch64/LoongArch64CompFPU.cpp index 5a19b7f14b..3685594c57 100644 --- a/Core/MIPS/LoongArch64/LoongArch64CompFPU.cpp +++ b/Core/MIPS/LoongArch64/LoongArch64CompFPU.cpp @@ -562,7 +562,7 @@ void LoongArch64JitBackend::CompIR_RoundingMode(IRInst inst) { void LoongArch64JitBackend::CompIR_FSpecial(IRInst inst) { CONDITIONAL_DISABLE; - auto callFuncF_F = [&](float (*func)(float)) { + auto callWithF0 = [&](const u8 *func) { regs_.FlushBeforeCall(); WriteDebugProfilerStatus(IRProfilerStatus::MATH_HELPER); @@ -579,6 +579,10 @@ void LoongArch64JitBackend::CompIR_FSpecial(IRInst inst) { FLD_S(F0, CTXREG, offset); } QuickCallFunction(func, SCRATCH1); + }; + + auto callFuncF_F = [&](float (*func)(float)) { + callWithF0((const u8 *)func); regs_.MapFPR(inst.dest, MIPSMap::NOINIT); // If it's already F0, we're done - MapReg doesn't actually overwrite the reg in that case. @@ -627,17 +631,18 @@ void LoongArch64JitBackend::CompIR_FSpecial(IRInst inst) { break; case IROp::FSinCos: - { - // Two calls here. The frontend makes sure dest doesn't overlap src1. - IRInst sinInst = inst; - sinInst.op = IROp::FSin; - CompIR_FSpecial(sinInst); - IRInst cosInst = inst; - cosInst.op = IROp::FCos; - cosInst.dest = inst.dest + 1; - CompIR_FSpecial(cosInst); + // The sine comes back in the low 32 bits of F0, the cosine in the high. + callWithF0((const u8 *)&vfpu_sincos_packed); + MOVFR2GR_S(SCRATCH1, F0); + MOVFRH2GR_S(SCRATCH2, F0); + regs_.SpillLockFPR(inst.dest, inst.dest + 1); + regs_.MapFPR(inst.dest, MIPSMap::NOINIT); + regs_.MapFPR(inst.dest + 1, MIPSMap::NOINIT); + regs_.ReleaseSpillLockFPR(inst.dest, inst.dest + 1); + MOVGR2FR_W(regs_.F(inst.dest), SCRATCH1); + MOVGR2FR_W(regs_.F(inst.dest + 1), SCRATCH2); + WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT); break; - } default: INVALIDOP; diff --git a/Core/MIPS/RiscV/RiscVCompFPU.cpp b/Core/MIPS/RiscV/RiscVCompFPU.cpp index 9460554f47..2caeea4b94 100644 --- a/Core/MIPS/RiscV/RiscVCompFPU.cpp +++ b/Core/MIPS/RiscV/RiscVCompFPU.cpp @@ -589,7 +589,7 @@ void RiscVJitBackend::CompIR_FSpecial(IRInst inst) { #error Currently hard float is required. #endif - auto callFuncF_F = [&](float (*func)(float)) { + auto callWithF10 = [&](const u8 *func) { regs_.FlushBeforeCall(); WriteDebugProfilerStatus(IRProfilerStatus::MATH_HELPER); @@ -602,6 +602,10 @@ void RiscVJitBackend::CompIR_FSpecial(IRInst inst) { FL(32, F10, CTXREG, offset); } QuickCallFunction(func, SCRATCH1); + }; + + auto callFuncF_F = [&](float (*func)(float)) { + callWithF10((const u8 *)func); regs_.MapFPR(inst.dest, MIPSMap::NOINIT); // If it's already F10, we're done - MapReg doesn't actually overwrite the reg in that case. @@ -650,17 +654,18 @@ void RiscVJitBackend::CompIR_FSpecial(IRInst inst) { break; case IROp::FSinCos: - { - // Two calls here. The frontend makes sure dest doesn't overlap src1. - IRInst sinInst = inst; - sinInst.op = IROp::FSin; - CompIR_FSpecial(sinInst); - IRInst cosInst = inst; - cosInst.op = IROp::FCos; - cosInst.dest = inst.dest + 1; - CompIR_FSpecial(cosInst); + // The sine comes back in the low 32 bits of F10, the cosine in the high. + callWithF10((const u8 *)&vfpu_sincos_packed); + FMV(FMv::X, FMv::D, SCRATCH1, F10); + regs_.SpillLockFPR(inst.dest, inst.dest + 1); + regs_.MapFPR(inst.dest, MIPSMap::NOINIT); + regs_.MapFPR(inst.dest + 1, MIPSMap::NOINIT); + regs_.ReleaseSpillLockFPR(inst.dest, inst.dest + 1); + FMV(FMv::W, FMv::X, regs_.F(inst.dest), SCRATCH1); + SRLI(SCRATCH1, SCRATCH1, 32); + FMV(FMv::W, FMv::X, regs_.F(inst.dest + 1), SCRATCH1); + WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT); break; - } default: INVALIDOP;