xref: /llvm-project/bolt/lib/Passes/LongJmp.cpp (revision be2f67c4d87deb513ba200ab3f4dba385faf709a)
1 //===- bolt/Passes/LongJmp.cpp --------------------------------------------===//
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 // This file implements the LongJmpPass class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "bolt/Passes/LongJmp.h"
14 
15 #define DEBUG_TYPE "longjmp"
16 
17 using namespace llvm;
18 
19 namespace opts {
20 extern cl::OptionCategory BoltOptCategory;
21 extern llvm::cl::opt<unsigned> AlignText;
22 extern cl::opt<unsigned> AlignFunctions;
23 extern cl::opt<bool> UseOldText;
24 extern cl::opt<bool> HotFunctionsAtEnd;
25 
26 static cl::opt<bool> GroupStubs("group-stubs",
27                                 cl::desc("share stubs across functions"),
28                                 cl::init(true), cl::cat(BoltOptCategory));
29 }
30 
31 namespace llvm {
32 namespace bolt {
33 
34 constexpr unsigned ColdFragAlign = 16;
35 
36 static void relaxStubToShortJmp(BinaryBasicBlock &StubBB, const MCSymbol *Tgt) {
37   const BinaryContext &BC = StubBB.getFunction()->getBinaryContext();
38   InstructionListType Seq;
39   BC.MIB->createShortJmp(Seq, Tgt, BC.Ctx.get());
40   StubBB.clear();
41   StubBB.addInstructions(Seq.begin(), Seq.end());
42 }
43 
44 static void relaxStubToLongJmp(BinaryBasicBlock &StubBB, const MCSymbol *Tgt) {
45   const BinaryContext &BC = StubBB.getFunction()->getBinaryContext();
46   InstructionListType Seq;
47   BC.MIB->createLongJmp(Seq, Tgt, BC.Ctx.get());
48   StubBB.clear();
49   StubBB.addInstructions(Seq.begin(), Seq.end());
50 }
51 
52 static BinaryBasicBlock *getBBAtHotColdSplitPoint(BinaryFunction &Func) {
53   if (!Func.isSplit() || Func.empty())
54     return nullptr;
55 
56   assert(!(*Func.begin()).isCold() && "Entry cannot be cold");
57   for (auto I = Func.getLayout().block_begin(),
58             E = Func.getLayout().block_end();
59        I != E; ++I) {
60     auto Next = std::next(I);
61     if (Next != E && (*Next)->isCold())
62       return *I;
63   }
64   llvm_unreachable("No hot-colt split point found");
65 }
66 
67 static bool shouldInsertStub(const BinaryContext &BC, const MCInst &Inst) {
68   return (BC.MIB->isBranch(Inst) || BC.MIB->isCall(Inst)) &&
69          !BC.MIB->isIndirectBranch(Inst) && !BC.MIB->isIndirectCall(Inst);
70 }
71 
72 std::pair<std::unique_ptr<BinaryBasicBlock>, MCSymbol *>
73 LongJmpPass::createNewStub(BinaryBasicBlock &SourceBB, const MCSymbol *TgtSym,
74                            bool TgtIsFunc, uint64_t AtAddress) {
75   BinaryFunction &Func = *SourceBB.getFunction();
76   const BinaryContext &BC = Func.getBinaryContext();
77   const bool IsCold = SourceBB.isCold();
78   MCSymbol *StubSym = BC.Ctx->createNamedTempSymbol("Stub");
79   std::unique_ptr<BinaryBasicBlock> StubBB = Func.createBasicBlock(StubSym);
80   MCInst Inst;
81   BC.MIB->createUncondBranch(Inst, TgtSym, BC.Ctx.get());
82   if (TgtIsFunc)
83     BC.MIB->convertJmpToTailCall(Inst);
84   StubBB->addInstruction(Inst);
85   StubBB->setExecutionCount(0);
86 
87   // Register this in stubs maps
88   auto registerInMap = [&](StubGroupsTy &Map) {
89     StubGroupTy &StubGroup = Map[TgtSym];
90     StubGroup.insert(
91         llvm::lower_bound(
92             StubGroup, std::make_pair(AtAddress, nullptr),
93             [&](const std::pair<uint64_t, BinaryBasicBlock *> &LHS,
94                 const std::pair<uint64_t, BinaryBasicBlock *> &RHS) {
95               return LHS.first < RHS.first;
96             }),
97         std::make_pair(AtAddress, StubBB.get()));
98   };
99 
100   Stubs[&Func].insert(StubBB.get());
101   StubBits[StubBB.get()] = BC.MIB->getUncondBranchEncodingSize();
102   if (IsCold) {
103     registerInMap(ColdLocalStubs[&Func]);
104     if (opts::GroupStubs && TgtIsFunc)
105       registerInMap(ColdStubGroups);
106     ++NumColdStubs;
107   } else {
108     registerInMap(HotLocalStubs[&Func]);
109     if (opts::GroupStubs && TgtIsFunc)
110       registerInMap(HotStubGroups);
111     ++NumHotStubs;
112   }
113 
114   return std::make_pair(std::move(StubBB), StubSym);
115 }
116 
117 BinaryBasicBlock *LongJmpPass::lookupStubFromGroup(
118     const StubGroupsTy &StubGroups, const BinaryFunction &Func,
119     const MCInst &Inst, const MCSymbol *TgtSym, uint64_t DotAddress) const {
120   const BinaryContext &BC = Func.getBinaryContext();
121   auto CandidatesIter = StubGroups.find(TgtSym);
122   if (CandidatesIter == StubGroups.end())
123     return nullptr;
124   const StubGroupTy &Candidates = CandidatesIter->second;
125   if (Candidates.empty())
126     return nullptr;
127   auto Cand = llvm::lower_bound(
128       Candidates, std::make_pair(DotAddress, nullptr),
129       [&](const std::pair<uint64_t, BinaryBasicBlock *> &LHS,
130           const std::pair<uint64_t, BinaryBasicBlock *> &RHS) {
131         return LHS.first < RHS.first;
132       });
133   if (Cand == Candidates.end())
134     return nullptr;
135   if (Cand != Candidates.begin()) {
136     const StubTy *LeftCand = std::prev(Cand);
137     if (Cand->first - DotAddress > DotAddress - LeftCand->first)
138       Cand = LeftCand;
139   }
140   int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
141   uint64_t Mask = ~((1ULL << BitsAvail) - 1);
142   uint64_t PCRelTgtAddress = Cand->first;
143   PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
144                                                  : PCRelTgtAddress - DotAddress;
145   LLVM_DEBUG({
146     if (Candidates.size() > 1)
147       dbgs() << "Considering stub group with " << Candidates.size()
148              << " candidates. DotAddress is " << Twine::utohexstr(DotAddress)
149              << ", chosen candidate address is "
150              << Twine::utohexstr(Cand->first) << "\n";
151   });
152   return PCRelTgtAddress & Mask ? nullptr : Cand->second;
153 }
154 
155 BinaryBasicBlock *
156 LongJmpPass::lookupGlobalStub(const BinaryBasicBlock &SourceBB,
157                               const MCInst &Inst, const MCSymbol *TgtSym,
158                               uint64_t DotAddress) const {
159   const BinaryFunction &Func = *SourceBB.getFunction();
160   const StubGroupsTy &StubGroups =
161       SourceBB.isCold() ? ColdStubGroups : HotStubGroups;
162   return lookupStubFromGroup(StubGroups, Func, Inst, TgtSym, DotAddress);
163 }
164 
165 BinaryBasicBlock *LongJmpPass::lookupLocalStub(const BinaryBasicBlock &SourceBB,
166                                                const MCInst &Inst,
167                                                const MCSymbol *TgtSym,
168                                                uint64_t DotAddress) const {
169   const BinaryFunction &Func = *SourceBB.getFunction();
170   const DenseMap<const BinaryFunction *, StubGroupsTy> &StubGroups =
171       SourceBB.isCold() ? ColdLocalStubs : HotLocalStubs;
172   const auto Iter = StubGroups.find(&Func);
173   if (Iter == StubGroups.end())
174     return nullptr;
175   return lookupStubFromGroup(Iter->second, Func, Inst, TgtSym, DotAddress);
176 }
177 
178 std::unique_ptr<BinaryBasicBlock>
179 LongJmpPass::replaceTargetWithStub(BinaryBasicBlock &BB, MCInst &Inst,
180                                    uint64_t DotAddress,
181                                    uint64_t StubCreationAddress) {
182   const BinaryFunction &Func = *BB.getFunction();
183   const BinaryContext &BC = Func.getBinaryContext();
184   std::unique_ptr<BinaryBasicBlock> NewBB;
185   const MCSymbol *TgtSym = BC.MIB->getTargetSymbol(Inst);
186   assert(TgtSym && "getTargetSymbol failed");
187 
188   BinaryBasicBlock::BinaryBranchInfo BI{0, 0};
189   BinaryBasicBlock *TgtBB = BB.getSuccessor(TgtSym, BI);
190   auto LocalStubsIter = Stubs.find(&Func);
191 
192   // If already using stub and the stub is from another function, create a local
193   // stub, since the foreign stub is now out of range
194   if (!TgtBB) {
195     auto SSIter = SharedStubs.find(TgtSym);
196     if (SSIter != SharedStubs.end()) {
197       TgtSym = BC.MIB->getTargetSymbol(*SSIter->second->begin());
198       --NumSharedStubs;
199     }
200   } else if (LocalStubsIter != Stubs.end() &&
201              LocalStubsIter->second.count(TgtBB)) {
202     // If we are replacing a local stub (because it is now out of range),
203     // use its target instead of creating a stub to jump to another stub
204     TgtSym = BC.MIB->getTargetSymbol(*TgtBB->begin());
205     TgtBB = BB.getSuccessor(TgtSym, BI);
206   }
207 
208   BinaryBasicBlock *StubBB = lookupLocalStub(BB, Inst, TgtSym, DotAddress);
209   // If not found, look it up in globally shared stub maps if it is a function
210   // call (TgtBB is not set)
211   if (!StubBB && !TgtBB) {
212     StubBB = lookupGlobalStub(BB, Inst, TgtSym, DotAddress);
213     if (StubBB) {
214       SharedStubs[StubBB->getLabel()] = StubBB;
215       ++NumSharedStubs;
216     }
217   }
218   MCSymbol *StubSymbol = StubBB ? StubBB->getLabel() : nullptr;
219 
220   if (!StubBB) {
221     std::tie(NewBB, StubSymbol) =
222         createNewStub(BB, TgtSym, /*is func?*/ !TgtBB, StubCreationAddress);
223     StubBB = NewBB.get();
224   }
225 
226   // Local branch
227   if (TgtBB) {
228     uint64_t OrigCount = BI.Count;
229     uint64_t OrigMispreds = BI.MispredictedCount;
230     BB.replaceSuccessor(TgtBB, StubBB, OrigCount, OrigMispreds);
231     StubBB->setExecutionCount(StubBB->getExecutionCount() + OrigCount);
232     if (NewBB) {
233       StubBB->addSuccessor(TgtBB, OrigCount, OrigMispreds);
234       StubBB->setIsCold(BB.isCold());
235     }
236     // Call / tail call
237   } else {
238     StubBB->setExecutionCount(StubBB->getExecutionCount() +
239                               BB.getExecutionCount());
240     if (NewBB) {
241       assert(TgtBB == nullptr);
242       StubBB->setIsCold(BB.isCold());
243       // Set as entry point because this block is valid but we have no preds
244       StubBB->getFunction()->addEntryPoint(*StubBB);
245     }
246   }
247   BC.MIB->replaceBranchTarget(Inst, StubSymbol, BC.Ctx.get());
248 
249   return NewBB;
250 }
251 
252 void LongJmpPass::updateStubGroups() {
253   auto update = [&](StubGroupsTy &StubGroups) {
254     for (auto &KeyVal : StubGroups) {
255       for (StubTy &Elem : KeyVal.second)
256         Elem.first = BBAddresses[Elem.second];
257       llvm::sort(KeyVal.second, llvm::less_first());
258     }
259   };
260 
261   for (auto &KeyVal : HotLocalStubs)
262     update(KeyVal.second);
263   for (auto &KeyVal : ColdLocalStubs)
264     update(KeyVal.second);
265   update(HotStubGroups);
266   update(ColdStubGroups);
267 }
268 
269 void LongJmpPass::tentativeBBLayout(const BinaryFunction &Func) {
270   const BinaryContext &BC = Func.getBinaryContext();
271   uint64_t HotDot = HotAddresses[&Func];
272   uint64_t ColdDot = ColdAddresses[&Func];
273   bool Cold = false;
274   for (const BinaryBasicBlock *BB : Func.getLayout().blocks()) {
275     if (Cold || BB->isCold()) {
276       Cold = true;
277       BBAddresses[BB] = ColdDot;
278       ColdDot += BC.computeCodeSize(BB->begin(), BB->end());
279     } else {
280       BBAddresses[BB] = HotDot;
281       HotDot += BC.computeCodeSize(BB->begin(), BB->end());
282     }
283   }
284 }
285 
286 uint64_t LongJmpPass::tentativeLayoutRelocColdPart(
287     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions,
288     uint64_t DotAddress) {
289   DotAddress = alignTo(DotAddress, llvm::Align(opts::AlignFunctions));
290   for (BinaryFunction *Func : SortedFunctions) {
291     if (!Func->isSplit())
292       continue;
293     DotAddress = alignTo(DotAddress, BinaryFunction::MinAlign);
294     uint64_t Pad =
295         offsetToAlignment(DotAddress, llvm::Align(Func->getAlignment()));
296     if (Pad <= Func->getMaxColdAlignmentBytes())
297       DotAddress += Pad;
298     ColdAddresses[Func] = DotAddress;
299     LLVM_DEBUG(dbgs() << Func->getPrintName() << " cold tentative: "
300                       << Twine::utohexstr(DotAddress) << "\n");
301     DotAddress += Func->estimateColdSize();
302     DotAddress = alignTo(DotAddress, Func->getConstantIslandAlignment());
303     DotAddress += Func->estimateConstantIslandSize();
304   }
305   return DotAddress;
306 }
307 
308 uint64_t LongJmpPass::tentativeLayoutRelocMode(
309     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions,
310     uint64_t DotAddress) {
311 
312   // Compute hot cold frontier
313   uint32_t LastHotIndex = -1u;
314   uint32_t CurrentIndex = 0;
315   if (opts::HotFunctionsAtEnd) {
316     for (BinaryFunction *BF : SortedFunctions) {
317       if (BF->hasValidIndex()) {
318         LastHotIndex = CurrentIndex;
319         break;
320       }
321 
322       ++CurrentIndex;
323     }
324   } else {
325     for (BinaryFunction *BF : SortedFunctions) {
326       if (!BF->hasValidIndex()) {
327         LastHotIndex = CurrentIndex;
328         break;
329       }
330 
331       ++CurrentIndex;
332     }
333   }
334 
335   // Hot
336   CurrentIndex = 0;
337   bool ColdLayoutDone = false;
338   for (BinaryFunction *Func : SortedFunctions) {
339     if (!BC.shouldEmit(*Func)) {
340       HotAddresses[Func] = Func->getAddress();
341       continue;
342     }
343 
344     if (!ColdLayoutDone && CurrentIndex >= LastHotIndex) {
345       DotAddress =
346           tentativeLayoutRelocColdPart(BC, SortedFunctions, DotAddress);
347       ColdLayoutDone = true;
348       if (opts::HotFunctionsAtEnd)
349         DotAddress = alignTo(DotAddress, opts::AlignText);
350     }
351 
352     DotAddress = alignTo(DotAddress, BinaryFunction::MinAlign);
353     uint64_t Pad =
354         offsetToAlignment(DotAddress, llvm::Align(Func->getAlignment()));
355     if (Pad <= Func->getMaxAlignmentBytes())
356       DotAddress += Pad;
357     HotAddresses[Func] = DotAddress;
358     LLVM_DEBUG(dbgs() << Func->getPrintName() << " tentative: "
359                       << Twine::utohexstr(DotAddress) << "\n");
360     if (!Func->isSplit())
361       DotAddress += Func->estimateSize();
362     else
363       DotAddress += Func->estimateHotSize();
364 
365     DotAddress = alignTo(DotAddress, Func->getConstantIslandAlignment());
366     DotAddress += Func->estimateConstantIslandSize();
367     ++CurrentIndex;
368   }
369   // BBs
370   for (BinaryFunction *Func : SortedFunctions)
371     tentativeBBLayout(*Func);
372 
373   return DotAddress;
374 }
375 
376 void LongJmpPass::tentativeLayout(
377     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions) {
378   uint64_t DotAddress = BC.LayoutStartAddress;
379 
380   if (!BC.HasRelocations) {
381     for (BinaryFunction *Func : SortedFunctions) {
382       HotAddresses[Func] = Func->getAddress();
383       DotAddress = alignTo(DotAddress, ColdFragAlign);
384       ColdAddresses[Func] = DotAddress;
385       if (Func->isSplit())
386         DotAddress += Func->estimateColdSize();
387       tentativeBBLayout(*Func);
388     }
389 
390     return;
391   }
392 
393   // Relocation mode
394   uint64_t EstimatedTextSize = 0;
395   if (opts::UseOldText) {
396     EstimatedTextSize = tentativeLayoutRelocMode(BC, SortedFunctions, 0);
397 
398     // Initial padding
399     if (EstimatedTextSize <= BC.OldTextSectionSize) {
400       DotAddress = BC.OldTextSectionAddress;
401       uint64_t Pad =
402           offsetToAlignment(DotAddress, llvm::Align(opts::AlignText));
403       if (Pad + EstimatedTextSize <= BC.OldTextSectionSize) {
404         DotAddress += Pad;
405       }
406     }
407   }
408 
409   if (!EstimatedTextSize || EstimatedTextSize > BC.OldTextSectionSize)
410     DotAddress = alignTo(BC.LayoutStartAddress, opts::AlignText);
411 
412   tentativeLayoutRelocMode(BC, SortedFunctions, DotAddress);
413 }
414 
415 bool LongJmpPass::usesStub(const BinaryFunction &Func,
416                            const MCInst &Inst) const {
417   const MCSymbol *TgtSym = Func.getBinaryContext().MIB->getTargetSymbol(Inst);
418   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(TgtSym);
419   auto Iter = Stubs.find(&Func);
420   if (Iter != Stubs.end())
421     return Iter->second.count(TgtBB);
422   return false;
423 }
424 
425 uint64_t LongJmpPass::getSymbolAddress(const BinaryContext &BC,
426                                        const MCSymbol *Target,
427                                        const BinaryBasicBlock *TgtBB) const {
428   if (TgtBB) {
429     auto Iter = BBAddresses.find(TgtBB);
430     assert(Iter != BBAddresses.end() && "Unrecognized BB");
431     return Iter->second;
432   }
433   uint64_t EntryID = 0;
434   const BinaryFunction *TargetFunc = BC.getFunctionForSymbol(Target, &EntryID);
435   auto Iter = HotAddresses.find(TargetFunc);
436   if (Iter == HotAddresses.end() || (TargetFunc && EntryID)) {
437     // Look at BinaryContext's resolution for this symbol - this is a symbol not
438     // mapped to a BinaryFunction
439     ErrorOr<uint64_t> ValueOrError = BC.getSymbolValue(*Target);
440     assert(ValueOrError && "Unrecognized symbol");
441     return *ValueOrError;
442   }
443   return Iter->second;
444 }
445 
446 bool LongJmpPass::relaxStub(BinaryBasicBlock &StubBB) {
447   const BinaryFunction &Func = *StubBB.getFunction();
448   const BinaryContext &BC = Func.getBinaryContext();
449   const int Bits = StubBits[&StubBB];
450   // Already working with the largest range?
451   if (Bits == static_cast<int>(BC.AsmInfo->getCodePointerSize() * 8))
452     return false;
453 
454   const static int RangeShortJmp = BC.MIB->getShortJmpEncodingSize();
455   const static int RangeSingleInstr = BC.MIB->getUncondBranchEncodingSize();
456   const static uint64_t ShortJmpMask = ~((1ULL << RangeShortJmp) - 1);
457   const static uint64_t SingleInstrMask =
458       ~((1ULL << (RangeSingleInstr - 1)) - 1);
459 
460   const MCSymbol *RealTargetSym = BC.MIB->getTargetSymbol(*StubBB.begin());
461   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(RealTargetSym);
462   uint64_t TgtAddress = getSymbolAddress(BC, RealTargetSym, TgtBB);
463   uint64_t DotAddress = BBAddresses[&StubBB];
464   uint64_t PCRelTgtAddress = DotAddress > TgtAddress ? DotAddress - TgtAddress
465                                                      : TgtAddress - DotAddress;
466   // If it fits in one instruction, do not relax
467   if (!(PCRelTgtAddress & SingleInstrMask))
468     return false;
469 
470   // Fits short jmp
471   if (!(PCRelTgtAddress & ShortJmpMask)) {
472     if (Bits >= RangeShortJmp)
473       return false;
474 
475     LLVM_DEBUG(dbgs() << "Relaxing stub to short jump. PCRelTgtAddress = "
476                       << Twine::utohexstr(PCRelTgtAddress)
477                       << " RealTargetSym = " << RealTargetSym->getName()
478                       << "\n");
479     relaxStubToShortJmp(StubBB, RealTargetSym);
480     StubBits[&StubBB] = RangeShortJmp;
481     return true;
482   }
483 
484   // The long jmp uses absolute address on AArch64
485   // So we could not use it for PIC binaries
486   if (BC.isAArch64() && !BC.HasFixedLoadAddress) {
487     errs() << "BOLT-ERROR: Unable to relax stub for PIC binary\n";
488     exit(1);
489   }
490 
491   LLVM_DEBUG(dbgs() << "Relaxing stub to long jump. PCRelTgtAddress = "
492                     << Twine::utohexstr(PCRelTgtAddress)
493                     << " RealTargetSym = " << RealTargetSym->getName() << "\n");
494   relaxStubToLongJmp(StubBB, RealTargetSym);
495   StubBits[&StubBB] = static_cast<int>(BC.AsmInfo->getCodePointerSize() * 8);
496   return true;
497 }
498 
499 bool LongJmpPass::needsStub(const BinaryBasicBlock &BB, const MCInst &Inst,
500                             uint64_t DotAddress) const {
501   const BinaryFunction &Func = *BB.getFunction();
502   const BinaryContext &BC = Func.getBinaryContext();
503   const MCSymbol *TgtSym = BC.MIB->getTargetSymbol(Inst);
504   assert(TgtSym && "getTargetSymbol failed");
505 
506   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(TgtSym);
507   // Check for shared stubs from foreign functions
508   if (!TgtBB) {
509     auto SSIter = SharedStubs.find(TgtSym);
510     if (SSIter != SharedStubs.end())
511       TgtBB = SSIter->second;
512   }
513 
514   int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
515   uint64_t Mask = ~((1ULL << BitsAvail) - 1);
516 
517   uint64_t PCRelTgtAddress = getSymbolAddress(BC, TgtSym, TgtBB);
518   PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
519                                                  : PCRelTgtAddress - DotAddress;
520 
521   return PCRelTgtAddress & Mask;
522 }
523 
524 bool LongJmpPass::relax(BinaryFunction &Func) {
525   const BinaryContext &BC = Func.getBinaryContext();
526   bool Modified = false;
527 
528   assert(BC.isAArch64() && "Unsupported arch");
529   constexpr int InsnSize = 4; // AArch64
530   std::vector<std::pair<BinaryBasicBlock *, std::unique_ptr<BinaryBasicBlock>>>
531       Insertions;
532 
533   BinaryBasicBlock *Frontier = getBBAtHotColdSplitPoint(Func);
534   uint64_t FrontierAddress = Frontier ? BBAddresses[Frontier] : 0;
535   if (FrontierAddress)
536     FrontierAddress += Frontier->getNumNonPseudos() * InsnSize;
537 
538   // Add necessary stubs for branch targets we know we can't fit in the
539   // instruction
540   for (BinaryBasicBlock &BB : Func) {
541     uint64_t DotAddress = BBAddresses[&BB];
542     // Stubs themselves are relaxed on the next loop
543     if (Stubs[&Func].count(&BB))
544       continue;
545 
546     for (MCInst &Inst : BB) {
547       if (BC.MIB->isPseudo(Inst))
548         continue;
549 
550       if (!shouldInsertStub(BC, Inst)) {
551         DotAddress += InsnSize;
552         continue;
553       }
554 
555       // Check and relax direct branch or call
556       if (!needsStub(BB, Inst, DotAddress)) {
557         DotAddress += InsnSize;
558         continue;
559       }
560       Modified = true;
561 
562       // Insert stubs close to the patched BB if call, but far away from the
563       // hot path if a branch, since this branch target is the cold region
564       // (but first check that the far away stub will be in range).
565       BinaryBasicBlock *InsertionPoint = &BB;
566       if (Func.isSimple() && !BC.MIB->isCall(Inst) && FrontierAddress &&
567           !BB.isCold()) {
568         int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
569         uint64_t Mask = ~((1ULL << BitsAvail) - 1);
570         assert(FrontierAddress > DotAddress &&
571                "Hot code should be before the frontier");
572         uint64_t PCRelTgt = FrontierAddress - DotAddress;
573         if (!(PCRelTgt & Mask))
574           InsertionPoint = Frontier;
575       }
576       // Always put stubs at the end of the function if non-simple. We can't
577       // change the layout of non-simple functions because it has jump tables
578       // that we do not control.
579       if (!Func.isSimple())
580         InsertionPoint = &*std::prev(Func.end());
581 
582       // Create a stub to handle a far-away target
583       Insertions.emplace_back(InsertionPoint,
584                               replaceTargetWithStub(BB, Inst, DotAddress,
585                                                     InsertionPoint == Frontier
586                                                         ? FrontierAddress
587                                                         : DotAddress));
588 
589       DotAddress += InsnSize;
590     }
591   }
592 
593   // Relax stubs if necessary
594   for (BinaryBasicBlock &BB : Func) {
595     if (!Stubs[&Func].count(&BB) || !BB.isValid())
596       continue;
597 
598     Modified |= relaxStub(BB);
599   }
600 
601   for (std::pair<BinaryBasicBlock *, std::unique_ptr<BinaryBasicBlock>> &Elmt :
602        Insertions) {
603     if (!Elmt.second)
604       continue;
605     std::vector<std::unique_ptr<BinaryBasicBlock>> NewBBs;
606     NewBBs.emplace_back(std::move(Elmt.second));
607     Func.insertBasicBlocks(Elmt.first, std::move(NewBBs), true);
608   }
609 
610   return Modified;
611 }
612 
613 void LongJmpPass::runOnFunctions(BinaryContext &BC) {
614   outs() << "BOLT-INFO: Starting stub-insertion pass\n";
615   std::vector<BinaryFunction *> Sorted = BC.getSortedFunctions();
616   bool Modified;
617   uint32_t Iterations = 0;
618   do {
619     ++Iterations;
620     Modified = false;
621     tentativeLayout(BC, Sorted);
622     updateStubGroups();
623     for (BinaryFunction *Func : Sorted) {
624       if (relax(*Func)) {
625         // Don't ruin non-simple functions, they can't afford to have the layout
626         // changed.
627         if (Func->isSimple())
628           Func->fixBranches();
629         Modified = true;
630       }
631     }
632   } while (Modified);
633   outs() << "BOLT-INFO: Inserted " << NumHotStubs
634          << " stubs in the hot area and " << NumColdStubs
635          << " stubs in the cold area. Shared " << NumSharedStubs
636          << " times, iterated " << Iterations << " times.\n";
637 }
638 } // namespace bolt
639 } // namespace llvm
640