diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -105,16 +105,18 @@ /// llvm.global_ctors. class GlobalCtorDtorScraper { public: - GlobalCtorDtorScraper(GenericLLVMIRPlatformSupport &PS, - StringRef InitFunctionPrefix) - : PS(PS), InitFunctionPrefix(InitFunctionPrefix) {} + StringRef InitFunctionPrefix, + StringRef DeInitFunctionPrefix) + : PS(PS), InitFunctionPrefix(InitFunctionPrefix), + DeInitFunctionPrefix(DeInitFunctionPrefix) {} Expected operator()(ThreadSafeModule TSM, MaterializationResponsibility &R); private: GenericLLVMIRPlatformSupport &PS; StringRef InitFunctionPrefix; + StringRef DeInitFunctionPrefix; }; /// Generic IR Platform Support @@ -125,12 +127,14 @@ class GenericLLVMIRPlatformSupport : public LLJIT::PlatformSupport { public: GenericLLVMIRPlatformSupport(LLJIT &J) - : J(J), InitFunctionPrefix(J.mangle("__orc_init_func.")) { + : J(J), InitFunctionPrefix(J.mangle("__orc_init_func.")), + DeInitFunctionPrefix(J.mangle("__orc_deinit_func.")) { getExecutionSession().setPlatform( std::make_unique(*this)); - setInitTransform(J, GlobalCtorDtorScraper(*this, InitFunctionPrefix)); + setInitTransform(J, GlobalCtorDtorScraper(*this, InitFunctionPrefix, + DeInitFunctionPrefix)); SymbolMap StdInterposes; @@ -203,6 +207,8 @@ InitSymbols[&JD].add(KV.first, SymbolLookupFlags::WeaklyReferencedSymbol); InitFunctions[&JD].add(KV.first); + } else if ((*KV.first).startswith(DeInitFunctionPrefix)) { + DeInitFunctions[&JD].add(KV.first); } } return Error::success(); @@ -256,6 +262,11 @@ }); } + void registerDeInitFunc(JITDylib &JD, SymbolStringPtr DeInitName) { + getExecutionSession().runSessionLocked( + [&]() { DeInitFunctions[&JD].add(DeInitName); }); + } + private: Expected> getInitializers(JITDylib &JD) { @@ -438,6 +449,7 @@ LLJIT &J; std::string InitFunctionPrefix; + std::string DeInitFunctionPrefix; DenseMap InitSymbols; DenseMap InitFunctions; DenseMap DeInitFunctions; @@ -459,40 +471,63 @@ auto Err = TSM.withModuleDo([&](Module &M) -> Error { auto &Ctx = M.getContext(); auto *GlobalCtors = M.getNamedGlobal("llvm.global_ctors"); - - // If there's no llvm.global_ctors or it's just a decl then skip. - if (!GlobalCtors || GlobalCtors->isDeclaration()) + auto *GlobalDtors = M.getNamedGlobal("llvm.global_dtors"); + + auto RegisterCOrDtors = [&](GlobalVariable *GlobalCOrDtors, + bool isCtor) -> Error { + // If there's no llvm.global_c/dtor or it's just a decl then skip. + if (!GlobalCOrDtors || GlobalCOrDtors->isDeclaration()) + return Error::success(); + std::string InitOrDeInitFunctionName; + if (isCtor) + raw_string_ostream(InitOrDeInitFunctionName) + << InitFunctionPrefix << M.getModuleIdentifier(); + else + raw_string_ostream(InitOrDeInitFunctionName) + << DeInitFunctionPrefix << M.getModuleIdentifier(); + + MangleAndInterner Mangle(PS.getExecutionSession(), M.getDataLayout()); + auto InternedInitOrDeInitName = Mangle(InitOrDeInitFunctionName); + if (auto Err = R.defineMaterializing( + {{InternedInitOrDeInitName, JITSymbolFlags::Callable}})) + return Err; + + auto *InitOrDeInitFunc = Function::Create( + FunctionType::get(Type::getVoidTy(Ctx), {}, false), + GlobalValue::ExternalLinkage, InitOrDeInitFunctionName, &M); + InitOrDeInitFunc->setVisibility(GlobalValue::HiddenVisibility); + std::vector> InitsOrDeInits; + auto COrDtors = isCtor ? getConstructors(M) : getDestructors(M); + + for (auto E : COrDtors) + InitsOrDeInits.push_back(std::make_pair(E.Func, E.Priority)); + llvm::sort(InitsOrDeInits, + [](const std::pair &LHS, + const std::pair &RHS) { + return LHS.first < RHS.first; + }); + + auto *InitOrDeInitFuncEntryBlock = + BasicBlock::Create(Ctx, "entry", InitOrDeInitFunc); + IRBuilder<> IB(InitOrDeInitFuncEntryBlock); + for (auto &KV : InitsOrDeInits) + IB.CreateCall(KV.first); + IB.CreateRetVoid(); + + if (isCtor) + PS.registerInitFunc(R.getTargetJITDylib(), InternedInitOrDeInitName); + else + PS.registerDeInitFunc(R.getTargetJITDylib(), InternedInitOrDeInitName); + + GlobalCOrDtors->eraseFromParent(); return Error::success(); + }; - std::string InitFunctionName; - raw_string_ostream(InitFunctionName) - << InitFunctionPrefix << M.getModuleIdentifier(); - - MangleAndInterner Mangle(PS.getExecutionSession(), M.getDataLayout()); - auto InternedName = Mangle(InitFunctionName); - if (auto Err = - R.defineMaterializing({{InternedName, JITSymbolFlags::Callable}})) + if (auto Err = RegisterCOrDtors(GlobalCtors, true)) + return Err; + if (auto Err = RegisterCOrDtors(GlobalDtors, false)) return Err; - auto *InitFunc = - Function::Create(FunctionType::get(Type::getVoidTy(Ctx), {}, false), - GlobalValue::ExternalLinkage, InitFunctionName, &M); - InitFunc->setVisibility(GlobalValue::HiddenVisibility); - std::vector> Inits; - for (auto E : getConstructors(M)) - Inits.push_back(std::make_pair(E.Func, E.Priority)); - llvm::sort(Inits, [](const std::pair &LHS, - const std::pair &RHS) { - return LHS.first < RHS.first; - }); - auto *EntryBlock = BasicBlock::Create(Ctx, "entry", InitFunc); - IRBuilder<> IB(EntryBlock); - for (auto &KV : Inits) - IB.CreateCall(KV.first); - IB.CreateRetVoid(); - - PS.registerInitFunc(R.getTargetJITDylib(), InternedName); - GlobalCtors->eraseFromParent(); return Error::success(); }); diff --git a/llvm/test/ExecutionEngine/OrcLazy/global-ctors-and-dtors.ll b/llvm/test/ExecutionEngine/OrcLazy/global-ctors-and-dtors.ll --- a/llvm/test/ExecutionEngine/OrcLazy/global-ctors-and-dtors.ll +++ b/llvm/test/ExecutionEngine/OrcLazy/global-ctors-and-dtors.ll @@ -11,14 +11,17 @@ ; CHECK: Hello ; CHECK: [ {{.*}}main{{.*}} ] ; CHECK: Goodbye +; CHECK: Goodbye again %class.Foo = type { i8 } @f = global %class.Foo zeroinitializer, align 1 @__dso_handle = external global i8 -@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_hello.cpp, i8* null }] +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_hello.cpp, i8* null }] +@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @printf_wrapper, i8* null }] @str = private unnamed_addr constant [6 x i8] c"Hello\00" @str2 = private unnamed_addr constant [8 x i8] c"Goodbye\00" +@str3 = global [14 x i8] c"Goodbye again\00" define linkonce_odr void @_ZN3FooD1Ev(%class.Foo* nocapture readnone %this) unnamed_addr align 2 { entry: @@ -35,4 +38,10 @@ ret void } +define void @printf_wrapper() { +entry: + %0 = tail call i32 @puts(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @str3, i64 0, i64 0)) + ret void +} + declare i32 @puts(i8* nocapture readonly)