[orc-rt] Implement rotl / rotr, fix missing include in unit test. (#177305)

In e838f27e0f3 the EndianTest.cpp unittest was updated to avoid using
`llvm::rotl` function, but the corresponding `orc_rt::rotl` function had
not been implemented yet.

This commit implements orc_rt::rotl, orc_rt::rotr, and
orc_rt::has_single_bit by copying their definitions from the
corresponding LLVM header (llvm-project/llvm/include/llvm/ADT/bit.h).
Unit tests for these functions are also copied from their LLVM
counterparts.

Thanks to @jaredwy for spotting this!
This commit is contained in:
Lang Hames 2026-01-22 16:15:04 +11:00 committed by GitHub
parent 2036bc524b
commit 2b22d76ba7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 101 additions and 0 deletions

View File

@ -128,6 +128,37 @@ template <typename T, typename _ = std::enable_if_t<std::is_unsigned_v<T>>>
return std::numeric_limits<T>::digits - countl_zero(x);
}
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
[[nodiscard]] constexpr inline bool has_single_bit(T Value) noexcept {
return (Value != 0) && ((Value & (Value - 1)) == 0);
}
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
[[nodiscard]] constexpr T rotl(T V, int R) {
constexpr unsigned N = std::numeric_limits<T>::digits;
static_assert(has_single_bit(N), "& (N - 1) is only valid for powers of two");
R = R & (N - 1);
if (R == 0)
return V;
return (V << R) | (V >> (N - R));
}
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
[[nodiscard]] constexpr T rotr(T V, int R) {
constexpr unsigned N = std::numeric_limits<T>::digits;
static_assert(has_single_bit(N), "& (N - 1) is only valid for powers of two");
R = R & (N - 1);
if (R == 0)
return V;
return (V >> R) | (V << (N - R));
}
} // namespace orc_rt
#endif // ORC_RT_BIT_H

View File

@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "orc-rt/Endian.h"
#include "orc-rt/bit.h"
#include "gtest/gtest.h"
#include <algorithm>

View File

@ -151,3 +151,72 @@ TEST(BitTest, BitWidth) {
EXPECT_EQ(32, orc_rt::bit_width(uint32_t(0xffffffffu)));
EXPECT_EQ(64, orc_rt::bit_width(uint64_t(0xffffffffffffffffull)));
}
TEST(BitTest, HasSingleBit) {
EXPECT_FALSE(orc_rt::has_single_bit(0U));
EXPECT_FALSE(orc_rt::has_single_bit(0ULL));
EXPECT_FALSE(orc_rt::has_single_bit(~0U));
EXPECT_FALSE(orc_rt::has_single_bit(~0ULL));
EXPECT_TRUE(orc_rt::has_single_bit(1U));
EXPECT_TRUE(orc_rt::has_single_bit(1ULL));
static const int8_t kValueS8 = -128;
EXPECT_TRUE(orc_rt::has_single_bit(static_cast<uint8_t>(kValueS8)));
static const int16_t kValueS16 = -32768;
EXPECT_TRUE(orc_rt::has_single_bit(static_cast<uint16_t>(kValueS16)));
}
TEST(BitTest, Rotl) {
EXPECT_EQ(0x53U, orc_rt::rotl<uint8_t>(0x53, 0));
EXPECT_EQ(0x4dU, orc_rt::rotl<uint8_t>(0x53, 2));
EXPECT_EQ(0xa6U, orc_rt::rotl<uint8_t>(0x53, 9));
EXPECT_EQ(0x9aU, orc_rt::rotl<uint8_t>(0x53, -5));
EXPECT_EQ(0xabcdU, orc_rt::rotl<uint16_t>(0xabcd, 0));
EXPECT_EQ(0xf36aU, orc_rt::rotl<uint16_t>(0xabcd, 6));
EXPECT_EQ(0xaf36U, orc_rt::rotl<uint16_t>(0xabcd, 18));
EXPECT_EQ(0xf36aU, orc_rt::rotl<uint16_t>(0xabcd, -10));
EXPECT_EQ(0xdeadbeefU, orc_rt::rotl<uint32_t>(0xdeadbeef, 0));
EXPECT_EQ(0x7ddfbd5bU, orc_rt::rotl<uint32_t>(0xdeadbeef, 17));
EXPECT_EQ(0x5b7ddfbdU, orc_rt::rotl<uint32_t>(0xdeadbeef, 41));
EXPECT_EQ(0xb6fbbf7aU, orc_rt::rotl<uint32_t>(0xdeadbeef, -22));
EXPECT_EQ(0x12345678deadbeefULL,
orc_rt::rotl<uint64_t>(0x12345678deadbeefULL, 0));
EXPECT_EQ(0xf56df77891a2b3c6ULL,
orc_rt::rotl<uint64_t>(0x12345678deadbeefULL, 35));
EXPECT_EQ(0x8d159e37ab6fbbc4ULL,
orc_rt::rotl<uint64_t>(0x12345678deadbeefULL, 70));
EXPECT_EQ(0xb7dde2468acf1bd5ULL,
orc_rt::rotl<uint64_t>(0x12345678deadbeefULL, -19));
}
TEST(BitTest, Rotr) {
EXPECT_EQ(0x53U, orc_rt::rotr<uint8_t>(0x53, 0));
EXPECT_EQ(0xd4U, orc_rt::rotr<uint8_t>(0x53, 2));
EXPECT_EQ(0xa9U, orc_rt::rotr<uint8_t>(0x53, 9));
EXPECT_EQ(0x6aU, orc_rt::rotr<uint8_t>(0x53, -5));
EXPECT_EQ(0xabcdU, orc_rt::rotr<uint16_t>(0xabcd, 0));
EXPECT_EQ(0x36afU, orc_rt::rotr<uint16_t>(0xabcd, 6));
EXPECT_EQ(0x6af3U, orc_rt::rotr<uint16_t>(0xabcd, 18));
EXPECT_EQ(0x36afU, orc_rt::rotr<uint16_t>(0xabcd, -10));
EXPECT_EQ(0xdeadbeefU, orc_rt::rotr<uint32_t>(0xdeadbeef, 0));
EXPECT_EQ(0xdf77ef56U, orc_rt::rotr<uint32_t>(0xdeadbeef, 17));
EXPECT_EQ(0x77ef56dfU, orc_rt::rotr<uint32_t>(0xdeadbeef, 41));
EXPECT_EQ(0xbbf7ab6fU, orc_rt::rotr<uint32_t>(0xdeadbeef, -22));
EXPECT_EQ(0x12345678deadbeefULL,
orc_rt::rotr<uint64_t>(0x12345678deadbeefULL, 0));
EXPECT_EQ(0x1bd5b7dde2468acfULL,
orc_rt::rotr<uint64_t>(0x12345678deadbeefULL, 35));
EXPECT_EQ(0xbc48d159e37ab6fbULL,
orc_rt::rotr<uint64_t>(0x12345678deadbeefULL, 70));
EXPECT_EQ(0xb3c6f56df77891a2ULL,
orc_rt::rotr<uint64_t>(0x12345678deadbeefULL, -19));
}