LLVM  14.0.0git
JITLinkGeneric.cpp
Go to the documentation of this file.
1 //===--------- JITLinkGeneric.cpp - Generic JIT linker utilities ----------===//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Generic JITLinker utility class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "JITLinkGeneric.h"
14 
17 
18 #define DEBUG_TYPE "jitlink"
19 
20 namespace llvm {
21 namespace jitlink {
22 
24 
25 void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) {
26 
27  LLVM_DEBUG({
28  dbgs() << "Starting link phase 1 for graph " << G->getName() << "\n";
29  });
30 
31  // Prune and optimize the graph.
32  if (auto Err = runPasses(Passes.PrePrunePasses))
33  return Ctx->notifyFailed(std::move(Err));
34 
35  LLVM_DEBUG({
36  dbgs() << "Link graph \"" << G->getName() << "\" pre-pruning:\n";
37  G->dump(dbgs());
38  });
39 
40  prune(*G);
41 
42  LLVM_DEBUG({
43  dbgs() << "Link graph \"" << G->getName() << "\" post-pruning:\n";
44  G->dump(dbgs());
45  });
46 
47  // Run post-pruning passes.
48  if (auto Err = runPasses(Passes.PostPrunePasses))
49  return Ctx->notifyFailed(std::move(Err));
50 
51  Ctx->getMemoryManager().allocate(
52  Ctx->getJITLinkDylib(), *G,
53  [S = std::move(Self)](AllocResult AR) mutable {
54  auto *TmpSelf = S.get();
55  TmpSelf->linkPhase2(std::move(S), std::move(AR));
56  });
57 }
58 
59 void JITLinkerBase::linkPhase2(std::unique_ptr<JITLinkerBase> Self,
60  AllocResult AR) {
61 
62  if (AR)
63  Alloc = std::move(*AR);
64  else
65  return Ctx->notifyFailed(AR.takeError());
66 
67  LLVM_DEBUG({
68  dbgs() << "Link graph \"" << G->getName()
69  << "\" before post-allocation passes:\n";
70  G->dump(dbgs());
71  });
72 
73  // Run post-allocation passes.
74  if (auto Err = runPasses(Passes.PostAllocationPasses))
75  return Ctx->notifyFailed(std::move(Err));
76 
77  // Notify client that the defined symbols have been assigned addresses.
78  LLVM_DEBUG(dbgs() << "Resolving symbols defined in " << G->getName() << "\n");
79 
80  if (auto Err = Ctx->notifyResolved(*G))
81  return Ctx->notifyFailed(std::move(Err));
82 
83  auto ExternalSymbols = getExternalSymbolNames();
84 
85  // If there are no external symbols then proceed immediately with phase 3.
86  if (ExternalSymbols.empty()) {
87  LLVM_DEBUG({
88  dbgs() << "No external symbols for " << G->getName()
89  << ". Proceeding immediately with link phase 3.\n";
90  });
91  // FIXME: Once callee expressions are defined to be sequenced before
92  // argument expressions (c++17) we can simplify this. See below.
93  auto &TmpSelf = *Self;
94  TmpSelf.linkPhase3(std::move(Self), AsyncLookupResult());
95  return;
96  }
97 
98  // Otherwise look up the externals.
99  LLVM_DEBUG({
100  dbgs() << "Issuing lookup for external symbols for " << G->getName()
101  << " (may trigger materialization/linking of other graphs)...\n";
102  });
103 
104  // We're about to hand off ownership of ourself to the continuation. Grab a
105  // pointer to the context so that we can call it to initiate the lookup.
106  //
107  // FIXME: Once callee expressions are defined to be sequenced before argument
108  // expressions (c++17) we can simplify all this to:
109  //
110  // Ctx->lookup(std::move(UnresolvedExternals),
111  // [Self=std::move(Self)](Expected<AsyncLookupResult> Result) {
112  // Self->linkPhase3(std::move(Self), std::move(Result));
113  // });
114  Ctx->lookup(std::move(ExternalSymbols),
116  [S = std::move(Self)](
118  auto &TmpSelf = *S;
119  TmpSelf.linkPhase3(std::move(S), std::move(LookupResult));
120  }));
121 }
122 
123 void JITLinkerBase::linkPhase3(std::unique_ptr<JITLinkerBase> Self,
125 
126  LLVM_DEBUG({
127  dbgs() << "Starting link phase 3 for graph " << G->getName() << "\n";
128  });
129 
130  // If the lookup failed, bail out.
131  if (!LR)
132  return abandonAllocAndBailOut(std::move(Self), LR.takeError());
133 
134  // Assign addresses to external addressables.
135  applyLookupResult(*LR);
136 
137  LLVM_DEBUG({
138  dbgs() << "Link graph \"" << G->getName()
139  << "\" before pre-fixup passes:\n";
140  G->dump(dbgs());
141  });
142 
143  if (auto Err = runPasses(Passes.PreFixupPasses))
144  return abandonAllocAndBailOut(std::move(Self), std::move(Err));
145 
146  LLVM_DEBUG({
147  dbgs() << "Link graph \"" << G->getName() << "\" before copy-and-fixup:\n";
148  G->dump(dbgs());
149  });
150 
151  // Fix up block content.
152  if (auto Err = fixUpBlocks(*G))
153  return abandonAllocAndBailOut(std::move(Self), std::move(Err));
154 
155  LLVM_DEBUG({
156  dbgs() << "Link graph \"" << G->getName() << "\" after copy-and-fixup:\n";
157  G->dump(dbgs());
158  });
159 
160  if (auto Err = runPasses(Passes.PostFixupPasses))
161  return abandonAllocAndBailOut(std::move(Self), std::move(Err));
162 
163  Alloc->finalize([S = std::move(Self)](FinalizeResult FR) mutable {
164  auto *TmpSelf = S.get();
165  TmpSelf->linkPhase4(std::move(S), std::move(FR));
166  });
167 }
168 
169 void JITLinkerBase::linkPhase4(std::unique_ptr<JITLinkerBase> Self,
170  FinalizeResult FR) {
171 
172  LLVM_DEBUG({
173  dbgs() << "Starting link phase 4 for graph " << G->getName() << "\n";
174  });
175 
176  if (!FR)
177  return Ctx->notifyFailed(FR.takeError());
178 
179  Ctx->notifyFinalized(std::move(*FR));
180 
181  LLVM_DEBUG({ dbgs() << "Link of graph " << G->getName() << " complete\n"; });
182 }
183 
184 Error JITLinkerBase::runPasses(LinkGraphPassList &Passes) {
185  for (auto &P : Passes)
186  if (auto Err = P(*G))
187  return Err;
188  return Error::success();
189 }
190 
191 JITLinkContext::LookupMap JITLinkerBase::getExternalSymbolNames() const {
192  // Identify unresolved external symbols.
193  JITLinkContext::LookupMap UnresolvedExternals;
194  for (auto *Sym : G->external_symbols()) {
195  assert(Sym->getAddress() == 0 &&
196  "External has already been assigned an address");
197  assert(Sym->getName() != StringRef() && Sym->getName() != "" &&
198  "Externals must be named");
199  SymbolLookupFlags LookupFlags =
200  Sym->getLinkage() == Linkage::Weak
203  UnresolvedExternals[Sym->getName()] = LookupFlags;
204  }
205  return UnresolvedExternals;
206 }
207 
208 void JITLinkerBase::applyLookupResult(AsyncLookupResult Result) {
209  for (auto *Sym : G->external_symbols()) {
210  assert(Sym->getOffset() == 0 &&
211  "External symbol is not at the start of its addressable block");
212  assert(Sym->getAddress() == 0 && "Symbol already resolved");
213  assert(!Sym->isDefined() && "Symbol being resolved is already defined");
214  auto ResultI = Result.find(Sym->getName());
215  if (ResultI != Result.end())
216  Sym->getAddressable().setAddress(ResultI->second.getAddress());
217  else
218  assert(Sym->getLinkage() == Linkage::Weak &&
219  "Failed to resolve non-weak reference");
220  }
221 
222  LLVM_DEBUG({
223  dbgs() << "Externals after applying lookup result:\n";
224  for (auto *Sym : G->external_symbols())
225  dbgs() << " " << Sym->getName() << ": "
226  << formatv("{0:x16}", Sym->getAddress()) << "\n";
227  });
228 }
229 
230 void JITLinkerBase::abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self,
231  Error Err) {
232  assert(Err && "Should not be bailing out on success value");
233  assert(Alloc && "can not call abandonAllocAndBailOut before allocation");
234  Alloc->abandon([S = std::move(Self), E1 = std::move(Err)](Error E2) mutable {
235  S->Ctx->notifyFailed(joinErrors(std::move(E1), std::move(E2)));
236  });
237 }
238 
239 void prune(LinkGraph &G) {
240  std::vector<Symbol *> Worklist;
241  DenseSet<Block *> VisitedBlocks;
242 
243  // Build the initial worklist from all symbols initially live.
244  for (auto *Sym : G.defined_symbols())
245  if (Sym->isLive())
246  Worklist.push_back(Sym);
247 
248  // Propagate live flags to all symbols reachable from the initial live set.
249  while (!Worklist.empty()) {
250  auto *Sym = Worklist.back();
251  Worklist.pop_back();
252 
253  auto &B = Sym->getBlock();
254 
255  // Skip addressables that we've visited before.
256  if (VisitedBlocks.count(&B))
257  continue;
258 
259  VisitedBlocks.insert(&B);
260 
261  for (auto &E : Sym->getBlock().edges()) {
262  // If the edge target is a defined symbol that is being newly marked live
263  // then add it to the worklist.
264  if (E.getTarget().isDefined() && !E.getTarget().isLive())
265  Worklist.push_back(&E.getTarget());
266 
267  // Mark the target live.
268  E.getTarget().setLive(true);
269  }
270  }
271 
272  // Collect all defined symbols to remove, then remove them.
273  {
274  LLVM_DEBUG(dbgs() << "Dead-stripping defined symbols:\n");
275  std::vector<Symbol *> SymbolsToRemove;
276  for (auto *Sym : G.defined_symbols())
277  if (!Sym->isLive())
278  SymbolsToRemove.push_back(Sym);
279  for (auto *Sym : SymbolsToRemove) {
280  LLVM_DEBUG(dbgs() << " " << *Sym << "...\n");
281  G.removeDefinedSymbol(*Sym);
282  }
283  }
284 
285  // Delete any unused blocks.
286  {
287  LLVM_DEBUG(dbgs() << "Dead-stripping blocks:\n");
288  std::vector<Block *> BlocksToRemove;
289  for (auto *B : G.blocks())
290  if (!VisitedBlocks.count(B))
291  BlocksToRemove.push_back(B);
292  for (auto *B : BlocksToRemove) {
293  LLVM_DEBUG(dbgs() << " " << *B << "...\n");
294  G.removeBlock(*B);
295  }
296  }
297 
298  // Collect all external symbols to remove, then remove them.
299  {
300  LLVM_DEBUG(dbgs() << "Removing unused external symbols:\n");
301  std::vector<Symbol *> SymbolsToRemove;
302  for (auto *Sym : G.external_symbols())
303  if (!Sym->isLive())
304  SymbolsToRemove.push_back(Sym);
305  for (auto *Sym : SymbolsToRemove) {
306  LLVM_DEBUG(dbgs() << " " << *Sym << "...\n");
307  G.removeExternalSymbol(*Sym);
308  }
309  }
310 }
311 
312 } // end namespace jitlink
313 } // end namespace llvm
MemoryBuffer.h
BinaryStreamReader.h
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
P
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
Definition: README-SSE.txt:411
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
Passes
const char * Passes
Definition: PassBuilderBindings.cpp:46
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
llvm::detail::DenseSetImpl::insert
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
llvm::detail::DenseSetImpl::count
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Definition: DenseSet.h:97
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::formatv
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Definition: FormatVariadic.h:250
llvm::orc::tpctypes::LookupResult
std::vector< JITTargetAddress > LookupResult
Definition: TargetProcessControlTypes.h:144
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::ms_demangle::QualifierMangleMode::Result
@ Result
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
llvm::DenseSet< Block * >
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::joinErrors
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:428
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition: Error.h:599
JITLinkGeneric.h