IR: Use interp for unhandled prefix cases.

The interpreter is not changed yet, so in theory this shouldn't change
behavior.
This commit is contained in:
Unknown W. Brackets
2019-03-03 10:44:59 -08:00
parent 62928e13d8
commit 7dc775e54f
2 changed files with 88 additions and 42 deletions
+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]