xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
10b57cec5SDimitry Andric //===--------- JITLinkGeneric.cpp - Generic JIT linker utilities ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Generic JITLinker utility class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "JITLinkGeneric.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
160b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric namespace llvm {
210b57cec5SDimitry Andric namespace jitlink {
220b57cec5SDimitry Andric 
2381ad6265SDimitry Andric JITLinkerBase::~JITLinkerBase() = default;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) {
260b57cec5SDimitry Andric 
275ffd83dbSDimitry Andric   LLVM_DEBUG({
285ffd83dbSDimitry Andric     dbgs() << "Starting link phase 1 for graph " << G->getName() << "\n";
295ffd83dbSDimitry Andric   });
305ffd83dbSDimitry Andric 
310b57cec5SDimitry Andric   // Prune and optimize the graph.
328bcb0991SDimitry Andric   if (auto Err = runPasses(Passes.PrePrunePasses))
330b57cec5SDimitry Andric     return Ctx->notifyFailed(std::move(Err));
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   LLVM_DEBUG({
368bcb0991SDimitry Andric     dbgs() << "Link graph \"" << G->getName() << "\" pre-pruning:\n";
37fe6060f1SDimitry Andric     G->dump(dbgs());
380b57cec5SDimitry Andric   });
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   prune(*G);
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   LLVM_DEBUG({
438bcb0991SDimitry Andric     dbgs() << "Link graph \"" << G->getName() << "\" post-pruning:\n";
44fe6060f1SDimitry Andric     G->dump(dbgs());
450b57cec5SDimitry Andric   });
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   // Run post-pruning passes.
488bcb0991SDimitry Andric   if (auto Err = runPasses(Passes.PostPrunePasses))
490b57cec5SDimitry Andric     return Ctx->notifyFailed(std::move(Err));
500b57cec5SDimitry Andric 
51*1db9f3b2SDimitry Andric   // Skip straight to phase 2 if the graph is empty with no associated actions.
52*1db9f3b2SDimitry Andric   if (G->allocActions().empty() && llvm::all_of(G->sections(), [](Section &S) {
53*1db9f3b2SDimitry Andric         return S.getMemLifetime() == orc::MemLifetime::NoAlloc;
54*1db9f3b2SDimitry Andric       })) {
55*1db9f3b2SDimitry Andric     linkPhase2(std::move(Self), nullptr);
56*1db9f3b2SDimitry Andric     return;
57*1db9f3b2SDimitry Andric   }
58*1db9f3b2SDimitry Andric 
59349cc55cSDimitry Andric   Ctx->getMemoryManager().allocate(
60349cc55cSDimitry Andric       Ctx->getJITLinkDylib(), *G,
61349cc55cSDimitry Andric       [S = std::move(Self)](AllocResult AR) mutable {
62bdd1243dSDimitry Andric         // FIXME: Once MSVC implements c++17 order of evaluation rules for calls
63bdd1243dSDimitry Andric         // this can be simplified to
64bdd1243dSDimitry Andric         //          S->linkPhase2(std::move(S), std::move(AR));
65349cc55cSDimitry Andric         auto *TmpSelf = S.get();
66349cc55cSDimitry Andric         TmpSelf->linkPhase2(std::move(S), std::move(AR));
67349cc55cSDimitry Andric       });
68349cc55cSDimitry Andric }
690b57cec5SDimitry Andric 
70349cc55cSDimitry Andric void JITLinkerBase::linkPhase2(std::unique_ptr<JITLinkerBase> Self,
71349cc55cSDimitry Andric                                AllocResult AR) {
72349cc55cSDimitry Andric 
73349cc55cSDimitry Andric   if (AR)
74349cc55cSDimitry Andric     Alloc = std::move(*AR);
75349cc55cSDimitry Andric   else
765f757f3fSDimitry Andric     return Ctx->notifyFailed(AR.takeError());
770b57cec5SDimitry Andric 
78e8d8bef9SDimitry Andric   LLVM_DEBUG({
79e8d8bef9SDimitry Andric     dbgs() << "Link graph \"" << G->getName()
80e8d8bef9SDimitry Andric            << "\" before post-allocation passes:\n";
81fe6060f1SDimitry Andric     G->dump(dbgs());
82e8d8bef9SDimitry Andric   });
83e8d8bef9SDimitry Andric 
84e8d8bef9SDimitry Andric   // Run post-allocation passes.
85e8d8bef9SDimitry Andric   if (auto Err = runPasses(Passes.PostAllocationPasses))
8606c3fb27SDimitry Andric     return abandonAllocAndBailOut(std::move(Self), std::move(Err));
87e8d8bef9SDimitry Andric 
888bcb0991SDimitry Andric   // Notify client that the defined symbols have been assigned addresses.
89fe6060f1SDimitry Andric   LLVM_DEBUG(dbgs() << "Resolving symbols defined in " << G->getName() << "\n");
90e8d8bef9SDimitry Andric 
91e8d8bef9SDimitry Andric   if (auto Err = Ctx->notifyResolved(*G))
9206c3fb27SDimitry Andric     return abandonAllocAndBailOut(std::move(Self), std::move(Err));
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   auto ExternalSymbols = getExternalSymbolNames();
950b57cec5SDimitry Andric 
96349cc55cSDimitry Andric   // If there are no external symbols then proceed immediately with phase 3.
97fe6060f1SDimitry Andric   if (ExternalSymbols.empty()) {
98fe6060f1SDimitry Andric     LLVM_DEBUG({
99fe6060f1SDimitry Andric       dbgs() << "No external symbols for " << G->getName()
100349cc55cSDimitry Andric              << ". Proceeding immediately with link phase 3.\n";
101fe6060f1SDimitry Andric     });
102bdd1243dSDimitry Andric     // FIXME: Once MSVC implements c++17 order of evaluation rules for calls
103bdd1243dSDimitry Andric     // this can be simplified. See below.
104fe6060f1SDimitry Andric     auto &TmpSelf = *Self;
105349cc55cSDimitry Andric     TmpSelf.linkPhase3(std::move(Self), AsyncLookupResult());
106fe6060f1SDimitry Andric     return;
107fe6060f1SDimitry Andric   }
108fe6060f1SDimitry Andric 
109fe6060f1SDimitry Andric   // Otherwise look up the externals.
1105ffd83dbSDimitry Andric   LLVM_DEBUG({
1115ffd83dbSDimitry Andric     dbgs() << "Issuing lookup for external symbols for " << G->getName()
1125ffd83dbSDimitry Andric            << " (may trigger materialization/linking of other graphs)...\n";
1135ffd83dbSDimitry Andric   });
1145ffd83dbSDimitry Andric 
1150b57cec5SDimitry Andric   // We're about to hand off ownership of ourself to the continuation. Grab a
1160b57cec5SDimitry Andric   // pointer to the context so that we can call it to initiate the lookup.
1170b57cec5SDimitry Andric   //
118bdd1243dSDimitry Andric   // FIXME: Once MSVC implements c++17 order of evaluation rules for calls this
119bdd1243dSDimitry Andric   // can be simplified to:
1200b57cec5SDimitry Andric   //
1210b57cec5SDimitry Andric   // Ctx->lookup(std::move(UnresolvedExternals),
1220b57cec5SDimitry Andric   //             [Self=std::move(Self)](Expected<AsyncLookupResult> Result) {
123349cc55cSDimitry Andric   //               Self->linkPhase3(std::move(Self), std::move(Result));
1240b57cec5SDimitry Andric   //             });
125349cc55cSDimitry Andric   Ctx->lookup(std::move(ExternalSymbols),
1268bcb0991SDimitry Andric               createLookupContinuation(
127349cc55cSDimitry Andric                   [S = std::move(Self)](
1288bcb0991SDimitry Andric                       Expected<AsyncLookupResult> LookupResult) mutable {
1298bcb0991SDimitry Andric                     auto &TmpSelf = *S;
130349cc55cSDimitry Andric                     TmpSelf.linkPhase3(std::move(S), std::move(LookupResult));
1318bcb0991SDimitry Andric                   }));
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
134349cc55cSDimitry Andric void JITLinkerBase::linkPhase3(std::unique_ptr<JITLinkerBase> Self,
135349cc55cSDimitry Andric                                Expected<AsyncLookupResult> LR) {
1365ffd83dbSDimitry Andric 
1375ffd83dbSDimitry Andric   LLVM_DEBUG({
138349cc55cSDimitry Andric     dbgs() << "Starting link phase 3 for graph " << G->getName() << "\n";
1395ffd83dbSDimitry Andric   });
1405ffd83dbSDimitry Andric 
1410b57cec5SDimitry Andric   // If the lookup failed, bail out.
1420b57cec5SDimitry Andric   if (!LR)
143349cc55cSDimitry Andric     return abandonAllocAndBailOut(std::move(Self), LR.takeError());
1440b57cec5SDimitry Andric 
1458bcb0991SDimitry Andric   // Assign addresses to external addressables.
1460b57cec5SDimitry Andric   applyLookupResult(*LR);
1470b57cec5SDimitry Andric 
1485ffd83dbSDimitry Andric   LLVM_DEBUG({
1495ffd83dbSDimitry Andric     dbgs() << "Link graph \"" << G->getName()
150e8d8bef9SDimitry Andric            << "\" before pre-fixup passes:\n";
151fe6060f1SDimitry Andric     G->dump(dbgs());
1525ffd83dbSDimitry Andric   });
1535ffd83dbSDimitry Andric 
154e8d8bef9SDimitry Andric   if (auto Err = runPasses(Passes.PreFixupPasses))
155349cc55cSDimitry Andric     return abandonAllocAndBailOut(std::move(Self), std::move(Err));
1565ffd83dbSDimitry Andric 
1570b57cec5SDimitry Andric   LLVM_DEBUG({
1588bcb0991SDimitry Andric     dbgs() << "Link graph \"" << G->getName() << "\" before copy-and-fixup:\n";
159fe6060f1SDimitry Andric     G->dump(dbgs());
1600b57cec5SDimitry Andric   });
1610b57cec5SDimitry Andric 
1625ffd83dbSDimitry Andric   // Fix up block content.
1635ffd83dbSDimitry Andric   if (auto Err = fixUpBlocks(*G))
164349cc55cSDimitry Andric     return abandonAllocAndBailOut(std::move(Self), std::move(Err));
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   LLVM_DEBUG({
1678bcb0991SDimitry Andric     dbgs() << "Link graph \"" << G->getName() << "\" after copy-and-fixup:\n";
168fe6060f1SDimitry Andric     G->dump(dbgs());
1690b57cec5SDimitry Andric   });
1700b57cec5SDimitry Andric 
1718bcb0991SDimitry Andric   if (auto Err = runPasses(Passes.PostFixupPasses))
172349cc55cSDimitry Andric     return abandonAllocAndBailOut(std::move(Self), std::move(Err));
1730b57cec5SDimitry Andric 
174*1db9f3b2SDimitry Andric   // Skip straight to phase 4 if the graph has no allocation.
175*1db9f3b2SDimitry Andric   if (!Alloc) {
176*1db9f3b2SDimitry Andric     linkPhase4(std::move(Self), JITLinkMemoryManager::FinalizedAlloc{});
177*1db9f3b2SDimitry Andric     return;
178*1db9f3b2SDimitry Andric   }
179*1db9f3b2SDimitry Andric 
180349cc55cSDimitry Andric   Alloc->finalize([S = std::move(Self)](FinalizeResult FR) mutable {
181bdd1243dSDimitry Andric     // FIXME: Once MSVC implements c++17 order of evaluation rules for calls
182bdd1243dSDimitry Andric     // this can be simplified to
183bdd1243dSDimitry Andric     //          S->linkPhase2(std::move(S), std::move(AR));
184349cc55cSDimitry Andric     auto *TmpSelf = S.get();
185349cc55cSDimitry Andric     TmpSelf->linkPhase4(std::move(S), std::move(FR));
186349cc55cSDimitry Andric   });
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
189349cc55cSDimitry Andric void JITLinkerBase::linkPhase4(std::unique_ptr<JITLinkerBase> Self,
190349cc55cSDimitry Andric                                FinalizeResult FR) {
1915ffd83dbSDimitry Andric 
1925ffd83dbSDimitry Andric   LLVM_DEBUG({
193349cc55cSDimitry Andric     dbgs() << "Starting link phase 4 for graph " << G->getName() << "\n";
1945ffd83dbSDimitry Andric   });
1955ffd83dbSDimitry Andric 
196349cc55cSDimitry Andric   if (!FR)
197349cc55cSDimitry Andric     return Ctx->notifyFailed(FR.takeError());
198349cc55cSDimitry Andric 
199349cc55cSDimitry Andric   Ctx->notifyFinalized(std::move(*FR));
2005ffd83dbSDimitry Andric 
2015ffd83dbSDimitry Andric   LLVM_DEBUG({ dbgs() << "Link of graph " << G->getName() << " complete\n"; });
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric 
2048bcb0991SDimitry Andric Error JITLinkerBase::runPasses(LinkGraphPassList &Passes) {
2050b57cec5SDimitry Andric   for (auto &P : Passes)
2068bcb0991SDimitry Andric     if (auto Err = P(*G))
2070b57cec5SDimitry Andric       return Err;
2080b57cec5SDimitry Andric   return Error::success();
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
211480093f4SDimitry Andric JITLinkContext::LookupMap JITLinkerBase::getExternalSymbolNames() const {
2128bcb0991SDimitry Andric   // Identify unresolved external symbols.
213480093f4SDimitry Andric   JITLinkContext::LookupMap UnresolvedExternals;
2148bcb0991SDimitry Andric   for (auto *Sym : G->external_symbols()) {
21504eeddc0SDimitry Andric     assert(!Sym->getAddress() &&
2160b57cec5SDimitry Andric            "External has already been assigned an address");
2178bcb0991SDimitry Andric     assert(Sym->getName() != StringRef() && Sym->getName() != "" &&
2180b57cec5SDimitry Andric            "Externals must be named");
219480093f4SDimitry Andric     SymbolLookupFlags LookupFlags =
220bdd1243dSDimitry Andric         Sym->isWeaklyReferenced() ? SymbolLookupFlags::WeaklyReferencedSymbol
221480093f4SDimitry Andric                                   : SymbolLookupFlags::RequiredSymbol;
222480093f4SDimitry Andric     UnresolvedExternals[Sym->getName()] = LookupFlags;
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric   return UnresolvedExternals;
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric void JITLinkerBase::applyLookupResult(AsyncLookupResult Result) {
2288bcb0991SDimitry Andric   for (auto *Sym : G->external_symbols()) {
229480093f4SDimitry Andric     assert(Sym->getOffset() == 0 &&
230480093f4SDimitry Andric            "External symbol is not at the start of its addressable block");
23104eeddc0SDimitry Andric     assert(!Sym->getAddress() && "Symbol already resolved");
2328bcb0991SDimitry Andric     assert(!Sym->isDefined() && "Symbol being resolved is already defined");
233480093f4SDimitry Andric     auto ResultI = Result.find(Sym->getName());
234bdd1243dSDimitry Andric     if (ResultI != Result.end()) {
23506c3fb27SDimitry Andric       Sym->getAddressable().setAddress(ResultI->second.getAddress());
236bdd1243dSDimitry Andric       Sym->setLinkage(ResultI->second.getFlags().isWeak() ? Linkage::Weak
237bdd1243dSDimitry Andric                                                           : Linkage::Strong);
238bdd1243dSDimitry Andric       Sym->setScope(ResultI->second.getFlags().isExported() ? Scope::Default
239bdd1243dSDimitry Andric                                                             : Scope::Hidden);
240bdd1243dSDimitry Andric     } else
241bdd1243dSDimitry Andric       assert(Sym->isWeaklyReferenced() &&
242480093f4SDimitry Andric              "Failed to resolve non-weak reference");
2430b57cec5SDimitry Andric   }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   LLVM_DEBUG({
2460b57cec5SDimitry Andric     dbgs() << "Externals after applying lookup result:\n";
247bdd1243dSDimitry Andric     for (auto *Sym : G->external_symbols()) {
2488bcb0991SDimitry Andric       dbgs() << "  " << Sym->getName() << ": "
249bdd1243dSDimitry Andric              << formatv("{0:x16}", Sym->getAddress().getValue());
250bdd1243dSDimitry Andric       switch (Sym->getLinkage()) {
251bdd1243dSDimitry Andric       case Linkage::Strong:
252bdd1243dSDimitry Andric         break;
253bdd1243dSDimitry Andric       case Linkage::Weak:
254bdd1243dSDimitry Andric         dbgs() << " (weak)";
255bdd1243dSDimitry Andric         break;
256bdd1243dSDimitry Andric       }
257bdd1243dSDimitry Andric       switch (Sym->getScope()) {
258bdd1243dSDimitry Andric       case Scope::Local:
259bdd1243dSDimitry Andric         llvm_unreachable("External symbol should not have local linkage");
260bdd1243dSDimitry Andric       case Scope::Hidden:
261bdd1243dSDimitry Andric         break;
262bdd1243dSDimitry Andric       case Scope::Default:
263bdd1243dSDimitry Andric         dbgs() << " (exported)";
264bdd1243dSDimitry Andric         break;
265bdd1243dSDimitry Andric       }
266bdd1243dSDimitry Andric       dbgs() << "\n";
267bdd1243dSDimitry Andric     }
2680b57cec5SDimitry Andric   });
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric 
271349cc55cSDimitry Andric void JITLinkerBase::abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self,
272349cc55cSDimitry Andric                                            Error Err) {
2730b57cec5SDimitry Andric   assert(Err && "Should not be bailing out on success value");
274349cc55cSDimitry Andric   assert(Alloc && "can not call abandonAllocAndBailOut before allocation");
275349cc55cSDimitry Andric   Alloc->abandon([S = std::move(Self), E1 = std::move(Err)](Error E2) mutable {
276349cc55cSDimitry Andric     S->Ctx->notifyFailed(joinErrors(std::move(E1), std::move(E2)));
277349cc55cSDimitry Andric   });
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2808bcb0991SDimitry Andric void prune(LinkGraph &G) {
2818bcb0991SDimitry Andric   std::vector<Symbol *> Worklist;
2828bcb0991SDimitry Andric   DenseSet<Block *> VisitedBlocks;
2830b57cec5SDimitry Andric 
2848bcb0991SDimitry Andric   // Build the initial worklist from all symbols initially live.
2858bcb0991SDimitry Andric   for (auto *Sym : G.defined_symbols())
2868bcb0991SDimitry Andric     if (Sym->isLive())
2878bcb0991SDimitry Andric       Worklist.push_back(Sym);
2880b57cec5SDimitry Andric 
2898bcb0991SDimitry Andric   // Propagate live flags to all symbols reachable from the initial live set.
2900b57cec5SDimitry Andric   while (!Worklist.empty()) {
2918bcb0991SDimitry Andric     auto *Sym = Worklist.back();
2920b57cec5SDimitry Andric     Worklist.pop_back();
2930b57cec5SDimitry Andric 
2948bcb0991SDimitry Andric     auto &B = Sym->getBlock();
2950b57cec5SDimitry Andric 
2968bcb0991SDimitry Andric     // Skip addressables that we've visited before.
2978bcb0991SDimitry Andric     if (VisitedBlocks.count(&B))
2980b57cec5SDimitry Andric       continue;
2990b57cec5SDimitry Andric 
3008bcb0991SDimitry Andric     VisitedBlocks.insert(&B);
3010b57cec5SDimitry Andric 
3028bcb0991SDimitry Andric     for (auto &E : Sym->getBlock().edges()) {
303e8d8bef9SDimitry Andric       // If the edge target is a defined symbol that is being newly marked live
304e8d8bef9SDimitry Andric       // then add it to the worklist.
305e8d8bef9SDimitry Andric       if (E.getTarget().isDefined() && !E.getTarget().isLive())
3068bcb0991SDimitry Andric         Worklist.push_back(&E.getTarget());
307e8d8bef9SDimitry Andric 
308e8d8bef9SDimitry Andric       // Mark the target live.
309e8d8bef9SDimitry Andric       E.getTarget().setLive(true);
3100b57cec5SDimitry Andric     }
3110b57cec5SDimitry Andric   }
3120b57cec5SDimitry Andric 
313e8d8bef9SDimitry Andric   // Collect all defined symbols to remove, then remove them.
3140b57cec5SDimitry Andric   {
315e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << "Dead-stripping defined symbols:\n");
3168bcb0991SDimitry Andric     std::vector<Symbol *> SymbolsToRemove;
3178bcb0991SDimitry Andric     for (auto *Sym : G.defined_symbols())
3188bcb0991SDimitry Andric       if (!Sym->isLive())
3198bcb0991SDimitry Andric         SymbolsToRemove.push_back(Sym);
3208bcb0991SDimitry Andric     for (auto *Sym : SymbolsToRemove) {
3218bcb0991SDimitry Andric       LLVM_DEBUG(dbgs() << "  " << *Sym << "...\n");
3228bcb0991SDimitry Andric       G.removeDefinedSymbol(*Sym);
3238bcb0991SDimitry Andric     }
3248bcb0991SDimitry Andric   }
3258bcb0991SDimitry Andric 
3268bcb0991SDimitry Andric   // Delete any unused blocks.
3278bcb0991SDimitry Andric   {
3288bcb0991SDimitry Andric     LLVM_DEBUG(dbgs() << "Dead-stripping blocks:\n");
3298bcb0991SDimitry Andric     std::vector<Block *> BlocksToRemove;
3308bcb0991SDimitry Andric     for (auto *B : G.blocks())
3318bcb0991SDimitry Andric       if (!VisitedBlocks.count(B))
3328bcb0991SDimitry Andric         BlocksToRemove.push_back(B);
3338bcb0991SDimitry Andric     for (auto *B : BlocksToRemove) {
3348bcb0991SDimitry Andric       LLVM_DEBUG(dbgs() << "  " << *B << "...\n");
3358bcb0991SDimitry Andric       G.removeBlock(*B);
3368bcb0991SDimitry Andric     }
3370b57cec5SDimitry Andric   }
338e8d8bef9SDimitry Andric 
339e8d8bef9SDimitry Andric   // Collect all external symbols to remove, then remove them.
340e8d8bef9SDimitry Andric   {
341e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << "Removing unused external symbols:\n");
342e8d8bef9SDimitry Andric     std::vector<Symbol *> SymbolsToRemove;
343e8d8bef9SDimitry Andric     for (auto *Sym : G.external_symbols())
344e8d8bef9SDimitry Andric       if (!Sym->isLive())
345e8d8bef9SDimitry Andric         SymbolsToRemove.push_back(Sym);
346e8d8bef9SDimitry Andric     for (auto *Sym : SymbolsToRemove) {
347e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "  " << *Sym << "...\n");
348e8d8bef9SDimitry Andric       G.removeExternalSymbol(*Sym);
349e8d8bef9SDimitry Andric     }
350e8d8bef9SDimitry Andric   }
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric } // end namespace jitlink
3540b57cec5SDimitry Andric } // end namespace llvm
355