mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
riscv: Implement FSin/similar.
This commit is contained in:
parent
921bd2391c
commit
6b632a103d
4 changed files with 79 additions and 7 deletions
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue