[compiler-rt] [llvm] Orc rt updates (PR #154693)
    Lang Hames via llvm-commits 
    llvm-commits at lists.llvm.org
       
    Thu Aug 21 01:10:31 PDT 2025
    
    
  
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/154693
None
>From f972d05385d14c5b060229b0a30e1a68119e0e5f Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Wed, 20 Aug 2025 17:29:31 +1000
Subject: [PATCH 1/3] [orc-rt] Expand span.h file comment. NFC.
---
 orc-rt/include/orc-rt/span.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/orc-rt/include/orc-rt/span.h b/orc-rt/include/orc-rt/span.h
index 7584a4508b749..aa0b3cc66a628 100644
--- a/orc-rt/include/orc-rt/span.h
+++ b/orc-rt/include/orc-rt/span.h
@@ -6,7 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// TODO: Replace all uses with std::span once we can use C++20.
+// A substitute for std::span that can be used until the ORC runtime is allowed
+// to assume c++-20.
+//
+// TODO: Replace all uses with std::span once we can assume c++20.
 //
 //===----------------------------------------------------------------------===//
 
>From 3d6cf2201a640f5d8fa98bdc735021fdae4ec91a Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Thu, 21 Aug 2025 17:07:34 +1000
Subject: [PATCH 2/3] [orc-rt] Add preliminary math.h header and basic
 operations.
The initial operations, isPowerOf2 and nextPowerOf2 will be used in an upcoming
patch to add support for bitmask-enums.
---
 orc-rt/include/orc-rt/math.h    | 35 +++++++++++++++
 orc-rt/unittests/CMakeLists.txt |  1 +
 orc-rt/unittests/math-test.cpp  | 78 +++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)
 create mode 100644 orc-rt/include/orc-rt/math.h
 create mode 100644 orc-rt/unittests/math-test.cpp
diff --git a/orc-rt/include/orc-rt/math.h b/orc-rt/include/orc-rt/math.h
new file mode 100644
index 0000000000000..4dd6ddd9e506c
--- /dev/null
+++ b/orc-rt/include/orc-rt/math.h
@@ -0,0 +1,35 @@
+//===--------- math.h - Math helpers for the ORC runtime --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Math helper functions for the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_MATH_H
+#define ORC_RT_MATH_H
+
+#include <cstdint>
+#include <limits>
+
+namespace orc_rt {
+
+/// Test whether the given value is a power of 2.
+template <typename T> constexpr bool isPowerOf2(T Val) noexcept {
+  return Val != 0 && (Val & (Val - 1)) == 0;
+}
+
+/// Calculates the next power of 2.
+template <typename T> constexpr T nextPowerOf2(T Val) noexcept {
+  for (size_t I = 1; I < std::numeric_limits<T>::digits; I <<= 1)
+    Val |= (Val >> I);
+  return Val + 1;
+}
+
+} // namespace orc_rt
+
+#endif // ORC_RT_MATH_H
diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt
index 98c28c9664c2a..51cd23304fc63 100644
--- a/orc-rt/unittests/CMakeLists.txt
+++ b/orc-rt/unittests/CMakeLists.txt
@@ -12,6 +12,7 @@ function(add_orc_rt_unittest test_dirname)
 endfunction()
 
 add_orc_rt_unittest(CoreTests
+  math-test.cpp
   span-test.cpp
   DISABLE_LLVM_LINK_LLVM_DYLIB
   )
diff --git a/orc-rt/unittests/math-test.cpp b/orc-rt/unittests/math-test.cpp
new file mode 100644
index 0000000000000..491bbd8baa6ee
--- /dev/null
+++ b/orc-rt/unittests/math-test.cpp
@@ -0,0 +1,78 @@
+//===- math-test.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for orc-rt's math.h APIs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/math.h"
+#include "gtest/gtest.h"
+
+using namespace orc_rt;
+
+TEST(STLExtrasTest, isPowerOf2) {
+  // Test [0..16]
+  EXPECT_FALSE(isPowerOf2(0x00));
+  EXPECT_TRUE(isPowerOf2(0x01));
+  EXPECT_TRUE(isPowerOf2(0x02));
+  EXPECT_FALSE(isPowerOf2(0x03));
+  EXPECT_TRUE(isPowerOf2(0x04));
+  EXPECT_FALSE(isPowerOf2(0x05));
+  EXPECT_FALSE(isPowerOf2(0x06));
+  EXPECT_FALSE(isPowerOf2(0x07));
+  EXPECT_TRUE(isPowerOf2(0x08));
+  EXPECT_FALSE(isPowerOf2(0x09));
+  EXPECT_FALSE(isPowerOf2(0x0A));
+  EXPECT_FALSE(isPowerOf2(0x0B));
+  EXPECT_FALSE(isPowerOf2(0x0C));
+  EXPECT_FALSE(isPowerOf2(0x0D));
+  EXPECT_FALSE(isPowerOf2(0x0E));
+  EXPECT_FALSE(isPowerOf2(0x0F));
+  EXPECT_TRUE(isPowerOf2(0x10));
+
+  // Test some higher powers of two and their adjacent values.
+  EXPECT_FALSE(isPowerOf2(0x1F));
+  EXPECT_TRUE(isPowerOf2(0x20));
+  EXPECT_FALSE(isPowerOf2(0x21));
+
+  EXPECT_FALSE(isPowerOf2(0x3F));
+  EXPECT_TRUE(isPowerOf2(0x40));
+  EXPECT_FALSE(isPowerOf2(0x41));
+
+  EXPECT_FALSE(isPowerOf2(0x7F));
+  EXPECT_TRUE(isPowerOf2(0x80));
+  EXPECT_FALSE(isPowerOf2(0x81));
+
+  // Test larger values.
+  EXPECT_FALSE(isPowerOf2(0x3fffffff));
+  EXPECT_TRUE(isPowerOf2(0x40000000));
+  EXPECT_FALSE(isPowerOf2(0x40000001));
+
+  // Test negatives.
+  EXPECT_FALSE(isPowerOf2(-1));
+}
+
+TEST(STLExtrasTest, nextPowerOf2) {
+  EXPECT_EQ(nextPowerOf2(0x00), (1 << 0));
+  EXPECT_EQ(nextPowerOf2(0x01), (1 << 1));
+  EXPECT_EQ(nextPowerOf2(0x02), (1 << 2));
+  EXPECT_EQ(nextPowerOf2(0x03), (1 << 2));
+  EXPECT_EQ(nextPowerOf2(0x04), (1 << 3));
+  EXPECT_EQ(nextPowerOf2(0x05), (1 << 3));
+  EXPECT_EQ(nextPowerOf2(0x06), (1 << 3));
+  EXPECT_EQ(nextPowerOf2(0x07), (1 << 3));
+  EXPECT_EQ(nextPowerOf2(0x08), (1 << 4));
+  EXPECT_EQ(nextPowerOf2(0x09), (1 << 4));
+  EXPECT_EQ(nextPowerOf2(0x0a), (1 << 4));
+  EXPECT_EQ(nextPowerOf2(0x0b), (1 << 4));
+  EXPECT_EQ(nextPowerOf2(0x0c), (1 << 4));
+  EXPECT_EQ(nextPowerOf2(0x0d), (1 << 4));
+  EXPECT_EQ(nextPowerOf2(0x0e), (1 << 4));
+  EXPECT_EQ(nextPowerOf2(0x0f), (1 << 4));
+  EXPECT_EQ(nextPowerOf2(0x10), (1 << 5));
+}
>From 3ae441518b8736cfaf92d9c42e2fda49969968a5 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Thu, 21 Aug 2025 17:38:27 +1000
Subject: [PATCH 3/3] [orc-rt] Add bitmask-enum helper utilities.
ORC_RT_MARK_AS_BITMASK_ENUM and ORC_RT_DECLARE_ENUM_AS_BITMASK can be used to
easily add support for bitmask operators (&, |, ^, ~) to enum types.
This code was derived from LLVM's include/llvm/ADT/BitmaskEnum.h header.
---
 compiler-rt/lib/orc/bitmask_enum.h     |  41 +++++--
 orc-rt/include/orc-rt/bitmask-enum.h   | 161 +++++++++++++++++++++++++
 orc-rt/unittests/CMakeLists.txt        |   1 +
 orc-rt/unittests/bitmask-enum-test.cpp | 143 ++++++++++++++++++++++
 4 files changed, 333 insertions(+), 13 deletions(-)
 create mode 100644 orc-rt/include/orc-rt/bitmask-enum.h
 create mode 100644 orc-rt/unittests/bitmask-enum-test.cpp
diff --git a/compiler-rt/lib/orc/bitmask_enum.h b/compiler-rt/lib/orc/bitmask_enum.h
index 77f4ca6b0fd69..3c55409523eb2 100644
--- a/compiler-rt/lib/orc/bitmask_enum.h
+++ b/compiler-rt/lib/orc/bitmask_enum.h
@@ -13,7 +13,7 @@
 #ifndef ORC_RT_BITMASK_ENUM_H
 #define ORC_RT_BITMASK_ENUM_H
 
-#include "stl_extras.h"
+#include "math-extras.h"
 
 #include <cassert>
 #include <type_traits>
@@ -73,6 +73,8 @@ namespace orc_rt {
     static constexpr std::underlying_type_t<Enum> value = LargestValue;        \
   }
 
+namespace detail {
+
 /// Traits class to determine whether an enum has been declared as a bitwise
 /// enum via ORC_RT_DECLARE_ENUM_AS_BITMASK.
 template <typename E, typename Enable = void>
@@ -98,7 +100,7 @@ struct largest_bitmask_enum_bit<
 };
 
 template <typename E> constexpr std::underlying_type_t<E> Mask() {
-  return bit_ceil(largest_bitmask_enum_bit<E>::value) - 1;
+  return nextPowerOf2(largest_bitmask_enum_bit<E>::value) - 1;
 }
 
 template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) {
@@ -108,39 +110,52 @@ template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) {
   return U;
 }
 
-template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+} // namespace detail
+
+template <typename E,
+          typename = std::enable_if_t<orc_rt::detail::is_bitmask_enum_v<E>>>
 constexpr E operator~(E Val) {
-  return static_cast<E>(~Underlying(Val) & Mask<E>());
+  return static_cast<E>(~orc_rt::detail::Underlying(Val) &
+                        orc_rt::detail::Mask<E>());
 }
 
-template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+template <typename E,
+          typename = std::enable_if_t<orc_rt::detail::is_bitmask_enum_v<E>>>
 constexpr E operator|(E LHS, E RHS) {
-  return static_cast<E>(Underlying(LHS) | Underlying(RHS));
+  return static_cast<E>(orc_rt::detail::Underlying(LHS) |
+                        orc_rt::detail::Underlying(RHS));
 }
 
-template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+template <typename E,
+          typename = std::enable_if_t<orc_rt::detail::is_bitmask_enum_v<E>>>
 constexpr E operator&(E LHS, E RHS) {
-  return static_cast<E>(Underlying(LHS) & Underlying(RHS));
+  return static_cast<E>(orc_rt::detail::Underlying(LHS) &
+                        orc_rt::detail::Underlying(RHS));
 }
 
-template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+template <typename E,
+          typename = std::enable_if_t<orc_rt::detail::is_bitmask_enum_v<E>>>
 constexpr E operator^(E LHS, E RHS) {
-  return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
+  return static_cast<E>(orc_rt::detail::Underlying(LHS) ^
+                        orc_rt::detail::Underlying(RHS));
 }
 
-template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+template <typename E,
+          typename = std::enable_if_t<orc_rt::detail::is_bitmask_enum_v<E>>>
 E &operator|=(E &LHS, E RHS) {
   LHS = LHS | RHS;
   return LHS;
 }
 
-template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+template <typename E,
+          typename = std::enable_if_t<orc_rt::detail::is_bitmask_enum_v<E>>>
 E &operator&=(E &LHS, E RHS) {
   LHS = LHS & RHS;
   return LHS;
 }
 
-template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+template <typename E,
+          typename = std::enable_if_t<orc_rt::detail::is_bitmask_enum_v<E>>>
 E &operator^=(E &LHS, E RHS) {
   LHS = LHS ^ RHS;
   return LHS;
diff --git a/orc-rt/include/orc-rt/bitmask-enum.h b/orc-rt/include/orc-rt/bitmask-enum.h
new file mode 100644
index 0000000000000..adc95424b83a8
--- /dev/null
+++ b/orc-rt/include/orc-rt/bitmask-enum.h
@@ -0,0 +1,161 @@
+//===---- bitmask-enum.h - Enable bitmask operations on enums ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides utilities for easily adding bitmask operation support to enums.
+//
+// This code was derived from LLVM's include/llvm/ADT/BitmaskEnum.h header, and
+// adapted for the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_BITMASK_ENUM_H
+#define ORC_RT_BITMASK_ENUM_H
+
+#include "math.h"
+
+#include <cassert>
+#include <type_traits>
+
+namespace orc_rt {
+
+/// ORC_RT_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you
+/// can perform bitwise operations on it without putting static_cast everywhere.
+///
+/// \code
+///   enum MyEnum {
+///     E1 = 1, E2 = 2, E3 = 4, E4 = 8,
+///     ORC_RT_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)
+///   };
+///
+///   void Foo() {
+///     MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!
+///   }
+/// \endcode
+///
+/// Normally when you do a bitwise operation on an enum value, you get back an
+/// instance of the underlying type (e.g. int).  But using this macro, bitwise
+/// ops on your enum will return you back instances of the enum.  This is
+/// particularly useful for enums which represent a combination of flags.
+///
+/// The parameter to ORC_RT_MARK_AS_BITMASK_ENUM should be the largest
+/// individual value in your enum.
+///
+/// All of the enum's values must be non-negative.
+#define ORC_RT_MARK_AS_BITMASK_ENUM(LargestValue)                              \
+  ORC_RT_BITMASK_LARGEST_ENUMERATOR = LargestValue
+
+/// ORC_RT_DECLARE_ENUM_AS_BITMASK can be used to declare an enum type as a bit
+/// set, so that bitwise operation on such enum does not require static_cast.
+///
+/// \code
+///   enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 };
+///   ORC_RT_DECLARE_ENUM_AS_BITMASK(MyEnum, E4);
+///
+///   void Foo() {
+///     MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast
+///   }
+/// \endcode
+///
+/// The second parameter to ORC_RT_DECLARE_ENUM_AS_BITMASK specifies the largest
+/// bit value of the enum type.
+///
+/// ORC_RT_DECLARE_ENUM_AS_BITMASK should be used in __orc_rt namespace.
+///
+/// This a non-intrusive alternative for ORC_RT_MARK_AS_BITMASK_ENUM. It allows
+/// declaring more than one non-scoped enumerations as bitmask types in the same
+/// scope. Otherwise it provides the same functionality as
+/// ORC_RT_MARK_AS_BITMASK_ENUM.
+#define ORC_RT_DECLARE_ENUM_AS_BITMASK(Enum, LargestValue)                     \
+  template <> struct is_bitmask_enum<Enum> : std::true_type {};                \
+  template <> struct largest_bitmask_enum_bit<Enum> {                          \
+    static constexpr std::underlying_type_t<Enum> value = LargestValue;        \
+  }
+
+/// Traits class to determine whether an enum has been declared as a bitwise
+/// enum via ORC_RT_DECLARE_ENUM_AS_BITMASK.
+template <typename E, typename Enable = void>
+struct is_bitmask_enum : std::false_type {};
+
+template <typename E>
+struct is_bitmask_enum<
+    E, std::enable_if_t<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR) >= 0>>
+    : std::true_type {};
+
+template <typename E>
+inline constexpr bool is_bitmask_enum_v = is_bitmask_enum<E>::value;
+
+/// Traits class to deermine bitmask enum largest bit.
+template <typename E, typename Enable = void> struct largest_bitmask_enum_bit;
+
+template <typename E>
+struct largest_bitmask_enum_bit<
+    E, std::enable_if_t<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR) >= 0>> {
+  using UnderlyingTy = std::underlying_type_t<E>;
+  static constexpr UnderlyingTy value =
+      static_cast<UnderlyingTy>(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR);
+};
+
+template <typename E>
+constexpr std::underlying_type_t<E> bitmask_enum_mask() noexcept {
+  return nextPowerOf2(largest_bitmask_enum_bit<E>::value) - 1;
+}
+
+template <typename E>
+constexpr std::underlying_type_t<E> bitmask_enum_to_underlying(E Val) noexcept {
+  auto U = static_cast<std::underlying_type_t<E>>(Val);
+  assert(U >= 0 && "Negative enum values are not allowed");
+  assert(U <= bitmask_enum_mask<E>() &&
+         "Enum value too large (or langest val too small");
+  return U;
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E operator~(E Val) noexcept {
+  return static_cast<E>(~bitmask_enum_to_underlying(Val) &
+                        bitmask_enum_mask<E>());
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E operator|(E LHS, E RHS) noexcept {
+  return static_cast<E>(bitmask_enum_to_underlying(LHS) |
+                        bitmask_enum_to_underlying(RHS));
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E operator&(E LHS, E RHS) noexcept {
+  return static_cast<E>(bitmask_enum_to_underlying(LHS) &
+                        bitmask_enum_to_underlying(RHS));
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E operator^(E LHS, E RHS) noexcept {
+  return static_cast<E>(bitmask_enum_to_underlying(LHS) ^
+                        bitmask_enum_to_underlying(RHS));
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E &operator|=(E &LHS, E RHS) noexcept {
+  LHS = LHS | RHS;
+  return LHS;
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E &operator&=(E &LHS, E RHS) noexcept {
+  LHS = LHS & RHS;
+  return LHS;
+}
+
+template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
+constexpr E &operator^=(E &LHS, E RHS) noexcept {
+  LHS = LHS ^ RHS;
+  return LHS;
+}
+
+} // namespace orc_rt
+
+#endif // ORC_RT_BITMASK_ENUM_H
diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt
index 51cd23304fc63..4aaf2caf0cd7d 100644
--- a/orc-rt/unittests/CMakeLists.txt
+++ b/orc-rt/unittests/CMakeLists.txt
@@ -12,6 +12,7 @@ function(add_orc_rt_unittest test_dirname)
 endfunction()
 
 add_orc_rt_unittest(CoreTests
+  bitmask-enum-test.cpp
   math-test.cpp
   span-test.cpp
   DISABLE_LLVM_LINK_LLVM_DYLIB
diff --git a/orc-rt/unittests/bitmask-enum-test.cpp b/orc-rt/unittests/bitmask-enum-test.cpp
new file mode 100644
index 0000000000000..3367a8d4b040e
--- /dev/null
+++ b/orc-rt/unittests/bitmask-enum-test.cpp
@@ -0,0 +1,143 @@
+//===-- bitmask-enum-test.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/bitmask-enum.h"
+#include "gtest/gtest.h"
+
+#include <sstream>
+#include <string>
+
+using namespace orc_rt;
+
+namespace {
+
+enum Flags { F0 = 0, F1 = 1, F2 = 2, F3 = 4, F4 = 8 };
+
+} // namespace
+
+namespace orc_rt {
+ORC_RT_DECLARE_ENUM_AS_BITMASK(Flags, F4);
+} // namespace orc_rt
+
+static_assert(is_bitmask_enum<Flags>::value != 0);
+static_assert(largest_bitmask_enum_bit<Flags>::value == Flags::F4);
+
+namespace {
+
+static_assert(is_bitmask_enum<Flags>::value != 0);
+static_assert(largest_bitmask_enum_bit<Flags>::value == Flags::F4);
+
+TEST(BitmaskEnumTest, BitwiseOr) {
+  Flags f = F1 | F2;
+  EXPECT_EQ(3, f);
+
+  f = f | F3;
+  EXPECT_EQ(7, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseOrEquals) {
+  Flags f = F1;
+  f |= F3;
+  EXPECT_EQ(5, f);
+
+  // |= should return a reference to the LHS.
+  f = F2;
+  (f |= F3) = F1;
+  EXPECT_EQ(F1, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseAnd) {
+  Flags f = static_cast<Flags>(3) & F2;
+  EXPECT_EQ(F2, f);
+
+  f = (f | F3) & (F1 | F2 | F3);
+  EXPECT_EQ(6, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseAndEquals) {
+  Flags f = F1 | F2 | F3;
+  f &= F1 | F2;
+  EXPECT_EQ(3, f);
+
+  // &= should return a reference to the LHS.
+  (f &= F1) = F3;
+  EXPECT_EQ(F3, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseXor) {
+  Flags f = (F1 | F2) ^ (F2 | F3);
+  EXPECT_EQ(5, f);
+
+  f = f ^ F1;
+  EXPECT_EQ(4, f);
+}
+
+TEST(BitmaskEnumTest, BitwiseXorEquals) {
+  Flags f = (F1 | F2);
+  f ^= (F2 | F4);
+  EXPECT_EQ(9, f);
+
+  // ^= should return a reference to the LHS.
+  (f ^= F4) = F3;
+  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.
+  EXPECT_EQ(15, ~F0);
+}
+
+enum class FlagsClass {
+  F0 = 0,
+  F1 = 1,
+  F2 = 2,
+  F3 = 4,
+  ORC_RT_MARK_AS_BITMASK_ENUM(F3)
+};
+
+TEST(BitmaskEnumTest, ScopedEnum) {
+  FlagsClass f = (FlagsClass::F1 & ~FlagsClass::F0) | FlagsClass::F2;
+  f |= FlagsClass::F3;
+  EXPECT_EQ(7, static_cast<int>(f));
+}
+
+struct Container {
+  enum Flags {
+    F0 = 0,
+    F1 = 1,
+    F2 = 2,
+    F3 = 4,
+    ORC_RT_MARK_AS_BITMASK_ENUM(F3)
+  };
+
+  static Flags getFlags() {
+    Flags f = F0 | F1;
+    f |= F2;
+    return f;
+  }
+};
+
+TEST(BitmaskEnumTest, EnumInStruct) { EXPECT_EQ(3, Container::getFlags()); }
+
+} // namespace
    
    
More information about the llvm-commits
mailing list