[SPU LLVM] Use select in FMA to shorten its dependency chain (#19052)
The `FMA` instruction conditionally zeros one multiplicand if the other is zero/denormal to emulate the xfloat's extended range. This patch replaces that with a `select(is_non_zero, fma(a, b, c), c)` which has a shorter dependency chain in most situations and probably allows LLVM to better optimize it with surrounding instructions. I added a AVX512 path that uses `vfixupimmps` to prevent a pessimization where LLVM transforms it into a strictly serial predicate chain. I confirmed that it works with denormals and both zeros. https://godbolt.org/z/hsP5G43Ye
This commit is contained in:
@@ -8491,22 +8491,28 @@ public:
|
|||||||
|
|
||||||
if (a_notnan)
|
if (a_notnan)
|
||||||
{
|
{
|
||||||
const auto ma = sext<s32[4]>(fcmp_uno(a != fsplat<f32[4]>(0.)));
|
const auto normal_fma = fma32x4(a, b, c, a_known, b_known);
|
||||||
const auto cb = bitcast<f32[4]>(bitcast<s32[4]>(b) & ma);
|
return eval(select(fcmp_uno(a != fsplat<f32[4]>(0.)), normal_fma, c));
|
||||||
return fma32x4(a, eval(cb), c, a_known, b_known);
|
|
||||||
}
|
}
|
||||||
else if (b_notnan)
|
else if (b_notnan)
|
||||||
{
|
{
|
||||||
const auto mb = sext<s32[4]>(fcmp_uno(b != fsplat<f32[4]>(0.)));
|
const auto normal_fma = fma32x4(a, b, c, a_known, b_known);
|
||||||
const auto ca = bitcast<f32[4]>(bitcast<s32[4]>(a) & mb);
|
return eval(select(fcmp_uno(b != fsplat<f32[4]>(0.)), normal_fma, c));
|
||||||
return fma32x4(eval(ca), b, c, a_known, b_known);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ma = sext<s32[4]>(fcmp_uno(a != fsplat<f32[4]>(0.)));
|
// Same number of operations well preventing a serial predicate chain pessimization
|
||||||
const auto mb = sext<s32[4]>(fcmp_uno(b != fsplat<f32[4]>(0.)));
|
if (m_use_avx512)
|
||||||
const auto ca = bitcast<f32[4]>(bitcast<s32[4]>(a) & mb);
|
{
|
||||||
const auto cb = bitcast<f32[4]>(bitcast<s32[4]>(b) & ma);
|
// 0/denormals -> +0, else 1st operand
|
||||||
return fma32x4(eval(ca), eval(cb), c, a_known, b_known);
|
const auto ca = vfixupimmps(a, b, splat<u32[4]>(0x00000800u), 0, 0xff);
|
||||||
|
const auto cb = vfixupimmps(b, a, splat<u32[4]>(0x00000800u), 0, 0xff);
|
||||||
|
return fma32x4(ca, cb, c, a_known, b_known);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto normal_fma = fma32x4(a, b, c, a_known, b_known);
|
||||||
|
const auto a_cmp = fcmp_uno(a != fsplat<f32[4]>(0.));
|
||||||
|
const auto b_cmp = fcmp_uno(b != fsplat<f32[4]>(0.));
|
||||||
|
return eval(select(a_cmp & b_cmp, normal_fma, c));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user