https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127055
--- Comment #22 from Matthias Kretz (Vir) <mkretz at gcc dot gnu.org> ---
> for patch at #c8, please also remove !flag_trapping_mathb from vector
> 27017:trunc<mode>2
That's already the case.
> 1) we need to fix the current vector expander with !flag_rounding_math
> there's different rounding mode used in the existed implementation ---
> roundps $3(ROUND_TRUNC) is used.
How is that wrong? Because it doesn't set if imm[3] = 1? That means it can just
emit more spurious FE_INEXACT, which we don't care about with
!flag_rounding_math anyway. But I agree we could be nicer here.
> The bit-manipulation solution seem correct and can drop !flag_rounding_math,
> but not sure about performance(the existed solution takes only 4 uops with
> -frounding-math).
The solution I posted in #c19 has higher latency than the existing solution.
Consequently, it should only be used with flag_rounding_math.
!flag_rounding_math already has a better solution.
The bit-manipulation solution is not ready yet (neither tested nor
benchmarked). In a std::simd implementation it looks like this (this is
inspired by the glibc implementation for round):
using _Up = _UInt<sizeof(_Tp)>;
using _Ip = __integer_from<sizeof(_Tp)>;
using _Lf = numeric_limits<_Tp>;
using _Vf = vec<_Tp, __width_of<_TV>>;
using _Vu = rebind_t<_Up, _Vf>;
using _Vi = rebind_t<_Ip, _Vf>;
constexpr int __mant_width = _Lf::digits - 1;
constexpr _Up __inf_bits = __builtin_bit_cast(_Up, _Lf::infinity());
constexpr _Up __exp_mask = __inf_bits >> __mant_width;
constexpr _Up __one_bits = __builtin_bit_cast(_Up, _Tp(1));
constexpr _Ip __bias = __one_bits >> __mant_width;
constexpr _Up __mant_mask = (1ull << __mant_width) - 1u;
constexpr _Up __half_bit = 1ull << (__mant_width - 1);
constexpr _Up __sign_bit = __builtin_bit_cast(_Up, _S_signmask<_TV>[0]);
_Vu __i0 = bit_cast<_Vu>(__x);
_Vi __j0 = _Vi((__i0 >> __mant_width) & __exp_mask) - __bias;
_Vi __jsatur = clamp(__j0, _Vi(), _Vi(_Ip(__mant_width - 1)));
_Vu __frac = __mant_mask >> _Vu(__jsatur);
_Vu __half = __half_bit >> _Vu(__jsatur);
_Vu __normal = (__i0 + __half) & ~__frac;
_Vu __small = __i0 & __sign_bit;
_Vu __one = __small | __one_bits;
auto __is_small = __j0 < _Ip(-1); // |x| < 0.5 → ±0.0
auto __is_one = __j0 == _Ip(-1); // 0.5 <= |x| < 1 → ±1.0
_Vu __r = select(__is_one, __one,
select(__is_small, __small, __normal));
return bit_cast<_TV>(__r);