blob: 368969b7a57e6e0b296cfebd03aac375832fc291 [file] [log] [blame]
Lang Hames68c9b8d2018-06-18 18:01:43 +00001//===----- 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/IR/Mangler.h"
12#include "llvm/IR/Module.h"
Lang Hames68c9b8d2018-06-18 18:01:43 +000013
14using namespace llvm;
15using namespace llvm::orc;
16
Lang Hames98440292018-09-29 23:49:57 +000017static ThreadSafeModule extractSubModule(ThreadSafeModule &TSM,
18 StringRef Suffix,
19 GVPredicate ShouldExtract) {
Lang Hames6a941342018-06-26 21:35:48 +000020
Lang Hames98440292018-09-29 23:49:57 +000021 auto DeleteExtractedDefs = [](GlobalValue &GV) {
22 // Bump the linkage: this global will be provided by the external module.
23 GV.setLinkage(GlobalValue::ExternalLinkage);
Lang Hames6a941342018-06-26 21:35:48 +000024
Lang Hames98440292018-09-29 23:49:57 +000025 // Delete the definition in the source module.
Lang Hames8d76c712018-09-26 01:24:12 +000026 if (isa<Function>(GV)) {
27 auto &F = cast<Function>(GV);
28 F.deleteBody();
29 F.setPersonalityFn(nullptr);
30 } else if (isa<GlobalVariable>(GV)) {
31 cast<GlobalVariable>(GV).setInitializer(nullptr);
Lang Hames98440292018-09-29 23:49:57 +000032 } else if (isa<GlobalAlias>(GV)) {
33 // We need to turn deleted aliases into function or variable decls based
34 // on the type of their aliasee.
35 auto &A = cast<GlobalAlias>(GV);
36 Constant *Aliasee = A.getAliasee();
37 assert(A.hasName() && "Anonymous alias?");
38 assert(Aliasee->hasName() && "Anonymous aliasee");
39 std::string AliasName = A.getName();
40
41 if (isa<Function>(Aliasee)) {
42 auto *F = cloneFunctionDecl(*A.getParent(), *cast<Function>(Aliasee));
43 A.replaceAllUsesWith(F);
44 A.eraseFromParent();
45 F->setName(AliasName);
46 } else if (isa<GlobalVariable>(Aliasee)) {
47 auto *G = cloneGlobalVariableDecl(*A.getParent(),
48 *cast<GlobalVariable>(Aliasee));
49 A.replaceAllUsesWith(G);
50 A.eraseFromParent();
51 G->setName(AliasName);
52 } else
53 llvm_unreachable("Alias to unsupported type");
Lang Hames8d76c712018-09-26 01:24:12 +000054 } else
55 llvm_unreachable("Unsupported global type");
Lang Hames8d76c712018-09-26 01:24:12 +000056 };
Lang Hames68c9b8d2018-06-18 18:01:43 +000057
Lang Hames98440292018-09-29 23:49:57 +000058 auto NewTSMod = cloneToNewContext(TSM, ShouldExtract, DeleteExtractedDefs);
Lang Hames8d76c712018-09-26 01:24:12 +000059 auto &M = *NewTSMod.getModule();
60 M.setModuleIdentifier((M.getModuleIdentifier() + Suffix).str());
Lang Hames68c9b8d2018-06-18 18:01:43 +000061
Lang Hames8d76c712018-09-26 01:24:12 +000062 return NewTSMod;
Lang Hames7bd89702018-07-05 19:01:27 +000063}
64
Lang Hames68c9b8d2018-06-18 18:01:43 +000065namespace llvm {
66namespace orc {
67
Lang Hames98440292018-09-29 23:49:57 +000068class PartitioningIRMaterializationUnit : public IRMaterializationUnit {
Lang Hames68c9b8d2018-06-18 18:01:43 +000069public:
Lang Hames98440292018-09-29 23:49:57 +000070 PartitioningIRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM,
71 CompileOnDemandLayer2 &Parent)
Lang Hames8d76c712018-09-26 01:24:12 +000072 : IRMaterializationUnit(ES, std::move(TSM)), Parent(Parent) {}
Lang Hames68c9b8d2018-06-18 18:01:43 +000073
Lang Hames98440292018-09-29 23:49:57 +000074 PartitioningIRMaterializationUnit(
75 ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags,
76 SymbolNameToDefinitionMap SymbolToDefinition,
77 CompileOnDemandLayer2 &Parent)
Lang Hames8d76c712018-09-26 01:24:12 +000078 : IRMaterializationUnit(std::move(TSM), std::move(SymbolFlags),
Lang Hames68c9b8d2018-06-18 18:01:43 +000079 std::move(SymbolToDefinition)),
Lang Hamesfd0c1e712018-07-20 18:31:50 +000080 Parent(Parent) {}
Lang Hames68c9b8d2018-06-18 18:01:43 +000081
82private:
83 void materialize(MaterializationResponsibility R) override {
Lang Hames98440292018-09-29 23:49:57 +000084 Parent.emitPartition(std::move(R), std::move(TSM),
85 std::move(SymbolToDefinition));
Lang Hames68c9b8d2018-06-18 18:01:43 +000086 }
87
Lang Hamescb5702c32018-10-06 23:02:06 +000088 void discard(const JITDylib &V, const SymbolStringPtr &Name) override {
Lang Hames68c9b8d2018-06-18 18:01:43 +000089 // All original symbols were materialized by the CODLayer and should be
90 // final. The function bodies provided by M should never be overridden.
91 llvm_unreachable("Discard should never be called on an "
92 "ExtractingIRMaterializationUnit");
93 }
94
Lang Hames7bd89702018-07-05 19:01:27 +000095 mutable std::mutex SourceModuleMutex;
Lang Hames68c9b8d2018-06-18 18:01:43 +000096 CompileOnDemandLayer2 &Parent;
Lang Hames68c9b8d2018-06-18 18:01:43 +000097};
98
Lang Hames98440292018-09-29 23:49:57 +000099Optional<CompileOnDemandLayer2::GlobalValueSet>
100CompileOnDemandLayer2::compileRequested(GlobalValueSet Requested) {
101 return std::move(Requested);
102}
103
104Optional<CompileOnDemandLayer2::GlobalValueSet>
105CompileOnDemandLayer2::compileWholeModule(GlobalValueSet Requested) {
106 return None;
107}
108
Lang Hames68c9b8d2018-06-18 18:01:43 +0000109CompileOnDemandLayer2::CompileOnDemandLayer2(
Lang Hamesd8048672018-09-26 05:08:29 +0000110 ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr,
Lang Hames8d76c712018-09-26 01:24:12 +0000111 IndirectStubsManagerBuilder BuildIndirectStubsManager)
Lang Hamesd8048672018-09-26 05:08:29 +0000112 : IRLayer(ES), BaseLayer(BaseLayer), LCTMgr(LCTMgr),
Lang Hames8d76c712018-09-26 01:24:12 +0000113 BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
Lang Hames68c9b8d2018-06-18 18:01:43 +0000114
Lang Hames98440292018-09-29 23:49:57 +0000115void CompileOnDemandLayer2::setPartitionFunction(PartitionFunction Partition) {
116 this->Partition = std::move(Partition);
Lang Hames68c9b8d2018-06-18 18:01:43 +0000117}
118
119void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
Lang Hames8d76c712018-09-26 01:24:12 +0000120 ThreadSafeModule TSM) {
Lang Hames98440292018-09-29 23:49:57 +0000121 assert(TSM.getModule() && "Null module");
122
Lang Hames68c9b8d2018-06-18 18:01:43 +0000123 auto &ES = getExecutionSession();
Lang Hames8d76c712018-09-26 01:24:12 +0000124 auto &M = *TSM.getModule();
Lang Hames68c9b8d2018-06-18 18:01:43 +0000125
Lang Hames98440292018-09-29 23:49:57 +0000126 // First, do some cleanup on the module:
127 cleanUpModule(M);
128
129 // Now sort the callables and non-callables, build re-exports and lodge the
130 // actual module with the implementation dylib.
131 auto &PDR = getPerDylibResources(R.getTargetJITDylib());
Lang Hames68c9b8d2018-06-18 18:01:43 +0000132
Lang Hames8d76c712018-09-26 01:24:12 +0000133 MangleAndInterner Mangle(ES, M.getDataLayout());
Lang Hames98440292018-09-29 23:49:57 +0000134 SymbolAliasMap NonCallables;
135 SymbolAliasMap Callables;
136 for (auto &GV : M.global_values()) {
137 assert(GV.hasName() && !GV.hasLocalLinkage() &&
138 "GlobalValues must have been promoted before adding to "
139 "CompileOnDemandLayer");
140 if (GV.isDeclaration() || GV.hasAppendingLinkage())
Lang Hames68c9b8d2018-06-18 18:01:43 +0000141 continue;
142
Lang Hames98440292018-09-29 23:49:57 +0000143 auto Name = Mangle(GV.getName());
144 auto Flags = JITSymbolFlags::fromGlobalValue(GV);
145 if (Flags.isCallable())
146 Callables[Name] = SymbolAliasMapEntry(Name, Flags);
147 else
148 NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
Lang Hames68c9b8d2018-06-18 18:01:43 +0000149 }
150
Lang Hames98440292018-09-29 23:49:57 +0000151 // Create a partitioning materialization unit and lodge it with the
152 // implementation dylib.
153 if (auto Err = PDR.getImplDylib().define(
154 llvm::make_unique<PartitioningIRMaterializationUnit>(
155 ES, std::move(TSM), *this))) {
Lang Hames68c9b8d2018-06-18 18:01:43 +0000156 ES.reportError(std::move(Err));
157 R.failMaterialization();
158 return;
159 }
160
Lang Hames98440292018-09-29 23:49:57 +0000161 R.replace(reexports(PDR.getImplDylib(), std::move(NonCallables)));
162 R.replace(lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(),
163 std::move(Callables)));
Lang Hames68c9b8d2018-06-18 18:01:43 +0000164}
165
Lang Hamesd8048672018-09-26 05:08:29 +0000166CompileOnDemandLayer2::PerDylibResources &
167CompileOnDemandLayer2::getPerDylibResources(JITDylib &TargetD) {
168 auto I = DylibResources.find(&TargetD);
169 if (I == DylibResources.end()) {
170 auto &ImplD =
171 getExecutionSession().createJITDylib(TargetD.getName() + ".impl");
172 TargetD.withSearchOrderDo([&](const JITDylibList &TargetSearchOrder) {
173 ImplD.setSearchOrder(TargetSearchOrder, false);
174 });
175 PerDylibResources PDR(ImplD, BuildIndirectStubsManager());
176 I = DylibResources.insert(std::make_pair(&TargetD, std::move(PDR))).first;
177 }
178
179 return I->second;
Lang Hames68c9b8d2018-06-18 18:01:43 +0000180}
181
Lang Hames98440292018-09-29 23:49:57 +0000182void CompileOnDemandLayer2::cleanUpModule(Module &M) {
183 for (auto &F : M.functions()) {
184 if (F.isDeclaration())
185 continue;
186
187 if (F.hasAvailableExternallyLinkage()) {
188 F.deleteBody();
189 F.setPersonalityFn(nullptr);
190 continue;
191 }
192 }
193}
194
195void CompileOnDemandLayer2::expandPartition(GlobalValueSet &Partition) {
196 // Expands the partition to ensure the following rules hold:
197 // (1) If any alias is in the partition, its aliasee is also in the partition.
198 // (2) If any aliasee is in the partition, its aliases are also in the
199 // partiton.
200 // (3) If any global variable is in the partition then all global variables
201 // are in the partition.
202 assert(!Partition.empty() && "Unexpected empty partition");
203
204 const Module &M = *(*Partition.begin())->getParent();
205 bool ContainsGlobalVariables = false;
206 std::vector<const GlobalValue *> GVsToAdd;
207
208 for (auto *GV : Partition)
209 if (isa<GlobalAlias>(GV))
210 GVsToAdd.push_back(
211 cast<GlobalValue>(cast<GlobalAlias>(GV)->getAliasee()));
212 else if (isa<GlobalVariable>(GV))
213 ContainsGlobalVariables = true;
214
215 for (auto &A : M.aliases())
216 if (Partition.count(cast<GlobalValue>(A.getAliasee())))
217 GVsToAdd.push_back(&A);
218
219 if (ContainsGlobalVariables)
220 for (auto &G : M.globals())
221 GVsToAdd.push_back(&G);
222
223 for (auto *GV : GVsToAdd)
224 Partition.insert(GV);
225}
226
227void CompileOnDemandLayer2::emitPartition(
228 MaterializationResponsibility R, ThreadSafeModule TSM,
229 IRMaterializationUnit::SymbolNameToDefinitionMap Defs) {
230
231 // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the
232 // extracted module key, extracted module, and source module key
233 // together. This could be used, for example, to provide a specific
234 // memory manager instance to the linking layer.
235
236 auto &ES = getExecutionSession();
237
238 GlobalValueSet RequestedGVs;
239 for (auto &Name : R.getRequestedSymbols()) {
240 assert(Defs.count(Name) && "No definition for symbol");
241 RequestedGVs.insert(Defs[Name]);
242 }
243
244 auto GVsToExtract = Partition(RequestedGVs);
245
246 // Take a 'None' partition to mean the whole module (as opposed to an empty
247 // partition, which means "materialize nothing"). Emit the whole module
248 // unmodified to the base layer.
249 if (GVsToExtract == None) {
250 Defs.clear();
251 BaseLayer.emit(std::move(R), ES.allocateVModule(), std::move(TSM));
252 return;
253 }
254
255 // If the partition is empty, return the whole module to the symbol table.
256 if (GVsToExtract->empty()) {
257 R.replace(llvm::make_unique<PartitioningIRMaterializationUnit>(
258 std::move(TSM), R.getSymbols(), std::move(Defs), *this));
259 return;
260 }
261
262 expandPartition(*GVsToExtract);
263
264 // Extract the requested partiton (plus any necessary aliases) and
265 // put the rest back into the impl dylib.
266 auto ShouldExtract = [&](const GlobalValue &GV) -> bool {
267 return GVsToExtract->count(&GV);
268 };
269
270 auto ExtractedTSM = extractSubModule(TSM, ".submodule", ShouldExtract);
271
272 R.replace(llvm::make_unique<PartitioningIRMaterializationUnit>(
273 ES, std::move(TSM), *this));
274
275 BaseLayer.emit(std::move(R), ES.allocateVModule(), std::move(ExtractedTSM));
Lang Hames68c9b8d2018-06-18 18:01:43 +0000276}
277
278} // end namespace orc
279} // end namespace llvm