blob: f22ae01a208085f5a13e2523a9f23fe00dcfa5a5 [file] [log] [blame]
Lang Hames68c9b8d2018-06-18 18:01:43 +00001//===----- CompileOnDemandLayer.cpp - Lazily emit IR on first call --------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Lang Hames68c9b8d2018-06-18 18:01:43 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
Lang Hames85fb9972019-12-16 02:50:40 -080010#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
Lang Hames68c9b8d2018-06-18 18:01:43 +000011#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");
Benjamin Krameradcd0262020-01-28 20:23:46 +010039 std::string AliasName = std::string(A.getName());
Lang Hames98440292018-09-29 23:49:57 +000040
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 Hames809e9d12019-08-02 15:21:37 +000058 auto NewTSM = cloneToNewContext(TSM, ShouldExtract, DeleteExtractedDefs);
59 NewTSM.withModuleDo([&](Module &M) {
60 M.setModuleIdentifier((M.getModuleIdentifier() + Suffix).str());
61 });
Lang Hames68c9b8d2018-06-18 18:01:43 +000062
Lang Hames809e9d12019-08-02 15:21:37 +000063 return NewTSM;
Lang Hames7bd89702018-07-05 19:01:27 +000064}
65
Lang Hames68c9b8d2018-06-18 18:01:43 +000066namespace llvm {
67namespace orc {
68
Lang Hames98440292018-09-29 23:49:57 +000069class PartitioningIRMaterializationUnit : public IRMaterializationUnit {
Lang Hames68c9b8d2018-06-18 18:01:43 +000070public:
Lang Hamesce2207a2020-01-21 16:28:30 -080071 PartitioningIRMaterializationUnit(ExecutionSession &ES,
Lang Hames85fb9972019-12-16 02:50:40 -080072 const IRSymbolMapper::ManglingOptions &MO,
Lang Hamesce2207a2020-01-21 16:28:30 -080073 ThreadSafeModule TSM, VModuleKey K,
74 CompileOnDemandLayer &Parent)
75 : IRMaterializationUnit(ES, MO, std::move(TSM), std::move(K)),
Lang Hames8b942742018-10-16 20:13:06 +000076 Parent(Parent) {}
Lang Hames68c9b8d2018-06-18 18:01:43 +000077
Lang Hames98440292018-09-29 23:49:57 +000078 PartitioningIRMaterializationUnit(
Lang Hames85fb9972019-12-16 02:50:40 -080079 ThreadSafeModule TSM, VModuleKey K, SymbolFlagsMap SymbolFlags,
80 SymbolStringPtr InitSymbol, SymbolNameToDefinitionMap SymbolToDefinition,
Lang Hames079df9a2018-10-15 22:56:10 +000081 CompileOnDemandLayer &Parent)
Lang Hames8b942742018-10-16 20:13:06 +000082 : IRMaterializationUnit(std::move(TSM), std::move(K),
Lang Hames85fb9972019-12-16 02:50:40 -080083 std::move(SymbolFlags), std::move(InitSymbol),
Lang Hames68c9b8d2018-06-18 18:01:43 +000084 std::move(SymbolToDefinition)),
Lang Hamesfd0c1e712018-07-20 18:31:50 +000085 Parent(Parent) {}
Lang Hames68c9b8d2018-06-18 18:01:43 +000086
87private:
88 void materialize(MaterializationResponsibility R) override {
Lang Hames98440292018-09-29 23:49:57 +000089 Parent.emitPartition(std::move(R), std::move(TSM),
90 std::move(SymbolToDefinition));
Lang Hames68c9b8d2018-06-18 18:01:43 +000091 }
92
Lang Hamescb5702c32018-10-06 23:02:06 +000093 void discard(const JITDylib &V, const SymbolStringPtr &Name) override {
Lang Hames68c9b8d2018-06-18 18:01:43 +000094 // All original symbols were materialized by the CODLayer and should be
95 // final. The function bodies provided by M should never be overridden.
96 llvm_unreachable("Discard should never be called on an "
97 "ExtractingIRMaterializationUnit");
98 }
99
Lang Hames7bd89702018-07-05 19:01:27 +0000100 mutable std::mutex SourceModuleMutex;
Lang Hames079df9a2018-10-15 22:56:10 +0000101 CompileOnDemandLayer &Parent;
Lang Hames68c9b8d2018-06-18 18:01:43 +0000102};
103
Lang Hames079df9a2018-10-15 22:56:10 +0000104Optional<CompileOnDemandLayer::GlobalValueSet>
105CompileOnDemandLayer::compileRequested(GlobalValueSet Requested) {
Bill Wendlingc55cf4a2020-02-10 07:06:45 -0800106 return std::move(Requested);
Lang Hames98440292018-09-29 23:49:57 +0000107}
108
Lang Hames079df9a2018-10-15 22:56:10 +0000109Optional<CompileOnDemandLayer::GlobalValueSet>
110CompileOnDemandLayer::compileWholeModule(GlobalValueSet Requested) {
Lang Hames98440292018-09-29 23:49:57 +0000111 return None;
112}
113
Lang Hames079df9a2018-10-15 22:56:10 +0000114CompileOnDemandLayer::CompileOnDemandLayer(
Lang Hamesd8048672018-09-26 05:08:29 +0000115 ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr,
Lang Hames8d76c712018-09-26 01:24:12 +0000116 IndirectStubsManagerBuilder BuildIndirectStubsManager)
Lang Hamesce2207a2020-01-21 16:28:30 -0800117 : IRLayer(ES, BaseLayer.getManglingOptions()), BaseLayer(BaseLayer),
118 LCTMgr(LCTMgr),
Lang Hames8d76c712018-09-26 01:24:12 +0000119 BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
Lang Hames68c9b8d2018-06-18 18:01:43 +0000120
Lang Hames079df9a2018-10-15 22:56:10 +0000121void CompileOnDemandLayer::setPartitionFunction(PartitionFunction Partition) {
Lang Hames98440292018-09-29 23:49:57 +0000122 this->Partition = std::move(Partition);
Lang Hames68c9b8d2018-06-18 18:01:43 +0000123}
124
Praveen Velliengirif5c40cb2019-08-03 14:42:13 +0000125void CompileOnDemandLayer::setImplMap(ImplSymbolMap *Imp) {
126 this->AliaseeImpls = Imp;
127}
Lang Hames8b942742018-10-16 20:13:06 +0000128void CompileOnDemandLayer::emit(MaterializationResponsibility R,
129 ThreadSafeModule TSM) {
Lang Hames809e9d12019-08-02 15:21:37 +0000130 assert(TSM && "Null module");
Lang Hames98440292018-09-29 23:49:57 +0000131
Lang Hames68c9b8d2018-06-18 18:01:43 +0000132 auto &ES = getExecutionSession();
Lang Hames68c9b8d2018-06-18 18:01:43 +0000133
Lang Hames809e9d12019-08-02 15:21:37 +0000134 // Sort the callables and non-callables, build re-exports and lodge the
Lang Hames98440292018-09-29 23:49:57 +0000135 // actual module with the implementation dylib.
136 auto &PDR = getPerDylibResources(R.getTargetJITDylib());
Lang Hames68c9b8d2018-06-18 18:01:43 +0000137
Lang Hames98440292018-09-29 23:49:57 +0000138 SymbolAliasMap NonCallables;
139 SymbolAliasMap Callables;
Lang Hames809e9d12019-08-02 15:21:37 +0000140 TSM.withModuleDo([&](Module &M) {
141 // First, do some cleanup on the module:
142 cleanUpModule(M);
Lang Hames809e9d12019-08-02 15:21:37 +0000143 });
Lang Hames68c9b8d2018-06-18 18:01:43 +0000144
Lang Hamesce2207a2020-01-21 16:28:30 -0800145 for (auto &KV : R.getSymbols()) {
146 auto &Name = KV.first;
147 auto &Flags = KV.second;
148 if (Flags.isCallable())
149 Callables[Name] = SymbolAliasMapEntry(Name, Flags);
150 else
151 NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
152 }
153
Lang Hames98440292018-09-29 23:49:57 +0000154 // Create a partitioning materialization unit and lodge it with the
155 // implementation dylib.
156 if (auto Err = PDR.getImplDylib().define(
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000157 std::make_unique<PartitioningIRMaterializationUnit>(
Lang Hamesce2207a2020-01-21 16:28:30 -0800158 ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(),
159 *this))) {
Lang Hames68c9b8d2018-06-18 18:01:43 +0000160 ES.reportError(std::move(Err));
161 R.failMaterialization();
162 return;
163 }
164
Lang Hames674df132019-11-25 21:57:27 -0800165 R.replace(reexports(PDR.getImplDylib(), std::move(NonCallables),
166 JITDylibLookupFlags::MatchAllSymbols));
Lang Hames98440292018-09-29 23:49:57 +0000167 R.replace(lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(),
Praveen Velliengirif5c40cb2019-08-03 14:42:13 +0000168 std::move(Callables), AliaseeImpls));
Lang Hames68c9b8d2018-06-18 18:01:43 +0000169}
170
Lang Hames079df9a2018-10-15 22:56:10 +0000171CompileOnDemandLayer::PerDylibResources &
172CompileOnDemandLayer::getPerDylibResources(JITDylib &TargetD) {
Lang Hamesd8048672018-09-26 05:08:29 +0000173 auto I = DylibResources.find(&TargetD);
174 if (I == DylibResources.end()) {
Lang Hames4fc68b92019-12-04 22:45:38 -0800175 auto &ImplD =
Lang Hames85fb9972019-12-16 02:50:40 -0800176 getExecutionSession().createBareJITDylib(TargetD.getName() + ".impl");
177 JITDylibSearchOrder NewSearchOrder;
Lang Hames674df132019-11-25 21:57:27 -0800178 TargetD.withSearchOrderDo(
179 [&](const JITDylibSearchOrder &TargetSearchOrder) {
Lang Hames85fb9972019-12-16 02:50:40 -0800180 NewSearchOrder = TargetSearchOrder;
Lang Hames674df132019-11-25 21:57:27 -0800181 });
Lang Hames85fb9972019-12-16 02:50:40 -0800182
183 assert(
184 !NewSearchOrder.empty() && NewSearchOrder.front().first == &TargetD &&
185 NewSearchOrder.front().second == JITDylibLookupFlags::MatchAllSymbols &&
186 "TargetD must be at the front of its own search order and match "
187 "non-exported symbol");
188 NewSearchOrder.insert(std::next(NewSearchOrder.begin()),
189 {&ImplD, JITDylibLookupFlags::MatchAllSymbols});
190 ImplD.setSearchOrder(NewSearchOrder, false);
191 TargetD.setSearchOrder(std::move(NewSearchOrder), false);
192
Lang Hamesd8048672018-09-26 05:08:29 +0000193 PerDylibResources PDR(ImplD, BuildIndirectStubsManager());
194 I = DylibResources.insert(std::make_pair(&TargetD, std::move(PDR))).first;
195 }
196
197 return I->second;
Lang Hames68c9b8d2018-06-18 18:01:43 +0000198}
199
Lang Hames079df9a2018-10-15 22:56:10 +0000200void CompileOnDemandLayer::cleanUpModule(Module &M) {
Lang Hames98440292018-09-29 23:49:57 +0000201 for (auto &F : M.functions()) {
202 if (F.isDeclaration())
203 continue;
204
205 if (F.hasAvailableExternallyLinkage()) {
206 F.deleteBody();
207 F.setPersonalityFn(nullptr);
208 continue;
209 }
210 }
211}
212
Lang Hames079df9a2018-10-15 22:56:10 +0000213void CompileOnDemandLayer::expandPartition(GlobalValueSet &Partition) {
Lang Hames98440292018-09-29 23:49:57 +0000214 // Expands the partition to ensure the following rules hold:
215 // (1) If any alias is in the partition, its aliasee is also in the partition.
216 // (2) If any aliasee is in the partition, its aliases are also in the
217 // partiton.
218 // (3) If any global variable is in the partition then all global variables
219 // are in the partition.
220 assert(!Partition.empty() && "Unexpected empty partition");
221
222 const Module &M = *(*Partition.begin())->getParent();
223 bool ContainsGlobalVariables = false;
224 std::vector<const GlobalValue *> GVsToAdd;
225
226 for (auto *GV : Partition)
227 if (isa<GlobalAlias>(GV))
228 GVsToAdd.push_back(
229 cast<GlobalValue>(cast<GlobalAlias>(GV)->getAliasee()));
230 else if (isa<GlobalVariable>(GV))
231 ContainsGlobalVariables = true;
232
233 for (auto &A : M.aliases())
234 if (Partition.count(cast<GlobalValue>(A.getAliasee())))
235 GVsToAdd.push_back(&A);
236
237 if (ContainsGlobalVariables)
238 for (auto &G : M.globals())
239 GVsToAdd.push_back(&G);
240
241 for (auto *GV : GVsToAdd)
242 Partition.insert(GV);
243}
244
Lang Hames079df9a2018-10-15 22:56:10 +0000245void CompileOnDemandLayer::emitPartition(
Lang Hames98440292018-09-29 23:49:57 +0000246 MaterializationResponsibility R, ThreadSafeModule TSM,
247 IRMaterializationUnit::SymbolNameToDefinitionMap Defs) {
248
249 // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the
250 // extracted module key, extracted module, and source module key
251 // together. This could be used, for example, to provide a specific
252 // memory manager instance to the linking layer.
253
254 auto &ES = getExecutionSession();
Lang Hames98440292018-09-29 23:49:57 +0000255 GlobalValueSet RequestedGVs;
256 for (auto &Name : R.getRequestedSymbols()) {
Lang Hames85fb9972019-12-16 02:50:40 -0800257 if (Name == R.getInitializerSymbol())
258 TSM.withModuleDo([&](Module &M) {
259 for (auto &GV : getStaticInitGVs(M))
260 RequestedGVs.insert(&GV);
261 });
262 else {
263 assert(Defs.count(Name) && "No definition for symbol");
264 RequestedGVs.insert(Defs[Name]);
265 }
Lang Hames98440292018-09-29 23:49:57 +0000266 }
267
Lang Hames809e9d12019-08-02 15:21:37 +0000268 /// Perform partitioning with the context lock held, since the partition
269 /// function is allowed to access the globals to compute the partition.
270 auto GVsToExtract =
271 TSM.withModuleDo([&](Module &M) { return Partition(RequestedGVs); });
Lang Hames98440292018-09-29 23:49:57 +0000272
273 // Take a 'None' partition to mean the whole module (as opposed to an empty
274 // partition, which means "materialize nothing"). Emit the whole module
275 // unmodified to the base layer.
276 if (GVsToExtract == None) {
277 Defs.clear();
Lang Hames8b942742018-10-16 20:13:06 +0000278 BaseLayer.emit(std::move(R), std::move(TSM));
Lang Hames98440292018-09-29 23:49:57 +0000279 return;
280 }
281
282 // If the partition is empty, return the whole module to the symbol table.
283 if (GVsToExtract->empty()) {
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000284 R.replace(std::make_unique<PartitioningIRMaterializationUnit>(
Lang Hames85fb9972019-12-16 02:50:40 -0800285 std::move(TSM), R.getVModuleKey(), R.getSymbols(),
286 R.getInitializerSymbol(), std::move(Defs), *this));
Lang Hames98440292018-09-29 23:49:57 +0000287 return;
288 }
289
Lang Hamesbf6603e2018-10-09 20:44:32 +0000290 // Ok -- we actually need to partition the symbols. Promote the symbol
Lang Hames809e9d12019-08-02 15:21:37 +0000291 // linkages/names, expand the partition to include any required symbols
292 // (i.e. symbols that can't be separated from our partition), and
293 // then extract the partition.
294 //
295 // FIXME: We apply this promotion once per partitioning. It's safe, but
296 // overkill.
297
298 auto ExtractedTSM =
299 TSM.withModuleDo([&](Module &M) -> Expected<ThreadSafeModule> {
300 auto PromotedGlobals = PromoteSymbols(M);
301 if (!PromotedGlobals.empty()) {
302 MangleAndInterner Mangle(ES, M.getDataLayout());
303 SymbolFlagsMap SymbolFlags;
304 for (auto &GV : PromotedGlobals)
305 SymbolFlags[Mangle(GV->getName())] =
306 JITSymbolFlags::fromGlobalValue(*GV);
307 if (auto Err = R.defineMaterializing(SymbolFlags))
Bill Wendlingc55cf4a2020-02-10 07:06:45 -0800308 return std::move(Err);
Lang Hames809e9d12019-08-02 15:21:37 +0000309 }
310
311 expandPartition(*GVsToExtract);
312
313 // Extract the requested partiton (plus any necessary aliases) and
314 // put the rest back into the impl dylib.
315 auto ShouldExtract = [&](const GlobalValue &GV) -> bool {
316 return GVsToExtract->count(&GV);
317 };
318
319 return extractSubModule(TSM, ".submodule", ShouldExtract);
320 });
321
322 if (!ExtractedTSM) {
323 ES.reportError(ExtractedTSM.takeError());
324 R.failMaterialization();
325 return;
Lang Hamesbf6603e2018-10-09 20:44:32 +0000326 }
327
Jonas Devlieghere0eaee542019-08-15 15:54:37 +0000328 R.replace(std::make_unique<PartitioningIRMaterializationUnit>(
Lang Hamesce2207a2020-01-21 16:28:30 -0800329 ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(), *this));
Lang Hames809e9d12019-08-02 15:21:37 +0000330 BaseLayer.emit(std::move(R), std::move(*ExtractedTSM));
Lang Hames68c9b8d2018-06-18 18:01:43 +0000331}
332
333} // end namespace orc
334} // end namespace llvm