Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions orc-rt/include/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
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
)

Expand Down
161 changes: 161 additions & 0 deletions orc-rt/include/orc-rt/bitmask-enum.h
Original file line number Diff line number Diff line change
@@ -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
35 changes: 35 additions & 0 deletions orc-rt/include/orc-rt/math.h
Original file line number Diff line number Diff line change
@@ -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
138 changes: 138 additions & 0 deletions orc-rt/include/orc-rt/rtti.h
Original file line number Diff line number Diff line change
@@ -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
5 changes: 4 additions & 1 deletion orc-rt/include/orc-rt/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
//===----------------------------------------------------------------------===//

Expand Down
1 change: 1 addition & 0 deletions orc-rt/lib/executor/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
set(files
orc-rt-executor.cpp
rtti.cpp
)

add_library(orc-rt-executor STATIC ${files})
Expand Down
24 changes: 24 additions & 0 deletions orc-rt/lib/executor/rtti.cpp
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions orc-rt/unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ function(add_orc_rt_unittest test_dirname)
endfunction()

add_orc_rt_unittest(CoreTests
bitmask-enum-test.cpp
math-test.cpp
rtti-test.cpp
span-test.cpp
DISABLE_LLVM_LINK_LLVM_DYLIB
)
Expand Down
Loading
Loading