diff --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt --- a/compiler-rt/lib/orc/CMakeLists.txt +++ b/compiler-rt/lib/orc/CMakeLists.txt @@ -2,7 +2,7 @@ # ORC runtime library implementation files. set(ORC_SOURCES - placeholder.cpp + extensible_rtti.cpp ) # Implementation files for all ORC architectures. @@ -82,3 +82,7 @@ PARENT_TARGET orc) endforeach() endif() # not Apple + +if(COMPILER_RT_INCLUDE_TESTS) + add_subdirectory(unittests) +endif() diff --git a/compiler-rt/lib/orc/extensible_rtti.h b/compiler-rt/lib/orc/extensible_rtti.h new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/orc/extensible_rtti.h @@ -0,0 +1,141 @@ +//===------ extensible_rtti.h - Extensible RTTI 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 { +// public: +// static char ID; +// virtual void foo() = 0; +// }; +// +// class MyDerivedClass1 : public RTTIExtends { +// public: +// static char ID; +// void foo() override {} +// }; +// +// class MyDerivedClass2 : public RTTIExtends { +// public: +// static char ID; +// void foo() override {} +// }; +// +// char MyBaseClass::ID = 0; +// char MyDerivedClass1::ID = 0; +// char MyDerivedClass2:: ID = 0; +// +// void fn() { +// std::unique_ptr B = std::make_unique(); +// outs() << isa(B) << "\n"; // Outputs "1". +// outs() << isa(B) << "\n"; // Outputs "1". +// outs() << isa(B) << "\n"; // Outputs "0'. +// } +// +// @endcode +// +//===----------------------------------------------------------------------===// + +#ifndef ORC_RT_EXTENSIBLE_RTTI_H +#define ORC_RT_EXTENSIBLE_RTTI_H + +namespace __orc_rt { + +template 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() { return &ID; } + + /// Returns the class ID for the dynamic type of this RTTIRoot instance. + virtual const void *dynamicClassID() const = 0; + + /// Returns true if this class's ID matches the given class ID. + virtual bool isA(const void *const ClassID) const { + return ClassID == classID(); + } + + /// Check whether this instance is a subclass of QueryT. + template bool isA() const { return isA(QueryT::classID()); } + + static bool classof(const RTTIRoot *R) { return R->isA(); } + +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 { +/// public: +/// static char ID; +/// }; +/// +/// class MyDerivedType : public RTTIExtends { +/// public: +/// static char ID; +/// }; +/// +template 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() { return &ThisT::ID; } + + const void *dynamicClassID() const override { return &ThisT::ID; } + + bool isA(const void *const ClassID) const override { + return ClassID == classID() || ParentT::isA(ClassID); + } + + static bool classof(const RTTIRoot *R) { return R->isA(); } +}; + +template +char RTTIExtends::ID = 0; + +/// Returns true if the given value is an instance of the template type +/// parameter. +template bool isa(const From &Value) { + return To::classof(&Value); +} + +} // end namespace __orc_rt + +#endif // ORC_RT_EXTENSIBLE_RTTI_H diff --git a/compiler-rt/lib/orc/extensible_rtti.cpp b/compiler-rt/lib/orc/extensible_rtti.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/orc/extensible_rtti.cpp @@ -0,0 +1,20 @@ +//===- extensible_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. +// +//===----------------------------------------------------------------------===// + +#include "extensible_rtti.h" + +namespace __orc_rt { + +char RTTIRoot::ID = 0; +void RTTIRoot::anchor() {} + +} // end namespace __orc_rt diff --git a/compiler-rt/lib/orc/placeholder.cpp b/compiler-rt/lib/orc/placeholder.cpp deleted file mode 100644 --- a/compiler-rt/lib/orc/placeholder.cpp +++ /dev/null @@ -1 +0,0 @@ -void placeholder(void) {} diff --git a/compiler-rt/lib/orc/unittests/CMakeLists.txt b/compiler-rt/lib/orc/unittests/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/orc/unittests/CMakeLists.txt @@ -0,0 +1,93 @@ +include_directories(..) + +add_custom_target(OrcRTUnitTests) +set_target_properties(OrcRTUnitTests PROPERTIES FOLDER "OrcRT unittests") + +set(ORC_UNITTEST_CFLAGS + ${ORC_CFLAGS} + ${COMPILER_RT_UNITTEST_CFLAGS} + ${COMPILER_RT_GTEST_CFLAGS} + -I${COMPILER_RT_SOURCE_DIR}/lib/orc + ) + +# We add the include directories one at a time in our CFLAGS. +foreach (DIR ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR}) + list(APPEND ORC_UNITTEST_CFLAGS -I${DIR}) +endforeach() + +function(add_orc_lib library) + add_library(${library} STATIC ${ARGN}) + set_target_properties(${library} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + FOLDER "Compiler-RT Runtime tests") +endfunction() + +function(get_orc_lib_for_arch arch lib) + if(APPLE) + set(tgt_name "RTOrc.test.osx") + else() + set(tgt_name "RTOrc.test.${arch}") + endif() + set(${lib} "${tgt_name}" PARENT_SCOPE) +endfunction() + +set(ORC_TEST_ARCH ${ORC_SUPPORTED_ARCH}) +set(ORC_UNITTEST_LINK_FLAGS + ${COMPILER_RT_UNITTEST_LINK_FLAGS} + ${CMAKE_THREAD_LIBS_INIT} + ) + +if(APPLE) + darwin_filter_host_archs(ORC_SUPPORTED_ARCH ORC_TEST_ARCH) + list(APPEND ORC_UNITTEST_CFLAGS ${DARWIN_osx_CFLAGS}) + list(APPEND LINK_FLAGS ${DARWIN_osx_LINK_FLAGS}) +endif() + +foreach(lib ${SANITIZER_TEST_CXX_LIBRARIES}) + list(APPEND ORC_UNITTEST_LINK_FLAGS -l${lib}) +endforeach() + +set(ORC_DEPS gtest orc) +# ORC uses C++ standard library headers. +if (TARGET cxx-headers OR HAVE_LIBCXX) + set(ORC_DEPS cxx-headers) +endif() + +macro(add_orc_unittest testname) + cmake_parse_arguments(TEST "" "" "SOURCES;HEADERS" ${ARGN}) + if(UNIX) + foreach(arch ${ORC_TEST_ARCH}) + set(TEST_OBJECTS) + get_orc_lib_for_arch(${arch} ORC_RUNTIME_LIBS) + generate_compiler_rt_tests(TEST_OBJECTS + OrcRTUnitTests "${testname}-${arch}-Test" "${arch}" + SOURCES ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE} + RUNTIME "${ORC_RUNTIME_LIBS}" + COMPILE_DEPS ${TEST_HEADERS} + DEPS ${ORC_DEPS} + CFLAGS ${ORC_UNITTEST_CFLAGS} + LINK_FLAGS ${LINK_FLAGS}) + endforeach() + endif() +endmacro() + +set(UNITTEST_SOURCES + extensible_rtti_test.cpp + orc_unit_test_main.cpp + ) + +if (COMPILER_RT_CAN_EXECUTE_TESTS) + + if (APPLE) + add_orc_lib("RTOrc.test.osx" + $) + else() + foreach(arch ${ORC_SUPPORTED_ARCH}) + add_orc_lib("RTOrc.test.${arch}" + $) + endforeach() + endif() + + add_orc_unittest(OrcUnitTest SOURCES ${UNITTEST_SOURCES}) + +endif() diff --git a/compiler-rt/lib/orc/unittests/extensible_rtti_test.cpp b/compiler-rt/lib/orc/unittests/extensible_rtti_test.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/orc/unittests/extensible_rtti_test.cpp @@ -0,0 +1,50 @@ +//===-- extensible_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 +// +//===----------------------------------------------------------------------===// +// +// This file is a part of the ORC runtime. +// +//===----------------------------------------------------------------------===// + +#include "extensible_rtti.h" +#include "gtest/gtest.h" + +using namespace __orc_rt; + +namespace { + +class MyBase : public RTTIExtends {}; + +class MyDerivedA : public RTTIExtends {}; + +class MyDerivedB : public RTTIExtends {}; + +} // end anonymous namespace + +TEST(ExtensibleRTTITest, BaseCheck) { + MyBase MB; + MyDerivedA MDA; + MyDerivedB MDB; + + // Check MB properties. + EXPECT_TRUE(isa(MB)); + EXPECT_TRUE(isa(MB)); + EXPECT_FALSE(isa(MB)); + EXPECT_FALSE(isa(MB)); + + // Check MDA properties. + EXPECT_TRUE(isa(MDA)); + EXPECT_TRUE(isa(MDA)); + EXPECT_TRUE(isa(MDA)); + EXPECT_FALSE(isa(MDA)); + + // Check MDB properties. + EXPECT_TRUE(isa(MDB)); + EXPECT_TRUE(isa(MDB)); + EXPECT_FALSE(isa(MDB)); + EXPECT_TRUE(isa(MDB)); +} diff --git a/compiler-rt/lib/orc/unittests/orc_unit_test_main.cpp b/compiler-rt/lib/orc/unittests/orc_unit_test_main.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/orc/unittests/orc_unit_test_main.cpp @@ -0,0 +1,18 @@ +//===-- orc_unit_test_main.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 "gtest/gtest.h" + +int main(int argc, char **argv) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}