• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===----- CompileOnDemandLayer.cpp - Lazily emit IR on first call --------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
11 #include "llvm/Bitcode/BitcodeReader.h"
12 #include "llvm/Bitcode/BitcodeWriter.h"
13 #include "llvm/IR/Mangler.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include "llvm/Transforms/Utils/Cloning.h"
17 
18 using namespace llvm;
19 using namespace llvm::orc;
20 
21 namespace {
22 
23 template <typename MaterializerFtor>
24 class LambdaValueMaterializer final : public ValueMaterializer {
25 public:
LambdaValueMaterializer(MaterializerFtor M)26   LambdaValueMaterializer(MaterializerFtor M) : M(std::move(M)) {}
27 
materialize(Value * V)28   Value *materialize(Value *V) final { return M(V); }
29 
30 private:
31   MaterializerFtor M;
32 };
33 
34 template <typename MaterializerFtor>
35 LambdaValueMaterializer<MaterializerFtor>
createLambdaValueMaterializer(MaterializerFtor M)36 createLambdaValueMaterializer(MaterializerFtor M) {
37   return LambdaValueMaterializer<MaterializerFtor>(std::move(M));
38 }
39 } // namespace
40 
extractAliases(MaterializationResponsibility & R,Module & M,MangleAndInterner & Mangle)41 static void extractAliases(MaterializationResponsibility &R, Module &M,
42                            MangleAndInterner &Mangle) {
43   SymbolAliasMap Aliases;
44 
45   std::vector<GlobalAlias *> ModAliases;
46   for (auto &A : M.aliases())
47     ModAliases.push_back(&A);
48 
49   for (auto *A : ModAliases) {
50     Constant *Aliasee = A->getAliasee();
51     assert(A->hasName() && "Anonymous alias?");
52     assert(Aliasee->hasName() && "Anonymous aliasee");
53     std::string AliasName = A->getName();
54 
55     Aliases[Mangle(AliasName)] = SymbolAliasMapEntry(
56         {Mangle(Aliasee->getName()), JITSymbolFlags::fromGlobalValue(*A)});
57 
58     if (isa<Function>(Aliasee)) {
59       auto *F = cloneFunctionDecl(M, *cast<Function>(Aliasee));
60       A->replaceAllUsesWith(F);
61       A->eraseFromParent();
62       F->setName(AliasName);
63     } else if (isa<GlobalValue>(Aliasee)) {
64       auto *G = cloneGlobalVariableDecl(M, *cast<GlobalVariable>(Aliasee));
65       A->replaceAllUsesWith(G);
66       A->eraseFromParent();
67       G->setName(AliasName);
68     }
69   }
70 
71   R.replace(symbolAliases(std::move(Aliases)));
72 }
73 
74 static std::unique_ptr<Module>
extractAndClone(Module & M,LLVMContext & NewContext,StringRef Suffix,function_ref<bool (const GlobalValue *)> ShouldCloneDefinition)75 extractAndClone(Module &M, LLVMContext &NewContext, StringRef Suffix,
76                 function_ref<bool(const GlobalValue *)> ShouldCloneDefinition) {
77   SmallVector<char, 1> ClonedModuleBuffer;
78 
79   {
80     std::set<GlobalValue *> ClonedDefsInSrc;
81     ValueToValueMapTy VMap;
82     auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
83       if (ShouldCloneDefinition(GV)) {
84         ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
85         return true;
86       }
87       return false;
88     });
89 
90     for (auto *GV : ClonedDefsInSrc) {
91       // Delete the definition and bump the linkage in the source module.
92       if (isa<Function>(GV)) {
93         auto &F = *cast<Function>(GV);
94         F.deleteBody();
95         F.setPersonalityFn(nullptr);
96       } else if (isa<GlobalVariable>(GV)) {
97         cast<GlobalVariable>(GV)->setInitializer(nullptr);
98       } else
99         llvm_unreachable("Unsupported global type");
100 
101       GV->setLinkage(GlobalValue::ExternalLinkage);
102     }
103 
104     BitcodeWriter BCWriter(ClonedModuleBuffer);
105 
106     BCWriter.writeModule(*Tmp);
107     BCWriter.writeSymtab();
108     BCWriter.writeStrtab();
109   }
110 
111   MemoryBufferRef ClonedModuleBufferRef(
112       StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
113       "cloned module buffer");
114 
115   auto ClonedModule =
116       cantFail(parseBitcodeFile(ClonedModuleBufferRef, NewContext));
117   ClonedModule->setModuleIdentifier((M.getName() + Suffix).str());
118   return ClonedModule;
119 }
120 
extractGlobals(Module & M,LLVMContext & NewContext)121 static std::unique_ptr<Module> extractGlobals(Module &M,
122                                               LLVMContext &NewContext) {
123   return extractAndClone(M, NewContext, ".globals", [](const GlobalValue *GV) {
124     return isa<GlobalVariable>(GV);
125   });
126 }
127 
128 namespace llvm {
129 namespace orc {
130 
131 class ExtractingIRMaterializationUnit : public IRMaterializationUnit {
132 public:
ExtractingIRMaterializationUnit(ExecutionSession & ES,CompileOnDemandLayer2 & Parent,std::unique_ptr<Module> M)133   ExtractingIRMaterializationUnit(ExecutionSession &ES,
134                                   CompileOnDemandLayer2 &Parent,
135                                   std::unique_ptr<Module> M)
136       : IRMaterializationUnit(ES, std::move(M)), Parent(Parent) {}
137 
ExtractingIRMaterializationUnit(std::unique_ptr<Module> M,SymbolFlagsMap SymbolFlags,SymbolNameToDefinitionMap SymbolToDefinition,CompileOnDemandLayer2 & Parent)138   ExtractingIRMaterializationUnit(std::unique_ptr<Module> M,
139                                   SymbolFlagsMap SymbolFlags,
140                                   SymbolNameToDefinitionMap SymbolToDefinition,
141                                   CompileOnDemandLayer2 &Parent)
142       : IRMaterializationUnit(std::move(M), std::move(SymbolFlags),
143                               std::move(SymbolToDefinition)),
144         Parent(Parent) {}
145 
146 private:
materialize(MaterializationResponsibility R)147   void materialize(MaterializationResponsibility R) override {
148     // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the
149     //        extracted module key, extracted module, and source module key
150     //        together. This could be used, for example, to provide a specific
151     //        memory manager instance to the linking layer.
152 
153     auto RequestedSymbols = R.getRequestedSymbols();
154 
155     // Extract the requested functions into a new module.
156     std::unique_ptr<Module> ExtractedFunctionsModule;
157     if (!RequestedSymbols.empty()) {
158       std::string Suffix;
159       std::set<const GlobalValue *> FunctionsToClone;
160       for (auto &Name : RequestedSymbols) {
161         auto I = SymbolToDefinition.find(Name);
162         assert(I != SymbolToDefinition.end() && I->second != nullptr &&
163                "Should have a non-null definition");
164         FunctionsToClone.insert(I->second);
165         Suffix += ".";
166         Suffix += *Name;
167       }
168 
169       std::lock_guard<std::mutex> Lock(SourceModuleMutex);
170       ExtractedFunctionsModule =
171           extractAndClone(*M, Parent.GetAvailableContext(), Suffix,
172                           [&](const GlobalValue *GV) -> bool {
173                             return FunctionsToClone.count(GV);
174                           });
175     }
176 
177     // Build a new ExtractingIRMaterializationUnit to delegate the unrequested
178     // symbols to.
179     SymbolFlagsMap DelegatedSymbolFlags;
180     IRMaterializationUnit::SymbolNameToDefinitionMap
181         DelegatedSymbolToDefinition;
182     for (auto &KV : SymbolToDefinition) {
183       if (RequestedSymbols.count(KV.first))
184         continue;
185       DelegatedSymbolFlags[KV.first] =
186           JITSymbolFlags::fromGlobalValue(*KV.second);
187       DelegatedSymbolToDefinition[KV.first] = KV.second;
188     }
189 
190     if (!DelegatedSymbolFlags.empty()) {
191       assert(DelegatedSymbolFlags.size() ==
192                  DelegatedSymbolToDefinition.size() &&
193              "SymbolFlags and SymbolToDefinition should have the same number "
194              "of entries");
195       R.replace(llvm::make_unique<ExtractingIRMaterializationUnit>(
196           std::move(M), std::move(DelegatedSymbolFlags),
197           std::move(DelegatedSymbolToDefinition), Parent));
198     }
199 
200     if (ExtractedFunctionsModule)
201       Parent.emitExtractedFunctionsModule(std::move(R),
202                                           std::move(ExtractedFunctionsModule));
203   }
204 
discard(const VSO & V,SymbolStringPtr Name)205   void discard(const VSO &V, SymbolStringPtr Name) override {
206     // All original symbols were materialized by the CODLayer and should be
207     // final. The function bodies provided by M should never be overridden.
208     llvm_unreachable("Discard should never be called on an "
209                      "ExtractingIRMaterializationUnit");
210   }
211 
212   mutable std::mutex SourceModuleMutex;
213   CompileOnDemandLayer2 &Parent;
214 };
215 
CompileOnDemandLayer2(ExecutionSession & ES,IRLayer & BaseLayer,JITCompileCallbackManager & CCMgr,IndirectStubsManagerBuilder BuildIndirectStubsManager,GetAvailableContextFunction GetAvailableContext)216 CompileOnDemandLayer2::CompileOnDemandLayer2(
217     ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr,
218     IndirectStubsManagerBuilder BuildIndirectStubsManager,
219     GetAvailableContextFunction GetAvailableContext)
220     : IRLayer(ES), BaseLayer(BaseLayer), CCMgr(CCMgr),
221       BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)),
222       GetAvailableContext(std::move(GetAvailableContext)) {}
223 
add(VSO & V,VModuleKey K,std::unique_ptr<Module> M)224 Error CompileOnDemandLayer2::add(VSO &V, VModuleKey K,
225                                  std::unique_ptr<Module> M) {
226   return IRLayer::add(V, K, std::move(M));
227 }
228 
emit(MaterializationResponsibility R,VModuleKey K,std::unique_ptr<Module> M)229 void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
230                                  std::unique_ptr<Module> M) {
231   auto &ES = getExecutionSession();
232   assert(M && "M should not be null");
233 
234   for (auto &GV : M->global_values())
235     if (GV.hasWeakLinkage())
236       GV.setLinkage(GlobalValue::ExternalLinkage);
237 
238   MangleAndInterner Mangle(ES, M->getDataLayout());
239 
240   extractAliases(R, *M, Mangle);
241 
242   auto GlobalsModule = extractGlobals(*M, GetAvailableContext());
243 
244   // Delete the bodies of any available externally functions, rename the
245   // rest, and build the compile callbacks.
246   std::map<SymbolStringPtr, std::pair<JITTargetAddress, JITSymbolFlags>>
247       StubCallbacksAndLinkages;
248   auto &TargetVSO = R.getTargetVSO();
249 
250   for (auto &F : M->functions()) {
251     if (F.isDeclaration())
252       continue;
253 
254     if (F.hasAvailableExternallyLinkage()) {
255       F.deleteBody();
256       F.setPersonalityFn(nullptr);
257       continue;
258     }
259 
260     assert(F.hasName() && "Function should have a name");
261     std::string StubUnmangledName = F.getName();
262     F.setName(F.getName() + "$body");
263     auto StubDecl = cloneFunctionDecl(*M, F);
264     StubDecl->setName(StubUnmangledName);
265     StubDecl->setPersonalityFn(nullptr);
266     StubDecl->setLinkage(GlobalValue::ExternalLinkage);
267     F.replaceAllUsesWith(StubDecl);
268 
269     auto StubName = Mangle(StubUnmangledName);
270     auto BodyName = Mangle(F.getName());
271     if (auto CallbackAddr = CCMgr.getCompileCallback(
272             [BodyName, &TargetVSO, &ES]() -> JITTargetAddress {
273               if (auto Sym = lookup({&TargetVSO}, BodyName))
274                 return Sym->getAddress();
275               else {
276                 ES.reportError(Sym.takeError());
277                 return 0;
278               }
279             })) {
280       auto Flags = JITSymbolFlags::fromGlobalValue(F);
281       Flags &= ~JITSymbolFlags::Weak;
282       StubCallbacksAndLinkages[std::move(StubName)] =
283           std::make_pair(*CallbackAddr, Flags);
284     } else {
285       ES.reportError(CallbackAddr.takeError());
286       R.failMaterialization();
287       return;
288     }
289   }
290 
291   // Build the stub inits map.
292   IndirectStubsManager::StubInitsMap StubInits;
293   for (auto &KV : StubCallbacksAndLinkages)
294     StubInits[*KV.first] = KV.second;
295 
296   // Build the function-body-extracting materialization unit.
297   if (auto Err = R.getTargetVSO().define(
298           llvm::make_unique<ExtractingIRMaterializationUnit>(ES, *this,
299                                                              std::move(M)))) {
300     ES.reportError(std::move(Err));
301     R.failMaterialization();
302     return;
303   }
304 
305   // Build the stubs.
306   // FIXME: Remove function bodies materialization unit if stub creation fails.
307   auto &StubsMgr = getStubsManager(TargetVSO);
308   if (auto Err = StubsMgr.createStubs(StubInits)) {
309     ES.reportError(std::move(Err));
310     R.failMaterialization();
311     return;
312   }
313 
314   // Resolve and finalize stubs.
315   SymbolMap ResolvedStubs;
316   for (auto &KV : StubCallbacksAndLinkages) {
317     if (auto Sym = StubsMgr.findStub(*KV.first, false))
318       ResolvedStubs[KV.first] = Sym;
319     else
320       llvm_unreachable("Stub went missing");
321   }
322 
323   R.resolve(ResolvedStubs);
324 
325   BaseLayer.emit(std::move(R), std::move(K), std::move(GlobalsModule));
326 }
327 
getStubsManager(const VSO & V)328 IndirectStubsManager &CompileOnDemandLayer2::getStubsManager(const VSO &V) {
329   std::lock_guard<std::mutex> Lock(CODLayerMutex);
330   StubManagersMap::iterator I = StubsMgrs.find(&V);
331   if (I == StubsMgrs.end())
332     I = StubsMgrs.insert(std::make_pair(&V, BuildIndirectStubsManager())).first;
333   return *I->second;
334 }
335 
emitExtractedFunctionsModule(MaterializationResponsibility R,std::unique_ptr<Module> M)336 void CompileOnDemandLayer2::emitExtractedFunctionsModule(
337     MaterializationResponsibility R, std::unique_ptr<Module> M) {
338   auto K = getExecutionSession().allocateVModule();
339   BaseLayer.emit(std::move(R), std::move(K), std::move(M));
340 }
341 
342 } // end namespace orc
343 } // end namespace llvm
344