IR: Use interp for unhandled prefixes.

This commit is contained in:
Unknown W. Brackets committed 2019-03-30 12:26:09 -07:00
1 parent 94465a29e9
commit a1fe60e28e
3 files changed
+92 -42

No files matched your search

+69 -30
View File
@@ -108,6 +108,25 @@ namespace MIPSComp {
return true;
}
static bool IsPrefixWithinSize(u32 prefix, VectorSize sz) {
int n = GetNumVectorElements(sz);
for (int i = n; 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;
if (regnum < n || abs || negate || constants) {
return false;
}
}
return true;
}
static bool IsPrefixWithinSize(u32 prefix, MIPSOpcode op) {
return IsPrefixWithinSize(prefix, GetVecSize(op));
}
void IRFrontend::Comp_VPFX(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_XFER);
int data = op & 0xFFFFF;
@@ -183,14 +202,10 @@ namespace MIPSComp {
// This puts the value into a temp reg, so we won't write the modified value back.
vregs[i] = tempReg + i;
if (!constants) {
// Prefix may say "z, z, z, z" but if this is a pair, we force to x.
// TODO: But some ops seem to use const 0 instead?
if (regnum >= n) {
WARN_LOG(CPU, "JIT: Invalid VFPU swizzle: %08x : %d / %d at PC = %08x (%s)", prefix, regnum, n, GetCompilerPC(), MIPSDisasmAt(GetCompilerPC()));
regnum = 0;
}
if (abs) {
// Depends on the op, but often zero.
ir.Write(IROp::SetConstF, vregs[i], ir.AddConstantFloat(0.0f));
} else if (abs) {
ir.Write(IROp::FAbs, vregs[i], origV[regnum]);
if (negate)
ir.Write(IROp::FNeg, vregs[i], vregs[i]);
@@ -343,12 +358,13 @@ namespace MIPSComp {
void IRFrontend::Comp_VVectorInit(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_XFER);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || js.HasSPrefix()) {
DISABLE;
}
// Vector init
// d[N] = CONST[N]
// Note: probably implemented as vmov with prefix hack.
VectorSize sz = GetVecSize(op);
int type = (op >> 16) & 0xF;
@@ -369,12 +385,13 @@ namespace MIPSComp {
void IRFrontend::Comp_VIdt(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_XFER);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || js.HasSPrefix()) {
DISABLE;
}
// Vector identity row
// d[N] = IDENTITY[N,m]
// Note: probably implemented as vmov with prefix hack.
int vd = _VD;
VectorSize sz = GetVecSize(op);
@@ -448,18 +465,22 @@ namespace MIPSComp {
void IRFrontend::Comp_VHdp(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) {
DISABLE;
}
// Vector homogenous dot product
// d[0] = s[0 .. n-2] dot t[0 .. n-2] + t[n-1]
// Note: s[n-1] is ignored / treated as 1.
// Note: s[n-1] is ignored / treated as 1 via prefix override.
int vd = _VD;
int vs = _VS;
int vt = _VT;
VectorSize sz = GetVecSize(op);
int n = GetNumVectorElements(sz);
if (js.prefixS & (0x0101 << (8 + n - 1)))
DISABLE;
// TODO: Force read one of them into regs? probably not.
u8 sregs[4], tregs[4], dregs[1];
@@ -469,9 +490,7 @@ namespace MIPSComp {
ir.Write(IROp::FMul, IRVTEMP_0, sregs[0], tregs[0]);
int n = GetNumVectorElements(sz);
for (int i = 1; i < n; i++) {
// sum += s[i]*t[i];
if (i == n - 1) {
ir.Write(IROp::FAdd, IRVTEMP_0, IRVTEMP_0, tregs[i]);
} else {
@@ -488,14 +507,15 @@ namespace MIPSComp {
void IRFrontend::Comp_Vhoriz(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix())
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
DISABLE;
}
// Vector horizontal add
// d[0] = s[0] + ... s[n-1]
// Vector horizontal average
// d[0] = (s[0] + ... s[n-1]) / n
// d[0] = s[0] / n + ... s[n-1] / n
// Note: Both are implemented as dot products against generated constants.
VectorSize sz = GetVecSize(op);
int n = GetNumVectorElements(sz);
@@ -525,7 +545,7 @@ namespace MIPSComp {
void IRFrontend::Comp_VDot(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) {
DISABLE;
}
@@ -563,8 +583,9 @@ namespace MIPSComp {
void IRFrontend::Comp_VecDo3(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix())
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) {
DISABLE;
}
// Vector arithmetic
// d[N] = OP(s[N], t[N]) (see below)
@@ -576,7 +597,11 @@ namespace MIPSComp {
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;
@@ -722,7 +747,7 @@ namespace MIPSComp {
void IRFrontend::Comp_VV2Op(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix())
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op))
DISABLE;
// Vector unary operation
@@ -731,8 +756,17 @@ namespace MIPSComp {
int vs = _VS;
int vd = _VD;
int optype = (op >> 16) & 0x1f;
if (optype >= 16 && !js.HasNoPrefix()) {
DISABLE;
} else if ((optype == 1 || optype == 2) && js.HasSPrefix()) {
DISABLE;
} else if (optype == 5 && js.HasDPrefix()) {
DISABLE;
}
// Pre-processing: Eliminate silly no-op VMOVs, common in Wipeout Pure
if (((op >> 16) & 0x1f) == 0 && vs == vd && js.HasNoPrefix()) {
if (optype == 0 && vs == vd && js.HasNoPrefix()) {
return;
}
@@ -756,7 +790,7 @@ namespace MIPSComp {
bool canSIMD = false;
// Some can be SIMD'd.
switch ((op >> 16) & 0x1f) {
switch (optype) {
case 0: // vmov
case 1: // vabs
case 2: // vneg
@@ -765,7 +799,7 @@ namespace MIPSComp {
}
if (canSIMD && !usingTemps && IsConsecutive4(sregs) && IsConsecutive4(dregs)) {
switch ((op >> 16) & 0x1f) {
switch (optype) {
case 0: // vmov
ir.Write(IROp::Vec4Mov, dregs[0], sregs[0]);
break;
@@ -781,7 +815,7 @@ namespace MIPSComp {
}
for (int i = 0; i < n; ++i) {
switch ((op >> 16) & 0x1f) {
switch (optype) {
case 0: // d[i] = s[i]; break; //vmov
// Probably for swizzle.
ir.Write(IROp::FMov, tempregs[i], sregs[i]);
@@ -848,7 +882,7 @@ namespace MIPSComp {
void IRFrontend::Comp_Vi2f(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op)) {
DISABLE;
}
@@ -904,6 +938,9 @@ namespace MIPSComp {
void IRFrontend::Comp_Vf2i(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || (js.prefixD & 0xFF) != 0) {
DISABLE;
}
// Vector float to integer
// d[N] = int(S[N] * mult)
@@ -1100,7 +1137,7 @@ namespace MIPSComp {
void IRFrontend::Comp_VScl(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
DISABLE;
}
@@ -1364,7 +1401,7 @@ namespace MIPSComp {
void IRFrontend::Comp_VCrs(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || js.HasSPrefix() || js.HasTPrefix()) {
DISABLE;
}
@@ -1378,7 +1415,7 @@ namespace MIPSComp {
void IRFrontend::Comp_VDet(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || (js.prefixT & 0x000CFCF0) != 0x000E0) {
DISABLE;
}
@@ -1633,8 +1670,9 @@ namespace MIPSComp {
void IRFrontend::Comp_Vcmp(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_COMP);
if (js.HasUnknownPrefix())
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || !IsPrefixWithinSize(js.prefixT, op)) {
DISABLE;
}
// Vector compare
// VFPU_CC[N] = COMPARE(s[N], t[N])
@@ -1657,7 +1695,7 @@ namespace MIPSComp {
void IRFrontend::Comp_Vcmov(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_COMP);
if (js.HasUnknownPrefix()) {
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
DISABLE;
}
@@ -1898,8 +1936,9 @@ namespace MIPSComp {
void IRFrontend::Comp_Vbfy(MIPSOpcode op) {
CONDITIONAL_DISABLE(VFPU_VEC);
if (js.HasUnknownPrefix())
if (js.HasUnknownPrefix() || !IsPrefixWithinSize(js.prefixS, op) || js.HasTPrefix()) {
DISABLE;
}
// Vector butterfly operation
// vbfy2: d[0] = s[0] + s[2], d[1] = s[1] + s[3], d[2] = s[0] - s[2], d[3] = s[1] - s[3]
+19 -12
View File
@@ -99,13 +99,23 @@ namespace MIPSComp {
prefixDFlag = PREFIX_UNKNOWN;
}
bool HasSPrefix() const {
return (prefixSFlag & PREFIX_KNOWN) == 0 || prefixS != 0xE4;
}
bool HasTPrefix() const {
return (prefixTFlag & PREFIX_KNOWN) == 0 || prefixT != 0xE4;
}
bool HasDPrefix() const {
return (prefixDFlag & PREFIX_KNOWN) == 0 || prefixD != 0x0;
}
bool MayHavePrefix() const {
if (HasUnknownPrefix()) {
return true;
} else if (prefixS != 0xE4 || prefixT != 0xE4 || prefixD != 0) {
return true;
} else if (VfpuWriteMask() != 0) {
return true;
}
return false;
}
@@ -118,22 +128,19 @@ namespace MIPSComp {
}
bool HasNoPrefix() const {
return (prefixDFlag & PREFIX_KNOWN) && (prefixSFlag & PREFIX_KNOWN) && (prefixTFlag & PREFIX_KNOWN) && (prefixS == 0xE4 && prefixT == 0xE4 && prefixD == 0);
return !HasSPrefix() && !HasTPrefix() && !HasDPrefix();
}
void EatPrefix() {
if ((prefixSFlag & PREFIX_KNOWN) == 0 || prefixS != 0xE4) {
if (HasSPrefix())
prefixSFlag = PREFIX_KNOWN_DIRTY;
prefixS = 0xE4;
}
if ((prefixTFlag & PREFIX_KNOWN) == 0 || prefixT != 0xE4) {
prefixS = 0xE4;
if (HasTPrefix())
prefixTFlag = PREFIX_KNOWN_DIRTY;
prefixT = 0xE4;
}
if ((prefixDFlag & PREFIX_KNOWN) == 0 || prefixD != 0x0) {
prefixT = 0xE4;
if (HasDPrefix())
prefixDFlag = PREFIX_KNOWN_DIRTY;
prefixD = 0x0;
}
prefixD = 0x0;
}
u8 VfpuWriteMask() const {
+4
View File
@@ -1166,6 +1166,7 @@ namespace MIPSInt
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
// TODO: May mishandle NAN / negative zero / etc.
// TODO: If S swizzle selects a lane that doesn't exist in sz, the result is always 0.
d[0] = std::min(s[0], t[0]);
d[1] = std::max(s[1], t[1]);
d[2] = std::min(s[2], t[2]);
@@ -1191,6 +1192,7 @@ namespace MIPSInt
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
// TODO: May mishandle NAN / negative zero / etc.
// TODO: If S swizzle selects a lane that doesn't exist in sz, the result is always 0.
d[0] = std::min(s[0], t[0]);
d[1] = std::min(s[1], t[1]);
d[2] = std::max(s[2], t[2]);
@@ -1216,6 +1218,7 @@ namespace MIPSInt
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
// TODO: May mishandle NAN / negative zero / etc.
// TODO: If S swizzle selects a lane that doesn't exist in sz, the result is always 0.
d[0] = std::max(s[0], t[0]);
d[1] = std::min(s[1], t[1]);
d[2] = std::max(s[2], t[2]);
@@ -1241,6 +1244,7 @@ namespace MIPSInt
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
// TODO: May mishandle NAN / negative zero / etc.
// TODO: If S swizzle selects a lane that doesn't exist in sz, the result is always 0.
d[0] = std::max(s[0], t[0]);
d[1] = std::max(s[1], t[1]);
d[2] = std::min(s[2], t[2]);