10b57cec5SDimitry Andric //===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef LLVM_ADT_BITMASKENUM_H
100b57cec5SDimitry Andric #define LLVM_ADT_BITMASKENUM_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include <cassert>
130b57cec5SDimitry Andric #include <type_traits>
140b57cec5SDimitry Andric #include <utility>
150b57cec5SDimitry Andric 
165f757f3fSDimitry Andric #include "llvm/ADT/STLForwardCompat.h"
170b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric /// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can
200b57cec5SDimitry Andric /// perform bitwise operations on it without putting static_cast everywhere.
210b57cec5SDimitry Andric ///
220b57cec5SDimitry Andric /// \code
230b57cec5SDimitry Andric ///   enum MyEnum {
240b57cec5SDimitry Andric ///     E1 = 1, E2 = 2, E3 = 4, E4 = 8,
250b57cec5SDimitry Andric ///     LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)
260b57cec5SDimitry Andric ///   };
270b57cec5SDimitry Andric ///
280b57cec5SDimitry Andric ///   void Foo() {
290b57cec5SDimitry Andric ///     MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!
300b57cec5SDimitry Andric ///   }
310b57cec5SDimitry Andric /// \endcode
320b57cec5SDimitry Andric ///
330b57cec5SDimitry Andric /// Normally when you do a bitwise operation on an enum value, you get back an
340b57cec5SDimitry Andric /// instance of the underlying type (e.g. int).  But using this macro, bitwise
350b57cec5SDimitry Andric /// ops on your enum will return you back instances of the enum.  This is
360b57cec5SDimitry Andric /// particularly useful for enums which represent a combination of flags.
370b57cec5SDimitry Andric ///
380b57cec5SDimitry Andric /// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual
390b57cec5SDimitry Andric /// value in your enum.
400b57cec5SDimitry Andric ///
410b57cec5SDimitry Andric /// All of the enum's values must be non-negative.
420b57cec5SDimitry Andric #define LLVM_MARK_AS_BITMASK_ENUM(LargestValue)                                \
430b57cec5SDimitry Andric   LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue
440b57cec5SDimitry Andric 
4506c3fb27SDimitry Andric /// LLVM_DECLARE_ENUM_AS_BITMASK can be used to declare an enum type as a bit
4606c3fb27SDimitry Andric /// set, so that bitwise operation on such enum does not require static_cast.
4706c3fb27SDimitry Andric ///
4806c3fb27SDimitry Andric /// \code
4906c3fb27SDimitry Andric ///   enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 };
5006c3fb27SDimitry Andric ///   LLVM_DECLARE_ENUM_AS_BITMASK(MyEnum, E4);
5106c3fb27SDimitry Andric ///
5206c3fb27SDimitry Andric ///   void Foo() {
5306c3fb27SDimitry Andric ///     MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast
5406c3fb27SDimitry Andric ///   }
5506c3fb27SDimitry Andric /// \endcode
5606c3fb27SDimitry Andric ///
5706c3fb27SDimitry Andric /// The second parameter to LLVM_DECLARE_ENUM_AS_BITMASK specifies the largest
5806c3fb27SDimitry Andric /// bit value of the enum type.
5906c3fb27SDimitry Andric ///
6006c3fb27SDimitry Andric /// LLVM_DECLARE_ENUM_AS_BITMASK should be used in llvm namespace.
6106c3fb27SDimitry Andric ///
6206c3fb27SDimitry Andric /// This a non-intrusive alternative for LLVM_MARK_AS_BITMASK_ENUM. It allows
6306c3fb27SDimitry Andric /// declaring more than one non-scoped enumerations as bitmask types in the same
6406c3fb27SDimitry Andric /// scope. Otherwise it provides the same functionality as
6506c3fb27SDimitry Andric /// LLVM_MARK_AS_BITMASK_ENUM.
6606c3fb27SDimitry Andric #define LLVM_DECLARE_ENUM_AS_BITMASK(Enum, LargestValue)                       \
6706c3fb27SDimitry Andric   template <> struct is_bitmask_enum<Enum> : std::true_type {};                \
6806c3fb27SDimitry Andric   template <> struct largest_bitmask_enum_bit<Enum> {                          \
6906c3fb27SDimitry Andric     static constexpr std::underlying_type_t<Enum> value = LargestValue;        \
7006c3fb27SDimitry Andric   }
7106c3fb27SDimitry Andric 
720b57cec5SDimitry Andric /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used
730b57cec5SDimitry Andric /// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace.
740b57cec5SDimitry Andric ///
750b57cec5SDimitry Andric /// Suppose you have an enum foo::bar::MyEnum.  Before using
760b57cec5SDimitry Andric /// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put
770b57cec5SDimitry Andric /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or
780b57cec5SDimitry Andric /// namespace foo::bar.  This allows the relevant operator overloads to be found
790b57cec5SDimitry Andric /// by ADL.
800b57cec5SDimitry Andric ///
810b57cec5SDimitry Andric /// You don't need to use this macro in namespace llvm; it's done at the bottom
820b57cec5SDimitry Andric /// of this file.
830b57cec5SDimitry Andric #define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()                               \
840b57cec5SDimitry Andric   using ::llvm::BitmaskEnumDetail::operator~;                                  \
850b57cec5SDimitry Andric   using ::llvm::BitmaskEnumDetail::operator|;                                  \
860b57cec5SDimitry Andric   using ::llvm::BitmaskEnumDetail::operator&;                                  \
870b57cec5SDimitry Andric   using ::llvm::BitmaskEnumDetail::operator^;                                  \
880b57cec5SDimitry Andric   using ::llvm::BitmaskEnumDetail::operator|=;                                 \
890b57cec5SDimitry Andric   using ::llvm::BitmaskEnumDetail::operator&=;                                 \
905f757f3fSDimitry Andric   using ::llvm::BitmaskEnumDetail::operator^=;                                 \
910b57cec5SDimitry Andric   /* Force a semicolon at the end of this macro. */                            \
925f757f3fSDimitry Andric   using ::llvm::BitmaskEnumDetail::any
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric namespace llvm {
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric /// Traits class to determine whether an enum has a
970b57cec5SDimitry Andric /// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator.
980b57cec5SDimitry Andric template <typename E, typename Enable = void>
990b57cec5SDimitry Andric struct is_bitmask_enum : std::false_type {};
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric template <typename E>
1020b57cec5SDimitry Andric struct is_bitmask_enum<
1035ffd83dbSDimitry Andric     E, std::enable_if_t<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= 0>>
1045ffd83dbSDimitry Andric     : std::true_type {};
10506c3fb27SDimitry Andric 
10606c3fb27SDimitry Andric /// Trait class to determine bitmask enumeration largest bit.
10706c3fb27SDimitry Andric template <typename E, typename Enable = void> struct largest_bitmask_enum_bit;
10806c3fb27SDimitry Andric 
10906c3fb27SDimitry Andric template <typename E>
11006c3fb27SDimitry Andric struct largest_bitmask_enum_bit<
11106c3fb27SDimitry Andric     E, std::enable_if_t<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= 0>> {
11206c3fb27SDimitry Andric   using UnderlyingTy = std::underlying_type_t<E>;
11306c3fb27SDimitry Andric   static constexpr UnderlyingTy value =
11406c3fb27SDimitry Andric       static_cast<UnderlyingTy>(E::LLVM_BITMASK_LARGEST_ENUMERATOR);
11506c3fb27SDimitry Andric };
11606c3fb27SDimitry Andric 
1170b57cec5SDimitry Andric namespace BitmaskEnumDetail {
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric /// Get a bitmask with 1s in all places up to the high-order bit of E's largest
1200b57cec5SDimitry Andric /// value.
12181ad6265SDimitry Andric template <typename E> constexpr std::underlying_type_t<E> Mask() {
1220b57cec5SDimitry Andric   // On overflow, NextPowerOf2 returns zero with the type uint64_t, so
1230b57cec5SDimitry Andric   // subtracting 1 gives us the mask with all bits set, like we want.
12406c3fb27SDimitry Andric   return NextPowerOf2(largest_bitmask_enum_bit<E>::value) - 1;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric /// Check that Val is in range for E, and return Val cast to E's underlying
1280b57cec5SDimitry Andric /// type.
12981ad6265SDimitry Andric template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) {
1305f757f3fSDimitry Andric   auto U = llvm::to_underlying(Val);
1310b57cec5SDimitry Andric   assert(U >= 0 && "Negative enum values are not allowed.");
1320b57cec5SDimitry Andric   assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)");
1330b57cec5SDimitry Andric   return U;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
1365ffd83dbSDimitry Andric constexpr unsigned bitWidth(uint64_t Value) {
1375ffd83dbSDimitry Andric   return Value ? 1 + bitWidth(Value >> 1) : 0;
1385ffd83dbSDimitry Andric }
1395ffd83dbSDimitry Andric 
1405ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
1415f757f3fSDimitry Andric constexpr bool any(E Val) {
1425f757f3fSDimitry Andric   return Val != static_cast<E>(0);
1435f757f3fSDimitry Andric }
1445f757f3fSDimitry Andric 
1455f757f3fSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
14681ad6265SDimitry Andric constexpr E operator~(E Val) {
1470b57cec5SDimitry Andric   return static_cast<E>(~Underlying(Val) & Mask<E>());
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
1505ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
15181ad6265SDimitry Andric constexpr E operator|(E LHS, E RHS) {
1520b57cec5SDimitry Andric   return static_cast<E>(Underlying(LHS) | Underlying(RHS));
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
1555ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
15681ad6265SDimitry Andric constexpr E operator&(E LHS, E RHS) {
1570b57cec5SDimitry Andric   return static_cast<E>(Underlying(LHS) & Underlying(RHS));
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
1605ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
16181ad6265SDimitry Andric constexpr E operator^(E LHS, E RHS) {
1620b57cec5SDimitry Andric   return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric // |=, &=, and ^= return a reference to LHS, to match the behavior of the
1660b57cec5SDimitry Andric // operators on builtin types.
1670b57cec5SDimitry Andric 
1685ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
1690b57cec5SDimitry Andric E &operator|=(E &LHS, E RHS) {
1700b57cec5SDimitry Andric   LHS = LHS | RHS;
1710b57cec5SDimitry Andric   return LHS;
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric 
1745ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
1750b57cec5SDimitry Andric E &operator&=(E &LHS, E RHS) {
1760b57cec5SDimitry Andric   LHS = LHS & RHS;
1770b57cec5SDimitry Andric   return LHS;
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
1805ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
1810b57cec5SDimitry Andric E &operator^=(E &LHS, E RHS) {
1820b57cec5SDimitry Andric   LHS = LHS ^ RHS;
1830b57cec5SDimitry Andric   return LHS;
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric } // namespace BitmaskEnumDetail
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric // Enable bitmask enums in namespace ::llvm and all nested namespaces.
1890b57cec5SDimitry Andric LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
1905ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
1915f757f3fSDimitry Andric constexpr unsigned BitWidth = BitmaskEnumDetail::bitWidth(
1925f757f3fSDimitry Andric     uint64_t{llvm::to_underlying(E::LLVM_BITMASK_LARGEST_ENUMERATOR)});
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric } // namespace llvm
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric #endif
197