From 2b36e0a625a5162cafa44e7fc32eacb7af985a8f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Aug 2023 09:42:16 -0700 Subject: [PATCH 1/3] irjit: ZeroFpCond -> FpCondFromReg. We already have a zero reg, so this is more useful and symmetrical. --- Core/MIPS/IR/IRCompFPU.cpp | 2 +- Core/MIPS/IR/IRInst.cpp | 2 +- Core/MIPS/IR/IRInst.h | 2 +- Core/MIPS/IR/IRInterpreter.cpp | 7 +++---- Core/MIPS/IR/IRNativeCommon.cpp | 2 +- Core/MIPS/IR/IRPassSimplify.cpp | 7 +++++-- Core/MIPS/RiscV/RiscVCompSystem.cpp | 9 +++++---- Core/MIPS/x86/IRToX86.cpp | 2 +- 8 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Core/MIPS/IR/IRCompFPU.cpp b/Core/MIPS/IR/IRCompFPU.cpp index 3c3ed87d03..e83f3a709f 100644 --- a/Core/MIPS/IR/IRCompFPU.cpp +++ b/Core/MIPS/IR/IRCompFPU.cpp @@ -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; } diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp index 5cdfc3824a..bc7d9f4a9a 100644 --- a/Core/MIPS/IR/IRInst.cpp +++ b/Core/MIPS/IR/IRInst.cpp @@ -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" }, diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index f626204791..dd93ed823b 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -138,12 +138,12 @@ enum class IROp : u8 { FSat0_1, FSatMinus1_1, + FpCondFromReg, FpCondToReg, FpCtrlFromReg, FpCtrlToReg, VfpuCtrlToReg, - ZeroFpCond, FCmp, FCmovVfpuCC, diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index fd5ecf7a13..1beed06f8d 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -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; diff --git a/Core/MIPS/IR/IRNativeCommon.cpp b/Core/MIPS/IR/IRNativeCommon.cpp index 523849e376..a8ec952737 100644 --- a/Core/MIPS/IR/IRNativeCommon.cpp +++ b/Core/MIPS/IR/IRNativeCommon.cpp @@ -287,8 +287,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: diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index beecf7264e..577f80579e 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -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); diff --git a/Core/MIPS/RiscV/RiscVCompSystem.cpp b/Core/MIPS/RiscV/RiscVCompSystem.cpp index c6c0070751..dbfa392a2b 100644 --- a/Core/MIPS/RiscV/RiscVCompSystem.cpp +++ b/Core/MIPS/RiscV/RiscVCompSystem.cpp @@ -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); diff --git a/Core/MIPS/x86/IRToX86.cpp b/Core/MIPS/x86/IRToX86.cpp index f543025cdb..a9ba6761b9 100644 --- a/Core/MIPS/x86/IRToX86.cpp +++ b/Core/MIPS/x86/IRToX86.cpp @@ -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: From 5d20f2aabdb271972e94c87f6f00050a66843be8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Aug 2023 09:57:19 -0700 Subject: [PATCH 2/3] irjit: Simplify VecDo3. --- Core/MIPS/IR/IRCompVFPU.cpp | 167 +++++++++++++++++------------------- 1 file changed, 78 insertions(+), 89 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index ab6906ae32..d4f361c143 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -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; } @@ -837,40 +838,28 @@ namespace MIPSComp { } 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 + case VecDo3Op::VSLT: // vslt + DISABLE; break; } } From 23c79f8e7fc9ebbb4f95b3229168077cec825220 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 13 Aug 2023 10:10:48 -0700 Subject: [PATCH 3/3] irjit: Implement vsge/vslt. These are not ideal especially for SIMD, but they do work. Improves performance in Silent Hill on RISC-V by like 20%. --- Core/MIPS/IR/IRCompVFPU.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index d4f361c143..374ebf8f3a 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -837,6 +837,11 @@ 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 (type) { case VecDo3Op::VADD: // d[i] = s[i] + t[i]; break; //vadd @@ -858,12 +863,25 @@ namespace MIPSComp { 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 - DISABLE; + 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]);