Line data Source code
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/IR/Mangler.h"
12 : #include "llvm/IR/Module.h"
13 :
14 : using namespace llvm;
15 : using namespace llvm::orc;
16 :
17 23 : static ThreadSafeModule extractSubModule(ThreadSafeModule &TSM,
18 : StringRef Suffix,
19 : GVPredicate ShouldExtract) {
20 :
21 : auto DeleteExtractedDefs = [](GlobalValue &GV) {
22 : // Bump the linkage: this global will be provided by the external module.
23 : GV.setLinkage(GlobalValue::ExternalLinkage);
24 :
25 : // Delete the definition in the source module.
26 : 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);
32 : } 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");
54 : } else
55 : llvm_unreachable("Unsupported global type");
56 : };
57 :
58 69 : auto NewTSMod = cloneToNewContext(TSM, ShouldExtract, DeleteExtractedDefs);
59 : auto &M = *NewTSMod.getModule();
60 23 : M.setModuleIdentifier((M.getModuleIdentifier() + Suffix).str());
61 :
62 23 : return NewTSMod;
63 : }
64 :
65 : namespace llvm {
66 : namespace orc {
67 :
68 : class PartitioningIRMaterializationUnit : public IRMaterializationUnit {
69 : public:
70 36 : PartitioningIRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM,
71 : VModuleKey K, CompileOnDemandLayer &Parent)
72 36 : : IRMaterializationUnit(ES, std::move(TSM), std::move(K)),
73 72 : Parent(Parent) {}
74 :
75 0 : PartitioningIRMaterializationUnit(
76 : ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags,
77 : SymbolNameToDefinitionMap SymbolToDefinition,
78 : CompileOnDemandLayer &Parent)
79 0 : : IRMaterializationUnit(std::move(TSM), std::move(K),
80 : std::move(SymbolFlags),
81 : std::move(SymbolToDefinition)),
82 0 : Parent(Parent) {}
83 :
84 : private:
85 24 : void materialize(MaterializationResponsibility R) override {
86 48 : Parent.emitPartition(std::move(R), std::move(TSM),
87 : std::move(SymbolToDefinition));
88 24 : }
89 :
90 0 : void discard(const JITDylib &V, const SymbolStringPtr &Name) override {
91 : // All original symbols were materialized by the CODLayer and should be
92 : // final. The function bodies provided by M should never be overridden.
93 0 : llvm_unreachable("Discard should never be called on an "
94 : "ExtractingIRMaterializationUnit");
95 : }
96 :
97 : mutable std::mutex SourceModuleMutex;
98 : CompileOnDemandLayer &Parent;
99 : };
100 :
101 : Optional<CompileOnDemandLayer::GlobalValueSet>
102 23 : CompileOnDemandLayer::compileRequested(GlobalValueSet Requested) {
103 23 : return std::move(Requested);
104 : }
105 :
106 : Optional<CompileOnDemandLayer::GlobalValueSet>
107 1 : CompileOnDemandLayer::compileWholeModule(GlobalValueSet Requested) {
108 1 : return None;
109 : }
110 :
111 13 : CompileOnDemandLayer::CompileOnDemandLayer(
112 : ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr,
113 13 : IndirectStubsManagerBuilder BuildIndirectStubsManager)
114 : : IRLayer(ES), BaseLayer(BaseLayer), LCTMgr(LCTMgr),
115 13 : BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
116 :
117 1 : void CompileOnDemandLayer::setPartitionFunction(PartitionFunction Partition) {
118 1 : this->Partition = std::move(Partition);
119 1 : }
120 :
121 13 : void CompileOnDemandLayer::emit(MaterializationResponsibility R,
122 : ThreadSafeModule TSM) {
123 : assert(TSM.getModule() && "Null module");
124 :
125 13 : auto &ES = getExecutionSession();
126 : auto &M = *TSM.getModule();
127 :
128 : // First, do some cleanup on the module:
129 13 : cleanUpModule(M);
130 :
131 : // Now sort the callables and non-callables, build re-exports and lodge the
132 : // actual module with the implementation dylib.
133 13 : auto &PDR = getPerDylibResources(R.getTargetJITDylib());
134 :
135 13 : MangleAndInterner Mangle(ES, M.getDataLayout());
136 : SymbolAliasMap NonCallables;
137 : SymbolAliasMap Callables;
138 70 : for (auto &GV : M.global_values()) {
139 71 : if (GV.isDeclaration() || GV.hasLocalLinkage() || GV.hasAppendingLinkage())
140 18 : continue;
141 :
142 26 : auto Name = Mangle(GV.getName());
143 26 : auto Flags = JITSymbolFlags::fromGlobalValue(GV);
144 26 : if (Flags.isCallable())
145 : Callables[Name] = SymbolAliasMapEntry(Name, Flags);
146 : else
147 : NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
148 : }
149 :
150 : // Create a partitioning materialization unit and lodge it with the
151 : // implementation dylib.
152 13 : if (auto Err = PDR.getImplDylib().define(
153 13 : llvm::make_unique<PartitioningIRMaterializationUnit>(
154 13 : ES, std::move(TSM), R.getVModuleKey(), *this))) {
155 0 : ES.reportError(std::move(Err));
156 0 : R.failMaterialization();
157 : return;
158 : }
159 :
160 39 : R.replace(reexports(PDR.getImplDylib(), std::move(NonCallables)));
161 52 : R.replace(lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(),
162 : std::move(Callables)));
163 : }
164 :
165 : CompileOnDemandLayer::PerDylibResources &
166 13 : CompileOnDemandLayer::getPerDylibResources(JITDylib &TargetD) {
167 13 : auto I = DylibResources.find(&TargetD);
168 13 : if (I == DylibResources.end()) {
169 : auto &ImplD =
170 24 : getExecutionSession().createJITDylib(TargetD.getName() + ".impl");
171 12 : TargetD.withSearchOrderDo([&](const JITDylibList &TargetSearchOrder) {
172 : ImplD.setSearchOrder(TargetSearchOrder, false);
173 : });
174 12 : PerDylibResources PDR(ImplD, BuildIndirectStubsManager());
175 12 : I = DylibResources.insert(std::make_pair(&TargetD, std::move(PDR))).first;
176 : }
177 :
178 13 : return I->second;
179 : }
180 :
181 13 : void CompileOnDemandLayer::cleanUpModule(Module &M) {
182 45 : for (auto &F : M.functions()) {
183 32 : if (F.isDeclaration())
184 : continue;
185 :
186 25 : if (F.hasAvailableExternallyLinkage()) {
187 : F.deleteBody();
188 1 : F.setPersonalityFn(nullptr);
189 1 : continue;
190 : }
191 : }
192 13 : }
193 :
194 23 : void CompileOnDemandLayer::expandPartition(GlobalValueSet &Partition) {
195 : // Expands the partition to ensure the following rules hold:
196 : // (1) If any alias is in the partition, its aliasee is also in the partition.
197 : // (2) If any aliasee is in the partition, its aliases are also in the
198 : // partiton.
199 : // (3) If any global variable is in the partition then all global variables
200 : // are in the partition.
201 : assert(!Partition.empty() && "Unexpected empty partition");
202 :
203 23 : const Module &M = *(*Partition.begin())->getParent();
204 : bool ContainsGlobalVariables = false;
205 : std::vector<const GlobalValue *> GVsToAdd;
206 :
207 47 : for (auto *GV : Partition)
208 24 : if (isa<GlobalAlias>(GV))
209 : GVsToAdd.push_back(
210 2 : cast<GlobalValue>(cast<GlobalAlias>(GV)->getAliasee()));
211 22 : else if (isa<GlobalVariable>(GV))
212 : ContainsGlobalVariables = true;
213 :
214 28 : for (auto &A : M.aliases())
215 10 : if (Partition.count(cast<GlobalValue>(A.getAliasee())))
216 0 : GVsToAdd.push_back(&A);
217 :
218 23 : if (ContainsGlobalVariables)
219 11 : for (auto &G : M.globals())
220 8 : GVsToAdd.push_back(&G);
221 :
222 33 : for (auto *GV : GVsToAdd)
223 : Partition.insert(GV);
224 23 : }
225 :
226 24 : void CompileOnDemandLayer::emitPartition(
227 : MaterializationResponsibility R, ThreadSafeModule TSM,
228 : IRMaterializationUnit::SymbolNameToDefinitionMap Defs) {
229 :
230 : // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the
231 : // extracted module key, extracted module, and source module key
232 : // together. This could be used, for example, to provide a specific
233 : // memory manager instance to the linking layer.
234 :
235 24 : auto &ES = getExecutionSession();
236 :
237 : GlobalValueSet RequestedGVs;
238 73 : for (auto &Name : R.getRequestedSymbols()) {
239 : assert(Defs.count(Name) && "No definition for symbol");
240 25 : RequestedGVs.insert(Defs[Name]);
241 : }
242 :
243 24 : auto GVsToExtract = Partition(RequestedGVs);
244 :
245 : // Take a 'None' partition to mean the whole module (as opposed to an empty
246 : // partition, which means "materialize nothing"). Emit the whole module
247 : // unmodified to the base layer.
248 24 : if (GVsToExtract == None) {
249 : Defs.clear();
250 2 : BaseLayer.emit(std::move(R), std::move(TSM));
251 1 : return;
252 : }
253 :
254 : // If the partition is empty, return the whole module to the symbol table.
255 23 : if (GVsToExtract->empty()) {
256 0 : R.replace(llvm::make_unique<PartitioningIRMaterializationUnit>(
257 : std::move(TSM), R.getSymbols(), std::move(Defs), *this));
258 0 : return;
259 : }
260 :
261 : // Ok -- we actually need to partition the symbols. Promote the symbol
262 : // linkages/names.
263 : // FIXME: We apply this once per partitioning. It's safe, but overkill.
264 : {
265 46 : auto PromotedGlobals = PromoteSymbols(*TSM.getModule());
266 23 : if (!PromotedGlobals.empty()) {
267 5 : MangleAndInterner Mangle(ES, TSM.getModule()->getDataLayout());
268 : SymbolFlagsMap SymbolFlags;
269 12 : for (auto &GV : PromotedGlobals)
270 14 : SymbolFlags[Mangle(GV->getName())] =
271 14 : JITSymbolFlags::fromGlobalValue(*GV);
272 10 : if (auto Err = R.defineMaterializing(SymbolFlags)) {
273 0 : ES.reportError(std::move(Err));
274 0 : R.failMaterialization();
275 : return;
276 : }
277 : }
278 : }
279 :
280 23 : expandPartition(*GVsToExtract);
281 :
282 : // Extract the requested partiton (plus any necessary aliases) and
283 : // put the rest back into the impl dylib.
284 : auto ShouldExtract = [&](const GlobalValue &GV) -> bool {
285 62 : return GVsToExtract->count(&GV);
286 : };
287 :
288 23 : auto ExtractedTSM = extractSubModule(TSM, ".submodule", ShouldExtract);
289 46 : R.replace(llvm::make_unique<PartitioningIRMaterializationUnit>(
290 23 : ES, std::move(TSM), R.getVModuleKey(), *this));
291 :
292 46 : BaseLayer.emit(std::move(R), std::move(ExtractedTSM));
293 : }
294 :
295 : } // end namespace orc
296 : } // end namespace llvm
|