diff --git a/Core/MIPS/RiscV/RiscVCompFPU.cpp b/Core/MIPS/RiscV/RiscVCompFPU.cpp index 84c7faa832..9d08930848 100644 --- a/Core/MIPS/RiscV/RiscVCompFPU.cpp +++ b/Core/MIPS/RiscV/RiscVCompFPU.cpp @@ -257,13 +257,70 @@ void RiscVJit::CompIR_RoundingMode(IRInst inst) { void RiscVJit::CompIR_FSpecial(IRInst inst) { CONDITIONAL_DISABLE; +#ifdef __riscv_float_abi_soft +#error Currently hard float is required. +#endif + + auto callFuncF_F = [&](float (*func)(float)){ + gpr.FlushBeforeCall(); + fpr.FlushBeforeCall(); + // It might be in a non-volatile register. + if (fpr.IsMapped(inst.src1)) { + FMV(32, F10, fpr.R(inst.src1)); + } else { + int offset = offsetof(MIPSState, f) + inst.src1 * 4; + FL(32, F10, CTXREG, offset); + } + QuickCallFunction(func); + + fpr.MapReg(inst.dest, MIPSMap::NOINIT); + // If it's already F10, we're done - MapReg doesn't actually overwrite the reg in that case. + if (fpr.R(inst.dest) != F10) { + FMV(32, fpr.R(inst.dest), F10); + } + }; + switch (inst.op) { case IROp::FSin: + callFuncF_F(&vfpu_sin); + break; + case IROp::FCos: + callFuncF_F(&vfpu_cos); + break; + case IROp::FRSqrt: + fpr.MapDirtyIn(inst.dest, inst.src1); + FSQRT(32, fpr.R(inst.dest), fpr.R(inst.src1)); + + // Ugh, we can't really avoid a temp here. Probably not worth a permanent one. + LI(SCRATCH1, 1.0f); + { + // TODO: Smarter allocation of a temp reg? + RiscVReg tempReg = fpr.R(inst.dest) == F31 ? F30 : F31; + fpr.FlushRiscVReg(tempReg); + FMV(FMv::W, FMv::X, tempReg, SCRATCH1); + FDIV(32, fpr.R(inst.dest), tempReg, fpr.R(inst.dest)); + } + break; + case IROp::FRecip: + fpr.MapDirtyIn(inst.dest, inst.src1); + LI(SCRATCH1, 1.0f); + if (inst.dest != inst.src1) { + // This is the easy case. + FMV(FMv::W, FMv::X, fpr.R(inst.dest), SCRATCH1); + FDIV(32, fpr.R(inst.dest), fpr.R(inst.dest), fpr.R(inst.src1)); + } else { + RiscVReg tempReg = fpr.R(inst.dest) == F31 ? F30 : F31; + fpr.FlushRiscVReg(tempReg); + FMV(FMv::W, FMv::X, tempReg, SCRATCH1); + FDIV(32, fpr.R(inst.dest), tempReg, fpr.R(inst.src1)); + } + break; + case IROp::FAsin: - CompIR_Generic(inst); + callFuncF_F(&vfpu_asin); break; default: diff --git a/Core/MIPS/RiscV/RiscVRegCache.h b/Core/MIPS/RiscV/RiscVRegCache.h index 72d680dc9b..10305f5e25 100644 --- a/Core/MIPS/RiscV/RiscVRegCache.h +++ b/Core/MIPS/RiscV/RiscVRegCache.h @@ -140,6 +140,7 @@ public: void FlushBeforeCall(); void FlushAll(); void FlushR(IRRegIndex r); + void FlushRiscVReg(RiscVGen::RiscVReg r); void DiscardR(IRRegIndex r); RiscVGen::RiscVReg GetAndLockTempR(); @@ -163,7 +164,6 @@ private: RiscVGen::RiscVReg AllocateReg(); RiscVGen::RiscVReg FindBestToSpill(bool unusedOnly, bool *clobbered); RiscVGen::RiscVReg RiscVRegForFlush(IRRegIndex r); - void FlushRiscVReg(RiscVGen::RiscVReg r); void SetRegImm(RiscVGen::RiscVReg reg, u64 imm); void AddMemBase(RiscVGen::RiscVReg reg); int GetMipsRegOffset(IRRegIndex r); diff --git a/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp b/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp index 3277bcda89..7721477731 100644 --- a/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp +++ b/Core/MIPS/RiscV/RiscVRegCacheFPU.cpp @@ -27,9 +27,6 @@ using namespace RiscVGen; using namespace RiscVJitConstants; -using namespace RiscVGen; -using namespace RiscVJitConstants; - RiscVRegCacheFPU::RiscVRegCacheFPU(MIPSState *mipsState, MIPSComp::JitOptions *jo) : mips_(mipsState), jo_(jo) {} @@ -279,6 +276,24 @@ RiscVReg RiscVRegCacheFPU::RiscVRegForFlush(IRRegIndex r) { } } +void RiscVRegCacheFPU::FlushBeforeCall() { + // Note: don't set this false at the end, since we don't flush everything. + if (!pendingFlush_) { + return; + } + + // These registers are not preserved by function calls. + for (int i = 0; i <= 7; ++i) { + FlushRiscVReg(RiscVReg(F0 + i)); + } + for (int i = 10; i <= 17; ++i) { + FlushRiscVReg(RiscVReg(F0 + i)); + } + for (int i = 28; i <= 31; ++i) { + FlushRiscVReg(RiscVReg(F0 + i)); + } +} + void RiscVRegCacheFPU::FlushAll() { if (!pendingFlush_) { // Nothing allocated. FPU regs are not nearly as common as GPR. diff --git a/Core/MIPS/RiscV/RiscVRegCacheFPU.h b/Core/MIPS/RiscV/RiscVRegCacheFPU.h index 934e312ca7..57d93fdb83 100644 --- a/Core/MIPS/RiscV/RiscVRegCacheFPU.h +++ b/Core/MIPS/RiscV/RiscVRegCacheFPU.h @@ -64,11 +64,12 @@ public: void MapInIn(IRRegIndex rd, IRRegIndex rs); void MapDirtyIn(IRRegIndex rd, IRRegIndex rs, bool avoidLoad = true); void MapDirtyInIn(IRRegIndex rd, IRRegIndex rs, IRRegIndex rt, bool avoidLoad = true); - void Map4Dirty(IRRegIndex rdbase, bool avoidLoad = true); void Map4DirtyIn(IRRegIndex rdbase, IRRegIndex rsbase, bool avoidLoad = true); void Map4DirtyInIn(IRRegIndex rdbase, IRRegIndex rsbase, IRRegIndex rtbase, bool avoidLoad = true); + void FlushBeforeCall(); void FlushAll(); void FlushR(IRRegIndex r); + void FlushRiscVReg(RiscVGen::RiscVReg r); void DiscardR(IRRegIndex r); RiscVGen::RiscVReg R(int preg); // Returns a cached register @@ -78,7 +79,6 @@ private: RiscVGen::RiscVReg AllocateReg(); RiscVGen::RiscVReg FindBestToSpill(bool unusedOnly, bool *clobbered); RiscVGen::RiscVReg RiscVRegForFlush(IRRegIndex r); - void FlushRiscVReg(RiscVGen::RiscVReg r); int GetMipsRegOffset(IRRegIndex r); bool IsValidReg(IRRegIndex r) const;