[llvm] baaf111 - [BitmaskEnum] Add support for shift operators. (#118007)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 29 04:33:10 PST 2024
Author: Sander de Smalen
Date: 2024-11-29T12:33:04Z
New Revision: baaf1115ca007f95fd08c52dc8bec54d310f5b27
URL: https://github.com/llvm/llvm-project/commit/baaf1115ca007f95fd08c52dc8bec54d310f5b27
DIFF: https://github.com/llvm/llvm-project/commit/baaf1115ca007f95fd08c52dc8bec54d310f5b27.diff
LOG: [BitmaskEnum] Add support for shift operators. (#118007)
For enums that describe a bitmask where successive bits within that mask
describe some enum value (as described in the same enum), it is useful
to support operator<< and operator>> as well.
For example:
```
enum class E : unsigned {
// 2 bits per option
OptionA = 0,
OptionB = 1,
OptionC = 2,
OptionD = 3,
OptionMask = 3,
// Given 3 values in the bitmask X, Y and Z, each is 2 bits in size
// and represents a choice of OptionA..OptionD.
ShiftX = 0,
ShiftY = 2,
ShiftZ = 4,
};
// The mask can be encoded with:
E mask;
mask |= getOptionFor(X) << E::ShiftX;
mask |= getOptionFor(Y) << E::ShiftY;
mask |= getOptionFor(Z) << E::ShiftZ;
// And to extract a value:
E OptionForX = (mask >> E::ShiftX) & E::OptionMask;
E OptionForY = (mask >> E::ShiftY) & E::OptionMask;
E OptionForZ = (mask >> E::ShiftZ) & E::OptionMask;
```
Added:
Modified:
llvm/include/llvm/ADT/BitmaskEnum.h
llvm/unittests/ADT/BitmaskEnumTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/BitmaskEnum.h b/llvm/include/llvm/ADT/BitmaskEnum.h
index c87e7cac65a5b1..dcb13bd8ba51a5 100644
--- a/llvm/include/llvm/ADT/BitmaskEnum.h
+++ b/llvm/include/llvm/ADT/BitmaskEnum.h
@@ -85,9 +85,13 @@
using ::llvm::BitmaskEnumDetail::operator|; \
using ::llvm::BitmaskEnumDetail::operator&; \
using ::llvm::BitmaskEnumDetail::operator^; \
+ using ::llvm::BitmaskEnumDetail::operator<<; \
+ using ::llvm::BitmaskEnumDetail::operator>>; \
using ::llvm::BitmaskEnumDetail::operator|=; \
using ::llvm::BitmaskEnumDetail::operator&=; \
using ::llvm::BitmaskEnumDetail::operator^=; \
+ using ::llvm::BitmaskEnumDetail::operator<<=; \
+ using ::llvm::BitmaskEnumDetail::operator>>=; \
/* Force a semicolon at the end of this macro. */ \
using ::llvm::BitmaskEnumDetail::any
@@ -162,6 +166,16 @@ constexpr E operator^(E LHS, E RHS) {
return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
}
+template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
+constexpr E operator<<(E LHS, E RHS) {
+ return static_cast<E>(Underlying(LHS) << Underlying(RHS));
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
+constexpr E operator>>(E LHS, E RHS) {
+ return static_cast<E>(Underlying(LHS) >> Underlying(RHS));
+}
+
// |=, &=, and ^= return a reference to LHS, to match the behavior of the
// operators on builtin types.
@@ -183,6 +197,18 @@ E &operator^=(E &LHS, E RHS) {
return LHS;
}
+template <typename e, typename = std::enable_if_t<is_bitmask_enum<e>::value>>
+e &operator<<=(e &lhs, e rhs) {
+ lhs = lhs << rhs;
+ return lhs;
+}
+
+template <typename e, typename = std::enable_if_t<is_bitmask_enum<e>::value>>
+e &operator>>=(e &lhs, e rhs) {
+ lhs = lhs >> rhs;
+ return lhs;
+}
+
} // namespace BitmaskEnumDetail
// Enable bitmask enums in namespace ::llvm and all nested namespaces.
diff --git a/llvm/unittests/ADT/BitmaskEnumTest.cpp b/llvm/unittests/ADT/BitmaskEnumTest.cpp
index c78937c3571fd1..2c0a80342a54c3 100644
--- a/llvm/unittests/ADT/BitmaskEnumTest.cpp
+++ b/llvm/unittests/ADT/BitmaskEnumTest.cpp
@@ -130,6 +130,22 @@ TEST(BitmaskEnumTest, BitwiseXorEquals) {
EXPECT_EQ(V3, f2);
}
+TEST(BitmaskEnumTest, BitwiseShift) {
+ Flags f = (F1 << F1);
+ EXPECT_EQ(f, F2);
+
+ Flags f2 = F1;
+ f2 <<= F1;
+ EXPECT_EQ(f2, F2);
+
+ Flags f3 = (F1 >> F1);
+ EXPECT_EQ(f3, F0);
+
+ Flags f4 = F1;
+ f4 >>= F1;
+ EXPECT_EQ(f4, F0);
+}
+
TEST(BitmaskEnumTest, ConstantExpression) {
constexpr Flags f1 = ~F1;
constexpr Flags f2 = F1 | F2;
More information about the llvm-commits
mailing list