Merge pull request #12091 from JosJuice/jitarm64-skip-quiet-bit
JitArm64: Use one instruction for making NaNs quiet
This commit is contained in:
commit
8cf0597d5f
|
@ -180,10 +180,6 @@ public:
|
||||||
|
|
||||||
void FloatCompare(UGeckoInstruction inst, bool upper = false);
|
void FloatCompare(UGeckoInstruction inst, bool upper = false);
|
||||||
|
|
||||||
// temp_gpr can be INVALID_REG if single is true
|
|
||||||
void EmitQuietNaNBitConstant(Arm64Gen::ARM64Reg dest_reg, bool single,
|
|
||||||
Arm64Gen::ARM64Reg temp_gpr);
|
|
||||||
|
|
||||||
bool IsFPRStoreSafe(size_t guest_reg) const;
|
bool IsFPRStoreSafe(size_t guest_reg) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -137,12 +137,6 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
|
||||||
|
|
||||||
const ARM64Reg temp_gpr = m_accurate_nans && !single ? gpr.GetReg() : ARM64Reg::INVALID_REG;
|
const ARM64Reg temp_gpr = m_accurate_nans && !single ? gpr.GetReg() : ARM64Reg::INVALID_REG;
|
||||||
|
|
||||||
if (m_accurate_nans)
|
|
||||||
{
|
|
||||||
if (V0Q == ARM64Reg::INVALID_REG)
|
|
||||||
V0Q = fpr.GetReg();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (op5)
|
switch (op5)
|
||||||
{
|
{
|
||||||
case 18:
|
case 18:
|
||||||
|
@ -202,10 +196,6 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
|
||||||
SwitchToFarCode();
|
SwitchToFarCode();
|
||||||
SetJumpTarget(nan);
|
SetJumpTarget(nan);
|
||||||
|
|
||||||
const ARM64Reg quiet_bit_reg = reg_encoder(V0Q);
|
|
||||||
|
|
||||||
EmitQuietNaNBitConstant(quiet_bit_reg, inputs_are_singles && output_is_single, temp_gpr);
|
|
||||||
|
|
||||||
Common::SmallVector<ARM64Reg, 3> inputs;
|
Common::SmallVector<ARM64Reg, 3> inputs;
|
||||||
inputs.push_back(VA);
|
inputs.push_back(VA);
|
||||||
if (use_b && VA != VB)
|
if (use_b && VA != VB)
|
||||||
|
@ -213,7 +203,7 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
|
||||||
if (use_c && VA != VC && (!use_b || VB != VC))
|
if (use_c && VA != VC && (!use_b || VB != VC))
|
||||||
inputs.push_back(VC);
|
inputs.push_back(VC);
|
||||||
|
|
||||||
// If any inputs are NaNs, pick the first NaN of them and OR it with the quiet bit
|
// If any inputs are NaNs, pick the first NaN of them and set its quiet bit
|
||||||
for (size_t i = 0; i < inputs.size(); ++i)
|
for (size_t i = 0; i < inputs.size(); ++i)
|
||||||
{
|
{
|
||||||
// Skip checking if the input is a NaN if it's the last input and we're guaranteed to have at
|
// Skip checking if the input is a NaN if it's the last input and we're guaranteed to have at
|
||||||
|
@ -228,8 +218,9 @@ void JitArm64::fp_arith(UGeckoInstruction inst)
|
||||||
skip = B(CCFlags::CC_VC);
|
skip = B(CCFlags::CC_VC);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_float_emit.ORR(EncodeRegToDouble(VD), EncodeRegToDouble(input),
|
// Make the NaN quiet
|
||||||
EncodeRegToDouble(quiet_bit_reg));
|
m_float_emit.FADD(VD, input, input);
|
||||||
|
|
||||||
nan_fixups.push_back(B());
|
nan_fixups.push_back(B());
|
||||||
|
|
||||||
if (check_input)
|
if (check_input)
|
||||||
|
@ -886,29 +877,6 @@ void JitArm64::ConvertSingleToDoublePair(size_t guest_reg, ARM64Reg dest_reg, AR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitArm64::EmitQuietNaNBitConstant(ARM64Reg dest_reg, bool single, ARM64Reg temp_gpr)
|
|
||||||
{
|
|
||||||
// dest_reg = QNaN & ~SNaN
|
|
||||||
//
|
|
||||||
// (Alternatively, dest_reg = QNaN would also work, but that would take
|
|
||||||
// two instructions to emit even for singles)
|
|
||||||
|
|
||||||
if (single)
|
|
||||||
{
|
|
||||||
m_float_emit.MOVI(32, dest_reg, 0x40, 16);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ASSERT(temp_gpr != ARM64Reg::INVALID_REG);
|
|
||||||
|
|
||||||
MOVI2R(EncodeRegTo64(temp_gpr), 0x0008'0000'0000'0000);
|
|
||||||
if (IsQuad(dest_reg))
|
|
||||||
m_float_emit.DUP(64, dest_reg, EncodeRegTo64(temp_gpr));
|
|
||||||
else
|
|
||||||
m_float_emit.FMOV(dest_reg, EncodeRegTo64(temp_gpr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JitArm64::IsFPRStoreSafe(size_t guest_reg) const
|
bool JitArm64::IsFPRStoreSafe(size_t guest_reg) const
|
||||||
{
|
{
|
||||||
return js.fpr_is_store_safe[guest_reg];
|
return js.fpr_is_store_safe[guest_reg];
|
||||||
|
|
|
@ -272,16 +272,15 @@ void JitArm64::ps_arith(UGeckoInstruction inst)
|
||||||
|
|
||||||
// Make the NaNs quiet
|
// Make the NaNs quiet
|
||||||
|
|
||||||
const ARM64Reg quiet_bit_reg = VD == result_reg ? reg_encoder(V2Q) : VD;
|
const ARM64Reg quiet_nan_reg = VD == result_reg ? reg_encoder(V2Q) : VD;
|
||||||
EmitQuietNaNBitConstant(quiet_bit_reg, singles, temp_gpr);
|
|
||||||
|
|
||||||
|
m_float_emit.FADD(size, quiet_nan_reg, result_reg, result_reg);
|
||||||
m_float_emit.FCMEQ(size, nan_temp_reg_paired, result_reg, result_reg);
|
m_float_emit.FCMEQ(size, nan_temp_reg_paired, result_reg, result_reg);
|
||||||
m_float_emit.ORR(quiet_bit_reg, quiet_bit_reg, result_reg);
|
|
||||||
if (negate_result)
|
if (negate_result)
|
||||||
m_float_emit.FNEG(size, result_reg, result_reg);
|
m_float_emit.FNEG(size, result_reg, result_reg);
|
||||||
if (VD == result_reg)
|
if (VD == result_reg)
|
||||||
m_float_emit.BIF(VD, quiet_bit_reg, nan_temp_reg_paired);
|
m_float_emit.BIF(VD, quiet_nan_reg, nan_temp_reg_paired);
|
||||||
else // quiet_bit_reg == VD
|
else // quiet_nan_reg == VD
|
||||||
m_float_emit.BIT(VD, result_reg, nan_temp_reg_paired);
|
m_float_emit.BIT(VD, result_reg, nan_temp_reg_paired);
|
||||||
|
|
||||||
nan_fixup = B();
|
nan_fixup = B();
|
||||||
|
@ -381,7 +380,6 @@ void JitArm64::ps_sumX(UGeckoInstruction inst)
|
||||||
const ARM64Reg VC = fpr.R(c, type);
|
const ARM64Reg VC = fpr.R(c, type);
|
||||||
const ARM64Reg VD = fpr.RW(d, type);
|
const ARM64Reg VD = fpr.RW(d, type);
|
||||||
const ARM64Reg V0 = fpr.GetReg();
|
const ARM64Reg V0 = fpr.GetReg();
|
||||||
const ARM64Reg V1 = m_accurate_nans ? fpr.GetReg() : ARM64Reg::INVALID_REG;
|
|
||||||
const ARM64Reg temp_gpr = m_accurate_nans && !singles ? gpr.GetReg() : ARM64Reg::INVALID_REG;
|
const ARM64Reg temp_gpr = m_accurate_nans && !singles ? gpr.GetReg() : ARM64Reg::INVALID_REG;
|
||||||
|
|
||||||
m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(VB), 1);
|
m_float_emit.DUP(size, reg_encoder(V0), reg_encoder(VB), 1);
|
||||||
|
@ -398,22 +396,23 @@ void JitArm64::ps_sumX(UGeckoInstruction inst)
|
||||||
SwitchToFarCode();
|
SwitchToFarCode();
|
||||||
SetJumpTarget(nan);
|
SetJumpTarget(nan);
|
||||||
|
|
||||||
EmitQuietNaNBitConstant(scalar_reg_encoder(V1), singles, temp_gpr);
|
|
||||||
|
|
||||||
if (upper)
|
if (upper)
|
||||||
{
|
{
|
||||||
m_float_emit.ORR(EncodeRegToDouble(V1), EncodeRegToDouble(V1), EncodeRegToDouble(input));
|
m_float_emit.FADD(scalar_reg_encoder(V0), scalar_reg_encoder(input),
|
||||||
m_float_emit.TRN1(size, reg_encoder(VD), reg_encoder(VC), reg_encoder(V1));
|
scalar_reg_encoder(input));
|
||||||
|
m_float_emit.TRN1(size, reg_encoder(VD), reg_encoder(VC), reg_encoder(V0));
|
||||||
}
|
}
|
||||||
else if (d != c)
|
else if (d != c)
|
||||||
{
|
{
|
||||||
m_float_emit.ORR(EncodeRegToDouble(VD), EncodeRegToDouble(V1), EncodeRegToDouble(input));
|
m_float_emit.FADD(scalar_reg_encoder(VD), scalar_reg_encoder(input),
|
||||||
|
scalar_reg_encoder(input));
|
||||||
m_float_emit.INS(size, VD, 1, VC, 1);
|
m_float_emit.INS(size, VD, 1, VC, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_float_emit.ORR(EncodeRegToDouble(V1), EncodeRegToDouble(V1), EncodeRegToDouble(input));
|
m_float_emit.FADD(scalar_reg_encoder(V0), scalar_reg_encoder(input),
|
||||||
m_float_emit.INS(size, VD, 0, V1, 0);
|
scalar_reg_encoder(input));
|
||||||
|
m_float_emit.INS(size, VD, 0, V0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FixupBranch nan_done = B();
|
FixupBranch nan_done = B();
|
||||||
|
@ -449,8 +448,6 @@ void JitArm64::ps_sumX(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
fpr.Unlock(V0);
|
fpr.Unlock(V0);
|
||||||
if (m_accurate_nans)
|
|
||||||
fpr.Unlock(V1);
|
|
||||||
if (temp_gpr != ARM64Reg::INVALID_REG)
|
if (temp_gpr != ARM64Reg::INVALID_REG)
|
||||||
gpr.Unlock(temp_gpr);
|
gpr.Unlock(temp_gpr);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue