From 268adf1aa1f8ccb54245403830db282ccb8d5f21 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Aug 2023 21:33:25 -0700 Subject: [PATCH] riscv: Implement scaled float/int convert. --- Core/MIPS/RiscV/RiscVCompFPU.cpp | 41 ++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/Core/MIPS/RiscV/RiscVCompFPU.cpp b/Core/MIPS/RiscV/RiscVCompFPU.cpp index 9dd2ea6958..c1491266da 100644 --- a/Core/MIPS/RiscV/RiscVCompFPU.cpp +++ b/Core/MIPS/RiscV/RiscVCompFPU.cpp @@ -254,10 +254,9 @@ void RiscVJitBackend::CompIR_FRound(IRInst inst) { void RiscVJitBackend::CompIR_FCvt(IRInst inst) { CONDITIONAL_DISABLE; + RiscVReg tempReg = INVALID_REG; switch (inst.op) { case IROp::FCvtWS: - case IROp::FCvtScaledWS: - case IROp::FCvtScaledSW: CompIR_Generic(inst); break; @@ -268,6 +267,44 @@ void RiscVJitBackend::CompIR_FCvt(IRInst inst) { FCVT(FConv::S, FConv::W, fpr.R(inst.dest), SCRATCH1); break; + case IROp::FCvtScaledWS: + if (cpu_info.RiscV_D) { + Round rm = Round::NEAREST_EVEN; + switch (inst.src2 >> 6) { + case 0: rm = Round::NEAREST_EVEN; break; + case 1: rm = Round::TOZERO; break; + case 2: rm = Round::UP; break; + case 3: rm = Round::DOWN; break; + } + + tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1); + // Prepare the double src1 and the multiplier. + FCVT(FConv::D, FConv::S, fpr.R(inst.dest), fpr.R(inst.src1)); + LI(SCRATCH1, 1UL << (inst.src2 & 0x1F)); + FCVT(FConv::D, FConv::WU, tempReg, SCRATCH1, rm); + + FMUL(64, fpr.R(inst.dest), fpr.R(inst.dest), tempReg, rm); + // NAN and clamping should all be correct. + FCVT(FConv::W, FConv::D, SCRATCH1, fpr.R(inst.dest), rm); + // TODO: Could combine with a transfer, often is one... + FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + } else { + CompIR_Generic(inst); + } + break; + + case IROp::FCvtScaledSW: + // TODO: This is probably proceeded by a GPR transfer, might be ideal to combine. + tempReg = fpr.MapDirtyInTemp(inst.dest, inst.src1); + FMV(FMv::X, FMv::W, SCRATCH1, fpr.R(inst.src1)); + FCVT(FConv::S, FConv::W, fpr.R(inst.dest), SCRATCH1); + + // Pre-divide so we can avoid any actual divide. + LI(SCRATCH1, 1.0f / (1UL << (inst.src2 & 0x1F))); + FMV(FMv::W, FMv::X, tempReg, SCRATCH1); + FMUL(32, fpr.R(inst.dest), fpr.R(inst.dest), tempReg); + break; + default: INVALIDOP; break;