From 161bddf3af09aa883c9414d793de79c89e51636a Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Wed, 9 Mar 2022 13:07:33 +0100 Subject: [PATCH] [ADT] Make BitmaskEnum operations constant expressions This avoids runtime initialization (a global constructor) whenever they appear in the initializer. The patch just adds the constexpr keyword to a couple of functions. Differential Revision: https://reviews.llvm.org/D121281 --- llvm/include/llvm/ADT/BitmaskEnum.h | 12 ++++++------ llvm/include/llvm/Support/MathExtras.h | 2 +- llvm/unittests/ADT/BitmaskEnumTest.cpp | 11 +++++++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/llvm/include/llvm/ADT/BitmaskEnum.h b/llvm/include/llvm/ADT/BitmaskEnum.h index 89e5508..205da12 100644 --- a/llvm/include/llvm/ADT/BitmaskEnum.h +++ b/llvm/include/llvm/ADT/BitmaskEnum.h @@ -77,7 +77,7 @@ namespace BitmaskEnumDetail { /// Get a bitmask with 1s in all places up to the high-order bit of E's largest /// value. -template std::underlying_type_t Mask() { +template constexpr std::underlying_type_t Mask() { // On overflow, NextPowerOf2 returns zero with the type uint64_t, so // subtracting 1 gives us the mask with all bits set, like we want. return NextPowerOf2(static_cast>( @@ -87,7 +87,7 @@ template std::underlying_type_t Mask() { /// Check that Val is in range for E, and return Val cast to E's underlying /// type. -template std::underlying_type_t Underlying(E Val) { +template constexpr std::underlying_type_t Underlying(E Val) { auto U = static_cast>(Val); assert(U >= 0 && "Negative enum values are not allowed."); assert(U <= Mask() && "Enum value too large (or largest val too small?)"); @@ -99,22 +99,22 @@ constexpr unsigned bitWidth(uint64_t Value) { } template ::value>> -E operator~(E Val) { +constexpr E operator~(E Val) { return static_cast(~Underlying(Val) & Mask()); } template ::value>> -E operator|(E LHS, E RHS) { +constexpr E operator|(E LHS, E RHS) { return static_cast(Underlying(LHS) | Underlying(RHS)); } template ::value>> -E operator&(E LHS, E RHS) { +constexpr E operator&(E LHS, E RHS) { return static_cast(Underlying(LHS) & Underlying(RHS)); } template ::value>> -E operator^(E LHS, E RHS) { +constexpr E operator^(E LHS, E RHS) { return static_cast(Underlying(LHS) ^ Underlying(RHS)); } diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h index 604d709..8c2f2af1 100644 --- a/llvm/include/llvm/Support/MathExtras.h +++ b/llvm/include/llvm/Support/MathExtras.h @@ -707,7 +707,7 @@ constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) { /// Returns the next power of two (in 64-bits) that is strictly greater than A. /// Returns zero on overflow. -inline uint64_t NextPowerOf2(uint64_t A) { +constexpr inline uint64_t NextPowerOf2(uint64_t A) { A |= (A >> 1); A |= (A >> 2); A |= (A >> 4); diff --git a/llvm/unittests/ADT/BitmaskEnumTest.cpp b/llvm/unittests/ADT/BitmaskEnumTest.cpp index f07e203..266a3f6 100644 --- a/llvm/unittests/ADT/BitmaskEnumTest.cpp +++ b/llvm/unittests/ADT/BitmaskEnumTest.cpp @@ -76,6 +76,17 @@ TEST(BitmaskEnumTest, BitwiseXorEquals) { EXPECT_EQ(F3, f); } +TEST(BitmaskEnumTest, ConstantExpression) { + constexpr Flags f1 = ~F1; + constexpr Flags f2 = F1 | F2; + constexpr Flags f3 = F1 & F2; + constexpr Flags f4 = F1 ^ F2; + EXPECT_EQ(f1, ~F1); + EXPECT_EQ(f2, F1 | F2); + EXPECT_EQ(f3, F1 & F2); + EXPECT_EQ(f4, F1 ^ F2); +} + TEST(BitmaskEnumTest, BitwiseNot) { Flags f = ~F1; EXPECT_EQ(14, f); // Largest value for f is 15. -- 2.7.4