[llvm] Orc rt updates (PR #154693)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 21 01:49:34 PDT 2025
https://github.com/lhames updated https://github.com/llvm/llvm-project/pull/154693
>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/4] [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 09961a9e02c7736e467b3db1d6b3fbb5bede1db1 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/4] [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/CMakeLists.txt | 1 +
orc-rt/include/orc-rt/math.h | 35 +++++++++++++++
orc-rt/unittests/CMakeLists.txt | 1 +
orc-rt/unittests/math-test.cpp | 78 +++++++++++++++++++++++++++++++++
4 files changed, 115 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/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index eb24f29b14695..e2096a80404b4 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -1,5 +1,6 @@
set(ORC_RT_HEADERS
orc-rt-c/orc-rt.h
+ orc-rt/math.h
orc-rt/span.h
)
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 3fb39468a93f887481e077b8ae47d7e32b2027f1 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/4] [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.
---
orc-rt/include/CMakeLists.txt | 1 +
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, 306 insertions(+)
create mode 100644 orc-rt/include/orc-rt/bitmask-enum.h
create mode 100644 orc-rt/unittests/bitmask-enum-test.cpp
diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index e2096a80404b4..f753de56c1b33 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -1,5 +1,6 @@
set(ORC_RT_HEADERS
orc-rt-c/orc-rt.h
+ orc-rt/bitmask-enum.h
orc-rt/math.h
orc-rt/span.h
)
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
>From bb6dd1e45d94b13f964133b8aece4bee4f765ce5 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Thu, 21 Aug 2025 18:32:40 +1000
Subject: [PATCH 4/4] [orc-rt] Add rtti header and unit tests.
The orc-rt extensible RTTI mechanism is used to provide simple dynamic RTTI
checks for orc-rt types that do not depend on standard C++ RTTI (meaning that
they will work equally well for programs compiled with -fno-rtti).
---
orc-rt/include/CMakeLists.txt | 1 +
orc-rt/include/orc-rt/rtti.h | 138 +++++++++++++++++++++++++++++
orc-rt/lib/executor/CMakeLists.txt | 1 +
orc-rt/lib/executor/rtti.cpp | 24 +++++
orc-rt/unittests/CMakeLists.txt | 1 +
orc-rt/unittests/rtti-test.cpp | 52 +++++++++++
6 files changed, 217 insertions(+)
create mode 100644 orc-rt/include/orc-rt/rtti.h
create mode 100644 orc-rt/lib/executor/rtti.cpp
create mode 100644 orc-rt/unittests/rtti-test.cpp
diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index f753de56c1b33..717b75290e052 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -2,6 +2,7 @@ set(ORC_RT_HEADERS
orc-rt-c/orc-rt.h
orc-rt/bitmask-enum.h
orc-rt/math.h
+ orc-rt/rtti.h
orc-rt/span.h
)
diff --git a/orc-rt/include/orc-rt/rtti.h b/orc-rt/include/orc-rt/rtti.h
new file mode 100644
index 0000000000000..3097edf68d7b2
--- /dev/null
+++ b/orc-rt/include/orc-rt/rtti.h
@@ -0,0 +1,138 @@
+//===------------- rtti.h - RTTI support for ORC RT -------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+//
+// Provides an extensible RTTI mechanism, that can be used regardless of whether
+// the runtime is built with -frtti or not. This is predominantly used to
+// support error handling.
+//
+// The RTTIRoot class defines methods for comparing type ids. Implementations
+// of these methods can be injected into new classes using the RTTIExtends
+// class template.
+//
+// E.g.
+//
+// @code{.cpp}
+// class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> {
+// public:
+// virtual void foo() = 0;
+// };
+//
+// class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> {
+// public:
+// void foo() override {}
+// };
+//
+// class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> {
+// public:
+// void foo() override {}
+// };
+//
+// void fn() {
+// std::unique_ptr<MyBaseClass> B = std::make_unique<MyDerivedClass1>();
+// outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1".
+// outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1".
+// outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'.
+// }
+//
+// @endcode
+//
+// Note:
+// This header was adapted from llvm/Support/ExtensibleRTTI.h, however the
+// data structures are not shared and the code need not be kept in sync.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_RTTI_H
+#define ORC_RT_RTTI_H
+
+namespace orc_rt {
+
+template <typename ThisT, typename ParentT> class RTTIExtends;
+
+/// Base class for the extensible RTTI hierarchy.
+///
+/// This class defines virtual methods, dynamicClassID and isA, that enable
+/// type comparisons.
+class RTTIRoot {
+public:
+ virtual ~RTTIRoot() = default;
+
+ /// Returns the class ID for this type.
+ static const void *classID() noexcept { return &ID; }
+
+ /// Returns the class ID for the dynamic type of this RTTIRoot instance.
+ virtual const void *dynamicClassID() const noexcept = 0;
+
+ /// Returns true if this class's ID matches the given class ID.
+ virtual bool isA(const void *const ClassID) const noexcept {
+ return ClassID == classID();
+ }
+
+ /// Check whether this instance is a subclass of QueryT.
+ template <typename QueryT> bool isA() const noexcept {
+ return isA(QueryT::classID());
+ }
+
+ static bool classof(const RTTIRoot *R) noexcept { return R->isA<RTTIRoot>(); }
+
+private:
+ virtual void anchor();
+
+ static char ID;
+};
+
+/// Inheritance utility for extensible RTTI.
+///
+/// Supports single inheritance only: A class can only have one
+/// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work),
+/// though it can have many non-ExtensibleRTTI parents.
+///
+/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
+/// newly introduced type, and the *second* argument is the parent class.
+///
+/// class MyType : public RTTIExtends<MyType, RTTIRoot> {
+/// ...
+/// };
+///
+/// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> {
+/// ...
+/// };
+///
+template <typename ThisT, typename ParentT> class RTTIExtends : public ParentT {
+public:
+ // Inherit constructors and isA methods from ParentT.
+ using ParentT::isA;
+ using ParentT::ParentT;
+
+ static char ID;
+
+ static const void *classID() noexcept { return &ThisT::ID; }
+
+ const void *dynamicClassID() const noexcept override { return &ThisT::ID; }
+
+ bool isA(const void *const ClassID) const noexcept override {
+ return ClassID == classID() || ParentT::isA(ClassID);
+ }
+
+ static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
+};
+
+template <typename ThisT, typename ParentT>
+char RTTIExtends<ThisT, ParentT>::ID = 0;
+
+/// Returns true if the given value is an instance of the template type
+/// parameter.
+template <typename To, typename From> bool isa(const From &Value) noexcept {
+ return To::classof(&Value);
+}
+
+} // namespace orc_rt
+
+#endif // ORC_RT_RTTI_H
diff --git a/orc-rt/lib/executor/CMakeLists.txt b/orc-rt/lib/executor/CMakeLists.txt
index 82d29455eb6df..40035bb4dcffb 100644
--- a/orc-rt/lib/executor/CMakeLists.txt
+++ b/orc-rt/lib/executor/CMakeLists.txt
@@ -1,5 +1,6 @@
set(files
orc-rt-executor.cpp
+ rtti.cpp
)
add_library(orc-rt-executor STATIC ${files})
diff --git a/orc-rt/lib/executor/rtti.cpp b/orc-rt/lib/executor/rtti.cpp
new file mode 100644
index 0000000000000..8c6d27fb25c73
--- /dev/null
+++ b/orc-rt/lib/executor/rtti.cpp
@@ -0,0 +1,24 @@
+//===- rtti.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 support library.
+//
+// Note:
+// This source file was adapted from lib/Support/ExtensibleRTTI.cpp, however
+// the data structures are not shared and the code need not be kept in sync.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/rtti.h"
+
+namespace orc_rt {
+
+char RTTIRoot::ID = 0;
+void RTTIRoot::anchor() {}
+
+} // namespace orc_rt
diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt
index 4aaf2caf0cd7d..00751e07742c6 100644
--- a/orc-rt/unittests/CMakeLists.txt
+++ b/orc-rt/unittests/CMakeLists.txt
@@ -14,6 +14,7 @@ endfunction()
add_orc_rt_unittest(CoreTests
bitmask-enum-test.cpp
math-test.cpp
+ rtti-test.cpp
span-test.cpp
DISABLE_LLVM_LINK_LLVM_DYLIB
)
diff --git a/orc-rt/unittests/rtti-test.cpp b/orc-rt/unittests/rtti-test.cpp
new file mode 100644
index 0000000000000..bb9fac6447010
--- /dev/null
+++ b/orc-rt/unittests/rtti-test.cpp
@@ -0,0 +1,52 @@
+//===-- rtti_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
+//
+//===----------------------------------------------------------------------===//
+//
+// Note:
+// This unit test was adapted from
+// llvm/unittests/Support/ExtensibleRTTITest.cpp
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/rtti.h"
+#include "gtest/gtest.h"
+
+using namespace orc_rt;
+
+namespace {
+
+class MyBase : public RTTIExtends<MyBase, RTTIRoot> {};
+
+class MyDerivedA : public RTTIExtends<MyDerivedA, MyBase> {};
+
+class MyDerivedB : public RTTIExtends<MyDerivedB, MyBase> {};
+
+} // end anonymous namespace
+
+TEST(ExtensibleRTTITest, BaseCheck) {
+ MyBase MB;
+ MyDerivedA MDA;
+ MyDerivedB MDB;
+
+ // Check MB properties.
+ EXPECT_TRUE(isa<RTTIRoot>(MB));
+ EXPECT_TRUE(isa<MyBase>(MB));
+ EXPECT_FALSE(isa<MyDerivedA>(MB));
+ EXPECT_FALSE(isa<MyDerivedB>(MB));
+
+ // Check MDA properties.
+ EXPECT_TRUE(isa<RTTIRoot>(MDA));
+ EXPECT_TRUE(isa<MyBase>(MDA));
+ EXPECT_TRUE(isa<MyDerivedA>(MDA));
+ EXPECT_FALSE(isa<MyDerivedB>(MDA));
+
+ // Check MDB properties.
+ EXPECT_TRUE(isa<RTTIRoot>(MDB));
+ EXPECT_TRUE(isa<MyBase>(MDB));
+ EXPECT_FALSE(isa<MyDerivedA>(MDB));
+ EXPECT_TRUE(isa<MyDerivedB>(MDB));
+}
More information about the llvm-commits
mailing list