https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127055
Bug ID: 127055
Summary: Missing vectorizations of round math functions
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: missed-optimization
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: mkretz at gcc dot gnu.org
Target Milestone: ---
Target: x86_64-*-*
The nearbyint, rint, trunc, ceil, floor, and round functions are not vectorized
as they should be. All functions should directly translate to (v)roundp[sd] or
vrndscalep[sdh]. The round function should translate to a blend of ceil/floor
selected on the sign bit of the input (unless I'm mistaken). Clang does a
decent job of vectorizing the test case (though its choice of add+round has
higher latency than blend of 2 round instructions).
Vectorization should work from x86-64-v2 on.
Test case (https://compiler-explorer.com/z/TeMj9G9ze):
#include <utility>
#define ROUND_FUN(name) \
template <typename V> \
V name(V x) \
{ \
using T = std::remove_cvref_t<decltype(x[0])>; \
constexpr auto [...is] = std::_IotaArray<sizeof(x) / sizeof(x[0])>; \
return V{T(__builtin_##name(x[is]))...}; \
}
ROUND_FUN(nearbyint)
ROUND_FUN(rint)
ROUND_FUN(trunc)
ROUND_FUN(ceil)
ROUND_FUN(floor)
#if 1
ROUND_FUN(round)
#else
template <typename V>
V round(V x)
{
using T = std::__conditional_t<sizeof(x[0]) == 4, int,
std::__conditional_t<sizeof(x[0]) == 2, short, long long>>;
using I [[gnu::vector_size(sizeof(V))]] = T;
return reinterpret_cast<I>(x) < 0 ? floor(x) : ceil(x);
}
#endif
using v2df [[gnu::vector_size(16)]] = double;
using v4sf [[gnu::vector_size(16)]] = float;
#define TEST(type, name) type test_##type##_##name(type x) { return name(x); }
TEST(v2df, nearbyint) // vroundpd 12
TEST(v2df, rint) // vroundpd 4
TEST(v2df, trunc) // vroundpd 11
TEST(v2df, ceil) // vroundpd 10
TEST(v2df, floor) // vroundpd 9
TEST(v2df, round) // vblendvpd(vroundpd 9, 10)
TEST(v4sf, nearbyint) // vroundps 12
TEST(v4sf, rint) // vroundps 4
TEST(v4sf, trunc) // vroundps 11
TEST(v4sf, ceil) // vroundps 10
TEST(v4sf, floor) // vroundps 9
TEST(v4sf, round) // vblendvps(vroundps 9, 10)
#if __AVX__
using v4df [[gnu::vector_size(32)]] = double;
using v8sf [[gnu::vector_size(32)]] = float;
TEST(v4df, nearbyint) // vroundpd 12
TEST(v4df, rint) // vroundpd 4
TEST(v4df, trunc) // vroundpd 11
TEST(v4df, ceil) // vroundpd 10
TEST(v4df, floor) // vroundpd 9
TEST(v4df, round) // vblendvpd(vroundpd 9, 10)
TEST(v8sf, nearbyint) // vroundps 12
TEST(v8sf, rint) // vroundps 4
TEST(v8sf, trunc) // vroundps 11
TEST(v8sf, ceil) // vroundps 10
TEST(v8sf, floor) // vroundps 9
TEST(v8sf, round) // vblendvps(vroundps 9, 10)
#if __AVX512F__
using v8df [[gnu::vector_size(64)]] = double;
using v16sf [[gnu::vector_size(64)]] = float;
TEST(v8df, nearbyint) // vrndscalepd 12
TEST(v8df, rint) // vrndscalepd 4
TEST(v8df, trunc) // vrndscalepd 11
TEST(v8df, ceil) // vrndscalepd 10
TEST(v8df, floor) // vrndscalepd 9
TEST(v8df, round) // vblendvpd(vrndscalepd 9, 10)
TEST(v16sf, nearbyint) // vrndscaleps 12
TEST(v16sf, rint) // vrndscaleps 4
TEST(v16sf, trunc) // vrndscaleps 11
TEST(v16sf, ceil) // vrndscaleps 10
TEST(v16sf, floor) // vrndscaleps 9
TEST(v16sf, round) // vblendvps(vrndscaleps 9, 10)
#if __AVX512FP16__
using v8hf [[gnu::vector_size(16)]] = _Float16;
using v16hf [[gnu::vector_size(32)]] = _Float16;
using v32hf [[gnu::vector_size(64)]] = _Float16;
TEST(v8hf, nearbyint) // vrndscaleph 12
TEST(v8hf, rint) // vrndscaleph 4
TEST(v8hf, trunc) // vrndscaleph 11
TEST(v8hf, ceil) // vrndscaleph 10
TEST(v8hf, floor) // vrndscaleph 9
TEST(v8hf, round) // vblendvps(vrndscaleph 9, 10)
TEST(v16hf, nearbyint) // vrndscaleph 12
TEST(v16hf, rint) // vrndscaleph 4
TEST(v16hf, trunc) // vrndscaleph 11
TEST(v16hf, ceil) // vrndscaleph 10
TEST(v16hf, floor) // vrndscaleph 9
TEST(v16hf, round) // vblendvps(vrndscaleph 9, 10)
TEST(v32hf, nearbyint) // vrndscaleph 12
TEST(v32hf, rint) // vrndscaleph 4
TEST(v32hf, trunc) // vrndscaleph 11
TEST(v32hf, ceil) // vrndscaleph 10
TEST(v32hf, floor) // vrndscaleph 9
TEST(v32hf, round) // vblendvps(vrndscaleph 9, 10)
#endif
#endif
#endif