LLVM: lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
14
15#define DEBUG_TYPE "jitlink"
16
17namespace llvm {
18namespace jitlink {
19
21
23
25
26
27 if (auto Err = runPasses(Passes.PrePrunePasses))
28 return Ctx->notifyFailed(std::move(Err));
29
31 dbgs() << "Link graph pre-pruning:\n";
32 G->dump(dbgs());
33 });
34
36
38 dbgs() << "Link graph post-pruning:\n";
39 G->dump(dbgs());
40 });
41
42
43 if (auto Err = runPasses(Passes.PostPrunePasses))
44 return Ctx->notifyFailed(std::move(Err));
45
46
47 if (G->allocActions().empty() && llvm::all_of(G->sections(), [](Section &S) {
48 return S.getMemLifetime() == orc::MemLifetime::NoAlloc;
49 })) {
51 return;
52 }
53
54 Ctx->getMemoryManager().allocate(
55 Ctx->getJITLinkDylib(), *G,
56 [S = std::move(Self)](AllocResult AR) mutable {
57
58
59
60 auto *TmpSelf = S.get();
61 TmpSelf->linkPhase2(std::move(S), std::move(AR));
62 });
63}
64
67
69
70 if (AR)
71 Alloc = std::move(*AR);
72 else
73 return Ctx->notifyFailed(AR.takeError());
74
76 dbgs() << "Link graph before post-allocation passes:\n";
77 G->dump(dbgs());
78 });
79
80
81 if (auto Err = runPasses(Passes.PostAllocationPasses))
82 return abandonAllocAndBailOut(std::move(Self), std::move(Err));
83
84
85 LLVM_DEBUG(dbgs() << "Resolving symbols defined in " << G->getName() << "\n");
86
87 if (auto Err = Ctx->notifyResolved(*G))
88 return abandonAllocAndBailOut(std::move(Self), std::move(Err));
89
90 auto ExternalSymbols = getExternalSymbolNames();
91
92
93 if (ExternalSymbols.empty()) {
95 dbgs() << "No external symbols for " << G->getName()
96 << ". Proceeding immediately with link phase 3.\n";
97 });
98
99
100 auto &TmpSelf = *Self;
102 return;
103 }
104
105
107 dbgs() << "Issuing lookup for external symbols for " << G->getName()
108 << " (may trigger materialization/linking of other graphs)...\n";
109 });
110
111
112
113
114
115
116
117
118
119
120
121 Ctx->lookup(std::move(ExternalSymbols),
123 [S = std::move(Self)](
125 auto &TmpSelf = *S;
126 TmpSelf.linkPhase3(std::move(S), std::move(LookupResult));
127 }));
128}
129
132
134
135
136 if (!LR)
137 return abandonAllocAndBailOut(std::move(Self), LR.takeError());
138
139
140 applyLookupResult(*LR);
141
143 dbgs() << "Link graph before pre-fixup passes:\n";
144 G->dump(dbgs());
145 });
146
147 if (auto Err = runPasses(Passes.PreFixupPasses))
148 return abandonAllocAndBailOut(std::move(Self), std::move(Err));
149
151 dbgs() << "Link graph before copy-and-fixup:\n";
152 G->dump(dbgs());
153 });
154
155
156 if (auto Err = fixUpBlocks(*G))
157 return abandonAllocAndBailOut(std::move(Self), std::move(Err));
158
160 dbgs() << "Link graph after copy-and-fixup:\n";
161 G->dump(dbgs());
162 });
163
164 if (auto Err = runPasses(Passes.PostFixupPasses))
165 return abandonAllocAndBailOut(std::move(Self), std::move(Err));
166
167
168 if (!Alloc) {
170 return;
171 }
172
173 Alloc->finalize([S = std::move(Self)](FinalizeResult FR) mutable {
174
175
176
177 auto *TmpSelf = S.get();
178 TmpSelf->linkPhase4(std::move(S), std::move(FR));
179 });
180}
181
184
186
187 if (!FR)
188 return Ctx->notifyFailed(FR.takeError());
189
190 Ctx->notifyFinalized(std::move(*FR));
191
193}
194
198 return Err;
200}
201
203
205 for (auto *Sym : G->external_symbols()) {
206 assert(!Sym->getAddress() &&
207 "External has already been assigned an address");
208 assert(Sym->hasName() && "Externals must be named");
212 UnresolvedExternals[Sym->getName()] = LookupFlags;
213 }
214 return UnresolvedExternals;
215}
216
218 for (auto *Sym : G->external_symbols()) {
219 assert(Sym->getOffset() == 0 &&
220 "External symbol is not at the start of its addressable block");
221 assert(!Sym->getAddress() && "Symbol already resolved");
222 assert(!Sym->isDefined() && "Symbol being resolved is already defined");
223 auto ResultI = Result.find(Sym->getName());
224 if (ResultI != Result.end()) {
225 Sym->getAddressable().setAddress(ResultI->second.getAddress());
226 Sym->setLinkage(ResultI->second.getFlags().isWeak() ? Linkage::Weak
228 Sym->setScope(ResultI->second.getFlags().isExported() ? Scope::Default
230 } else
231 assert(Sym->isWeaklyReferenced() &&
232 "Failed to resolve non-weak reference");
233 }
234
236 dbgs() << "Externals after applying lookup result:\n";
237 for (auto *Sym : G->external_symbols()) {
238 dbgs() << " " << Sym->getName() << ": "
239 << formatv("{0:x16}", Sym->getAddress().getValue());
240 switch (Sym->getLinkage()) {
242 break;
244 dbgs() << " (weak)";
245 break;
246 }
247 switch (Sym->getScope()) {
251 "side-effects-only linkage");
253 break;
255 dbgs() << " (exported)";
256 break;
257 }
258 dbgs() << "\n";
259 }
260 });
261}
262
263void JITLinkerBase::abandonAllocAndBailOut(std::unique_ptr Self,
265 assert(Err && "Should not be bailing out on success value");
266 assert(Alloc && "can not call abandonAllocAndBailOut before allocation");
267 Alloc->abandon([S = std::move(Self), E1 = std::move(Err)](Error E2) mutable {
268 S->Ctx->notifyFailed(joinErrors(std::move(E1), std::move(E2)));
269 });
270}
271
273 std::vector<Symbol *> Worklist;
275
276
277 for (auto *Sym : G.defined_symbols())
278 if (Sym->isLive())
279 Worklist.push_back(Sym);
280
281
282 while (!Worklist.empty()) {
283 auto *Sym = Worklist.back();
284 Worklist.pop_back();
285
286 auto &B = Sym->getBlock();
287
288
290 continue;
291
293
294 for (auto &E : Sym->getBlock().edges()) {
295
296
297 if (E.getTarget().isDefined() && .getTarget().isLive())
298 Worklist.push_back(&E.getTarget());
299
300
301 E.getTarget().setLive(true);
302 }
303 }
304
305
306 {
307 LLVM_DEBUG(dbgs() << "Dead-stripping defined symbols:\n");
308 std::vector<Symbol *> SymbolsToRemove;
309 for (auto *Sym : G.defined_symbols())
310 if (!Sym->isLive())
311 SymbolsToRemove.push_back(Sym);
312 for (auto *Sym : SymbolsToRemove) {
314 G.removeDefinedSymbol(*Sym);
315 }
316 }
317
318
319 {
321 std::vector<Block *> BlocksToRemove;
322 for (auto *B : G.blocks())
324 BlocksToRemove.push_back(B);
325 for (auto *B : BlocksToRemove) {
328 }
329 }
330
331
332 {
333 LLVM_DEBUG(dbgs() << "Removing unused external symbols:\n");
334 std::vector<Symbol *> SymbolsToRemove;
335 for (auto *Sym : G.external_symbols())
336 if (!Sym->isLive())
337 SymbolsToRemove.push_back(Sym);
338 for (auto *Sym : SymbolsToRemove) {
340 G.removeExternalSymbol(*Sym);
341 }
342 }
343}
344
345}
346}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
SmallPtrSet< const BasicBlock *, 8 > VisitedBlocks
Function const char * Passes
Implements a dense probed hash-table based set.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
DenseMap< orc::SymbolStringPtr, SymbolLookupFlags > LookupMap
Represents a finalized allocation.
void linkPhase4(std::unique_ptr< JITLinkerBase > Self, FinalizeResult FR)
Definition JITLinkGeneric.cpp:182
void linkPhase3(std::unique_ptr< JITLinkerBase > Self, Expected< AsyncLookupResult > LookupResult)
Definition JITLinkGeneric.cpp:130
Expected< std::unique_ptr< InFlightAlloc > > AllocResult
void linkPhase1(std::unique_ptr< JITLinkerBase > Self)
Definition JITLinkGeneric.cpp:22
Expected< JITLinkMemoryManager::FinalizedAlloc > FinalizeResult
void linkPhase2(std::unique_ptr< JITLinkerBase > Self, AllocResult AR)
Definition JITLinkGeneric.cpp:65
Represents an object file section.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
std::unique_ptr< JITLinkAsyncLookupContinuation > createLookupContinuation(Continuation Cont)
Create a lookup continuation from a function object.
SymbolLookupFlags
Flags for symbol lookup.
void prune(LinkGraph &G)
Removes dead symbols/blocks/addressables.
Definition JITLinkGeneric.cpp:272
DenseMap< orc::SymbolStringPtr, orc::ExecutorSymbolDef > AsyncLookupResult
A map of symbol names to resolved addresses.
std::vector< LinkGraphPassFunction > LinkGraphPassList
A list of LinkGraph passes.
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
Error joinErrors(Error E1, Error E2)
Concatenate errors.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.