From a5a2671af3ba2d32714616045139711fdf15dea7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Jul 2023 11:57:30 -0700 Subject: [PATCH 1/2] irjit: Implement vf2ix. Used in LittleBigPlanet when playing intro movies. --- Core/MIPS/IR/IRCompVFPU.cpp | 50 +++++++++++++++++++++++++++++++- Core/MIPS/IR/IRInst.cpp | 1 + Core/MIPS/IR/IRInst.h | 4 +-- Core/MIPS/IR/IRInterpreter.cpp | 28 +++++++++++++++++- Core/MIPS/IR/IRPassSimplify.cpp | 1 + Core/MIPS/RiscV/RiscVCompFPU.cpp | 1 + Core/MIPS/RiscV/RiscVJit.cpp | 1 + 7 files changed, 81 insertions(+), 5 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 70128b4c62..fafd6668bf 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -986,7 +986,55 @@ namespace MIPSComp { // d[N] = int(S[N] * mult) // Note: saturates on overflow. - DISABLE; + VectorSize sz = GetVecSize(op); + int n = GetNumVectorElements(sz); + + int imm = (op >> 16) & 0x1f; + + u8 sregs[4], dregs[4]; + GetVectorRegsPrefixS(sregs, sz, _VS); + GetVectorRegsPrefixD(dregs, sz, _VD); + + // Same values as FCR31. + uint8_t rmode = (op >> 21) & 3; + if (((op >> 21) & 0x1C) != 0x10) + INVALIDOP; + + u8 tempregs[4]; + for (int i = 0; i < n; ++i) { + if (!IsOverlapSafe(dregs[i], n, sregs)) { + tempregs[i] = IRVTEMP_PFX_T + i; // Need IRVTEMP_0 for the scaling factor + } else { + tempregs[i] = dregs[i]; + } + } + if (imm != 0) { + for (int i = 0; i < n; i++) + ir.Write(IROp::FCvtScaledWS, dregs[i], sregs[i], (uint8_t)(imm | (rmode << 6))); + } else { + for (int i = 0; i < n; i++) { + switch (rmode) { + case 0: // vf2in + ir.Write(IROp::FRound, dregs[i], sregs[i]); + break; + + case 1: // vf2iz + ir.Write(IROp::FTrunc, dregs[i], sregs[i]); + break; + + case 2: // vf2iu + ir.Write(IROp::FCeil, dregs[i], sregs[i]); + break; + + case 3: // vf2id + ir.Write(IROp::FFloor, dregs[i], sregs[i]); + break; + + default: + INVALIDOP; + } + } + } } void IRFrontend::Comp_Mftv(MIPSOpcode op) { diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp index 116908c656..ed7bd403b0 100644 --- a/Core/MIPS/IR/IRInst.cpp +++ b/Core/MIPS/IR/IRInst.cpp @@ -105,6 +105,7 @@ static const IRMeta irMeta[] = { { IROp::FFloor, "FFloor", "FF" }, { IROp::FCvtWS, "FCvtWS", "FF" }, { IROp::FCvtSW, "FCvtSW", "FF" }, + { IROp::FCvtScaledWS, "FCvtScaledWS", "FFI" }, { IROp::FCmp, "FCmp", "mFF" }, { IROp::FSat0_1, "FSat(0 - 1)", "FF" }, { IROp::FSatMinus1_1, "FSat(-1 - 1)", "FF" }, diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index d4eb47f49a..2e5a1afce8 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -127,6 +127,7 @@ enum class IROp : u8 { FCvtWS, FCvtSW, + FCvtScaledWS, FMovFromGPR, FMovToGPR, @@ -304,9 +305,6 @@ enum : IRReg { IRVTEMP_PFX_D = 232 - 32, IRVTEMP_0 = 236 - 32, - // 16 float temps for vector S and T prefixes and things like that. - // IRVTEMP_0 = 208 - 64, // -64 to be relative to v[0] - // Hacky way to get to other state IRREG_VFPU_CTRL_BASE = 208, IRREG_VFPU_CC = 211, diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index 561adf6f25..22b012787f 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -834,7 +834,7 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { mips->fi[inst->dest] = my_isinf(value) && value < 0.0f ? -2147483648LL : 2147483647LL; break; } else { - mips->fs[inst->dest] = (int)floorf(value + 0.5f); + mips->fs[inst->dest] = (int)round_ieee_754(value); } break; } @@ -931,6 +931,32 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { } break; //cvt.w.s } + case IROp::FCvtScaledWS: + { + float src = mips->f[inst->src1]; + if (my_isnan(src)) { + // TODO: True for negatives too? + mips->fs[inst->dest] = 2147483647L; + break; + } + + float mult = (float)(1UL << (inst->src2 & 0x1F)); + double sv = src * mult; // (float)0x7fffffff == (float)0x80000000 + // Cap/floor it to 0x7fffffff / 0x80000000 + if (sv > (double)0x7fffffff) { + mips->fs[inst->dest] = 0x7fffffff; + } else if (sv <= (double)(int)0x80000000) { + mips->fs[inst->dest] = 0x80000000; + } else { + switch (inst->src2 >> 6) { + case 0: mips->fs[inst->dest] = (int)round_ieee_754(sv); break; + case 1: mips->fs[inst->dest] = src >= 0 ? (int)floor(sv) : (int)ceil(sv); break; + case 2: mips->fs[inst->dest] = (int)ceil(sv); break; + case 3: mips->fs[inst->dest] = (int)floor(sv); break; + } + } + break; + } case IROp::ZeroFpCond: mips->fpcond = 0; diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index 52ea66c5d4..247b3b6865 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -667,6 +667,7 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts case IROp::FCeil: case IROp::FFloor: case IROp::FCvtSW: + case IROp::FCvtScaledWS: case IROp::FSin: case IROp::FCos: case IROp::FSqrt: diff --git a/Core/MIPS/RiscV/RiscVCompFPU.cpp b/Core/MIPS/RiscV/RiscVCompFPU.cpp index 84c7faa832..38d23f900c 100644 --- a/Core/MIPS/RiscV/RiscVCompFPU.cpp +++ b/Core/MIPS/RiscV/RiscVCompFPU.cpp @@ -190,6 +190,7 @@ void RiscVJit::CompIR_FCvt(IRInst inst) { switch (inst.op) { case IROp::FCvtWS: + case IROp::FCvtScaledWS: case IROp::FCvtSW: CompIR_Generic(inst); break; diff --git a/Core/MIPS/RiscV/RiscVJit.cpp b/Core/MIPS/RiscV/RiscVJit.cpp index b94369c4ca..6edea8d25e 100644 --- a/Core/MIPS/RiscV/RiscVJit.cpp +++ b/Core/MIPS/RiscV/RiscVJit.cpp @@ -265,6 +265,7 @@ void RiscVJit::CompileIRInst(IRInst inst) { case IROp::FCvtWS: case IROp::FCvtSW: + case IROp::FCvtScaledWS: CompIR_FCvt(inst); break; From e228748449c88b78e4b362aa9b1493562efa02e0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 29 Jul 2023 18:15:49 -0700 Subject: [PATCH 2/2] irjit: Add FCvtScaledSW to safely scale vi2f. --- Core/MIPS/IR/IRCompVFPU.cpp | 42 ++++++-------------------------- Core/MIPS/IR/IRInst.cpp | 1 + Core/MIPS/IR/IRInst.h | 1 + Core/MIPS/IR/IRInterpreter.cpp | 3 +++ Core/MIPS/IR/IRPassSimplify.cpp | 1 + Core/MIPS/RiscV/RiscVCompFPU.cpp | 1 + Core/MIPS/RiscV/RiscVJit.cpp | 1 + 7 files changed, 15 insertions(+), 35 deletions(-) diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index fafd6668bf..1c767d8e3d 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -929,37 +929,17 @@ namespace MIPSComp { VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - int imm = (op >> 16) & 0x1f; - const float mult = 1.0f / (float)(1UL << imm); + uint8_t imm = (op >> 16) & 0x1f; u8 sregs[4], dregs[4]; GetVectorRegsPrefixS(sregs, sz, _VS); GetVectorRegsPrefixD(dregs, sz, _VD); - u8 tempregs[4]; - for (int i = 0; i < n; ++i) { - if (!IsOverlapSafe(dregs[i], n, sregs)) { - tempregs[i] = IRVTEMP_PFX_T + i; // Need IRVTEMP_0 for the scaling factor - } else { - tempregs[i] = dregs[i]; - } - } - if (mult != 1.0f) - ir.Write(IROp::SetConstF, IRVTEMP_0, ir.AddConstantFloat(mult)); - // TODO: Use the SCVTF with builtin scaling where possible. for (int i = 0; i < n; i++) { - ir.Write(IROp::FCvtSW, tempregs[i], sregs[i]); - } - if (mult != 1.0f) { - for (int i = 0; i < n; i++) { - ir.Write(IROp::FMul, tempregs[i], tempregs[i], IRVTEMP_0); - } - } - - for (int i = 0; i < n; ++i) { - if (dregs[i] != tempregs[i]) { - ir.Write(IROp::FMov, dregs[i], tempregs[i]); - } + if (imm == 0) + ir.Write(IROp::FCvtSW, dregs[i], sregs[i]); + else + ir.Write(IROp::FCvtScaledSW, dregs[i], sregs[i], imm); } ApplyPrefixD(dregs, sz); } @@ -989,7 +969,7 @@ namespace MIPSComp { VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - int imm = (op >> 16) & 0x1f; + uint8_t imm = (op >> 16) & 0x1f; u8 sregs[4], dregs[4]; GetVectorRegsPrefixS(sregs, sz, _VS); @@ -1000,17 +980,9 @@ namespace MIPSComp { if (((op >> 21) & 0x1C) != 0x10) INVALIDOP; - u8 tempregs[4]; - for (int i = 0; i < n; ++i) { - if (!IsOverlapSafe(dregs[i], n, sregs)) { - tempregs[i] = IRVTEMP_PFX_T + i; // Need IRVTEMP_0 for the scaling factor - } else { - tempregs[i] = dregs[i]; - } - } if (imm != 0) { for (int i = 0; i < n; i++) - ir.Write(IROp::FCvtScaledWS, dregs[i], sregs[i], (uint8_t)(imm | (rmode << 6))); + ir.Write(IROp::FCvtScaledWS, dregs[i], sregs[i], imm | (rmode << 6)); } else { for (int i = 0; i < n; i++) { switch (rmode) { diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp index ed7bd403b0..6d7d46e888 100644 --- a/Core/MIPS/IR/IRInst.cpp +++ b/Core/MIPS/IR/IRInst.cpp @@ -106,6 +106,7 @@ static const IRMeta irMeta[] = { { IROp::FCvtWS, "FCvtWS", "FF" }, { IROp::FCvtSW, "FCvtSW", "FF" }, { IROp::FCvtScaledWS, "FCvtScaledWS", "FFI" }, + { IROp::FCvtScaledSW, "FCvtScaledSW", "FFI" }, { IROp::FCmp, "FCmp", "mFF" }, { IROp::FSat0_1, "FSat(0 - 1)", "FF" }, { IROp::FSatMinus1_1, "FSat(-1 - 1)", "FF" }, diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index 2e5a1afce8..2ffc5c79f2 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -128,6 +128,7 @@ enum class IROp : u8 { FCvtWS, FCvtSW, FCvtScaledWS, + FCvtScaledSW, FMovFromGPR, FMovToGPR, diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index 22b012787f..c15d61f518 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -931,6 +931,9 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, int count) { } break; //cvt.w.s } + case IROp::FCvtScaledSW: + mips->f[inst->dest] = (float)mips->fs[inst->src1] * (1.0f / (1UL << (inst->src2 & 0x1F))); + break; case IROp::FCvtScaledWS: { float src = mips->f[inst->src1]; diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index 247b3b6865..7f218d35c7 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -668,6 +668,7 @@ bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts case IROp::FFloor: case IROp::FCvtSW: case IROp::FCvtScaledWS: + case IROp::FCvtScaledSW: case IROp::FSin: case IROp::FCos: case IROp::FSqrt: diff --git a/Core/MIPS/RiscV/RiscVCompFPU.cpp b/Core/MIPS/RiscV/RiscVCompFPU.cpp index 38d23f900c..fd3807d907 100644 --- a/Core/MIPS/RiscV/RiscVCompFPU.cpp +++ b/Core/MIPS/RiscV/RiscVCompFPU.cpp @@ -192,6 +192,7 @@ void RiscVJit::CompIR_FCvt(IRInst inst) { case IROp::FCvtWS: case IROp::FCvtScaledWS: case IROp::FCvtSW: + case IROp::FCvtScaledSW: CompIR_Generic(inst); break; diff --git a/Core/MIPS/RiscV/RiscVJit.cpp b/Core/MIPS/RiscV/RiscVJit.cpp index 6edea8d25e..73962198c2 100644 --- a/Core/MIPS/RiscV/RiscVJit.cpp +++ b/Core/MIPS/RiscV/RiscVJit.cpp @@ -266,6 +266,7 @@ void RiscVJit::CompileIRInst(IRInst inst) { case IROp::FCvtWS: case IROp::FCvtSW: case IROp::FCvtScaledWS: + case IROp::FCvtScaledSW: CompIR_FCvt(inst); break;