CompileOnDemandLayer.h [plain text]
#ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
#define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
#include "IndirectionUtils.h"
#include "LambdaResolver.h"
#include "LogicalDylib.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <list>
#include <memory>
#include <set>
#include "llvm/Support/Debug.h"
namespace llvm {
namespace orc {
template <typename BaseLayerT,
typename CompileCallbackMgrT = JITCompileCallbackManager,
typename IndirectStubsMgrT = IndirectStubsManager>
class CompileOnDemandLayer {
private:
template <typename MaterializerFtor>
class LambdaMaterializer final : public ValueMaterializer {
public:
LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {}
Value *materializeDeclFor(Value *V) final { return M(V); }
private:
MaterializerFtor M;
};
template <typename MaterializerFtor>
LambdaMaterializer<MaterializerFtor>
createLambdaMaterializer(MaterializerFtor M) {
return LambdaMaterializer<MaterializerFtor>(std::move(M));
}
typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
template <typename ResourceT>
class ResourceOwner {
public:
ResourceOwner() = default;
ResourceOwner(const ResourceOwner&) = delete;
ResourceOwner& operator=(const ResourceOwner&) = delete;
virtual ~ResourceOwner() { }
virtual ResourceT& getResource() const = 0;
};
template <typename ResourceT, typename ResourcePtrT>
class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
public:
ResourceOwnerImpl(ResourcePtrT ResourcePtr)
: ResourcePtr(std::move(ResourcePtr)) {}
ResourceT& getResource() const override { return *ResourcePtr; }
private:
ResourcePtrT ResourcePtr;
};
template <typename ResourceT, typename ResourcePtrT>
std::unique_ptr<ResourceOwner<ResourceT>>
wrapOwnership(ResourcePtrT ResourcePtr) {
typedef ResourceOwnerImpl<ResourceT, ResourcePtrT> RO;
return llvm::make_unique<RO>(std::move(ResourcePtr));
}
struct LogicalModuleResources {
std::unique_ptr<ResourceOwner<Module>> SourceModule;
std::set<const Function*> StubsToClone;
std::unique_ptr<IndirectStubsMgrT> StubsMgr;
LogicalModuleResources() = default;
LogicalModuleResources(LogicalModuleResources &&Other)
: SourceModule(std::move(Other.SourceModule)),
StubsToClone(std::move(Other.StubsToClone)),
StubsMgr(std::move(Other.StubsMgr)) {}
LogicalModuleResources& operator=(LogicalModuleResources &&Other) {
SourceModule = std::move(Other.SourceModule);
StubsToClone = std::move(Other.StubsToClone);
StubsMgr = std::move(Other.StubsMgr);
return *this;
}
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
if (Name.endswith("$stub_ptr") && !ExportedSymbolsOnly) {
assert(!ExportedSymbolsOnly && "Stubs are never exported");
return StubsMgr->findPointer(Name.drop_back(9));
}
return StubsMgr->findStub(Name, ExportedSymbolsOnly);
}
};
struct LogicalDylibResources {
typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)>
SymbolResolverFtor;
typedef std::function<typename BaseLayerT::ModuleSetHandleT(
BaseLayerT&,
std::unique_ptr<Module>,
std::unique_ptr<RuntimeDyld::SymbolResolver>)>
ModuleAdderFtor;
LogicalDylibResources() = default;
LogicalDylibResources(LogicalDylibResources &&Other)
: ExternalSymbolResolver(std::move(Other.ExternalSymbolResolver)),
MemMgr(std::move(Other.MemMgr)),
ModuleAdder(std::move(Other.ModuleAdder)) {}
LogicalDylibResources& operator=(LogicalDylibResources &&Other) {
ExternalSymbolResolver = std::move(Other.ExternalSymbolResolver);
MemMgr = std::move(Other.MemMgr);
ModuleAdder = std::move(Other.ModuleAdder);
return *this;
}
SymbolResolverFtor ExternalSymbolResolver;
std::unique_ptr<ResourceOwner<RuntimeDyld::MemoryManager>> MemMgr;
ModuleAdderFtor ModuleAdder;
};
typedef LogicalDylib<BaseLayerT, LogicalModuleResources,
LogicalDylibResources> CODLogicalDylib;
typedef typename CODLogicalDylib::LogicalModuleHandle LogicalModuleHandle;
typedef std::list<CODLogicalDylib> LogicalDylibList;
public:
typedef typename LogicalDylibList::iterator ModuleSetHandleT;
typedef std::function<std::set<Function*>(Function&)> PartitioningFtor;
typedef std::function<std::unique_ptr<IndirectStubsMgrT>()>
IndirectStubsManagerBuilderT;
CompileOnDemandLayer(BaseLayerT &BaseLayer, PartitioningFtor Partition,
CompileCallbackMgrT &CallbackMgr,
IndirectStubsManagerBuilderT CreateIndirectStubsManager,
bool CloneStubsIntoPartitions = true)
: BaseLayer(BaseLayer), Partition(Partition),
CompileCallbackMgr(CallbackMgr),
CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)),
CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
template <typename ModuleSetT, typename MemoryManagerPtrT,
typename SymbolResolverPtrT>
ModuleSetHandleT addModuleSet(ModuleSetT Ms,
MemoryManagerPtrT MemMgr,
SymbolResolverPtrT Resolver) {
LogicalDylibs.push_back(CODLogicalDylib(BaseLayer));
auto &LDResources = LogicalDylibs.back().getDylibResources();
LDResources.ExternalSymbolResolver =
[Resolver](const std::string &Name) {
return Resolver->findSymbol(Name);
};
auto &MemMgrRef = *MemMgr;
LDResources.MemMgr =
wrapOwnership<RuntimeDyld::MemoryManager>(std::move(MemMgr));
LDResources.ModuleAdder =
[&MemMgrRef](BaseLayerT &B, std::unique_ptr<Module> M,
std::unique_ptr<RuntimeDyld::SymbolResolver> R) {
std::vector<std::unique_ptr<Module>> Ms;
Ms.push_back(std::move(M));
return B.addModuleSet(std::move(Ms), &MemMgrRef, std::move(R));
};
for (auto &M : Ms)
addLogicalModule(LogicalDylibs.back(), std::move(M));
return std::prev(LogicalDylibs.end());
}
void removeModuleSet(ModuleSetHandleT H) {
LogicalDylibs.erase(H);
}
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
for (auto LDI = LogicalDylibs.begin(), LDE = LogicalDylibs.end();
LDI != LDE; ++LDI)
if (auto Symbol = findSymbolIn(LDI, Name, ExportedSymbolsOnly))
return Symbol;
return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
}
JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
bool ExportedSymbolsOnly) {
return H->findSymbol(Name, ExportedSymbolsOnly);
}
private:
template <typename ModulePtrT>
void addLogicalModule(CODLogicalDylib &LD, ModulePtrT SrcMPtr) {
makeAllSymbolsExternallyAccessible(*SrcMPtr);
auto LMH = LD.createLogicalModule();
auto &LMResources = LD.getLogicalModuleResources(LMH);
LMResources.SourceModule = wrapOwnership<Module>(std::move(SrcMPtr));
Module &SrcM = LMResources.SourceModule->getResource();
const DataLayout &DL = SrcM.getDataLayout();
auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(),
SrcM.getContext());
GVsM->setDataLayout(DL);
ValueToValueMapTy VMap;
{
typename IndirectStubsMgrT::StubInitsMap StubInits;
for (auto &F : SrcM) {
if (F.isDeclaration())
continue;
if (CloneStubsIntoPartitions)
LMResources.StubsToClone.insert(&F);
auto CCInfo = CompileCallbackMgr.getCompileCallback();
StubInits[mangle(F.getName(), DL)] =
std::make_pair(CCInfo.getAddress(),
JITSymbolBase::flagsFromGlobalValue(F));
CCInfo.setCompileAction([this, &LD, LMH, &F]() {
return this->extractAndCompile(LD, LMH, F);
});
}
LMResources.StubsMgr = CreateIndirectStubsManager();
auto EC = LMResources.StubsMgr->createStubs(StubInits);
(void)EC;
assert(!EC && "Error generating stubs");
}
for (auto &GV : SrcM.globals())
if (!GV.isDeclaration() && !VMap.count(&GV))
cloneGlobalVariableDecl(*GVsM, GV, &VMap);
for (auto &A : SrcM.aliases())
if (!VMap.count(&A))
cloneGlobalAliasDecl(*GVsM, A, VMap);
auto Materializer = createLambdaMaterializer(
[this, &GVsM, &LMResources](Value *V) -> Value* {
if (auto *F = dyn_cast<Function>(V)) {
if (F->isDeclaration())
return cloneFunctionDecl(*GVsM, *F);
const DataLayout &DL = GVsM->getDataLayout();
std::string FName = mangle(F->getName(), DL);
auto StubSym = LMResources.StubsMgr->findStub(FName, false);
unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType());
ConstantInt *StubAddr =
ConstantInt::get(GVsM->getContext(),
APInt(PtrBitWidth, StubSym.getAddress()));
Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr,
StubAddr, F->getType());
return GlobalAlias::create(F->getFunctionType(),
F->getType()->getAddressSpace(),
F->getLinkage(), F->getName(),
Init, GVsM.get());
}
return nullptr;
});
for (auto &GV : SrcM.globals())
if (!GV.isDeclaration())
moveGlobalVariableInitializer(GV, VMap, &Materializer);
for (auto &A : SrcM.aliases()) {
auto *NewA = cast<GlobalAlias>(VMap[&A]);
assert(NewA && "Alias not cloned?");
Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr,
&Materializer);
NewA->setAliasee(cast<Constant>(Init));
}
auto GVsResolver = createLambdaResolver(
[&LD, LMH](const std::string &Name) {
auto &LMResources = LD.getLogicalModuleResources(LMH);
if (auto Sym = LMResources.StubsMgr->findStub(Name, false))
return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags());
return LD.getDylibResources().ExternalSymbolResolver(Name);
},
[](const std::string &Name) {
return RuntimeDyld::SymbolInfo(nullptr);
});
auto GVsH =
LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM),
std::move(GVsResolver));
LD.addToLogicalModule(LMH, GVsH);
}
static std::string mangle(StringRef Name, const DataLayout &DL) {
std::string MangledName;
{
raw_string_ostream MangledNameStream(MangledName);
Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
}
return MangledName;
}
TargetAddress extractAndCompile(CODLogicalDylib &LD,
LogicalModuleHandle LMH,
Function &F) {
auto &LMResources = LD.getLogicalModuleResources(LMH);
Module &SrcM = LMResources.SourceModule->getResource();
if (F.isDeclaration())
return 0;
std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout());
auto Part = Partition(F);
auto PartH = emitPartition(LD, LMH, Part);
TargetAddress CalledAddr = 0;
for (auto *SubF : Part) {
std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout());
auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false);
assert(FnBodySym && "Couldn't find function body.");
TargetAddress FnBodyAddr = FnBodySym.getAddress();
if (SubF == &F)
CalledAddr = FnBodyAddr;
if (auto EC = LMResources.StubsMgr->updatePointer(FnName, FnBodyAddr))
return 0;
}
return CalledAddr;
}
template <typename PartitionT>
BaseLayerModuleSetHandleT emitPartition(CODLogicalDylib &LD,
LogicalModuleHandle LMH,
const PartitionT &Part) {
auto &LMResources = LD.getLogicalModuleResources(LMH);
Module &SrcM = LMResources.SourceModule->getResource();
std::string NewName = SrcM.getName();
for (auto *F : Part) {
NewName += ".";
NewName += F->getName();
}
auto M = llvm::make_unique<Module>(NewName, SrcM.getContext());
M->setDataLayout(SrcM.getDataLayout());
ValueToValueMapTy VMap;
auto Materializer = createLambdaMaterializer([this, &LMResources, &M,
&VMap](Value *V) -> Value * {
if (auto *GV = dyn_cast<GlobalVariable>(V))
return cloneGlobalVariableDecl(*M, *GV);
if (auto *F = dyn_cast<Function>(V)) {
if (!LMResources.StubsToClone.count(F))
return cloneFunctionDecl(*M, *F);
auto *StubPtr = createImplPointer(*F->getType(), *M,
F->getName() + "$stub_ptr", nullptr);
auto *ClonedF = cloneFunctionDecl(*M, *F);
makeStub(*ClonedF, *StubPtr);
ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage);
ClonedF->addFnAttr(Attribute::AlwaysInline);
return ClonedF;
}
if (auto *A = dyn_cast<GlobalAlias>(V)) {
auto *Ty = A->getValueType();
if (Ty->isFunctionTy())
return Function::Create(cast<FunctionType>(Ty),
GlobalValue::ExternalLinkage, A->getName(),
M.get());
return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage,
nullptr, A->getName(), nullptr,
GlobalValue::NotThreadLocal,
A->getType()->getAddressSpace());
}
return nullptr;
});
for (auto *F : Part)
cloneFunctionDecl(*M, *F, &VMap);
for (auto *F : Part)
moveFunctionBody(*F, VMap, &Materializer);
auto Resolver = createLambdaResolver(
[this, &LD, LMH](const std::string &Name) {
if (auto Symbol = LD.findSymbolInternally(LMH, Name))
return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
Symbol.getFlags());
return LD.getDylibResources().ExternalSymbolResolver(Name);
},
[this, &LD, LMH](const std::string &Name) {
if (auto Symbol = LD.findSymbolInternally(LMH, Name))
return RuntimeDyld::SymbolInfo(Symbol.getAddress(),
Symbol.getFlags());
return RuntimeDyld::SymbolInfo(nullptr);
});
return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M),
std::move(Resolver));
}
BaseLayerT &BaseLayer;
PartitioningFtor Partition;
CompileCallbackMgrT &CompileCallbackMgr;
IndirectStubsManagerBuilderT CreateIndirectStubsManager;
LogicalDylibList LogicalDylibs;
bool CloneStubsIntoPartitions;
};
} }
#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H