SPU LLVM + zero with saturation subtract
- Added a LLVM SPU recompiler implementation as LLVM can't take advantage of the rounding mode. - Further optimized the method by replacing MSB check with saturation subtraction. Negative values are saturated to zero due to the float's sign bit.
This commit is contained in:
@@ -3354,8 +3354,8 @@ void spu_recompiler::CLZ(spu_opcode_t op)
|
||||
}
|
||||
|
||||
// Use signed conversion to float, as exponent is ilog2
|
||||
// Fixup "negative" cases by overwriting with zero
|
||||
const u32 exp_bias = 127;
|
||||
// "Negative" values are zeroed due to saturation subtract
|
||||
constexpr u32 exp_bias = 127;
|
||||
|
||||
const XmmLink& vf = XmmAlloc();
|
||||
const XmmLink& v1 = XmmAlloc();
|
||||
@@ -3365,10 +3365,8 @@ void spu_recompiler::CLZ(spu_opcode_t op)
|
||||
c->pcmpeqd(v1, va);
|
||||
c->pand(v1, XmmConst(v128::from32p(32 ^ (31 + exp_bias))));
|
||||
c->pxor(v1, XmmConst(v128::from32p(31 + exp_bias)));
|
||||
c->psubd(v1, vf); // (x==0)? 32 : 31 - (exponent - exp_bias)
|
||||
c->psrad(va, 31);
|
||||
c->pandn(va, v1);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), va);
|
||||
c->psubusw(v1, vf); // (x==0)? 32 : 31 - (exponent - exp_bias)
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), v1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -6329,7 +6329,30 @@ public:
|
||||
|
||||
void CLZ(spu_opcode_t op)
|
||||
{
|
||||
#ifdef ARCH_ARM64
|
||||
set_vr(op.rt, ctlz(get_vr(op.ra)));
|
||||
#else
|
||||
if (m_use_avx512)
|
||||
{
|
||||
set_vr(op.rt, ctlz(get_vr(op.ra)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Implement manually since LLVM can't take advantage of round-towards-zero.
|
||||
// Helpful as when converting to a float the exponent is always floor(ilog2)
|
||||
|
||||
constexpr u32 exp_bias = 127;
|
||||
value_t<f32[4]> flt;
|
||||
|
||||
const auto a = get_vr(op.ra);
|
||||
flt.value = m_ir->CreateSIToFP(a.value, get_type<f32[4]>()); // only correct with round-towards-zero!
|
||||
const auto exp = bitcast<u32[4]>(flt) >> 23;
|
||||
|
||||
// "Negative" values cause saturation due to float's sign bit
|
||||
const auto offset = select(a == 0, splat<u32[4]>(32), splat<u32[4]>(exp_bias + 31));
|
||||
const auto lzcnt = sub_sat(bitcast<u16[8]>(offset), bitcast<u16[8]>(exp));
|
||||
set_vr(op.rt, bitcast<u32[4]>(lzcnt));
|
||||
#endif
|
||||
}
|
||||
|
||||
void XSWD(spu_opcode_t op)
|
||||
|
||||
Reference in New Issue
Block a user