mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-16 07:50:28 +02:00
Merge pull request #17900 from unknownbrackets/irjit-vsgelt
irjit: Implement vsge/vslt
This commit is contained in:
9 files changed
+114
-104
No files matched your search
@@ -102,7 +102,7 @@ void IRFrontend::Comp_FPUComp(MIPSOpcode op) {
|
||||
int opc = op & 0xF;
|
||||
if (opc >= 8) opc -= 8; // alias
|
||||
if (opc == 0) { // f, sf (signalling false)
|
||||
ir.Write(IROp::ZeroFpCond);
|
||||
ir.Write(IROp::FpCondFromReg, 0, MIPS_REG_ZERO);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+96
-89
@@ -729,47 +729,65 @@ namespace MIPSComp {
|
||||
// Vector arithmetic
|
||||
// d[N] = OP(s[N], t[N]) (see below)
|
||||
|
||||
enum class VecDo3Op : uint8_t {
|
||||
INVALID,
|
||||
VADD,
|
||||
VSUB,
|
||||
VDIV,
|
||||
VMUL,
|
||||
VMIN,
|
||||
VMAX,
|
||||
VSGE,
|
||||
VSLT,
|
||||
};
|
||||
VecDo3Op type = VecDo3Op::INVALID;
|
||||
|
||||
// Check that we can support the ops, and prepare temporary values for ops that need it.
|
||||
bool allowSIMD = true;
|
||||
switch (op >> 26) {
|
||||
case 24: //VFPU0
|
||||
switch ((op >> 23) & 7) {
|
||||
case 0: // d[i] = s[i] + t[i]; break; //vadd
|
||||
case 1: // d[i] = s[i] - t[i]; break; //vsub
|
||||
break;
|
||||
case 7: // d[i] = s[i] / t[i]; break; //vdiv
|
||||
if (!js.HasNoPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
INVALIDOP;
|
||||
case 0: type = VecDo3Op::VADD; break;
|
||||
case 1: type = VecDo3Op::VSUB; break;
|
||||
case 7: type = VecDo3Op::VDIV; break;
|
||||
default: INVALIDOP;
|
||||
}
|
||||
break;
|
||||
case 25: //VFPU1
|
||||
switch ((op >> 23) & 7) {
|
||||
case 0: // d[i] = s[i] * t[i]; break; //vmul
|
||||
break;
|
||||
default:
|
||||
INVALIDOP;
|
||||
case 0: type = VecDo3Op::VMUL; break;
|
||||
default: INVALIDOP;
|
||||
}
|
||||
break;
|
||||
case 27: //VFPU3
|
||||
switch ((op >> 23) & 7) {
|
||||
case 2: // vmin
|
||||
case 3: // vmax
|
||||
allowSIMD = false;
|
||||
break;
|
||||
case 6: // vsge
|
||||
case 7: // vslt
|
||||
allowSIMD = false;
|
||||
break;
|
||||
default:
|
||||
INVALIDOP;
|
||||
case 2: type = VecDo3Op::VMIN; break;
|
||||
case 3: type = VecDo3Op::VMAX; break;
|
||||
case 6: type = VecDo3Op::VSGE; break;
|
||||
case 7: type = VecDo3Op::VSLT; break;
|
||||
default: INVALIDOP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
INVALIDOP;
|
||||
default: INVALIDOP;
|
||||
}
|
||||
_assert_(type != VecDo3Op::INVALID);
|
||||
|
||||
bool allowSIMD = true;
|
||||
switch (type) {
|
||||
case VecDo3Op::VADD:
|
||||
case VecDo3Op::VSUB:
|
||||
case VecDo3Op::VMUL:
|
||||
break;
|
||||
case VecDo3Op::VDIV:
|
||||
if (!js.HasNoPrefix()) {
|
||||
DISABLE;
|
||||
}
|
||||
break;
|
||||
case VecDo3Op::VMIN:
|
||||
case VecDo3Op::VMAX:
|
||||
case VecDo3Op::VSGE:
|
||||
case VecDo3Op::VSLT:
|
||||
allowSIMD = false;
|
||||
break;
|
||||
}
|
||||
|
||||
VectorSize sz = GetVecSize(op);
|
||||
@@ -792,38 +810,21 @@ namespace MIPSComp {
|
||||
// If all three are consecutive 4, we're safe regardless of if we use temps so we should not check that here.
|
||||
if (allowSIMD && IsVec4(sz, dregs) && IsVec4(sz, sregs) && IsVec4(sz, tregs)) {
|
||||
IROp opFunc = IROp::Nop;
|
||||
switch (op >> 26) {
|
||||
case 24: //VFPU0
|
||||
switch ((op >> 23) & 7) {
|
||||
case 0: // d[i] = s[i] + t[i]; break; //vadd
|
||||
opFunc = IROp::Vec4Add;
|
||||
break;
|
||||
case 1: // d[i] = s[i] - t[i]; break; //vsub
|
||||
opFunc = IROp::Vec4Sub;
|
||||
break;
|
||||
case 7: // d[i] = s[i] / t[i]; break; //vdiv
|
||||
opFunc = IROp::Vec4Div;
|
||||
break;
|
||||
}
|
||||
switch (type) {
|
||||
case VecDo3Op::VADD: // d[i] = s[i] + t[i]; break; //vadd
|
||||
opFunc = IROp::Vec4Add;
|
||||
break;
|
||||
case 25: //VFPU1
|
||||
switch ((op >> 23) & 7)
|
||||
{
|
||||
case 0: // d[i] = s[i] * t[i]; break; //vmul
|
||||
opFunc = IROp::Vec4Mul;
|
||||
break;
|
||||
}
|
||||
case VecDo3Op::VSUB: // d[i] = s[i] - t[i]; break; //vsub
|
||||
opFunc = IROp::Vec4Sub;
|
||||
break;
|
||||
case 27: //VFPU3
|
||||
switch ((op >> 23) & 7)
|
||||
{
|
||||
case 2: // vmin
|
||||
case 3: // vmax
|
||||
case 6: // vsge
|
||||
case 7: // vslt
|
||||
DISABLE;
|
||||
break;
|
||||
}
|
||||
case VecDo3Op::VDIV: // d[i] = s[i] / t[i]; break; //vdiv
|
||||
opFunc = IROp::Vec4Div;
|
||||
break;
|
||||
case VecDo3Op::VMUL: // d[i] = s[i] * t[i]; break; //vmul
|
||||
opFunc = IROp::Vec4Mul;
|
||||
break;
|
||||
default:
|
||||
// Leave it Nop, disabled below.
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -836,45 +837,51 @@ namespace MIPSComp {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == VecDo3Op::VSGE || type == VecDo3Op::VSLT) {
|
||||
// TODO: Consider a dedicated op? For now, we abuse FpCond a bit.
|
||||
ir.Write(IROp::FpCondToReg, IRTEMP_0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
switch (op >> 26) {
|
||||
case 24: //VFPU0
|
||||
switch ((op >> 23) & 7) {
|
||||
case 0: // d[i] = s[i] + t[i]; break; //vadd
|
||||
ir.Write(IROp::FAdd, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case 1: // d[i] = s[i] - t[i]; break; //vsub
|
||||
ir.Write(IROp::FSub, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case 7: // d[i] = s[i] / t[i]; break; //vdiv
|
||||
ir.Write(IROp::FDiv, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
}
|
||||
switch (type) {
|
||||
case VecDo3Op::VADD: // d[i] = s[i] + t[i]; break; //vadd
|
||||
ir.Write(IROp::FAdd, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case 25: //VFPU1
|
||||
switch ((op >> 23) & 7) {
|
||||
case 0: // d[i] = s[i] * t[i]; break; //vmul
|
||||
ir.Write(IROp::FMul, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
}
|
||||
case VecDo3Op::VSUB: // d[i] = s[i] - t[i]; break; //vsub
|
||||
ir.Write(IROp::FSub, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case 27: //VFPU3
|
||||
switch ((op >> 23) & 7) {
|
||||
case 2: // vmin
|
||||
ir.Write(IROp::FMin, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case 3: // vmax
|
||||
ir.Write(IROp::FMax, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case 6: // vsge
|
||||
case 7: // vslt
|
||||
DISABLE;
|
||||
break;
|
||||
}
|
||||
case VecDo3Op::VDIV: // d[i] = s[i] / t[i]; break; //vdiv
|
||||
ir.Write(IROp::FDiv, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case VecDo3Op::VMUL: // d[i] = s[i] * t[i]; break; //vmul
|
||||
ir.Write(IROp::FMul, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case VecDo3Op::VMIN: // vmin
|
||||
ir.Write(IROp::FMin, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case VecDo3Op::VMAX: // vmax
|
||||
ir.Write(IROp::FMax, tempregs[i], sregs[i], tregs[i]);
|
||||
break;
|
||||
case VecDo3Op::VSGE: // vsge
|
||||
ir.Write(IROp::FCmp, (int)IRFpCompareMode::LessUnordered, sregs[i], tregs[i]);
|
||||
ir.Write(IROp::FpCondToReg, IRTEMP_1);
|
||||
ir.Write(IROp::XorConst, IRTEMP_1, IRTEMP_1, ir.AddConstant(1));
|
||||
ir.Write(IROp::FMovFromGPR, tempregs[i], IRTEMP_1);
|
||||
ir.Write(IROp::FCvtSW, tempregs[i], tempregs[i]);
|
||||
break;
|
||||
case VecDo3Op::VSLT: // vslt
|
||||
ir.Write(IROp::FCmp, (int)IRFpCompareMode::LessOrdered, sregs[i], tregs[i]);
|
||||
ir.Write(IROp::FpCondToReg, IRTEMP_1);
|
||||
ir.Write(IROp::FMovFromGPR, tempregs[i], IRTEMP_1);
|
||||
ir.Write(IROp::FCvtSW, tempregs[i], tempregs[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == VecDo3Op::VSGE || type == VecDo3Op::VSLT) {
|
||||
ir.Write(IROp::FpCondFromReg, IRTEMP_0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (dregs[i] != tempregs[i]) {
|
||||
ir.Write(IROp::FMov, dregs[i], tempregs[i]);
|
||||
|
||||
@@ -113,7 +113,7 @@ static const IRMeta irMeta[] = {
|
||||
{ IROp::FSatMinus1_1, "FSat(-1 - 1)", "FF" },
|
||||
{ IROp::FMovFromGPR, "FMovFromGPR", "FG" },
|
||||
{ IROp::FMovToGPR, "FMovToGPR", "GF" },
|
||||
{ IROp::ZeroFpCond, "ZeroFpCond", "" },
|
||||
{ IROp::FpCondFromReg, "FpCondFromReg", "_G" },
|
||||
{ IROp::FpCondToReg, "FpCondToReg", "G" },
|
||||
{ IROp::FpCtrlFromReg, "FpCtrlFromReg", "_G" },
|
||||
{ IROp::FpCtrlToReg, "FpCtrlToReg", "G" },
|
||||
|
||||
@@ -138,12 +138,12 @@ enum class IROp : u8 {
|
||||
FSat0_1,
|
||||
FSatMinus1_1,
|
||||
|
||||
FpCondFromReg,
|
||||
FpCondToReg,
|
||||
FpCtrlFromReg,
|
||||
FpCtrlToReg,
|
||||
VfpuCtrlToReg,
|
||||
|
||||
ZeroFpCond,
|
||||
FCmp,
|
||||
|
||||
FCmovVfpuCC,
|
||||
|
||||
@@ -850,6 +850,9 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
|
||||
break;
|
||||
}
|
||||
|
||||
case IROp::FpCondFromReg:
|
||||
mips->fpcond = mips->r[inst->dest];
|
||||
break;
|
||||
case IROp::FpCondToReg:
|
||||
mips->r[inst->dest] = mips->fpcond;
|
||||
break;
|
||||
@@ -1001,10 +1004,6 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) {
|
||||
break;
|
||||
}
|
||||
|
||||
case IROp::ZeroFpCond:
|
||||
mips->fpcond = 0;
|
||||
break;
|
||||
|
||||
case IROp::FMovFromGPR:
|
||||
memcpy(&mips->f[inst->dest], &mips->r[inst->src1], 4);
|
||||
break;
|
||||
|
||||
@@ -289,8 +289,8 @@ void IRNativeBackend::CompileIRInst(IRInst inst) {
|
||||
case IROp::SetCtrlVFPU:
|
||||
case IROp::SetCtrlVFPUReg:
|
||||
case IROp::SetCtrlVFPUFReg:
|
||||
case IROp::FpCondFromReg:
|
||||
case IROp::FpCondToReg:
|
||||
case IROp::ZeroFpCond:
|
||||
case IROp::FpCtrlFromReg:
|
||||
case IROp::FpCtrlToReg:
|
||||
case IROp::VfpuCtrlToReg:
|
||||
|
||||
@@ -740,6 +740,10 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts
|
||||
out.Write(inst);
|
||||
break;
|
||||
|
||||
case IROp::FpCondFromReg:
|
||||
gpr.MapDirtyIn(IRREG_FPCOND, inst.src1);
|
||||
out.Write(inst);
|
||||
break;
|
||||
case IROp::FpCondToReg:
|
||||
if (gpr.IsImm(IRREG_FPCOND)) {
|
||||
gpr.SetImm(inst.dest, gpr.GetImm(IRREG_FPCOND));
|
||||
@@ -779,7 +783,6 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts
|
||||
out.Write(inst);
|
||||
break;
|
||||
|
||||
case IROp::ZeroFpCond:
|
||||
case IROp::FCmp:
|
||||
gpr.MapDirty(IRREG_FPCOND);
|
||||
goto doDefault;
|
||||
@@ -1383,6 +1386,7 @@ bool ReorderLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts)
|
||||
|
||||
case IROp::MtHi:
|
||||
case IROp::MtLo:
|
||||
case IROp::FpCondFromReg:
|
||||
if (inst.src1 && otherRegs[inst.src1] != RegState::CHANGED)
|
||||
otherRegs[inst.src1] = RegState::READ;
|
||||
otherQueue.push_back(inst);
|
||||
@@ -1391,7 +1395,6 @@ bool ReorderLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts)
|
||||
|
||||
case IROp::Nop:
|
||||
case IROp::Downcount:
|
||||
case IROp::ZeroFpCond:
|
||||
if (queuing) {
|
||||
// These are freebies. Sometimes helps with delay slots.
|
||||
otherQueue.push_back(inst);
|
||||
|
||||
@@ -105,16 +105,17 @@ void RiscVJitBackend::CompIR_Transfer(IRInst inst) {
|
||||
FMV(FMv::X, FMv::W, gpr.R(IRREG_VFPU_CTRL_BASE + inst.dest), fpr.R(inst.src1));
|
||||
break;
|
||||
|
||||
case IROp::FpCondFromReg:
|
||||
gpr.MapDirtyIn(IRREG_FPCOND, inst.src1);
|
||||
MV(gpr.R(IRREG_FPCOND), gpr.R(inst.src1));
|
||||
break;
|
||||
|
||||
case IROp::FpCondToReg:
|
||||
gpr.MapDirtyIn(inst.dest, IRREG_FPCOND);
|
||||
MV(gpr.R(inst.dest), gpr.R(IRREG_FPCOND));
|
||||
gpr.MarkDirty(gpr.R(inst.dest), gpr.IsNormalized32(IRREG_FPCOND));
|
||||
break;
|
||||
|
||||
case IROp::ZeroFpCond:
|
||||
gpr.SetImm(IRREG_FPCOND, 0);
|
||||
break;
|
||||
|
||||
case IROp::FpCtrlFromReg:
|
||||
gpr.MapDirtyIn(IRREG_FPCOND, inst.src1, MapType::AVOID_LOAD_MARK_NORM32);
|
||||
LI(SCRATCH1, 0x0181FFFF);
|
||||
|
||||
@@ -259,6 +259,7 @@ void IRToX86::ConvertIRToNative(const IRInst *instructions, int count, const u32
|
||||
// Cross moves
|
||||
case IROp::FMovFromGPR:
|
||||
case IROp::FMovToGPR:
|
||||
case IROp::FpCondFromReg:
|
||||
case IROp::FpCondToReg:
|
||||
case IROp::VfpuCtrlToReg:
|
||||
|
||||
@@ -266,7 +267,6 @@ void IRToX86::ConvertIRToNative(const IRInst *instructions, int count, const u32
|
||||
case IROp::SetCtrlVFPU:
|
||||
case IROp::SetCtrlVFPUReg:
|
||||
case IROp::SetCtrlVFPUFReg:
|
||||
case IROp::ZeroFpCond:
|
||||
|
||||
// Block Exits
|
||||
case IROp::ExitToConst:
|
||||
|
||||
Reference in new issue
Block a user