diff --git a/orc-rt/include/orc-rt/bit.h b/orc-rt/include/orc-rt/bit.h index 241a529436de..8471f127dccb 100644 --- a/orc-rt/include/orc-rt/bit.h +++ b/orc-rt/include/orc-rt/bit.h @@ -128,6 +128,37 @@ template >> return std::numeric_limits::digits - countl_zero(x); } +template >> +[[nodiscard]] constexpr inline bool has_single_bit(T Value) noexcept { + return (Value != 0) && ((Value & (Value - 1)) == 0); +} + +template >> +[[nodiscard]] constexpr T rotl(T V, int R) { + constexpr unsigned N = std::numeric_limits::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 >> +[[nodiscard]] constexpr T rotr(T V, int R) { + constexpr unsigned N = std::numeric_limits::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 diff --git a/orc-rt/unittests/EndianTest.cpp b/orc-rt/unittests/EndianTest.cpp index 018f70d0ecd4..8bc0006e63e8 100644 --- a/orc-rt/unittests/EndianTest.cpp +++ b/orc-rt/unittests/EndianTest.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "orc-rt/Endian.h" +#include "orc-rt/bit.h" #include "gtest/gtest.h" #include diff --git a/orc-rt/unittests/bit-test.cpp b/orc-rt/unittests/bit-test.cpp index eaacfeda63d9..2a266e670dfc 100644 --- a/orc-rt/unittests/bit-test.cpp +++ b/orc-rt/unittests/bit-test.cpp @@ -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(kValueS8))); + + static const int16_t kValueS16 = -32768; + EXPECT_TRUE(orc_rt::has_single_bit(static_cast(kValueS16))); +} + +TEST(BitTest, Rotl) { + EXPECT_EQ(0x53U, orc_rt::rotl(0x53, 0)); + EXPECT_EQ(0x4dU, orc_rt::rotl(0x53, 2)); + EXPECT_EQ(0xa6U, orc_rt::rotl(0x53, 9)); + EXPECT_EQ(0x9aU, orc_rt::rotl(0x53, -5)); + + EXPECT_EQ(0xabcdU, orc_rt::rotl(0xabcd, 0)); + EXPECT_EQ(0xf36aU, orc_rt::rotl(0xabcd, 6)); + EXPECT_EQ(0xaf36U, orc_rt::rotl(0xabcd, 18)); + EXPECT_EQ(0xf36aU, orc_rt::rotl(0xabcd, -10)); + + EXPECT_EQ(0xdeadbeefU, orc_rt::rotl(0xdeadbeef, 0)); + EXPECT_EQ(0x7ddfbd5bU, orc_rt::rotl(0xdeadbeef, 17)); + EXPECT_EQ(0x5b7ddfbdU, orc_rt::rotl(0xdeadbeef, 41)); + EXPECT_EQ(0xb6fbbf7aU, orc_rt::rotl(0xdeadbeef, -22)); + + EXPECT_EQ(0x12345678deadbeefULL, + orc_rt::rotl(0x12345678deadbeefULL, 0)); + EXPECT_EQ(0xf56df77891a2b3c6ULL, + orc_rt::rotl(0x12345678deadbeefULL, 35)); + EXPECT_EQ(0x8d159e37ab6fbbc4ULL, + orc_rt::rotl(0x12345678deadbeefULL, 70)); + EXPECT_EQ(0xb7dde2468acf1bd5ULL, + orc_rt::rotl(0x12345678deadbeefULL, -19)); +} + +TEST(BitTest, Rotr) { + EXPECT_EQ(0x53U, orc_rt::rotr(0x53, 0)); + EXPECT_EQ(0xd4U, orc_rt::rotr(0x53, 2)); + EXPECT_EQ(0xa9U, orc_rt::rotr(0x53, 9)); + EXPECT_EQ(0x6aU, orc_rt::rotr(0x53, -5)); + + EXPECT_EQ(0xabcdU, orc_rt::rotr(0xabcd, 0)); + EXPECT_EQ(0x36afU, orc_rt::rotr(0xabcd, 6)); + EXPECT_EQ(0x6af3U, orc_rt::rotr(0xabcd, 18)); + EXPECT_EQ(0x36afU, orc_rt::rotr(0xabcd, -10)); + + EXPECT_EQ(0xdeadbeefU, orc_rt::rotr(0xdeadbeef, 0)); + EXPECT_EQ(0xdf77ef56U, orc_rt::rotr(0xdeadbeef, 17)); + EXPECT_EQ(0x77ef56dfU, orc_rt::rotr(0xdeadbeef, 41)); + EXPECT_EQ(0xbbf7ab6fU, orc_rt::rotr(0xdeadbeef, -22)); + + EXPECT_EQ(0x12345678deadbeefULL, + orc_rt::rotr(0x12345678deadbeefULL, 0)); + EXPECT_EQ(0x1bd5b7dde2468acfULL, + orc_rt::rotr(0x12345678deadbeefULL, 35)); + EXPECT_EQ(0xbc48d159e37ab6fbULL, + orc_rt::rotr(0x12345678deadbeefULL, 70)); + EXPECT_EQ(0xb3c6f56df77891a2ULL, + orc_rt::rotr(0x12345678deadbeefULL, -19)); +}