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

Reply via email to