1 //===- CompileOnDemandLayer.h - Compile each function on demand -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // JIT layer for breaking up modules and inserting callbacks to allow
11 // individual functions to be compiled on demand.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
16 #define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H
18 #include "IndirectionUtils.h"
19 #include "LambdaResolver.h"
20 #include "LogicalDylib.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Transforms/Utils/Cloning.h"
32 /// @brief Compile-on-demand layer.
34 /// When a module is added to this layer a stub is created for each of its
35 /// function definitions. The stubs and other global values are immediately
36 /// added to the layer below. When a stub is called it triggers the extraction
37 /// of the function body from the original module. The extracted body is then
38 /// compiled and executed.
39 template <typename BaseLayerT,
40 typename CompileCallbackMgrT = JITCompileCallbackManager,
41 typename IndirectStubsMgrT = IndirectStubsManager>
42 class CompileOnDemandLayer {
45 template <typename MaterializerFtor>
46 class LambdaMaterializer final : public ValueMaterializer {
48 LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {}
49 Value *materialize(Value *V) final { return M(V); }
55 template <typename MaterializerFtor>
56 LambdaMaterializer<MaterializerFtor>
57 createLambdaMaterializer(MaterializerFtor M) {
58 return LambdaMaterializer<MaterializerFtor>(std::move(M));
61 typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
63 // Provide type-erasure for the Modules and MemoryManagers.
64 template <typename ResourceT>
67 ResourceOwner() = default;
68 ResourceOwner(const ResourceOwner&) = delete;
69 ResourceOwner& operator=(const ResourceOwner&) = delete;
70 virtual ~ResourceOwner() { }
71 virtual ResourceT& getResource() const = 0;
74 template <typename ResourceT, typename ResourcePtrT>
75 class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
77 ResourceOwnerImpl(ResourcePtrT ResourcePtr)
78 : ResourcePtr(std::move(ResourcePtr)) {}
79 ResourceT& getResource() const override { return *ResourcePtr; }
81 ResourcePtrT ResourcePtr;
84 template <typename ResourceT, typename ResourcePtrT>
85 std::unique_ptr<ResourceOwner<ResourceT>>
86 wrapOwnership(ResourcePtrT ResourcePtr) {
87 typedef ResourceOwnerImpl<ResourceT, ResourcePtrT> RO;
88 return llvm::make_unique<RO>(std::move(ResourcePtr));
91 struct LogicalModuleResources {
92 std::unique_ptr<ResourceOwner<Module>> SourceModule;
93 std::set<const Function*> StubsToClone;
94 std::unique_ptr<IndirectStubsMgrT> StubsMgr;
96 LogicalModuleResources() = default;
98 // Explicit move constructor to make MSVC happy.
99 LogicalModuleResources(LogicalModuleResources &&Other)
100 : SourceModule(std::move(Other.SourceModule)),
101 StubsToClone(std::move(Other.StubsToClone)),
102 StubsMgr(std::move(Other.StubsMgr)) {}
104 // Explicit move assignment to make MSVC happy.
105 LogicalModuleResources& operator=(LogicalModuleResources &&Other) {
106 SourceModule = std::move(Other.SourceModule);
107 StubsToClone = std::move(Other.StubsToClone);
108 StubsMgr = std::move(Other.StubsMgr);
112 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
113 if (Name.endswith("$stub_ptr") && !ExportedSymbolsOnly) {
114 assert(!ExportedSymbolsOnly && "Stubs are never exported");
115 return StubsMgr->findPointer(Name.drop_back(9));
117 return StubsMgr->findStub(Name, ExportedSymbolsOnly);
122 struct LogicalDylibResources {
123 typedef std::function<JITSymbol(const std::string&)> SymbolResolverFtor;
125 typedef std::function<typename BaseLayerT::ModuleSetHandleT(
127 std::unique_ptr<Module>,
128 std::unique_ptr<JITSymbolResolver>)>
131 LogicalDylibResources() = default;
133 // Explicit move constructor to make MSVC happy.
134 LogicalDylibResources(LogicalDylibResources &&Other)
135 : ExternalSymbolResolver(std::move(Other.ExternalSymbolResolver)),
136 MemMgr(std::move(Other.MemMgr)),
137 ModuleAdder(std::move(Other.ModuleAdder)) {}
139 // Explicit move assignment operator to make MSVC happy.
140 LogicalDylibResources& operator=(LogicalDylibResources &&Other) {
141 ExternalSymbolResolver = std::move(Other.ExternalSymbolResolver);
142 MemMgr = std::move(Other.MemMgr);
143 ModuleAdder = std::move(Other.ModuleAdder);
147 std::unique_ptr<JITSymbolResolver> ExternalSymbolResolver;
148 std::unique_ptr<ResourceOwner<RuntimeDyld::MemoryManager>> MemMgr;
149 ModuleAdderFtor ModuleAdder;
152 typedef LogicalDylib<BaseLayerT, LogicalModuleResources,
153 LogicalDylibResources> CODLogicalDylib;
155 typedef typename CODLogicalDylib::LogicalModuleHandle LogicalModuleHandle;
156 typedef std::list<CODLogicalDylib> LogicalDylibList;
160 /// @brief Handle to a set of loaded modules.
161 typedef typename LogicalDylibList::iterator ModuleSetHandleT;
163 /// @brief Module partitioning functor.
164 typedef std::function<std::set<Function*>(Function&)> PartitioningFtor;
166 /// @brief Builder for IndirectStubsManagers.
167 typedef std::function<std::unique_ptr<IndirectStubsMgrT>()>
168 IndirectStubsManagerBuilderT;
170 /// @brief Construct a compile-on-demand layer instance.
171 CompileOnDemandLayer(BaseLayerT &BaseLayer, PartitioningFtor Partition,
172 CompileCallbackMgrT &CallbackMgr,
173 IndirectStubsManagerBuilderT CreateIndirectStubsManager,
174 bool CloneStubsIntoPartitions = true)
175 : BaseLayer(BaseLayer), Partition(std::move(Partition)),
176 CompileCallbackMgr(CallbackMgr),
177 CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)),
178 CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
180 /// @brief Add a module to the compile-on-demand layer.
181 template <typename ModuleSetT, typename MemoryManagerPtrT,
182 typename SymbolResolverPtrT>
183 ModuleSetHandleT addModuleSet(ModuleSetT Ms,
184 MemoryManagerPtrT MemMgr,
185 SymbolResolverPtrT Resolver) {
187 LogicalDylibs.push_back(CODLogicalDylib(BaseLayer));
188 auto &LDResources = LogicalDylibs.back().getDylibResources();
190 LDResources.ExternalSymbolResolver = std::move(Resolver);
192 auto &MemMgrRef = *MemMgr;
194 wrapOwnership<RuntimeDyld::MemoryManager>(std::move(MemMgr));
196 LDResources.ModuleAdder =
197 [&MemMgrRef](BaseLayerT &B, std::unique_ptr<Module> M,
198 std::unique_ptr<JITSymbolResolver> R) {
199 std::vector<std::unique_ptr<Module>> Ms;
200 Ms.push_back(std::move(M));
201 return B.addModuleSet(std::move(Ms), &MemMgrRef, std::move(R));
204 // Process each of the modules in this module set.
206 addLogicalModule(LogicalDylibs.back(), std::move(M));
208 return std::prev(LogicalDylibs.end());
211 /// @brief Remove the module represented by the given handle.
213 /// This will remove all modules in the layers below that were derived from
214 /// the module represented by H.
215 void removeModuleSet(ModuleSetHandleT H) {
216 LogicalDylibs.erase(H);
219 /// @brief Search for the given named symbol.
220 /// @param Name The name of the symbol to search for.
221 /// @param ExportedSymbolsOnly If true, search only for exported symbols.
222 /// @return A handle for the given named symbol, if it exists.
223 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
224 for (auto LDI = LogicalDylibs.begin(), LDE = LogicalDylibs.end();
226 if (auto Symbol = findSymbolIn(LDI, Name, ExportedSymbolsOnly))
228 return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
231 /// @brief Get the address of a symbol provided by this layer, or some layer
233 JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
234 bool ExportedSymbolsOnly) {
235 return H->findSymbol(Name, ExportedSymbolsOnly);
238 /// @brief Update the stub for the given function to point at FnBodyAddr.
239 /// This can be used to support re-optimization.
240 /// @return true if the function exists and the stub is updated, false
243 // FIXME: We should track and free associated resources (unused compile
244 // callbacks, uncompiled IR, and no-longer-needed/reachable function
246 // FIXME: Return Error once the JIT APIs are Errorized.
247 bool updatePointer(std::string FuncName, JITTargetAddress FnBodyAddr) {
248 //Find out which logical dylib contains our symbol
249 auto LDI = LogicalDylibs.begin();
250 for (auto LDE = LogicalDylibs.end(); LDI != LDE; ++LDI) {
251 if (auto LMResources = LDI->getLogicalModuleResourcesForSymbol(FuncName, false)) {
252 Module &SrcM = LMResources->SourceModule->getResource();
253 std::string CalledFnName = mangle(FuncName, SrcM.getDataLayout());
254 if (auto EC = LMResources->StubsMgr->updatePointer(CalledFnName, FnBodyAddr)) {
266 template <typename ModulePtrT>
267 void addLogicalModule(CODLogicalDylib &LD, ModulePtrT SrcMPtr) {
269 // Bump the linkage and rename any anonymous/privote members in SrcM to
270 // ensure that everything will resolve properly after we partition SrcM.
271 makeAllSymbolsExternallyAccessible(*SrcMPtr);
273 // Create a logical module handle for SrcM within the logical dylib.
274 auto LMH = LD.createLogicalModule();
275 auto &LMResources = LD.getLogicalModuleResources(LMH);
277 LMResources.SourceModule = wrapOwnership<Module>(std::move(SrcMPtr));
279 Module &SrcM = LMResources.SourceModule->getResource();
281 // Create stub functions.
282 const DataLayout &DL = SrcM.getDataLayout();
284 LMResources.StubsMgr = CreateIndirectStubsManager();
286 typename IndirectStubsMgrT::StubInitsMap StubInits;
287 for (auto &F : SrcM) {
288 // Skip declarations.
289 if (F.isDeclaration())
292 // Skip weak functions for which we already have definitions.
293 auto MangledName = mangle(F.getName(), DL);
294 if (F.hasWeakLinkage() || F.hasLinkOnceLinkage())
295 if (auto Sym = LD.findSymbol(MangledName, false))
298 // Record all functions defined by this module.
299 if (CloneStubsIntoPartitions)
300 LMResources.StubsToClone.insert(&F);
302 // Create a callback, associate it with the stub for the function,
303 // and set the compile action to compile the partition containing the
305 auto CCInfo = CompileCallbackMgr.getCompileCallback();
306 StubInits[MangledName] =
307 std::make_pair(CCInfo.getAddress(),
308 JITSymbolFlags::fromGlobalValue(F));
309 CCInfo.setCompileAction([this, &LD, LMH, &F]() {
310 return this->extractAndCompile(LD, LMH, F);
314 auto EC = LMResources.StubsMgr->createStubs(StubInits);
316 // FIXME: This should be propagated back to the user. Stub creation may
317 // fail for remote JITs.
318 assert(!EC && "Error generating stubs");
321 // If this module doesn't contain any globals or aliases we can bail out
322 // early and avoid the overhead of creating and managing an empty globals
324 if (SrcM.global_empty() && SrcM.alias_empty())
327 // Create the GlobalValues module.
328 auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(),
330 GVsM->setDataLayout(DL);
332 ValueToValueMapTy VMap;
334 // Clone global variable decls.
335 for (auto &GV : SrcM.globals())
336 if (!GV.isDeclaration() && !VMap.count(&GV))
337 cloneGlobalVariableDecl(*GVsM, GV, &VMap);
340 for (auto &A : SrcM.aliases())
342 cloneGlobalAliasDecl(*GVsM, A, VMap);
344 // Now we need to clone the GV and alias initializers.
346 // Initializers may refer to functions declared (but not defined) in this
347 // module. Build a materializer to clone decls on demand.
348 auto Materializer = createLambdaMaterializer(
349 [this, &GVsM, &LMResources](Value *V) -> Value* {
350 if (auto *F = dyn_cast<Function>(V)) {
351 // Decls in the original module just get cloned.
352 if (F->isDeclaration())
353 return cloneFunctionDecl(*GVsM, *F);
355 // Definitions in the original module (which we have emitted stubs
356 // for at this point) get turned into a constant alias to the stub
358 const DataLayout &DL = GVsM->getDataLayout();
359 std::string FName = mangle(F->getName(), DL);
360 auto StubSym = LMResources.StubsMgr->findStub(FName, false);
361 unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType());
362 ConstantInt *StubAddr =
363 ConstantInt::get(GVsM->getContext(),
364 APInt(PtrBitWidth, StubSym.getAddress()));
365 Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr,
366 StubAddr, F->getType());
367 return GlobalAlias::create(F->getFunctionType(),
368 F->getType()->getAddressSpace(),
369 F->getLinkage(), F->getName(),
376 // Clone the global variable initializers.
377 for (auto &GV : SrcM.globals())
378 if (!GV.isDeclaration())
379 moveGlobalVariableInitializer(GV, VMap, &Materializer);
381 // Clone the global alias initializers.
382 for (auto &A : SrcM.aliases()) {
383 auto *NewA = cast<GlobalAlias>(VMap[&A]);
384 assert(NewA && "Alias not cloned?");
385 Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr,
387 NewA->setAliasee(cast<Constant>(Init));
390 // Build a resolver for the globals module and add it to the base layer.
391 auto GVsResolver = createLambdaResolver(
392 [&LD, LMH](const std::string &Name) {
393 if (auto Sym = LD.findSymbol(Name, false))
395 auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver;
396 return LDResolver->findSymbolInLogicalDylib(Name);
398 [&LD](const std::string &Name) {
399 auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver;
400 return LDResolver->findSymbol(Name);
403 auto GVsH = LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM),
404 std::move(GVsResolver));
405 LD.addToLogicalModule(LMH, GVsH);
408 static std::string mangle(StringRef Name, const DataLayout &DL) {
409 std::string MangledName;
411 raw_string_ostream MangledNameStream(MangledName);
412 Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
417 JITTargetAddress extractAndCompile(CODLogicalDylib &LD,
418 LogicalModuleHandle LMH,
420 auto &LMResources = LD.getLogicalModuleResources(LMH);
421 Module &SrcM = LMResources.SourceModule->getResource();
423 // If F is a declaration we must already have compiled it.
424 if (F.isDeclaration())
427 // Grab the name of the function being called here.
428 std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout());
430 auto Part = Partition(F);
431 auto PartH = emitPartition(LD, LMH, Part);
433 JITTargetAddress CalledAddr = 0;
434 for (auto *SubF : Part) {
435 std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout());
436 auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false);
437 assert(FnBodySym && "Couldn't find function body.");
439 JITTargetAddress FnBodyAddr = FnBodySym.getAddress();
441 // If this is the function we're calling record the address so we can
442 // return it from this function.
444 CalledAddr = FnBodyAddr;
446 // Update the function body pointer for the stub.
447 if (auto EC = LMResources.StubsMgr->updatePointer(FnName, FnBodyAddr))
454 template <typename PartitionT>
455 BaseLayerModuleSetHandleT emitPartition(CODLogicalDylib &LD,
456 LogicalModuleHandle LMH,
457 const PartitionT &Part) {
458 auto &LMResources = LD.getLogicalModuleResources(LMH);
459 Module &SrcM = LMResources.SourceModule->getResource();
461 // Create the module.
462 std::string NewName = SrcM.getName();
463 for (auto *F : Part) {
465 NewName += F->getName();
468 auto M = llvm::make_unique<Module>(NewName, SrcM.getContext());
469 M->setDataLayout(SrcM.getDataLayout());
470 ValueToValueMapTy VMap;
472 auto Materializer = createLambdaMaterializer([this, &LMResources, &M,
473 &VMap](Value *V) -> Value * {
474 if (auto *GV = dyn_cast<GlobalVariable>(V))
475 return cloneGlobalVariableDecl(*M, *GV);
477 if (auto *F = dyn_cast<Function>(V)) {
478 // Check whether we want to clone an available_externally definition.
479 if (!LMResources.StubsToClone.count(F))
480 return cloneFunctionDecl(*M, *F);
482 // Ok - we want an inlinable stub. For that to work we need a decl
483 // for the stub pointer.
484 auto *StubPtr = createImplPointer(*F->getType(), *M,
485 F->getName() + "$stub_ptr", nullptr);
486 auto *ClonedF = cloneFunctionDecl(*M, *F);
487 makeStub(*ClonedF, *StubPtr);
488 ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage);
489 ClonedF->addFnAttr(Attribute::AlwaysInline);
493 if (auto *A = dyn_cast<GlobalAlias>(V)) {
494 auto *Ty = A->getValueType();
495 if (Ty->isFunctionTy())
496 return Function::Create(cast<FunctionType>(Ty),
497 GlobalValue::ExternalLinkage, A->getName(),
500 return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage,
501 nullptr, A->getName(), nullptr,
502 GlobalValue::NotThreadLocal,
503 A->getType()->getAddressSpace());
509 // Create decls in the new module.
511 cloneFunctionDecl(*M, *F, &VMap);
513 // Move the function bodies.
515 moveFunctionBody(*F, VMap, &Materializer);
517 // Create memory manager and symbol resolver.
518 auto Resolver = createLambdaResolver(
519 [this, &LD, LMH](const std::string &Name) {
520 if (auto Sym = LD.findSymbolInternally(LMH, Name))
522 auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver;
523 return LDResolver->findSymbolInLogicalDylib(Name);
525 [this, &LD](const std::string &Name) {
526 auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver;
527 return LDResolver->findSymbol(Name);
530 return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M),
531 std::move(Resolver));
534 BaseLayerT &BaseLayer;
535 PartitioningFtor Partition;
536 CompileCallbackMgrT &CompileCallbackMgr;
537 IndirectStubsManagerBuilderT CreateIndirectStubsManager;
539 LogicalDylibList LogicalDylibs;
540 bool CloneStubsIntoPartitions;
543 } // End namespace orc.
544 } // End namespace llvm.
546 #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H