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
|
// Use signed conversion to float, as exponent is ilog2
|
||||||
// Fixup "negative" cases by overwriting with zero
|
// "Negative" values are zeroed due to saturation subtract
|
||||||
const u32 exp_bias = 127;
|
constexpr u32 exp_bias = 127;
|
||||||
|
|
||||||
const XmmLink& vf = XmmAlloc();
|
const XmmLink& vf = XmmAlloc();
|
||||||
const XmmLink& v1 = XmmAlloc();
|
const XmmLink& v1 = XmmAlloc();
|
||||||
@@ -3365,10 +3365,8 @@ void spu_recompiler::CLZ(spu_opcode_t op)
|
|||||||
c->pcmpeqd(v1, va);
|
c->pcmpeqd(v1, va);
|
||||||
c->pand(v1, XmmConst(v128::from32p(32 ^ (31 + exp_bias))));
|
c->pand(v1, XmmConst(v128::from32p(32 ^ (31 + exp_bias))));
|
||||||
c->pxor(v1, XmmConst(v128::from32p(31 + exp_bias)));
|
c->pxor(v1, XmmConst(v128::from32p(31 + exp_bias)));
|
||||||
c->psubd(v1, vf); // (x==0)? 32 : 31 - (exponent - exp_bias)
|
c->psubusw(v1, vf); // (x==0)? 32 : 31 - (exponent - exp_bias)
|
||||||
c->psrad(va, 31);
|
c->movdqa(SPU_OFF_128(gpr, op.rt), v1);
|
||||||
c->pandn(va, v1);
|
|
||||||
c->movdqa(SPU_OFF_128(gpr, op.rt), va);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6329,7 +6329,30 @@ public:
|
|||||||
|
|
||||||
void CLZ(spu_opcode_t op)
|
void CLZ(spu_opcode_t op)
|
||||||
{
|
{
|
||||||
|
#ifdef ARCH_ARM64
|
||||||
set_vr(op.rt, ctlz(get_vr(op.ra)));
|
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)
|
void XSWD(spu_opcode_t op)
|
||||||
|
|||||||
Reference in New Issue
Block a user