12f09f445SMaksim Panchenko //===- bolt/Passes/FrameOptimizer.cpp -------------------------------------===// 2a34c753fSRafael Auler // 3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a34c753fSRafael Auler // 7a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8a34c753fSRafael Auler // 92f09f445SMaksim Panchenko // This file implements the FrameOptimizerPass class. 102f09f445SMaksim Panchenko // 11a34c753fSRafael Auler //===----------------------------------------------------------------------===// 12a34c753fSRafael Auler 13a34c753fSRafael Auler #include "bolt/Passes/FrameOptimizer.h" 14a34c753fSRafael Auler #include "bolt/Core/ParallelUtilities.h" 15a34c753fSRafael Auler #include "bolt/Passes/BinaryFunctionCallGraph.h" 16a34c753fSRafael Auler #include "bolt/Passes/DataflowInfoManager.h" 17a34c753fSRafael Auler #include "bolt/Passes/ShrinkWrapping.h" 18a34c753fSRafael Auler #include "bolt/Passes/StackAvailableExpressions.h" 19a34c753fSRafael Auler #include "bolt/Passes/StackReachingUses.h" 203332904aSRafael Auler #include "bolt/Utils/CommandLineOpts.h" 21a34c753fSRafael Auler #include "llvm/Support/Timer.h" 22a34c753fSRafael Auler #include <deque> 23a34c753fSRafael Auler #include <unordered_map> 24a34c753fSRafael Auler 25a34c753fSRafael Auler #define DEBUG_TYPE "fop" 26a34c753fSRafael Auler 27a34c753fSRafael Auler using namespace llvm; 28a34c753fSRafael Auler 29a34c753fSRafael Auler namespace opts { 30a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity; 31a34c753fSRafael Auler extern cl::opt<bool> TimeOpts; 32a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory; 33a34c753fSRafael Auler 34a34c753fSRafael Auler using namespace bolt; 35a34c753fSRafael Auler 36a34c753fSRafael Auler cl::opt<FrameOptimizationType> 37a34c753fSRafael Auler FrameOptimization("frame-opt", 38a34c753fSRafael Auler cl::init(FOP_NONE), 39a34c753fSRafael Auler cl::desc("optimize stack frame accesses"), 40a34c753fSRafael Auler cl::values( 41a34c753fSRafael Auler clEnumValN(FOP_NONE, "none", "do not perform frame optimization"), 42a34c753fSRafael Auler clEnumValN(FOP_HOT, "hot", "perform FOP on hot functions"), 43a34c753fSRafael Auler clEnumValN(FOP_ALL, "all", "perform FOP on all functions")), 44a34c753fSRafael Auler cl::ZeroOrMore, 45a34c753fSRafael Auler cl::cat(BoltOptCategory)); 46a34c753fSRafael Auler 47b92436efSFangrui Song cl::opt<bool> RemoveStores( 48b92436efSFangrui Song "frame-opt-rm-stores", cl::init(FOP_NONE), 49a34c753fSRafael Auler cl::desc("apply additional analysis to remove stores (experimental)"), 50a34c753fSRafael Auler cl::cat(BoltOptCategory)); 51a34c753fSRafael Auler 52a34c753fSRafael Auler } // namespace opts 53a34c753fSRafael Auler 54a34c753fSRafael Auler namespace llvm { 55a34c753fSRafael Auler namespace bolt { 56a34c753fSRafael Auler 57a34c753fSRafael Auler void FrameOptimizerPass::removeUnnecessaryLoads(const RegAnalysis &RA, 58a34c753fSRafael Auler const FrameAnalysis &FA, 59a34c753fSRafael Auler BinaryFunction &BF) { 6060b09997SMaksim Panchenko StackAvailableExpressions SAE(RA, FA, BF); 61a34c753fSRafael Auler SAE.run(); 62a34c753fSRafael Auler 63a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Performing unnecessary loads removal\n"); 64a34c753fSRafael Auler std::deque<std::pair<BinaryBasicBlock *, MCInst *>> ToErase; 65a34c753fSRafael Auler bool Changed = false; 66a34c753fSRafael Auler const auto ExprEnd = SAE.expr_end(); 6760b09997SMaksim Panchenko MCPlusBuilder *MIB = BF.getBinaryContext().MIB.get(); 68a34c753fSRafael Auler for (BinaryBasicBlock &BB : BF) { 69a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tNow at BB " << BB.getName() << "\n"); 70a34c753fSRafael Auler const MCInst *Prev = nullptr; 71a34c753fSRafael Auler for (MCInst &Inst : BB) { 72a34c753fSRafael Auler LLVM_DEBUG({ 73a34c753fSRafael Auler dbgs() << "\t\tNow at "; 74a34c753fSRafael Auler Inst.dump(); 75a34c753fSRafael Auler for (auto I = Prev ? SAE.expr_begin(*Prev) : SAE.expr_begin(BB); 76a34c753fSRafael Auler I != ExprEnd; ++I) { 77a34c753fSRafael Auler dbgs() << "\t\t\tReached by: "; 78a34c753fSRafael Auler (*I)->dump(); 79a34c753fSRafael Auler } 80a34c753fSRafael Auler }); 81a34c753fSRafael Auler // if Inst is a load from stack and the current available expressions show 82a34c753fSRafael Auler // this value is available in a register or immediate, replace this load 83a34c753fSRafael Auler // with move from register or from immediate. 84a34c753fSRafael Auler ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst); 85a34c753fSRafael Auler if (!FIEX) { 86a34c753fSRafael Auler Prev = &Inst; 87a34c753fSRafael Auler continue; 88a34c753fSRafael Auler } 89a34c753fSRafael Auler // FIXME: Change to remove IsSimple == 0. We're being conservative here, 90a34c753fSRafael Auler // but once replaceMemOperandWithReg is ready, we should feed it with all 91a34c753fSRafael Auler // sorts of complex instructions. 92a34c753fSRafael Auler if (FIEX->IsLoad == false || FIEX->IsSimple == false || 93a34c753fSRafael Auler FIEX->StackOffset >= 0) { 94a34c753fSRafael Auler Prev = &Inst; 95a34c753fSRafael Auler continue; 96a34c753fSRafael Auler } 97a34c753fSRafael Auler 98a34c753fSRafael Auler for (auto I = Prev ? SAE.expr_begin(*Prev) : SAE.expr_begin(BB); 99a34c753fSRafael Auler I != ExprEnd; ++I) { 100a34c753fSRafael Auler const MCInst *AvailableInst = *I; 101a34c753fSRafael Auler ErrorOr<const FrameIndexEntry &> FIEY = FA.getFIEFor(*AvailableInst); 102a34c753fSRafael Auler if (!FIEY) 103a34c753fSRafael Auler continue; 104a34c753fSRafael Auler assert(FIEY->IsStore && FIEY->IsSimple); 105a34c753fSRafael Auler if (FIEX->StackOffset != FIEY->StackOffset || FIEX->Size != FIEY->Size) 106a34c753fSRafael Auler continue; 107a34c753fSRafael Auler // TODO: Change push/pops to stack adjustment instruction 10860b09997SMaksim Panchenko if (MIB->isPop(Inst)) 109a34c753fSRafael Auler continue; 110a34c753fSRafael Auler 111a34c753fSRafael Auler ++NumRedundantLoads; 11242465efdSRafael Auler FreqRedundantLoads += BB.getKnownExecutionCount(); 113a34c753fSRafael Auler Changed = true; 114a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Redundant load instruction: "); 115a34c753fSRafael Auler LLVM_DEBUG(Inst.dump()); 116a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Related store instruction: "); 117a34c753fSRafael Auler LLVM_DEBUG(AvailableInst->dump()); 118a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n"); 119a34c753fSRafael Auler // Replace load 120a34c753fSRafael Auler if (FIEY->IsStoreFromReg) { 12160b09997SMaksim Panchenko if (!MIB->replaceMemOperandWithReg(Inst, FIEY->RegOrImm)) { 122a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FAILED to change operand to a reg\n"); 123a34c753fSRafael Auler break; 124a34c753fSRafael Auler } 12542465efdSRafael Auler FreqLoadsChangedToReg += BB.getKnownExecutionCount(); 12660b09997SMaksim Panchenko MIB->removeAnnotation(Inst, "FrameAccessEntry"); 127a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changed operand to a reg\n"); 12860b09997SMaksim Panchenko if (MIB->isRedundantMove(Inst)) { 129a34c753fSRafael Auler ++NumLoadsDeleted; 13042465efdSRafael Auler FreqLoadsDeleted += BB.getKnownExecutionCount(); 131a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Created a redundant move\n"); 132a34c753fSRafael Auler // Delete it! 133a34c753fSRafael Auler ToErase.push_front(std::make_pair(&BB, &Inst)); 134a34c753fSRafael Auler } 135a34c753fSRafael Auler } else { 136a34c753fSRafael Auler char Buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 137a34c753fSRafael Auler support::ulittle64_t::ref(Buf + 0) = FIEY->RegOrImm; 138a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changing operand to an imm... "); 13960b09997SMaksim Panchenko if (!MIB->replaceMemOperandWithImm(Inst, StringRef(Buf, 8), 0)) { 140a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FAILED\n"); 141a34c753fSRafael Auler } else { 14242465efdSRafael Auler FreqLoadsChangedToImm += BB.getKnownExecutionCount(); 14360b09997SMaksim Panchenko MIB->removeAnnotation(Inst, "FrameAccessEntry"); 144a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Ok\n"); 145a34c753fSRafael Auler } 146a34c753fSRafael Auler } 147a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changed to: "); 148a34c753fSRafael Auler LLVM_DEBUG(Inst.dump()); 149a34c753fSRafael Auler break; 150a34c753fSRafael Auler } 151a34c753fSRafael Auler Prev = &Inst; 152a34c753fSRafael Auler } 153a34c753fSRafael Auler } 154f92ab6afSAmir Ayupov if (Changed) 155a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n"); 156f92ab6afSAmir Ayupov 157a34c753fSRafael Auler // TODO: Implement an interface of eraseInstruction that works out the 158a34c753fSRafael Auler // complete list of elements to remove. 159f92ab6afSAmir Ayupov for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase) 160a34c753fSRafael Auler I.first->eraseInstruction(I.first->findInstruction(I.second)); 161a34c753fSRafael Auler } 162a34c753fSRafael Auler 163a34c753fSRafael Auler void FrameOptimizerPass::removeUnusedStores(const FrameAnalysis &FA, 164a34c753fSRafael Auler BinaryFunction &BF) { 16560b09997SMaksim Panchenko StackReachingUses SRU(FA, BF); 166a34c753fSRafael Auler SRU.run(); 167a34c753fSRafael Auler 168a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Performing unused stores removal\n"); 169a34c753fSRafael Auler std::vector<std::pair<BinaryBasicBlock *, MCInst *>> ToErase; 170a34c753fSRafael Auler bool Changed = false; 171a34c753fSRafael Auler for (BinaryBasicBlock &BB : BF) { 172a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tNow at BB " << BB.getName() << "\n"); 173a34c753fSRafael Auler const MCInst *Prev = nullptr; 174f40d25ddSAmir Ayupov for (MCInst &Inst : llvm::reverse(BB)) { 175a34c753fSRafael Auler LLVM_DEBUG({ 176a34c753fSRafael Auler dbgs() << "\t\tNow at "; 177a34c753fSRafael Auler Inst.dump(); 178a34c753fSRafael Auler for (auto I = Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB); 179a34c753fSRafael Auler I != SRU.expr_end(); ++I) { 180a34c753fSRafael Auler dbgs() << "\t\t\tReached by: "; 181a34c753fSRafael Auler (*I)->dump(); 182a34c753fSRafael Auler } 183a34c753fSRafael Auler }); 184a34c753fSRafael Auler ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst); 185a34c753fSRafael Auler if (!FIEX) { 186a34c753fSRafael Auler Prev = &Inst; 187a34c753fSRafael Auler continue; 188a34c753fSRafael Auler } 189a34c753fSRafael Auler if (FIEX->IsLoad || !FIEX->IsSimple || FIEX->StackOffset >= 0) { 190a34c753fSRafael Auler Prev = &Inst; 191a34c753fSRafael Auler continue; 192a34c753fSRafael Auler } 193a34c753fSRafael Auler 194a34c753fSRafael Auler if (SRU.isStoreUsed(*FIEX, 195a34c753fSRafael Auler Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB))) { 196a34c753fSRafael Auler Prev = &Inst; 197a34c753fSRafael Auler continue; 198a34c753fSRafael Auler } 199a34c753fSRafael Auler // TODO: Change push/pops to stack adjustment instruction 20060b09997SMaksim Panchenko if (BF.getBinaryContext().MIB->isPush(Inst)) 201a34c753fSRafael Auler continue; 202a34c753fSRafael Auler 203a34c753fSRafael Auler ++NumRedundantStores; 20442465efdSRafael Auler FreqRedundantStores += BB.getKnownExecutionCount(); 205a34c753fSRafael Auler Changed = true; 206a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Unused store instruction: "); 207a34c753fSRafael Auler LLVM_DEBUG(Inst.dump()); 208a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n"); 209a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FIE offset = " << FIEX->StackOffset 210a34c753fSRafael Auler << " size = " << (int)FIEX->Size << "\n"); 211a34c753fSRafael Auler // Delete it! 212a34c753fSRafael Auler ToErase.emplace_back(&BB, &Inst); 213a34c753fSRafael Auler Prev = &Inst; 214a34c753fSRafael Auler } 215a34c753fSRafael Auler } 216a34c753fSRafael Auler 217f92ab6afSAmir Ayupov for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase) 218a34c753fSRafael Auler I.first->eraseInstruction(I.first->findInstruction(I.second)); 219f92ab6afSAmir Ayupov 220f92ab6afSAmir Ayupov if (Changed) 221a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n"); 222a34c753fSRafael Auler } 223a34c753fSRafael Auler 224*a5f3d1a8SAmir Ayupov Error FrameOptimizerPass::runOnFunctions(BinaryContext &BC) { 225a34c753fSRafael Auler if (opts::FrameOptimization == FOP_NONE) 226*a5f3d1a8SAmir Ayupov return Error::success(); 227a34c753fSRafael Auler 228a34c753fSRafael Auler std::unique_ptr<BinaryFunctionCallGraph> CG; 229a34c753fSRafael Auler std::unique_ptr<FrameAnalysis> FA; 230a34c753fSRafael Auler std::unique_ptr<RegAnalysis> RA; 231a34c753fSRafael Auler 232a34c753fSRafael Auler { 233a34c753fSRafael Auler NamedRegionTimer T1("callgraph", "create call graph", "FOP", 234a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts); 235a34c753fSRafael Auler CG = std::make_unique<BinaryFunctionCallGraph>(buildCallGraph(BC)); 236a34c753fSRafael Auler } 237a34c753fSRafael Auler 238a34c753fSRafael Auler { 239a34c753fSRafael Auler NamedRegionTimer T1("frameanalysis", "frame analysis", "FOP", 240a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts); 241a34c753fSRafael Auler FA = std::make_unique<FrameAnalysis>(BC, *CG); 242a34c753fSRafael Auler } 243a34c753fSRafael Auler 244a34c753fSRafael Auler { 24540c2e0faSMaksim Panchenko NamedRegionTimer T1("reganalysis", "reg analysis", "FOP", "FOP breakdown", 24640c2e0faSMaksim Panchenko opts::TimeOpts); 247a34c753fSRafael Auler RA = std::make_unique<RegAnalysis>(BC, &BC.getBinaryFunctions(), CG.get()); 248a34c753fSRafael Auler } 249a34c753fSRafael Auler 250a34c753fSRafael Auler // Perform caller-saved register optimizations, then callee-saved register 251a34c753fSRafael Auler // optimizations (shrink wrapping) 252a34c753fSRafael Auler for (auto &I : BC.getBinaryFunctions()) { 253a34c753fSRafael Auler if (!FA->hasFrameInfo(I.second)) 254a34c753fSRafael Auler continue; 255a34c753fSRafael Auler // Restrict pass execution if user asked to only run on hot functions 256a34c753fSRafael Auler if (opts::FrameOptimization == FOP_HOT) { 257a34c753fSRafael Auler if (I.second.getKnownExecutionCount() < BC.getHotThreshold()) 258a34c753fSRafael Auler continue; 259a34c753fSRafael Auler LLVM_DEBUG( 260a34c753fSRafael Auler dbgs() << "Considering " << I.second.getPrintName() 261a34c753fSRafael Auler << " for frame optimizations because its execution count ( " 262a34c753fSRafael Auler << I.second.getKnownExecutionCount() 263a34c753fSRafael Auler << " ) exceeds our hotness threshold ( " 264a34c753fSRafael Auler << BC.getHotThreshold() << " )\n"); 265a34c753fSRafael Auler } 266a34c753fSRafael Auler 267a34c753fSRafael Auler { 268a34c753fSRafael Auler NamedRegionTimer T1("removeloads", "remove loads", "FOP", "FOP breakdown", 269a34c753fSRafael Auler opts::TimeOpts); 270a3cfdd74SRafael Auler if (!FA->hasStackArithmetic(I.second)) 27160b09997SMaksim Panchenko removeUnnecessaryLoads(*RA, *FA, I.second); 272a34c753fSRafael Auler } 273a34c753fSRafael Auler 274a34c753fSRafael Auler if (opts::RemoveStores) { 275a34c753fSRafael Auler NamedRegionTimer T1("removestores", "remove stores", "FOP", 276a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts); 277a3cfdd74SRafael Auler if (!FA->hasStackArithmetic(I.second)) 27860b09997SMaksim Panchenko removeUnusedStores(*FA, I.second); 279a34c753fSRafael Auler } 280a34c753fSRafael Auler // Don't even start shrink wrapping if no profiling info is available 281a34c753fSRafael Auler if (I.second.getKnownExecutionCount() == 0) 282a34c753fSRafael Auler continue; 283a34c753fSRafael Auler } 284a34c753fSRafael Auler 285a34c753fSRafael Auler { 286a34c753fSRafael Auler NamedRegionTimer T1("shrinkwrapping", "shrink wrapping", "FOP", 287a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts); 288a34c753fSRafael Auler performShrinkWrapping(*RA, *FA, BC); 289a34c753fSRafael Auler } 290a34c753fSRafael Auler 291a34c753fSRafael Auler outs() << "BOLT-INFO: FOP optimized " << NumRedundantLoads 292a34c753fSRafael Auler << " redundant load(s) and " << NumRedundantStores 293a34c753fSRafael Auler << " unused store(s)\n"; 29442465efdSRafael Auler outs() << "BOLT-INFO: Frequency of redundant loads is " << FreqRedundantLoads 29542465efdSRafael Auler << " and frequency of unused stores is " << FreqRedundantStores 29642465efdSRafael Auler << "\n"; 29742465efdSRafael Auler outs() << "BOLT-INFO: Frequency of loads changed to use a register is " 29842465efdSRafael Auler << FreqLoadsChangedToReg 29942465efdSRafael Auler << " and frequency of loads changed to use an immediate is " 30042465efdSRafael Auler << FreqLoadsChangedToImm << "\n"; 30142465efdSRafael Auler outs() << "BOLT-INFO: FOP deleted " << NumLoadsDeleted 30242465efdSRafael Auler << " load(s) (dyn count: " << FreqLoadsDeleted << ") and " 30342465efdSRafael Auler << NumRedundantStores << " store(s)\n"; 304a34c753fSRafael Auler FA->printStats(); 305a34c753fSRafael Auler ShrinkWrapping::printStats(); 306*a5f3d1a8SAmir Ayupov return Error::success(); 307a34c753fSRafael Auler } 308a34c753fSRafael Auler 309a34c753fSRafael Auler void FrameOptimizerPass::performShrinkWrapping(const RegAnalysis &RA, 310a34c753fSRafael Auler const FrameAnalysis &FA, 311a34c753fSRafael Auler BinaryContext &BC) { 312a34c753fSRafael Auler // Initialize necessary annotations to allow safe parallel accesses to 313a34c753fSRafael Auler // annotation index in MIB 314a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex(CalleeSavedAnalysis::getSaveTagName()); 315a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex(CalleeSavedAnalysis::getRestoreTagName()); 316a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex(StackLayoutModifier::getTodoTagName()); 317a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex(StackLayoutModifier::getSlotTagName()); 318a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex( 319a34c753fSRafael Auler StackLayoutModifier::getOffsetCFIRegTagName()); 320a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ReachingDefs"); 321a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ReachingUses"); 322a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("LivenessAnalysis"); 323a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackReachingUses"); 324a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("PostDominatorAnalysis"); 325a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("DominatorAnalysis"); 326a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackPointerTracking"); 327a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackPointerTrackingForInternalCalls"); 328a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackAvailableExpressions"); 329a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackAllocationAnalysis"); 330a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ShrinkWrap-Todo"); 331a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("PredictiveStackPointerTracking"); 332a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ReachingInsnsBackward"); 333a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ReachingInsns"); 334a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("AccessesDeletedPos"); 335a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("DeleteMe"); 336a34c753fSRafael Auler 33742465efdSRafael Auler std::vector<std::pair<uint64_t, const BinaryFunction *>> Top10Funcs; 33842465efdSRafael Auler auto LogFunc = [&](BinaryFunction &BF) { 33989f14332SKazu Hirata auto Lower = llvm::lower_bound( 34089f14332SKazu Hirata Top10Funcs, BF.getKnownExecutionCount(), 34142465efdSRafael Auler [](const std::pair<uint64_t, const BinaryFunction *> &Elmt, 34242465efdSRafael Auler uint64_t Value) { return Elmt.first > Value; }); 34342465efdSRafael Auler if (Lower == Top10Funcs.end() && Top10Funcs.size() >= 10) 34442465efdSRafael Auler return; 34542465efdSRafael Auler Top10Funcs.insert(Lower, 34642465efdSRafael Auler std::make_pair<>(BF.getKnownExecutionCount(), &BF)); 34742465efdSRafael Auler if (Top10Funcs.size() > 10) 34842465efdSRafael Auler Top10Funcs.resize(10); 34942465efdSRafael Auler }; 35042465efdSRafael Auler (void)LogFunc; 35142465efdSRafael Auler 352a34c753fSRafael Auler ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) { 35342465efdSRafael Auler if (BF.getFunctionScore() == 0) 354a34c753fSRafael Auler return true; 355a34c753fSRafael Auler 356a34c753fSRafael Auler return false; 357a34c753fSRafael Auler }; 358a34c753fSRafael Auler 35942465efdSRafael Auler const bool HotOnly = opts::FrameOptimization == FOP_HOT; 36042465efdSRafael Auler 361a34c753fSRafael Auler ParallelUtilities::WorkFuncWithAllocTy WorkFunction = 362a34c753fSRafael Auler [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) { 36360b09997SMaksim Panchenko DataflowInfoManager Info(BF, &RA, &FA, AllocatorId); 36460b09997SMaksim Panchenko ShrinkWrapping SW(FA, BF, Info, AllocatorId); 365a34c753fSRafael Auler 36642465efdSRafael Auler if (SW.perform(HotOnly)) { 367a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(FuncsChangedMutex); 368a34c753fSRafael Auler FuncsChanged.insert(&BF); 36942465efdSRafael Auler LLVM_DEBUG(LogFunc(BF)); 370a34c753fSRafael Auler } 371a34c753fSRafael Auler }; 372a34c753fSRafael Auler 373a34c753fSRafael Auler ParallelUtilities::runOnEachFunctionWithUniqueAllocId( 374a34c753fSRafael Auler BC, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC, WorkFunction, 375a34c753fSRafael Auler SkipPredicate, "shrink-wrapping"); 37642465efdSRafael Auler 37742465efdSRafael Auler if (!Top10Funcs.empty()) { 37842465efdSRafael Auler outs() << "BOLT-INFO: top 10 functions changed by shrink wrapping:\n"; 37942465efdSRafael Auler for (const auto &Elmt : Top10Funcs) 38042465efdSRafael Auler outs() << Elmt.first << " : " << Elmt.second->getPrintName() << "\n"; 38142465efdSRafael Auler } 382a34c753fSRafael Auler } 383a34c753fSRafael Auler 384a34c753fSRafael Auler } // namespace bolt 385a34c753fSRafael Auler } // namespace llvm 386