2018-06-19 02:01:43 +08:00
|
|
|
//===----- CompileOnDemandLayer.cpp - Lazily emit IR on first call --------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
|
2018-07-06 03:01:27 +08:00
|
|
|
#include "llvm/Bitcode/BitcodeReader.h"
|
|
|
|
#include "llvm/Bitcode/BitcodeWriter.h"
|
2018-06-19 02:01:43 +08:00
|
|
|
#include "llvm/IR/Mangler.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2018-07-06 03:01:27 +08:00
|
|
|
#include "llvm/Transforms/Utils/Cloning.h"
|
2018-06-19 02:01:43 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::orc;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <typename MaterializerFtor>
|
|
|
|
class LambdaValueMaterializer final : public ValueMaterializer {
|
|
|
|
public:
|
|
|
|
LambdaValueMaterializer(MaterializerFtor M) : M(std::move(M)) {}
|
|
|
|
|
|
|
|
Value *materialize(Value *V) final { return M(V); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
MaterializerFtor M;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename MaterializerFtor>
|
|
|
|
LambdaValueMaterializer<MaterializerFtor>
|
|
|
|
createLambdaValueMaterializer(MaterializerFtor M) {
|
|
|
|
return LambdaValueMaterializer<MaterializerFtor>(std::move(M));
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2018-06-27 05:35:48 +08:00
|
|
|
static void extractAliases(MaterializationResponsibility &R, Module &M,
|
|
|
|
MangleAndInterner &Mangle) {
|
|
|
|
SymbolAliasMap Aliases;
|
|
|
|
|
|
|
|
std::vector<GlobalAlias *> ModAliases;
|
|
|
|
for (auto &A : M.aliases())
|
|
|
|
ModAliases.push_back(&A);
|
|
|
|
|
|
|
|
for (auto *A : ModAliases) {
|
|
|
|
Constant *Aliasee = A->getAliasee();
|
|
|
|
assert(A->hasName() && "Anonymous alias?");
|
|
|
|
assert(Aliasee->hasName() && "Anonymous aliasee");
|
|
|
|
std::string AliasName = A->getName();
|
|
|
|
|
|
|
|
Aliases[Mangle(AliasName)] = SymbolAliasMapEntry(
|
|
|
|
{Mangle(Aliasee->getName()), JITSymbolFlags::fromGlobalValue(*A)});
|
|
|
|
|
|
|
|
if (isa<Function>(Aliasee)) {
|
|
|
|
auto *F = cloneFunctionDecl(M, *cast<Function>(Aliasee));
|
|
|
|
A->replaceAllUsesWith(F);
|
|
|
|
A->eraseFromParent();
|
|
|
|
F->setName(AliasName);
|
|
|
|
} else if (isa<GlobalValue>(Aliasee)) {
|
|
|
|
auto *G = cloneGlobalVariableDecl(M, *cast<GlobalVariable>(Aliasee));
|
|
|
|
A->replaceAllUsesWith(G);
|
|
|
|
A->eraseFromParent();
|
|
|
|
G->setName(AliasName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 04:54:36 +08:00
|
|
|
R.replace(symbolAliases(std::move(Aliases)));
|
2018-06-27 05:35:48 +08:00
|
|
|
}
|
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
static std::unique_ptr<Module>
|
|
|
|
extractAndClone(Module &M, LLVMContext &NewContext, StringRef Suffix,
|
|
|
|
function_ref<bool(const GlobalValue *)> ShouldCloneDefinition) {
|
|
|
|
SmallVector<char, 1> ClonedModuleBuffer;
|
2018-06-19 02:01:43 +08:00
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
{
|
|
|
|
std::set<GlobalValue *> ClonedDefsInSrc;
|
|
|
|
ValueToValueMapTy VMap;
|
|
|
|
auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
|
|
|
|
if (ShouldCloneDefinition(GV)) {
|
|
|
|
ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
for (auto *GV : ClonedDefsInSrc) {
|
|
|
|
// Delete the definition and bump the linkage in the source module.
|
|
|
|
if (isa<Function>(GV)) {
|
|
|
|
auto &F = *cast<Function>(GV);
|
|
|
|
F.deleteBody();
|
|
|
|
F.setPersonalityFn(nullptr);
|
|
|
|
} else if (isa<GlobalVariable>(GV)) {
|
|
|
|
cast<GlobalVariable>(GV)->setInitializer(nullptr);
|
|
|
|
} else
|
|
|
|
llvm_unreachable("Unsupported global type");
|
|
|
|
|
|
|
|
GV->setLinkage(GlobalValue::ExternalLinkage);
|
|
|
|
}
|
2018-06-19 02:01:43 +08:00
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
BitcodeWriter BCWriter(ClonedModuleBuffer);
|
2018-06-19 02:01:43 +08:00
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
BCWriter.writeModule(*Tmp);
|
|
|
|
BCWriter.writeSymtab();
|
|
|
|
BCWriter.writeStrtab();
|
|
|
|
}
|
2018-06-19 02:01:43 +08:00
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
MemoryBufferRef ClonedModuleBufferRef(
|
|
|
|
StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
|
|
|
|
"cloned module buffer");
|
2018-06-19 02:01:43 +08:00
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
auto ClonedModule =
|
|
|
|
cantFail(parseBitcodeFile(ClonedModuleBufferRef, NewContext));
|
|
|
|
ClonedModule->setModuleIdentifier((M.getName() + Suffix).str());
|
|
|
|
return ClonedModule;
|
|
|
|
}
|
2018-06-19 02:01:43 +08:00
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
static std::unique_ptr<Module> extractGlobals(Module &M,
|
|
|
|
LLVMContext &NewContext) {
|
|
|
|
return extractAndClone(M, NewContext, ".globals", [](const GlobalValue *GV) {
|
|
|
|
return isa<GlobalVariable>(GV);
|
|
|
|
});
|
2018-06-19 02:01:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace orc {
|
|
|
|
|
|
|
|
class ExtractingIRMaterializationUnit : public IRMaterializationUnit {
|
|
|
|
public:
|
|
|
|
ExtractingIRMaterializationUnit(
|
|
|
|
ExecutionSession &ES, CompileOnDemandLayer2 &Parent,
|
|
|
|
std::unique_ptr<Module> M,
|
|
|
|
std::shared_ptr<SymbolResolver> BackingResolver)
|
|
|
|
: IRMaterializationUnit(ES, std::move(M)), Parent(Parent),
|
|
|
|
BackingResolver(std::move(BackingResolver)) {}
|
|
|
|
|
|
|
|
ExtractingIRMaterializationUnit(
|
|
|
|
std::unique_ptr<Module> M, SymbolFlagsMap SymbolFlags,
|
|
|
|
SymbolNameToDefinitionMap SymbolToDefinition,
|
|
|
|
CompileOnDemandLayer2 &Parent,
|
|
|
|
std::shared_ptr<SymbolResolver> BackingResolver)
|
|
|
|
: IRMaterializationUnit(std::move(M), std::move(SymbolFlags),
|
|
|
|
std::move(SymbolToDefinition)),
|
|
|
|
Parent(Parent), BackingResolver(std::move(BackingResolver)) {}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void materialize(MaterializationResponsibility R) override {
|
|
|
|
// FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the
|
|
|
|
// extracted module key, extracted module, and source module key
|
|
|
|
// together. This could be used, for example, to provide a specific
|
|
|
|
// memory manager instance to the linking layer.
|
|
|
|
|
|
|
|
// FIXME: The derived constructor should *only* look for the names of
|
|
|
|
// original function definitions in the target VSO. All other
|
|
|
|
// symbols should be looked up in the backing resolver.
|
|
|
|
|
|
|
|
auto RequestedSymbols = R.getRequestedSymbols();
|
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
// Extract the requested functions into a new module.
|
|
|
|
std::unique_ptr<Module> ExtractedFunctionsModule;
|
|
|
|
if (!RequestedSymbols.empty()) {
|
|
|
|
std::string Suffix;
|
|
|
|
std::set<const GlobalValue *> FunctionsToClone;
|
|
|
|
for (auto &Name : RequestedSymbols) {
|
|
|
|
auto I = SymbolToDefinition.find(Name);
|
|
|
|
assert(I != SymbolToDefinition.end() && I->second != nullptr &&
|
|
|
|
"Should have a non-null definition");
|
|
|
|
FunctionsToClone.insert(I->second);
|
|
|
|
Suffix += ".";
|
|
|
|
Suffix += *Name;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::lock_guard<std::mutex> Lock(SourceModuleMutex);
|
|
|
|
ExtractedFunctionsModule =
|
|
|
|
extractAndClone(*M, Parent.GetAvailableContext(), Suffix,
|
|
|
|
[&](const GlobalValue *GV) -> bool {
|
|
|
|
return FunctionsToClone.count(GV);
|
|
|
|
});
|
|
|
|
}
|
2018-06-19 02:01:43 +08:00
|
|
|
|
|
|
|
// Build a new ExtractingIRMaterializationUnit to delegate the unrequested
|
|
|
|
// symbols to.
|
|
|
|
SymbolFlagsMap DelegatedSymbolFlags;
|
|
|
|
IRMaterializationUnit::SymbolNameToDefinitionMap
|
|
|
|
DelegatedSymbolToDefinition;
|
|
|
|
for (auto &KV : SymbolToDefinition) {
|
|
|
|
if (RequestedSymbols.count(KV.first))
|
|
|
|
continue;
|
|
|
|
DelegatedSymbolFlags[KV.first] =
|
|
|
|
JITSymbolFlags::fromGlobalValue(*KV.second);
|
|
|
|
DelegatedSymbolToDefinition[KV.first] = KV.second;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DelegatedSymbolFlags.empty()) {
|
|
|
|
assert(DelegatedSymbolFlags.size() ==
|
|
|
|
DelegatedSymbolToDefinition.size() &&
|
|
|
|
"SymbolFlags and SymbolToDefinition should have the same number "
|
|
|
|
"of entries");
|
2018-07-10 04:54:36 +08:00
|
|
|
R.replace(llvm::make_unique<ExtractingIRMaterializationUnit>(
|
2018-06-19 02:01:43 +08:00
|
|
|
std::move(M), std::move(DelegatedSymbolFlags),
|
|
|
|
std::move(DelegatedSymbolToDefinition), Parent, BackingResolver));
|
|
|
|
}
|
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
if (ExtractedFunctionsModule)
|
|
|
|
Parent.emitExtractedFunctionsModule(
|
|
|
|
std::move(R), std::move(ExtractedFunctionsModule), BackingResolver);
|
2018-06-19 02:01:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void discard(const VSO &V, SymbolStringPtr Name) override {
|
|
|
|
// All original symbols were materialized by the CODLayer and should be
|
|
|
|
// final. The function bodies provided by M should never be overridden.
|
|
|
|
llvm_unreachable("Discard should never be called on an "
|
|
|
|
"ExtractingIRMaterializationUnit");
|
|
|
|
}
|
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
mutable std::mutex SourceModuleMutex;
|
2018-06-19 02:01:43 +08:00
|
|
|
CompileOnDemandLayer2 &Parent;
|
|
|
|
std::shared_ptr<SymbolResolver> BackingResolver;
|
|
|
|
};
|
|
|
|
|
|
|
|
CompileOnDemandLayer2::CompileOnDemandLayer2(
|
|
|
|
ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr,
|
|
|
|
IndirectStubsManagerBuilder BuildIndirectStubsManager,
|
|
|
|
GetSymbolResolverFunction GetSymbolResolver,
|
|
|
|
SetSymbolResolverFunction SetSymbolResolver,
|
|
|
|
GetAvailableContextFunction GetAvailableContext)
|
|
|
|
: IRLayer(ES), BaseLayer(BaseLayer), CCMgr(CCMgr),
|
|
|
|
BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)),
|
|
|
|
GetSymbolResolver(std::move(GetSymbolResolver)),
|
|
|
|
SetSymbolResolver(std::move(SetSymbolResolver)),
|
|
|
|
GetAvailableContext(std::move(GetAvailableContext)) {}
|
|
|
|
|
|
|
|
Error CompileOnDemandLayer2::add(VSO &V, VModuleKey K,
|
|
|
|
std::unique_ptr<Module> M) {
|
|
|
|
return IRLayer::add(V, K, std::move(M));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
|
|
|
|
std::unique_ptr<Module> M) {
|
|
|
|
auto &ES = getExecutionSession();
|
|
|
|
assert(M && "M should not be null");
|
|
|
|
|
|
|
|
for (auto &GV : M->global_values())
|
|
|
|
if (GV.hasWeakLinkage())
|
|
|
|
GV.setLinkage(GlobalValue::ExternalLinkage);
|
|
|
|
|
|
|
|
MangleAndInterner Mangle(ES, M->getDataLayout());
|
|
|
|
|
2018-06-27 05:35:48 +08:00
|
|
|
extractAliases(R, *M, Mangle);
|
|
|
|
|
2018-07-06 03:01:27 +08:00
|
|
|
auto GlobalsModule = extractGlobals(*M, GetAvailableContext());
|
2018-06-27 05:35:48 +08:00
|
|
|
|
2018-06-19 02:01:43 +08:00
|
|
|
// Delete the bodies of any available externally functions, rename the
|
|
|
|
// rest, and build the compile callbacks.
|
|
|
|
std::map<SymbolStringPtr, std::pair<JITTargetAddress, JITSymbolFlags>>
|
|
|
|
StubCallbacksAndLinkages;
|
|
|
|
auto &TargetVSO = R.getTargetVSO();
|
|
|
|
|
|
|
|
for (auto &F : M->functions()) {
|
|
|
|
if (F.isDeclaration())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (F.hasAvailableExternallyLinkage()) {
|
|
|
|
F.deleteBody();
|
2018-07-06 03:01:27 +08:00
|
|
|
F.setPersonalityFn(nullptr);
|
2018-06-19 02:01:43 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(F.hasName() && "Function should have a name");
|
2018-06-27 05:35:48 +08:00
|
|
|
std::string StubUnmangledName = F.getName();
|
2018-06-19 02:01:43 +08:00
|
|
|
F.setName(F.getName() + "$body");
|
2018-06-27 05:35:48 +08:00
|
|
|
auto StubDecl = cloneFunctionDecl(*M, F);
|
|
|
|
StubDecl->setName(StubUnmangledName);
|
2018-07-06 03:01:27 +08:00
|
|
|
StubDecl->setPersonalityFn(nullptr);
|
|
|
|
StubDecl->setLinkage(GlobalValue::ExternalLinkage);
|
2018-06-27 05:35:48 +08:00
|
|
|
F.replaceAllUsesWith(StubDecl);
|
2018-07-06 03:01:27 +08:00
|
|
|
|
2018-06-27 05:35:48 +08:00
|
|
|
auto StubName = Mangle(StubUnmangledName);
|
2018-06-19 02:01:43 +08:00
|
|
|
auto BodyName = Mangle(F.getName());
|
|
|
|
if (auto CallbackAddr = CCMgr.getCompileCallback(
|
|
|
|
[BodyName, &TargetVSO, &ES]() -> JITTargetAddress {
|
|
|
|
if (auto Sym = lookup({&TargetVSO}, BodyName))
|
|
|
|
return Sym->getAddress();
|
|
|
|
else {
|
|
|
|
ES.reportError(Sym.takeError());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
})) {
|
|
|
|
auto Flags = JITSymbolFlags::fromGlobalValue(F);
|
|
|
|
Flags &= ~JITSymbolFlags::Weak;
|
|
|
|
StubCallbacksAndLinkages[std::move(StubName)] =
|
|
|
|
std::make_pair(*CallbackAddr, Flags);
|
|
|
|
} else {
|
|
|
|
ES.reportError(CallbackAddr.takeError());
|
|
|
|
R.failMaterialization();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the stub inits map.
|
|
|
|
IndirectStubsManager::StubInitsMap StubInits;
|
|
|
|
for (auto &KV : StubCallbacksAndLinkages)
|
|
|
|
StubInits[*KV.first] = KV.second;
|
|
|
|
|
|
|
|
// Build the function-body-extracting materialization unit.
|
2018-06-27 05:35:48 +08:00
|
|
|
auto SR = GetSymbolResolver(K);
|
2018-06-19 02:01:43 +08:00
|
|
|
if (auto Err = R.getTargetVSO().define(
|
|
|
|
llvm::make_unique<ExtractingIRMaterializationUnit>(
|
2018-06-27 05:35:48 +08:00
|
|
|
ES, *this, std::move(M), SR))) {
|
2018-06-19 02:01:43 +08:00
|
|
|
ES.reportError(std::move(Err));
|
|
|
|
R.failMaterialization();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-27 05:35:48 +08:00
|
|
|
// Replace the fallback symbol resolver: We will re-use M's VModuleKey for
|
|
|
|
// the GlobalsModule.
|
|
|
|
SetSymbolResolver(K, SR);
|
|
|
|
|
2018-06-19 02:01:43 +08:00
|
|
|
// Build the stubs.
|
|
|
|
// FIXME: Remove function bodies materialization unit if stub creation fails.
|
|
|
|
auto &StubsMgr = getStubsManager(TargetVSO);
|
|
|
|
if (auto Err = StubsMgr.createStubs(StubInits)) {
|
|
|
|
ES.reportError(std::move(Err));
|
|
|
|
R.failMaterialization();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve and finalize stubs.
|
|
|
|
SymbolMap ResolvedStubs;
|
|
|
|
for (auto &KV : StubCallbacksAndLinkages) {
|
|
|
|
if (auto Sym = StubsMgr.findStub(*KV.first, false))
|
|
|
|
ResolvedStubs[KV.first] = Sym;
|
|
|
|
else
|
|
|
|
llvm_unreachable("Stub went missing");
|
|
|
|
}
|
|
|
|
|
|
|
|
R.resolve(ResolvedStubs);
|
|
|
|
|
|
|
|
BaseLayer.emit(std::move(R), std::move(K), std::move(GlobalsModule));
|
|
|
|
}
|
|
|
|
|
|
|
|
IndirectStubsManager &CompileOnDemandLayer2::getStubsManager(const VSO &V) {
|
|
|
|
std::lock_guard<std::mutex> Lock(CODLayerMutex);
|
|
|
|
StubManagersMap::iterator I = StubsMgrs.find(&V);
|
|
|
|
if (I == StubsMgrs.end())
|
|
|
|
I = StubsMgrs.insert(std::make_pair(&V, BuildIndirectStubsManager())).first;
|
|
|
|
return *I->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CompileOnDemandLayer2::emitExtractedFunctionsModule(
|
|
|
|
MaterializationResponsibility R, std::unique_ptr<Module> M,
|
|
|
|
std::shared_ptr<SymbolResolver> Resolver) {
|
|
|
|
auto &TargetVSO = R.getTargetVSO();
|
|
|
|
auto K = getExecutionSession().allocateVModule();
|
|
|
|
|
|
|
|
auto ExtractedFunctionsResolver = createSymbolResolver(
|
|
|
|
[=](SymbolFlagsMap &Flags, const SymbolNameSet &Symbols) {
|
|
|
|
return Resolver->lookupFlags(Flags, Symbols);
|
|
|
|
},
|
|
|
|
[=, &TargetVSO](std::shared_ptr<AsynchronousSymbolQuery> Query,
|
|
|
|
SymbolNameSet Symbols) {
|
|
|
|
auto RemainingSymbols = TargetVSO.lookup(Query, std::move(Symbols));
|
|
|
|
return Resolver->lookup(std::move(Query), std::move(RemainingSymbols));
|
|
|
|
});
|
|
|
|
|
|
|
|
SetSymbolResolver(K, std::move(ExtractedFunctionsResolver));
|
|
|
|
BaseLayer.emit(std::move(R), std::move(K), std::move(M));
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace orc
|
|
|
|
} // end namespace llvm
|