Index: include/llvm/Transforms/IPO/PassManagerBuilder.h =================================================================== --- include/llvm/Transforms/IPO/PassManagerBuilder.h +++ include/llvm/Transforms/IPO/PassManagerBuilder.h @@ -60,9 +60,10 @@ public: /// Extensions are passed the builder itself (so they can see how it is /// configured) as well as the pass manager to add stuff to. - typedef std::function - ExtensionFn; + typedef void ExtensionProc(const PassManagerBuilder &Builder, + legacy::PassManagerBase &PM); + typedef std::function ExtensionFn; + enum ExtensionPointTy { /// EP_EarlyAsPossible - This extension point allows adding passes before /// any other transformations, allowing them to see the code as it is coming @@ -179,7 +180,7 @@ /// Adds an extension that will be used by all PassManagerBuilder instances. /// This is intended to be used by plugins, to register a set of /// optimisations to run automatically. - static void addGlobalExtension(ExtensionPointTy Ty, ExtensionFn Fn); + static void addGlobalExtension(ExtensionPointTy Ty, ExtensionProc Fn); void addExtension(ExtensionPointTy Ty, ExtensionFn Fn); private: @@ -208,10 +209,12 @@ /// used by optimizer plugins to allow all front ends to transparently use /// them. Create a static instance of this class in your plugin, providing a /// private function that the PassManagerBuilder can use to add your passes. +/// Currently limited to real functions to avoid crashes when used within the +/// main executable before a loaded plugin has a chance to use this. struct RegisterStandardPasses { RegisterStandardPasses(PassManagerBuilder::ExtensionPointTy Ty, - PassManagerBuilder::ExtensionFn Fn) { - PassManagerBuilder::addGlobalExtension(Ty, std::move(Fn)); + PassManagerBuilder::ExtensionProc Fn) { + PassManagerBuilder::addGlobalExtension(Ty, Fn); } }; Index: lib/Transforms/IPO/PassManagerBuilder.cpp =================================================================== --- lib/Transforms/IPO/PassManagerBuilder.cpp +++ lib/Transforms/IPO/PassManagerBuilder.cpp @@ -198,10 +198,9 @@ static ManagedStatic, 8> > GlobalExtensions; -void PassManagerBuilder::addGlobalExtension( - PassManagerBuilder::ExtensionPointTy Ty, - PassManagerBuilder::ExtensionFn Fn) { - GlobalExtensions->push_back(std::make_pair(Ty, std::move(Fn))); +void PassManagerBuilder::addGlobalExtension(ExtensionPointTy Ty, + ExtensionProc Fn) { + GlobalExtensions->push_back(std::make_pair(Ty, Fn)); } void PassManagerBuilder::addExtension(ExtensionPointTy Ty, ExtensionFn Fn) { Index: unittests/Transforms/CMakeLists.txt =================================================================== --- unittests/Transforms/CMakeLists.txt +++ unittests/Transforms/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(IPO) +add_subdirectory(Registration) add_subdirectory(Scalar) add_subdirectory(Utils) Index: unittests/Transforms/Registration/CMakeLists.txt =================================================================== --- /dev/null +++ unittests/Transforms/Registration/CMakeLists.txt @@ -0,0 +1,36 @@ +set(LLVM_LINK_COMPONENTS + Support + IPO + ) + +add_llvm_unittest(IPOLoading + Registration.cpp + ) + + +if ( LLVM_INCLUDE_TESTS ) + add_library(LoadablePass SHARED LoadablePass.cxx) + + set_output_directory(LoadablePass + BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + ) + + set_target_properties(LoadablePass + PROPERTIES PREFIX "" + SUFFIX ".so" + ) + + add_dependencies(IPOLoading LoadablePass) + add_dependencies(LoadablePass LLVMCore) + + if ( LLVM_LINK_LLVM_DYLIB ) + target_compile_definitions(LoadablePass PRIVATE LLVM_DYLIB_PASSREG_TEST_2) + target_link_libraries(LoadablePass LLVM) + elseif ( BUILD_SHARED_LIBS ) + # Broken in Debug mode when building static libraries + target_compile_definitions(LoadablePass PRIVATE LLVM_DYLIB_PASSREG_TEST_2) + target_link_libraries(LoadablePass LLVMipo) + endif () + +endif () Index: unittests/Transforms/Registration/LoadablePass.cxx =================================================================== --- /dev/null +++ unittests/Transforms/Registration/LoadablePass.cxx @@ -0,0 +1,32 @@ +//===- llvm/unittest/Transforms/Registration/LoadablePass.cxx -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/IPO/PassManagerBuilder.h" + +#ifdef _WIN32 +#define LLVM_PASS_EXPORT_TEST extern "C" __declspec(dllexport) +#else +#define LLVM_PASS_EXPORT_TEST extern "C" +#endif + +using namespace llvm; + +static void EmptyPass2(const PassManagerBuilder &, legacy::PassManagerBase &) {} + +LLVM_PASS_EXPORT_TEST void TestPassReg( + void (*addGlobalExtension)(PassManagerBuilder::ExtensionPointTy, + PassManagerBuilder::ExtensionProc)) { + addGlobalExtension(PassManagerBuilder::EP_EarlyAsPossible, + EmptyPass2); +} + +#ifdef LLVM_DYLIB_PASSREG_TEST_2 +static RegisterStandardPasses sLocalPass(PassManagerBuilder::EP_EarlyAsPossible, + EmptyPass2); +#endif Index: unittests/Transforms/Registration/Registration.cpp =================================================================== --- /dev/null +++ unittests/Transforms/Registration/Registration.cpp @@ -0,0 +1,61 @@ +//===-- Registration.cpp - Unit tests for pass registration & shutdown ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::sys; + +static std::string LibPath(const std::string Name = "LoadablePass") { + const std::vector& Argvs = testing::internal::GetArgvs(); + const char *Argv0 = Argvs.size() > 0 ? Argvs[0].c_str() : "IPOTests"; + void *Ptr = (void*)(intptr_t)LibPath; + std::string Path = fs::getMainExecutable(Argv0, Ptr); + llvm::SmallString<256> Buf(path::parent_path(Path)); + path::append(Buf, (Name+".so").c_str()); + return Buf.str(); +} + +template static T FuncPtr(void *Ptr) { + union { + T F; + void *P; + } Tmp; + Tmp.P = Ptr; + return Tmp.F; +} + +static void +EmptyPass(const PassManagerBuilder &, legacy::PassManagerBase &) { +} + +static RegisterStandardPasses LocalPass(PassManagerBuilder::EP_LoopOptimizerEnd, + EmptyPass); + +typedef void (*TestPassReg)(void (*)(PassManagerBuilder::ExtensionPointTy, + PassManagerBuilder::ExtensionProc)); + +TEST(Registration, shutdownOrder) { + std::string Err; + llvm_shutdown_obj Shutdown; + DynamicLibrary DL = + DynamicLibrary::getPermanentLibrary(LibPath().c_str(), &Err); + EXPECT_TRUE(DL.isValid()); + EXPECT_TRUE(Err.empty()); + + TestPassReg RP = FuncPtr(DL.getAddressOfSymbol("TestPassReg")); + EXPECT_TRUE(RP != nullptr); + if (RP) + RP(&PassManagerBuilder::addGlobalExtension); +}