Merge pull request #17900 from unknownbrackets/irjit-vsgelt

irjit: Implement vsge/vslt
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2023-08-13 19:59:14 +02:00
commit d6cdb6e5d9
9 files changed
+114 -104

No files matched your search

+1 -1
View File
@@ -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
View File
@@ -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]);
+1 -1
View File
@@ -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" },
+1 -1
View File
@@ -138,12 +138,12 @@ enum class IROp : u8 {
FSat0_1,
FSatMinus1_1,
FpCondFromReg,
FpCondToReg,
FpCtrlFromReg,
FpCtrlToReg,
VfpuCtrlToReg,
ZeroFpCond,
FCmp,
FCmovVfpuCC,
+3 -4
View File
@@ -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;
+1 -1
View File
@@ -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:
+5 -2
View File
@@ -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);
+5 -4
View File
@@ -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);
+1 -1
View File
@@ -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: