diff --git a/Core/MIPS/ARM/ArmIRCompVec.cpp b/Core/MIPS/ARM/ArmIRCompVec.cpp index b4436570ba..fe98a56139 100644 --- a/Core/MIPS/ARM/ArmIRCompVec.cpp +++ b/Core/MIPS/ARM/ArmIRCompVec.cpp @@ -123,12 +123,12 @@ void ArmJitBackend::CompIR_VecAssign(IRInst inst) { if (inst.dest == inst.src1) { // Go through the scratch regs, since a lane may be read after it's written. for (int i = 0; i < 4; ++i) - VMOV((ARMReg)(SCRATCHF1 + i), regs_.F(inst.src1 + ((inst.src2 >> (i * 2)) & 3))); + VMOV((ARMReg)(SCRATCHF1 + i), regs_.F(inst.src1 + Vec4ShuffleLane(inst.src2, i))); for (int i = 0; i < 4; ++i) VMOV(regs_.F(inst.dest + i), (ARMReg)(SCRATCHF1 + i)); } else { for (int i = 0; i < 4; ++i) - VMOV(regs_.F(inst.dest + i), regs_.F(inst.src1 + ((inst.src2 >> (i * 2)) & 3))); + VMOV(regs_.F(inst.dest + i), regs_.F(inst.src1 + Vec4ShuffleLane(inst.src2, i))); } break; diff --git a/Core/MIPS/ARM64/Arm64IRCompVec.cpp b/Core/MIPS/ARM64/Arm64IRCompVec.cpp index a681eb9e47..45924a088e 100644 --- a/Core/MIPS/ARM64/Arm64IRCompVec.cpp +++ b/Core/MIPS/ARM64/Arm64IRCompVec.cpp @@ -277,8 +277,8 @@ uint8_t Arm64ShuffleResult(uint8_t mask, uint8_t prev) { uint8_t result = 0; for (int i = 0; i < 4; ++i) { - int takeLane = (mask >> (i * 2)) & 3; - int lane = (prev >> (takeLane * 2)) & 3; + int takeLane = Vec4ShuffleLane(mask, i); + int lane = Vec4ShuffleLane(prev, takeLane); result |= lane << (i * 2); } return result; diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 81e4350d33..ac8003b9ec 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -156,10 +156,10 @@ namespace MIPSComp { static bool IsPrefixWithinSize(u32 prefix, VectorSize sz) { int n = GetNumVectorElements(sz); for (int i = 0; i < 4; i++) { - int regnum = (prefix >> (i * 2)) & 3; - int abs = (prefix >> (8 + i)) & 1; - int negate = (prefix >> (16 + i)) & 1; - int constants = (prefix >> (12 + i)) & 1; + int regnum = VFPUPrefixSwizzle(prefix, i); + bool abs = VFPUPrefixAbs(prefix, i); + bool negate = VFPUPrefixNegate(prefix, i); + bool constants = VFPUPrefixIsConstant(prefix, i); if (constants) { continue; } @@ -178,19 +178,6 @@ namespace MIPSComp { return IsPrefixWithinSize(prefix, GetVecSize(op)); } - // Whether lane i of an S or T prefix is a constant, and its value. Past the vector size, the dot - // products add in the lanes where both S and T are constants, and read zero for the rest - // (cpu/vfpu/prefix_lanes), which IsPrefixWithinSize() lets through. - static bool PrefixLaneConstant(u32 prefix, int i, float *value) { - static const float constants[8] = { 0.f, 1.f, 2.f, 0.5f, 3.f, 1.f / 3.f, 0.25f, 1.f / 6.f }; - if (((prefix >> (12 + i)) & 1) == 0) - return false; - const int regnum = (prefix >> (i * 2)) & 3; - const int abs = (prefix >> (8 + i)) & 1; - const int negate = (prefix >> (16 + i)) & 1; - *value = negate ? -constants[regnum + (abs << 2)] : constants[regnum + (abs << 2)]; - return true; - } void IRFrontend::Comp_VPFX(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_XFER); @@ -229,7 +216,6 @@ namespace MIPSComp { int n = GetNumVectorElements(sz); u8 origV[4]{}; - static const float constantArray[8] = { 0.f, 1.f, 2.f, 0.5f, 3.f, 1.f / 3.f, 0.25f, 1.f / 6.f }; for (int i = 0; i < n; i++) origV[i] = vregs[i]; @@ -277,10 +263,10 @@ namespace MIPSComp { // Check if we're just zeroing certain lanes - this is common. u32 zeroedLanes = 0; for (int i = 0; i < 4; ++i) { - int regnum = (prefix >> (i * 2)) & 3; - int abs = (prefix >> (8 + i)) & 1; - int negate = (prefix >> (16 + i)) & 1; - int constants = (prefix >> (12 + i)) & 1; + int regnum = VFPUPrefixSwizzle(prefix, i); + bool abs = VFPUPrefixAbs(prefix, i); + bool negate = VFPUPrefixNegate(prefix, i); + bool constants = VFPUPrefixIsConstant(prefix, i); if (!constants && regnum == i && !abs && !negate) continue; @@ -304,10 +290,10 @@ namespace MIPSComp { // Alright, fall back to the generic approach. for (int i = 0; i < n; i++) { - int regnum = (prefix >> (i * 2)) & 3; - int abs = (prefix >> (8 + i)) & 1; - int negate = (prefix >> (16 + i)) & 1; - int constants = (prefix >> (12 + i)) & 1; + int regnum = VFPUPrefixSwizzle(prefix, i); + bool abs = VFPUPrefixAbs(prefix, i); + bool negate = VFPUPrefixNegate(prefix, i); + bool constants = VFPUPrefixIsConstant(prefix, i); // Unchanged, hurray. if (!constants && regnum == i && !abs && !negate) @@ -331,11 +317,7 @@ namespace MIPSComp { ir.Write(IROp::FMov, vregs[i], origV[regnum]); } } else { - if (negate) { - ir.WriteSetConstantFloat(vregs[i], -constantArray[regnum + (abs << 2)]); - } else { - ir.WriteSetConstantFloat(vregs[i], constantArray[regnum + (abs << 2)]); - } + ir.WriteSetConstantFloat(vregs[i], VFPUPrefixConstant(prefix, i)); } } } @@ -385,10 +367,6 @@ namespace MIPSComp { } } - inline int GetDSat(int prefix, int i) { - return (prefix >> (i * 2)) & 3; - } - // "D" prefix is really a post process. No need to allocate a temporary register (except // dummies to simulate writemask, which is done in GetVectorRegsPrefixD void IRFrontend::ApplyPrefixD(u8 *vregs, VectorSize sz, int vectorReg) { @@ -402,7 +380,7 @@ namespace MIPSComp { for (int i = 0; i < n; i++) { if (js.VfpuWriteMask(i)) continue; - int sat = GetDSat(js.prefixD, i); + int sat = VFPUPrefixSat(js.prefixD, i); if (sat == 1) { // clamped = x < 0 ? (x > 1 ? 1 : x) : x [0, 1] ir.Write(IROp::FSat0_1, vregs[i], vregs[i]); @@ -752,10 +730,10 @@ namespace MIPSComp { VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - // Constants past n are added in too (see PrefixLaneConstant()), rare enough for the interpreter. + // On the PSP, an S constant past n is added in too (cpu/vfpu/prefix_lanes), which + // IsPrefixWithinSize() lets through. Rare enough for the interpreter. for (int i = n; i < 4; i++) { - float s; - if (PrefixLaneConstant(js.prefixS, i, &s)) + if (VFPUPrefixIsConstant(js.prefixS, i)) DISABLE; } @@ -798,11 +776,11 @@ namespace MIPSComp { VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - // Lanes past n where both prefixes are constants add their product (see - // PrefixLaneConstant()), rare enough for the interpreter. + // On the PSP, lanes past n where both prefixes are constants add their product, and the rest + // read zero (cpu/vfpu/prefix_lanes). IsPrefixWithinSize() lets those through, and they're + // rare enough for the interpreter. for (int i = n; i < 4; i++) { - float s, t; - if (PrefixLaneConstant(js.prefixS, i, &s) && PrefixLaneConstant(js.prefixT, i, &t)) + if (VFPUPrefixIsConstant(js.prefixS, i) && VFPUPrefixIsConstant(js.prefixT, i)) DISABLE; } diff --git a/Core/MIPS/IR/IRInst.h b/Core/MIPS/IR/IRInst.h index cc392e2a84..0f746246ae 100644 --- a/Core/MIPS/IR/IRInst.h +++ b/Core/MIPS/IR/IRInst.h @@ -278,6 +278,11 @@ enum class Vec4Init { Set_0001, }; +// The source lane of dest lane i in a Vec4Shuffle, two bits per lane like a VFPU prefix's swizzle. +inline int Vec4ShuffleLane(u32 shuffle, int i) { + return (shuffle >> (i * 2)) & 3; +} + enum class IRRoundMode : uint8_t { RINT_0 = 0, CAST_1 = 1, diff --git a/Core/MIPS/IR/IRInterpreter.cpp b/Core/MIPS/IR/IRInterpreter.cpp index 0562274298..6d67305c97 100644 --- a/Core/MIPS/IR/IRInterpreter.cpp +++ b/Core/MIPS/IR/IRInterpreter.cpp @@ -465,7 +465,7 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst) { // or a big switch - there are only 256 shuffles possible (4^4) float temp[4]; for (u32 i = 0; i < 4; i++) - temp[i] = mips->f[(u32)inst->src1 + (u32)((inst->src2 >> (i * 2)) & 3)]; + temp[i] = mips->f[(u32)inst->src1 + (u32)Vec4ShuffleLane(inst->src2, i)]; const u32 dest = inst->dest; for (u32 i = 0; i < 4; i++) mips->f[dest + i] = temp[i]; diff --git a/Core/MIPS/InterpreterVFPU.cpp b/Core/MIPS/InterpreterVFPU.cpp index da6ee4b726..598fec521c 100644 --- a/Core/MIPS/InterpreterVFPU.cpp +++ b/Core/MIPS/InterpreterVFPU.cpp @@ -129,17 +129,16 @@ static void ApplyPrefixST(MIPSState *mips, float *r, u32 data, VectorSize size, int n = GetNumVectorElements(size); float origV[4]{ invalid, invalid, invalid, invalid }; - static const float constantArray[8] = {0.f, 1.f, 2.f, 0.5f, 3.f, 1.f/3.f, 0.25f, 1.f/6.f}; for (int i = 0; i < n; i++) { origV[i] = r[i]; } for (int i = 0; i < n; i++) { - int regnum = (data >> (i*2)) & 3; - int abs = (data >> (8+i)) & 1; - int negate = (data >> (16+i)) & 1; - int constants = (data >> (12+i)) & 1; + int regnum = VFPUPrefixSwizzle(data, i); + bool abs = VFPUPrefixAbs(data, i); + bool negate = VFPUPrefixNegate(data, i); + bool constants = VFPUPrefixIsConstant(data, i); if (!constants) { if (regnum >= n) { @@ -150,7 +149,7 @@ static void ApplyPrefixST(MIPSState *mips, float *r, u32 data, VectorSize size, if (abs) ((u32 *)r)[i] = ((u32 *)r)[i] & 0x7FFFFFFF; } else { - r[i] = constantArray[regnum + (abs<<2)]; + r[i] = vfpuPrefixConstants[regnum + (abs << 2)]; } if (negate) @@ -176,7 +175,7 @@ void ApplyPrefixD(MIPSState *mips, float *v, VectorSize size, bool onlyWriteMask int n = GetNumVectorElements(size); for (int i = 0; i < n; i++) { - int sat = (data >> (i * 2)) & 3; + int sat = VFPUPrefixSat(data, i); if (sat == 1) v[i] = vfpu_clamp(v[i], 0.0f, 1.0f); else if (sat == 3) @@ -202,10 +201,10 @@ static void RetainInvalidSwizzleST(MIPSState *mips, float *d, VectorSize sz) { // TODO: We can probably do some faster check of sPrefix and tPrefix to skip over this loop. for (int i = 0; i < n; i++) { - int swizzleS = (sPrefix >> (i + i)) & 3; - int swizzleT = (tPrefix >> (i + i)) & 3; - int constS = (sPrefix >> (12 + i)) & 1; - int constT = (tPrefix >> (12 + i)) & 1; + int swizzleS = VFPUPrefixSwizzle(sPrefix, i); + int swizzleT = VFPUPrefixSwizzle(tPrefix, i); + bool constS = VFPUPrefixIsConstant(sPrefix, i); + bool constT = VFPUPrefixIsConstant(tPrefix, i); if ((swizzleS >= n && !constS) || (swizzleT >= n && !constT)) d[i] = 0.0f; } diff --git a/Core/MIPS/JitCommon/JitState.h b/Core/MIPS/JitCommon/JitState.h index 5f04f20687..a5f2725dd4 100644 --- a/Core/MIPS/JitCommon/JitState.h +++ b/Core/MIPS/JitCommon/JitState.h @@ -143,12 +143,12 @@ namespace MIPSComp { u8 VfpuWriteMask() const { _assert_(prefixDFlag & JitState::PREFIX_KNOWN); - return (prefixD >> 8) & 0xF; + return VFPUPrefixWriteMask(prefixD); } bool VfpuWriteMask(int i) const { _assert_(prefixDFlag & JitState::PREFIX_KNOWN); - return (prefixD >> (8 + i)) & 1; + return VFPUPrefixWriteMask(prefixD, i); } void LogPrefix() { diff --git a/Core/MIPS/LoongArch64/LoongArch64CompVec.cpp b/Core/MIPS/LoongArch64/LoongArch64CompVec.cpp index 4121fa1c70..ab940a082d 100644 --- a/Core/MIPS/LoongArch64/LoongArch64CompVec.cpp +++ b/Core/MIPS/LoongArch64/LoongArch64CompVec.cpp @@ -209,7 +209,7 @@ void LoongArch64JitBackend::CompIR_VecAssign(IRInst inst) { } else { regs_.Map(inst); for (int i = 0; i < 4; ++i) { - int lane = (inst.src2 >> (i * 2)) & 3; + int lane = Vec4ShuffleLane(inst.src2, i); FMOV_S(regs_.F(inst.dest + i), regs_.F(inst.src1 + lane)); } } diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index f975cbc95c..527553ae96 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -369,6 +369,8 @@ void MIPSState::Init() { UpdateBlockShadowHook(); } +const float vfpuPrefixConstants[8] = { 0.f, 1.f, 2.f, 0.5f, 3.f, 1.f / 3.f, 0.25f, 1.f / 6.f }; + bool MIPSState::HasDefaultPrefix() const { return vfpuCtrl[VFPU_CTRL_SPREFIX] == 0xe4 && vfpuCtrl[VFPU_CTRL_TPREFIX] == 0xe4 && vfpuCtrl[VFPU_CTRL_DPREFIX] == 0; } diff --git a/Core/MIPS/MIPS.h b/Core/MIPS/MIPS.h index d38090cc39..9d5e79ef9b 100644 --- a/Core/MIPS/MIPS.h +++ b/Core/MIPS/MIPS.h @@ -109,6 +109,26 @@ enum { //unknown.... }; +// The fields of the VFPU prefixes. Lane i of an S or T prefix takes the lane its swizzle names, or +// with the constant bit, the constant the swizzle and abs bit pick, then the abs and negate. Lane i +// of a D prefix has a saturation (1 = [0:1], 3 = [-1:1]) and a write mask bit, set to keep the lane. +inline int VFPUPrefixSwizzle(u32 prefix, int i) { return (prefix >> (i * 2)) & 3; } +inline bool VFPUPrefixAbs(u32 prefix, int i) { return (prefix >> (8 + i)) & 1; } +inline bool VFPUPrefixIsConstant(u32 prefix, int i) { return (prefix >> (12 + i)) & 1; } +inline bool VFPUPrefixNegate(u32 prefix, int i) { return (prefix >> (16 + i)) & 1; } +inline int VFPUPrefixSat(u32 prefix, int i) { return (prefix >> (i * 2)) & 3; } +inline u8 VFPUPrefixWriteMask(u32 prefix) { return (prefix >> 8) & 0xF; } +inline bool VFPUPrefixWriteMask(u32 prefix, int i) { return (prefix >> (8 + i)) & 1; } + +// The constants of an S or T prefix, by swizzle + 4 * abs. +extern const float vfpuPrefixConstants[8]; + +// The value of a lane with the constant bit, negate and all. +inline float VFPUPrefixConstant(u32 prefix, int i) { + const float c = vfpuPrefixConstants[VFPUPrefixSwizzle(prefix, i) + (VFPUPrefixAbs(prefix, i) << 2)]; + return VFPUPrefixNegate(prefix, i) ? -c : c; +} + enum VCondition { VC_FL, @@ -239,10 +259,10 @@ public: #endif u8 VfpuWriteMask() const { - return (vfpuCtrl[VFPU_CTRL_DPREFIX] >> 8) & 0xF; + return VFPUPrefixWriteMask(vfpuCtrl[VFPU_CTRL_DPREFIX]); } bool VfpuWriteMask(int i) const { - return (vfpuCtrl[VFPU_CTRL_DPREFIX] >> (8 + i)) & 1; + return VFPUPrefixWriteMask(vfpuCtrl[VFPU_CTRL_DPREFIX], i); } bool HasDefaultPrefix() const; diff --git a/Core/MIPS/MIPSDisVFPU.cpp b/Core/MIPS/MIPSDisVFPU.cpp index 6dfc9472bc..da1c3e974d 100644 --- a/Core/MIPS/MIPSDisVFPU.cpp +++ b/Core/MIPS/MIPSDisVFPU.cpp @@ -159,10 +159,10 @@ namespace MIPSDis static const char * const constan[8] = {"0","1","2","1/2","3","1/3","1/4","1/6"}; for (int i=0; i<4; i++) { - int regnum = (data>>(i*2)) & 3; - int abs = (data>>(8+i)) & 1; - int negate = (data>>(16+i)) & 1; - int constants = (data>>(12+i)) & 1; + int regnum = VFPUPrefixSwizzle(data, i); + bool abs = VFPUPrefixAbs(data, i); + bool negate = VFPUPrefixNegate(data, i); + bool constants = VFPUPrefixIsConstant(data, i); if (negate && outpos < outSize) outpos += truncate_cpy(out + outpos, outSize - outpos, "-"); if (abs && !constants && outpos < outSize) @@ -191,8 +191,8 @@ namespace MIPSDis static const char * const satNames[4] = {"", "[0:1]", "X", "[-1:1]"}; for (int i=0; i<4; i++) { - int sat = (data>>i*2)&3; - int mask = (data>>(8+i))&1; + int sat = VFPUPrefixSat(data, i); + bool mask = VFPUPrefixWriteMask(data, i); if (sat && outpos < outSize) outpos += truncate_cpy(out + outpos, outSize - outpos, satNames[sat]); if (mask && outpos < outSize) diff --git a/Core/MIPS/RiscV/RiscVCompVec.cpp b/Core/MIPS/RiscV/RiscVCompVec.cpp index 51141203e4..c2c00e5589 100644 --- a/Core/MIPS/RiscV/RiscVCompVec.cpp +++ b/Core/MIPS/RiscV/RiscVCompVec.cpp @@ -194,7 +194,7 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) { } else { regs_.Map(inst); for (int i = 0; i < 4; ++i) { - int lane = (inst.src2 >> (i * 2)) & 3; + int lane = Vec4ShuffleLane(inst.src2, i); FMV(32, regs_.F(inst.dest + i), regs_.F(inst.src1 + lane)); } }