riscv: Implement FSin/similar.

This commit is contained in:
Unknown W. Brackets 2023-07-29 08:02:41 -07:00
parent 921bd2391c
commit 6b632a103d
4 changed files with 79 additions and 7 deletions

View file

@ -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:

View file

@ -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);

View file

@ -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.

View file

@ -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;