JitArm64: Add asserts for unexpected single to float conversions

If the register pressure is high when allocating registers,
Arm64FPRCache may spill a guest register which we are going to
allocate later during the current instruction, which has the
side effect of turning it into double precision. This will have
bad consequences if we are assuming that it is single precision,
so let's add some asserts to detect if that ever happens.
This commit is contained in:
JosJuice 2021-01-24 14:10:04 +01:00
parent 2a6fffd60e
commit 88f3fec04e
2 changed files with 47 additions and 6 deletions

View File

@ -32,8 +32,11 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
bool use_c = op5 >= 25; // fmul and all kind of fmaddXX
bool use_b = op5 != 25; // fmul uses no B
bool inputs_are_singles = fpr.IsSingle(a, !packed) && (!use_b || fpr.IsSingle(b, !packed)) &&
const auto inputs_are_singles_func = [&] {
return fpr.IsSingle(a, !packed) && (!use_b || fpr.IsSingle(b, !packed)) &&
(!use_c || fpr.IsSingle(c, !packed));
};
const bool inputs_are_singles = inputs_are_singles_func();
ARM64Reg VA{}, VB{}, VC{}, VD{};
@ -117,6 +120,9 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
}
}
ASSERT_MSG(DYNA_REC, inputs_are_singles == inputs_are_singles_func(),
"Register allocation turned singles into doubles in the middle of fp_arith");
if (single || packed)
fpr.FixSinglePrecision(d);
}
@ -196,6 +202,9 @@ void JitArm64::fp_logic(UGeckoInstruction inst)
break;
}
}
ASSERT_MSG(DYNA_REC, single == fpr.IsSingle(b, !packed),
"Register allocation turned singles into doubles in the middle of fp_logic");
}
void JitArm64::fselx(UGeckoInstruction inst)
@ -209,6 +218,7 @@ void JitArm64::fselx(UGeckoInstruction inst)
const u32 c = inst.FC;
const u32 d = inst.FD;
const bool a_single = fpr.IsSingle(a, true);
if (fpr.IsSingle(a, true))
{
const ARM64Reg VA = fpr.R(a, RegType::LowerPairSingle);
@ -220,15 +230,20 @@ void JitArm64::fselx(UGeckoInstruction inst)
m_float_emit.FCMPE(EncodeRegToDouble(VA));
}
const bool single = fpr.IsSingle(b, true) && fpr.IsSingle(c, true);
const RegType type = single ? RegType::LowerPairSingle : RegType::LowerPair;
const auto reg_encoder = single ? EncodeRegToSingle : EncodeRegToDouble;
const bool b_and_c_singles = fpr.IsSingle(b, true) && fpr.IsSingle(c, true);
const RegType type = b_and_c_singles ? RegType::LowerPairSingle : RegType::LowerPair;
const auto reg_encoder = b_and_c_singles ? EncodeRegToSingle : EncodeRegToDouble;
const ARM64Reg VB = fpr.R(b, type);
const ARM64Reg VC = fpr.R(c, type);
const ARM64Reg VD = fpr.RW(d, type);
m_float_emit.FCSEL(reg_encoder(VD), reg_encoder(VC), reg_encoder(VB), CC_GE);
ASSERT_MSG(DYNA_REC,
a_single == fpr.IsSingle(a, true) &&
b_and_c_singles == (fpr.IsSingle(b, true) && fpr.IsSingle(c, true)),
"Register allocation turned singles into doubles in the middle of fselx");
}
void JitArm64::frspx(UGeckoInstruction inst)
@ -241,7 +256,8 @@ void JitArm64::frspx(UGeckoInstruction inst)
const u32 b = inst.FB;
const u32 d = inst.FD;
if (fpr.IsSingle(b, true))
const bool single = fpr.IsSingle(b, true);
if (single)
{
// Source is already in single precision, so no need to do anything but to copy to PSR1.
const ARM64Reg VB = fpr.R(b, RegType::LowerPairSingle);
@ -257,6 +273,9 @@ void JitArm64::frspx(UGeckoInstruction inst)
m_float_emit.FCVT(32, 64, EncodeRegToDouble(VD), EncodeRegToDouble(VB));
}
ASSERT_MSG(DYNA_REC, b == d || single == fpr.IsSingle(b, true),
"Register allocation turned singles into doubles in the middle of frspx");
}
void JitArm64::fcmpX(UGeckoInstruction inst)
@ -320,6 +339,9 @@ void JitArm64::fcmpX(UGeckoInstruction inst)
SetJumpTarget(continue3);
}
SetJumpTarget(continue1);
ASSERT_MSG(DYNA_REC, singles == (fpr.IsSingle(a, true) && fpr.IsSingle(b, true)),
"Register allocation turned singles into doubles in the middle of fcmpX");
}
void JitArm64::fctiwzx(UGeckoInstruction inst)
@ -357,4 +379,7 @@ void JitArm64::fctiwzx(UGeckoInstruction inst)
}
m_float_emit.ORR(EncodeRegToDouble(VD), EncodeRegToDouble(VD), EncodeRegToDouble(V0));
fpr.Unlock(V0);
ASSERT_MSG(DYNA_REC, b == d || single == fpr.IsSingle(b, true),
"Register allocation turned singles into doubles in the middle of fctiwzx");
}

View File

@ -66,6 +66,9 @@ void JitArm64::ps_mergeXX(UGeckoInstruction inst)
ASSERT_MSG(DYNA_REC, 0, "ps_merge - invalid op");
break;
}
ASSERT_MSG(DYNA_REC, singles == (fpr.IsSingle(a) && fpr.IsSingle(b)),
"Register allocation turned singles into doubles in the middle of ps_mergeXX");
}
void JitArm64::ps_mulsX(UGeckoInstruction inst)
@ -92,6 +95,9 @@ void JitArm64::ps_mulsX(UGeckoInstruction inst)
m_float_emit.FMUL(size, reg_encoder(VD), reg_encoder(VA), reg_encoder(VC), upper ? 1 : 0);
ASSERT_MSG(DYNA_REC, singles == (fpr.IsSingle(a) && fpr.IsSingle(c)),
"Register allocation turned singles into doubles in the middle of ps_mulsX");
fpr.FixSinglePrecision(d);
}
@ -250,6 +256,10 @@ void JitArm64::ps_maddXX(UGeckoInstruction inst)
ASSERT_MSG(DYNA_REC, 0, "ps_madd - invalid op");
break;
}
ASSERT_MSG(DYNA_REC, singles == (fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c)),
"Register allocation turned singles into doubles in the middle of ps_maddXX");
fpr.FixSinglePrecision(d);
if (V0Q != INVALID_REG)
@ -291,6 +301,9 @@ void JitArm64::ps_sel(UGeckoInstruction inst)
m_float_emit.MOV(VD, V0);
fpr.Unlock(V0Q);
}
ASSERT_MSG(DYNA_REC, singles == (fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c)),
"Register allocation turned singles into doubles in the middle of ps_sel");
}
void JitArm64::ps_sumX(UGeckoInstruction inst)
@ -330,6 +343,9 @@ void JitArm64::ps_sumX(UGeckoInstruction inst)
m_float_emit.INS(size, VD, upper ? 1 : 0, V0, upper ? 1 : 0);
}
ASSERT_MSG(DYNA_REC, singles == (fpr.IsSingle(a) && fpr.IsSingle(b) && fpr.IsSingle(c)),
"Register allocation turned singles into doubles in the middle of ps_sumX");
fpr.FixSinglePrecision(d);
fpr.Unlock(V0);