diff --git a/llvm/include/llvm/ADT/bit.h b/llvm/include/llvm/ADT/bit.h --- a/llvm/include/llvm/ADT/bit.h +++ b/llvm/include/llvm/ADT/bit.h @@ -350,6 +350,37 @@ return detail::PopulationCounter::count(Value); } +// Forward-declare rotr so that rotl can use it. +template >> +[[nodiscard]] constexpr T rotr(T V, int R); + +template >> +[[nodiscard]] constexpr T rotl(T V, int R) { + unsigned N = std::numeric_limits::digits; + + R = R % N; + if (!R) + return V; + + if (R < 0) + return llvm::rotr(V, -R); + + return (V << R) | (V >> (N - R)); +} + +template [[nodiscard]] constexpr T rotr(T V, int R) { + unsigned N = std::numeric_limits::digits; + + R = R % N; + if (!R) + return V; + + if (R < 0) + return llvm::rotl(V, -R); + + return (V >> R) | (V << (N - R)); +} + } // namespace llvm #endif diff --git a/llvm/unittests/ADT/BitTest.cpp b/llvm/unittests/ADT/BitTest.cpp --- a/llvm/unittests/ADT/BitTest.cpp +++ b/llvm/unittests/ADT/BitTest.cpp @@ -354,4 +354,48 @@ EXPECT_EQ(1, llvm::popcount(1U << I)); } +TEST(BitTest, Rotl) { + EXPECT_EQ(0x53U, llvm::rotl(0x53, 0)); + EXPECT_EQ(0x4dU, llvm::rotl(0x53, 2)); + EXPECT_EQ(0xa6U, llvm::rotl(0x53, 9)); + EXPECT_EQ(0x9aU, llvm::rotl(0x53, -5)); + + EXPECT_EQ(0xabcdU, llvm::rotl(0xabcd, 0)); + EXPECT_EQ(0xf36aU, llvm::rotl(0xabcd, 6)); + EXPECT_EQ(0xaf36U, llvm::rotl(0xabcd, 18)); + EXPECT_EQ(0xf36aU, llvm::rotl(0xabcd, -10)); + + EXPECT_EQ(0xdeadbeefU, llvm::rotl(0xdeadbeef, 0)); + EXPECT_EQ(0x7ddfbd5bU, llvm::rotl(0xdeadbeef, 17)); + EXPECT_EQ(0x5b7ddfbdU, llvm::rotl(0xdeadbeef, 41)); + EXPECT_EQ(0xb6fbbf7aU, llvm::rotl(0xdeadbeef, -22)); + + EXPECT_EQ(0x12345678deadbeefULL, llvm::rotl(0x12345678deadbeefULL, 0)); + EXPECT_EQ(0xf56df77891a2b3c6ULL, llvm::rotl(0x12345678deadbeefULL, 35)); + EXPECT_EQ(0x8d159e37ab6fbbc4ULL, llvm::rotl(0x12345678deadbeefULL, 70)); + EXPECT_EQ(0xb7dde2468acf1bd5ULL, llvm::rotl(0x12345678deadbeefULL, -19)); +} + +TEST(BitTest, Rotr) { + EXPECT_EQ(0x53U, llvm::rotr(0x53, 0)); + EXPECT_EQ(0xd4U, llvm::rotr(0x53, 2)); + EXPECT_EQ(0xa9U, llvm::rotr(0x53, 9)); + EXPECT_EQ(0x6aU, llvm::rotr(0x53, -5)); + + EXPECT_EQ(0xabcdU, llvm::rotr(0xabcd, 0)); + EXPECT_EQ(0x36afU, llvm::rotr(0xabcd, 6)); + EXPECT_EQ(0x6af3U, llvm::rotr(0xabcd, 18)); + EXPECT_EQ(0x36afU, llvm::rotr(0xabcd, -10)); + + EXPECT_EQ(0xdeadbeefU, llvm::rotr(0xdeadbeef, 0)); + EXPECT_EQ(0xdf77ef56U, llvm::rotr(0xdeadbeef, 17)); + EXPECT_EQ(0x77ef56dfU, llvm::rotr(0xdeadbeef, 41)); + EXPECT_EQ(0xbbf7ab6fU, llvm::rotr(0xdeadbeef, -22)); + + EXPECT_EQ(0x12345678deadbeefULL, llvm::rotr(0x12345678deadbeefULL, 0)); + EXPECT_EQ(0x1bd5b7dde2468acfULL, llvm::rotr(0x12345678deadbeefULL, 35)); + EXPECT_EQ(0xbc48d159e37ab6fbULL, llvm::rotr(0x12345678deadbeefULL, 70)); + EXPECT_EQ(0xb3c6f56df77891a2ULL, llvm::rotr(0x12345678deadbeefULL, -19)); +} + } // anonymous namespace