xref: /llvm-project/bolt/include/bolt/Passes/ShrinkWrapping.h (revision 52cf07116bf0a8cab87b0f55176d198bcaa02575)
1 //===- bolt/Passes/ShrinkWrapping.h -----------------------------*- C++ -*-===//
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 #ifndef BOLT_PASSES_SHRINKWRAPPING_H
10 #define BOLT_PASSES_SHRINKWRAPPING_H
11 
12 #include "bolt/Passes/FrameAnalysis.h"
13 #include "llvm/MC/MCRegisterInfo.h"
14 #include <atomic>
15 
16 namespace llvm {
17 namespace bolt {
18 class DataflowInfoManager;
19 
20 /// Encapsulates logic required to analyze a binary function and detect which
21 /// registers are being saved as callee-saved, where are these saves and where
22 /// are the points where their original value are being restored.
23 class CalleeSavedAnalysis {
24   const FrameAnalysis &FA;
25   const BinaryContext &BC;
26   BinaryFunction &BF;
27   DataflowInfoManager &Info;
28   MCPlusBuilder::AllocatorIdTy AllocatorId;
29 
30   std::optional<unsigned> SaveTagIndex;
31   std::optional<unsigned> RestoreTagIndex;
32 
33   /// Compute all stores of callee-saved regs. Those are the ones that stores a
34   /// register whose definition is not local.
35   void analyzeSaves();
36 
37   /// Similar to analyzeSaves, tries to determine all instructions that recover
38   /// the original value of the callee-saved register before exiting the
39   /// function.
40   void analyzeRestores();
41 
getSaveTag()42   unsigned getSaveTag() {
43     if (SaveTagIndex)
44       return *SaveTagIndex;
45     SaveTagIndex = BC.MIB->getOrCreateAnnotationIndex(getSaveTagName());
46     return *SaveTagIndex;
47   }
48 
getRestoreTag()49   unsigned getRestoreTag() {
50     if (RestoreTagIndex)
51       return *RestoreTagIndex;
52     RestoreTagIndex = BC.MIB->getOrCreateAnnotationIndex(getRestoreTagName());
53     return *RestoreTagIndex;
54   }
55 
56 public:
57   BitVector CalleeSaved;
58   std::vector<int64_t> OffsetsByReg;
59   BitVector HasRestores;
60   std::vector<uint64_t> SavingCost;
61   std::vector<const FrameIndexEntry *> SaveFIEByReg;
62   std::vector<const FrameIndexEntry *> LoadFIEByReg;
63 
CalleeSavedAnalysis(const FrameAnalysis & FA,BinaryFunction & BF,DataflowInfoManager & Info,MCPlusBuilder::AllocatorIdTy AllocId)64   CalleeSavedAnalysis(const FrameAnalysis &FA, BinaryFunction &BF,
65                       DataflowInfoManager &Info,
66                       MCPlusBuilder::AllocatorIdTy AllocId)
67       : FA(FA), BC(BF.getBinaryContext()), BF(BF), Info(Info),
68         AllocatorId(AllocId), CalleeSaved(BC.MRI->getNumRegs(), false),
69         OffsetsByReg(BC.MRI->getNumRegs(), 0LL),
70         HasRestores(BC.MRI->getNumRegs(), false),
71         SavingCost(BC.MRI->getNumRegs(), 0ULL),
72         SaveFIEByReg(BC.MRI->getNumRegs(), nullptr),
73         LoadFIEByReg(BC.MRI->getNumRegs(), nullptr) {}
74 
75   ~CalleeSavedAnalysis();
76 
compute()77   void compute() {
78     analyzeSaves();
79     analyzeRestores();
80   }
81 
82   /// Retrieves the value of the callee-saved register that is saved by this
83   /// instruction or 0 if this is not a CSR save instruction.
getSavedReg(const MCInst & Inst)84   uint16_t getSavedReg(const MCInst &Inst) {
85     auto Val = BC.MIB->tryGetAnnotationAs<decltype(FrameIndexEntry::RegOrImm)>(
86         Inst, getSaveTag());
87     if (Val)
88       return *Val;
89     return 0;
90   }
91 
92   /// Retrieves the value of the callee-saved register that is restored by this
93   /// instruction or 0 if this is not a CSR restore instruction.
getRestoredReg(const MCInst & Inst)94   uint16_t getRestoredReg(const MCInst &Inst) {
95     auto Val = BC.MIB->tryGetAnnotationAs<decltype(FrameIndexEntry::RegOrImm)>(
96         Inst, getRestoreTag());
97     if (Val)
98       return *Val;
99     return 0;
100   }
101 
102   /// Routines to compute all saves/restores for a Reg (needs to traverse all
103   /// instructions).
104   std::vector<MCInst *> getSavesByReg(uint16_t Reg);
105   std::vector<MCInst *> getRestoresByReg(uint16_t Reg);
106 
107   /// Returns the identifying string used to annotate instructions with metadata
108   /// for this analysis. These are deleted in the destructor.
getSaveTagName()109   static StringRef getSaveTagName() { return StringRef("CSA-SavedReg"); }
110 
getRestoreTagName()111   static StringRef getRestoreTagName() { return StringRef("CSA-RestoredReg"); }
112 };
113 
114 /// Identifies in a given binary function all stack regions being used and allow
115 /// us to edit the layout, removing or inserting new regions. When the layout is
116 /// modified, all affected stack-accessing instructions are updated.
117 class StackLayoutModifier {
118   const FrameAnalysis &FA;
119   const BinaryContext &BC;
120   BinaryFunction &BF;
121   DataflowInfoManager &Info;
122   MCPlusBuilder::AllocatorIdTy AllocatorId;
123 
124   // Keep track of stack slots we know how to safely move
125   std::map<int64_t, int64_t> AvailableRegions;
126 
127   DenseSet<int64_t> CollapsedRegions;
128   DenseSet<int64_t> InsertedRegions;
129 
130   // A map of chunks of stack memory we don't really know what's happening there
131   // and we need to leave it untouched.
132   std::map<int64_t, int64_t> BlacklistedRegions;
133 
134   // Maps stack slots to the regs that are saved to them
135   DenseMap<int64_t, std::set<MCPhysReg>> RegionToRegMap;
136   DenseMap<int, std::set<int64_t>> RegToRegionMap;
137 
138   // If we can't understand how to move stack slots, IsSimple will be false
139   bool IsSimple{true};
140 
141   bool IsInitialized{false};
142 
143   std::optional<unsigned> TodoTagIndex;
144   std::optional<unsigned> SlotTagIndex;
145   std::optional<unsigned> OffsetCFIRegTagIndex;
146 
147 public:
148   // Keep a worklist of operations to perform on the function to perform
149   // the requested layout modifications via collapseRegion()/insertRegion().
150   struct WorklistItem {
151     enum ActionType : uint8_t {
152       None = 0,
153       AdjustLoadStoreOffset,
154       AdjustCFI,
155     } Action;
156 
157     int64_t OffsetUpdate{0};
WorklistItemWorklistItem158     WorklistItem() : Action(None) {}
WorklistItemWorklistItem159     WorklistItem(ActionType Action) : Action(Action) {}
WorklistItemWorklistItem160     WorklistItem(ActionType Action, int OffsetUpdate)
161         : Action(Action), OffsetUpdate(OffsetUpdate) {}
162   };
163 
164 private:
165   /// Mark the stack region identified by \p Offset and \p Size to be a
166   /// no-touch zone, whose accesses cannot be relocated to another region.
167   void blacklistRegion(int64_t Offset, int64_t Size);
168 
169   /// Check if this region overlaps with blacklisted addresses
170   bool isRegionBlacklisted(int64_t Offset, int64_t Size);
171 
172   /// Check if the region identified by \p Offset and \p Size has any conflicts
173   /// with available regions so far. If it has, blacklist all involved regions
174   /// and return true.
175   bool blacklistAllInConflictWith(int64_t Offset, int64_t Size);
176 
177   /// If \p Point is identified as frame pointer initialization (defining the
178   /// value of FP with SP), check for non-standard initialization that precludes
179   /// us from changing the stack layout. If positive, update blacklisted
180   /// regions.
181   void checkFramePointerInitialization(MCInst &Point);
182 
183   /// If \p Point is restoring the value with SP with FP plus offset,
184   /// add a slottag to this instruction as it needs to be updated when we
185   /// change the stack layout.
186   void checkStackPointerRestore(MCInst &Point);
187 
188   /// Make sense of each stack offsets we can freely change
189   void classifyStackAccesses();
190   void classifyCFIs();
191 
192   /// Used to keep track of modifications to the function that will later be
193   /// performed by performChanges();
194   void scheduleChange(MCInst &Inst, WorklistItem Item);
195 
getTodoTag()196   unsigned getTodoTag() {
197     if (TodoTagIndex)
198       return *TodoTagIndex;
199     TodoTagIndex = BC.MIB->getOrCreateAnnotationIndex(getTodoTagName());
200     return *TodoTagIndex;
201   }
202 
getSlotTag()203   unsigned getSlotTag() {
204     if (SlotTagIndex)
205       return *SlotTagIndex;
206     SlotTagIndex = BC.MIB->getOrCreateAnnotationIndex(getSlotTagName());
207     return *SlotTagIndex;
208   }
209 
getOffsetCFIRegTag()210   unsigned getOffsetCFIRegTag() {
211     if (OffsetCFIRegTagIndex)
212       return *OffsetCFIRegTagIndex;
213     OffsetCFIRegTagIndex =
214         BC.MIB->getOrCreateAnnotationIndex(getOffsetCFIRegTagName());
215     return *OffsetCFIRegTagIndex;
216   }
217 
218 public:
StackLayoutModifier(const FrameAnalysis & FA,BinaryFunction & BF,DataflowInfoManager & Info,MCPlusBuilder::AllocatorIdTy AllocId)219   StackLayoutModifier(const FrameAnalysis &FA, BinaryFunction &BF,
220                       DataflowInfoManager &Info,
221                       MCPlusBuilder::AllocatorIdTy AllocId)
222       : FA(FA), BC(BF.getBinaryContext()), BF(BF), Info(Info),
223         AllocatorId(AllocId) {}
224 
~StackLayoutModifier()225   ~StackLayoutModifier() {
226     for (BinaryBasicBlock &BB : BF) {
227       for (MCInst &Inst : BB) {
228         BC.MIB->removeAnnotation(Inst, getTodoTag());
229         BC.MIB->removeAnnotation(Inst, getSlotTag());
230         BC.MIB->removeAnnotation(Inst, getOffsetCFIRegTag());
231       }
232     }
233   }
234 
235   /// Retrieves the value of the callee-saved register that is restored by this
236   /// instruction or 0 if this is not a CSR restore instruction.
getOffsetCFIReg(const MCInst & Inst)237   uint16_t getOffsetCFIReg(const MCInst &Inst) {
238     auto Val = BC.MIB->tryGetAnnotationAs<uint16_t>(Inst, getOffsetCFIRegTag());
239     if (Val)
240       return *Val;
241     return 0;
242   }
243 
244   /// Check if it is possible to delete the push instruction \p DeletedPush.
245   /// This involves collapsing the region accessed by this push and updating all
246   /// other instructions that access affected memory regions. Return true if we
247   /// can update this.
248   bool canCollapseRegion(int64_t RegionAddr);
249   bool canCollapseRegion(MCInst *DeletedPush);
250 
251   /// Notify the layout manager that \p DeletedPush was deleted and that it
252   /// needs to update other affected stack-accessing instructions.
253   bool collapseRegion(MCInst *Alloc, int64_t RegionAddr, int64_t RegionSize);
254   bool collapseRegion(MCInst *DeletedPush);
255 
256   /// Set the new stack address difference for load/store instructions that
257   /// referenced a stack location that was deleted via collapseRegion.
258   void setOffsetForCollapsedAccesses(int64_t NewOffset);
259 
260   /// Check if it is possible to insert a push instruction at point \p P.
261   /// This involves inserting a new region in the stack, possibly affecting
262   /// instructions that access the frame. Return true if we can update them all.
263   bool canInsertRegion(ProgramPoint P);
264 
265   /// Notify the layout manager that a new push instruction has been inserted
266   /// at point \p P and that it will need to update relevant instructions.
267   bool insertRegion(ProgramPoint P, int64_t RegionSz);
268 
269   /// Perform all changes scheduled by collapseRegion()/insertRegion()
270   void performChanges();
271 
272   /// Perform initial assessment of the function trying to understand its stack
273   /// accesses.
274   void initialize();
275 
getTodoTagName()276   static StringRef getTodoTagName() { return StringRef("SLM-TodoTag"); }
277 
getSlotTagName()278   static StringRef getSlotTagName() { return StringRef("SLM-SlotTag"); }
279 
getOffsetCFIRegTagName()280   static StringRef getOffsetCFIRegTagName() {
281     return StringRef("SLM-OffsetCFIReg");
282   }
283 };
284 
285 /// Implements a pass to optimize callee-saved register spills. These spills
286 /// typically happen at function prologue/epilogue. When these are hot basic
287 /// blocks, this pass will try to move these spills to cold blocks whenever
288 /// possible.
289 class ShrinkWrapping {
290   const FrameAnalysis &FA;
291   const BinaryContext &BC;
292   BinaryFunction &BF;
293   DataflowInfoManager &Info;
294   MCPlusBuilder::AllocatorIdTy AllocatorId;
295   StackLayoutModifier SLM;
296   /// For each CSR, store a vector of all CFI indexes deleted as a consequence
297   /// of moving this Callee-Saved Reg
298   DenseMap<unsigned, std::vector<uint32_t>> DeletedPushCFIs;
299   DenseMap<unsigned, std::vector<uint32_t>> DeletedPopCFIs;
300   BitVector HasDeletedOffsetCFIs;
301   SmallPtrSet<const MCCFIInstruction *, 16> UpdatedCFIs;
302   std::vector<BitVector> UsesByReg;
303   std::vector<int64_t> PushOffsetByReg;
304   std::vector<int64_t> PopOffsetByReg;
305   std::vector<MCPhysReg> DomOrder;
306   CalleeSavedAnalysis CSA;
307   std::vector<std::vector<uint64_t>> BestSaveCount;
308   std::vector<std::vector<MCInst *>> BestSavePos;
309 
310   /// Pass stats
311   static std::atomic<std::uint64_t> SpillsMovedRegularMode;
312   static std::atomic<std::uint64_t> SpillsMovedPushPopMode;
313   static std::atomic<std::uint64_t> SpillsMovedDynamicCount;
314   static std::atomic<std::uint64_t> SpillsFailedDynamicCount;
315   static std::atomic<std::uint64_t> InstrDynamicCount;
316   static std::atomic<std::uint64_t> StoreDynamicCount;
317 
318   std::optional<unsigned> AnnotationIndex;
319 
320   /// Allow our custom worklist-sensitive analysis
321   /// PredictiveStackPointerTracking to access WorklistItem
322 public:
323   struct WorklistItem {
324     enum ActionType : uint8_t {
325       Erase = 0,
326       ChangeToAdjustment,
327       InsertLoadOrStore,
328       InsertPushOrPop
329     } Action;
330     FrameIndexEntry FIEToInsert;
331     unsigned AffectedReg;
332     int Adjustment{0};
WorklistItemWorklistItem333     WorklistItem(ActionType Action, unsigned AffectedReg)
334         : Action(Action), FIEToInsert(), AffectedReg(AffectedReg) {}
WorklistItemWorklistItem335     WorklistItem(ActionType Action, unsigned AffectedReg, int Adjustment)
336         : Action(Action), FIEToInsert(), AffectedReg(AffectedReg),
337           Adjustment(Adjustment) {}
WorklistItemWorklistItem338     WorklistItem(ActionType Action, const FrameIndexEntry &FIE,
339                  unsigned AffectedReg)
340         : Action(Action), FIEToInsert(FIE), AffectedReg(AffectedReg) {}
341   };
342 
343   /// Insertion todo items scheduled to happen at the end of BBs. Since we
344   /// can't annotate BBs we maintain this bookkeeping here.
345   DenseMap<BinaryBasicBlock *, std::vector<WorklistItem>> Todo;
346 
347   /// Annotation name used to tag instructions with removal or insertion actions
getAnnotationName()348   static StringRef getAnnotationName() { return StringRef("ShrinkWrap-Todo"); }
349 
getAnnotationIndex()350   unsigned getAnnotationIndex() {
351     if (AnnotationIndex)
352       return *AnnotationIndex;
353     AnnotationIndex = BC.MIB->getOrCreateAnnotationIndex(getAnnotationName());
354     return *AnnotationIndex;
355   }
356 
357 private:
358   using BBIterTy = BinaryBasicBlock::iterator;
359 
360   /// Calculate all possible uses/defs of these callee-saved regs
361   void classifyCSRUses();
362 
363   // Ensure we don't work on cases where there are no uses of the callee-saved
364   // register. These unnecessary spills should have been removed by previous
365   // passes.
366   void pruneUnwantedCSRs();
367 
368   // Map regs to their possible save possibilities (at start of these BBs)
369   void computeSaveLocations();
370 
371   /// Look into the best save location found for saving callee-saved reg
372   /// \p CSR and evaluates whether we would benefit by moving the spill to this
373   /// new save location. Returns true in case it is profitable to perform the
374   /// move.
375   bool validateBestSavePos(unsigned CSR, MCInst *&BestPosSave,
376                            uint64_t &TotalEstimatedWin);
377 
378   /// Populate the Todo map with worklistitems to change the function
scheduleChange(ProgramPoint PP,T &&...Item)379   template <typename... T> void scheduleChange(ProgramPoint PP, T &&...Item) {
380     if (PP.isInst()) {
381       auto &WList = BC.MIB->getOrCreateAnnotationAs<std::vector<WorklistItem>>(
382           *PP.getInst(), getAnnotationIndex(), AllocatorId);
383       WList.emplace_back(std::forward<T>(Item)...);
384       return;
385     }
386     BinaryBasicBlock *BB = PP.getBB();
387     // Avoid inserting on BBs with no instructions because we have a dataflow
388     // analysis that depends on insertions happening before real instructions
389     // (PredictiveStackPointerTracking)
390     assert(BB->size() != 0 &&
391            "doRestorePlacement() should have handled empty BBs");
392     Todo[BB].emplace_back(std::forward<T>(Item)...);
393   }
394 
395   /// Determine the POP ordering according to which CSR save is the dominator.
396   void computeDomOrder();
397 
398   /// Check that the best possible location for a spill save (as determined by
399   /// computeSaveLocations) is cold enough to be worth moving the save to it.
400   /// \p CSR is the callee-saved register number, \p BestPosSave returns the
401   /// pointer to the cold location in case the function returns true, while
402   /// \p TotalEstimatedWin contains the ins dyn count reduction after moving.
403   bool isBestSavePosCold(unsigned CSR, MCInst *&BestPosSave,
404                          uint64_t &TotalEstimatedWin);
405 
406   /// Auxiliary function used to create basic blocks for critical edges and
407   /// update the dominance frontier with these new locations
408   void splitFrontierCritEdges(
409       BinaryFunction *Func, SmallVector<ProgramPoint, 4> &Frontier,
410       const SmallVector<bool, 4> &IsCritEdge,
411       const SmallVector<BinaryBasicBlock *, 4> &From,
412       const SmallVector<SmallVector<BinaryBasicBlock *, 4>, 4> &To);
413 
414   /// After the best save location for a spill has been established in
415   /// \p BestPosSave for reg \p CSR, compute adequate locations to restore
416   /// the spilled value. This will be at the dominance frontier.
417   /// Returns an empty vector if we failed. In case of success, set
418   /// \p UsePushPops to true if we can operate in the push/pops mode.
419   SmallVector<ProgramPoint, 4> doRestorePlacement(MCInst *BestPosSave,
420                                                   unsigned CSR,
421                                                   uint64_t TotalEstimatedWin);
422 
423   /// Checks whether using push and pops (instead of the longer load-store
424   /// counterparts) is correct for reg \p CSR
425   bool validatePushPopsMode(unsigned CSR, MCInst *BestPosSave,
426                             int64_t SaveOffset);
427 
428   /// Adjust restore locations to the correct SP offset if we are using POPs
429   /// instead of random-access load instructions.
430   SmallVector<ProgramPoint, 4>
431   fixPopsPlacements(const SmallVector<ProgramPoint, 4> &RestorePoints,
432                     int64_t SaveOffset, unsigned CSR);
433 
434   /// When moving spills, mark all old spill locations to be deleted
435   void scheduleOldSaveRestoresRemoval(unsigned CSR, bool UsePushPops);
436   /// Return true if \p Inst uses reg \p CSR
437   bool doesInstUsesCSR(const MCInst &Inst, uint16_t CSR);
438   /// When moving spills, mark all new spill locations for insertion
439   void
440   scheduleSaveRestoreInsertions(unsigned CSR, MCInst *BestPosSave,
441                                 SmallVector<ProgramPoint, 4> &RestorePoints,
442                                 bool UsePushPops);
443 
444   /// Coordinate the replacement of callee-saved spills from their original
445   /// place (at prologue and epilogues) to colder basic blocks as determined
446   /// by computeSaveLocations().
447   void moveSaveRestores();
448 
449   /// Compare multiple basic blocks created by splitting critical edges. If they
450   /// have the same contents and successor, fold them into one.
451   bool foldIdenticalSplitEdges();
452 
453   /// After the spill locations for reg \p CSR has been moved and all affected
454   /// CFI has been removed, insert new updated CFI information for these
455   /// locations.
456   void insertUpdatedCFI(unsigned CSR, int SPValPush, int SPValPop);
457 
458   /// In case the function anchors the CFA reg as SP and we inserted pushes/pops
459   /// insert def_cfa_offsets at appropriate places (and delete old
460   /// def_cfa_offsets)
461   void rebuildCFIForSP();
462 
463   /// Rebuild all CFI for affected Callee-Saved Registers.
464   void rebuildCFI();
465 
466   /// Create a load-store instruction (depending on the contents of \p FIE).
467   /// If \p CreatePushOrPop is true, create a push/pop instead. Current SP/FP
468   /// values, as determined by StackPointerTracking, should be informed via
469   /// \p SPVal and \p FPVal in order to emit the correct offset form SP/FP.
470   Expected<MCInst> createStackAccess(int SPVal, int FPVal,
471                                      const FrameIndexEntry &FIE,
472                                      bool CreatePushOrPop);
473 
474   /// Update the CFI referenced by \p Inst with \p NewOffset, if the CFI has
475   /// an offset.
476   void updateCFIInstOffset(MCInst &Inst, int64_t NewOffset);
477 
478   /// Insert any CFI that should be attached to a register spill save/restore.
479   BBIterTy insertCFIsForPushOrPop(BinaryBasicBlock &BB, BBIterTy Pos,
480                                   unsigned Reg, bool IsPush, int Sz,
481                                   int64_t NewOffset);
482 
483   /// Auxiliary function to processInsertionsList, adding a new instruction
484   /// before \p InsertionPoint as requested by \p Item. Return an updated
485   /// InsertionPoint for other instructions that need to be inserted at the same
486   /// original location, since this insertion may have invalidated the previous
487   /// location.
488   Expected<BBIterTy> processInsertion(BBIterTy InsertionPoint,
489                                       BinaryBasicBlock *CurBB,
490                                       const WorklistItem &Item, int64_t SPVal,
491                                       int64_t FPVal);
492 
493   /// Auxiliary function to processInsertions(), helping perform all the
494   /// insertion tasks in the todo list associated with a single insertion point.
495   /// Return true if at least one insertion was performed.
496   Expected<BBIterTy> processInsertionsList(BBIterTy InsertionPoint,
497                                            BinaryBasicBlock *CurBB,
498                                            std::vector<WorklistItem> &TodoList,
499                                            int64_t SPVal, int64_t FPVal);
500 
501   /// Apply all insertion todo tasks regarding insertion of new stores/loads or
502   /// push/pops at annotated points. Return false if the entire function had
503   /// no todo tasks annotation and this pass has nothing to do.
504   Expected<bool> processInsertions();
505 
506   /// Apply all deletion todo tasks (or tasks to change a push/pop to a memory
507   /// access no-op)
508   void processDeletions();
509 
510 public:
ShrinkWrapping(const FrameAnalysis & FA,BinaryFunction & BF,DataflowInfoManager & Info,MCPlusBuilder::AllocatorIdTy AllocId)511   ShrinkWrapping(const FrameAnalysis &FA, BinaryFunction &BF,
512                  DataflowInfoManager &Info,
513                  MCPlusBuilder::AllocatorIdTy AllocId)
514       : FA(FA), BC(BF.getBinaryContext()), BF(BF), Info(Info),
515         AllocatorId(AllocId), SLM(FA, BF, Info, AllocId),
516         CSA(FA, BF, Info, AllocId) {}
517 
~ShrinkWrapping()518   ~ShrinkWrapping() {
519     for (BinaryBasicBlock &BB : BF)
520       for (MCInst &Inst : BB)
521         BC.MIB->removeAnnotation(Inst, getAnnotationIndex());
522   }
523 
524   Expected<bool> perform(bool HotOnly = false);
525 
526   static void printStats(BinaryContext &BC);
527 };
528 
529 } // end namespace bolt
530 } // end namespace llvm
531 
532 #endif
533