[Orc] Fix global variable destructor function support when --jit-kind=orc-lazy

The bug was reported here https://bugs.llvm.org/show_bug.cgi?id=52030

This patch follows the idea that @lhames commented in the above webpage.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D110990
This commit is contained in:
luxufan 2021-10-09 15:40:03 +08:00
parent 4c0da23663
commit 02ac5e5cf1
2 changed files with 79 additions and 35 deletions

View File

@ -105,16 +105,18 @@ private:
/// 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<ThreadSafeModule> operator()(ThreadSafeModule TSM,
MaterializationResponsibility &R);
private:
GenericLLVMIRPlatformSupport &PS;
StringRef InitFunctionPrefix;
StringRef DeInitFunctionPrefix;
};
/// Generic IR Platform Support
@ -125,12 +127,14 @@ private:
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<GenericLLVMIRPlatform>(*this));
setInitTransform(J, GlobalCtorDtorScraper(*this, InitFunctionPrefix));
setInitTransform(J, GlobalCtorDtorScraper(*this, InitFunctionPrefix,
DeInitFunctionPrefix));
SymbolMap StdInterposes;
@ -203,6 +207,8 @@ public:
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 @@ public:
});
}
void registerDeInitFunc(JITDylib &JD, SymbolStringPtr DeInitName) {
getExecutionSession().runSessionLocked(
[&]() { DeInitFunctions[&JD].add(DeInitName); });
}
private:
Expected<std::vector<JITTargetAddress>> getInitializers(JITDylib &JD) {
@ -438,6 +449,7 @@ private:
LLJIT &J;
std::string InitFunctionPrefix;
std::string DeInitFunctionPrefix;
DenseMap<JITDylib *, SymbolLookupSet> InitSymbols;
DenseMap<JITDylib *, SymbolLookupSet> InitFunctions;
DenseMap<JITDylib *, SymbolLookupSet> DeInitFunctions;
@ -459,40 +471,63 @@ GlobalCtorDtorScraper::operator()(ThreadSafeModule TSM,
auto Err = TSM.withModuleDo([&](Module &M) -> Error {
auto &Ctx = M.getContext();
auto *GlobalCtors = M.getNamedGlobal("llvm.global_ctors");
auto *GlobalDtors = M.getNamedGlobal("llvm.global_dtors");
// If there's no llvm.global_ctors or it's just a decl then skip.
if (!GlobalCtors || GlobalCtors->isDeclaration())
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<std::pair<Function *, unsigned>> 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<Function *, unsigned> &LHS,
const std::pair<Function *, unsigned> &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<std::pair<Function *, unsigned>> Inits;
for (auto E : getConstructors(M))
Inits.push_back(std::make_pair(E.Func, E.Priority));
llvm::sort(Inits, [](const std::pair<Function *, unsigned> &LHS,
const std::pair<Function *, unsigned> &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();
});

View File

@ -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 @@ entry:
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)