1a34c753fSRafael Auler //===--- 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 // 9a34c753fSRafael Auler //===----------------------------------------------------------------------===// 10a34c753fSRafael Auler 11a34c753fSRafael Auler #include "bolt/Passes/FrameOptimizer.h" 12a34c753fSRafael Auler #include "bolt/Core/ParallelUtilities.h" 13a34c753fSRafael Auler #include "bolt/Passes/BinaryFunctionCallGraph.h" 14a34c753fSRafael Auler #include "bolt/Passes/DataflowInfoManager.h" 15a34c753fSRafael Auler #include "bolt/Passes/ShrinkWrapping.h" 16a34c753fSRafael Auler #include "bolt/Passes/StackAvailableExpressions.h" 17a34c753fSRafael Auler #include "bolt/Passes/StackReachingUses.h" 18a34c753fSRafael Auler #include "llvm/Support/Timer.h" 19a34c753fSRafael Auler #include <deque> 20a34c753fSRafael Auler #include <unordered_map> 21a34c753fSRafael Auler 22a34c753fSRafael Auler #define DEBUG_TYPE "fop" 23a34c753fSRafael Auler 24a34c753fSRafael Auler using namespace llvm; 25a34c753fSRafael Auler 26a34c753fSRafael Auler namespace opts { 27a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity; 28a34c753fSRafael Auler extern cl::opt<bool> TimeOpts; 29a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory; 30a34c753fSRafael Auler 31a34c753fSRafael Auler using namespace bolt; 32a34c753fSRafael Auler 33a34c753fSRafael Auler cl::opt<FrameOptimizationType> 34a34c753fSRafael Auler FrameOptimization("frame-opt", 35a34c753fSRafael Auler cl::init(FOP_NONE), 36a34c753fSRafael Auler cl::desc("optimize stack frame accesses"), 37a34c753fSRafael Auler cl::values( 38a34c753fSRafael Auler clEnumValN(FOP_NONE, "none", "do not perform frame optimization"), 39a34c753fSRafael Auler clEnumValN(FOP_HOT, "hot", "perform FOP on hot functions"), 40a34c753fSRafael Auler clEnumValN(FOP_ALL, "all", "perform FOP on all functions")), 41a34c753fSRafael Auler cl::ZeroOrMore, 42a34c753fSRafael Auler cl::cat(BoltOptCategory)); 43a34c753fSRafael Auler 44a34c753fSRafael Auler cl::opt<bool> 45a34c753fSRafael Auler RemoveStores("frame-opt-rm-stores", 46a34c753fSRafael Auler cl::init(FOP_NONE), 47a34c753fSRafael Auler cl::desc("apply additional analysis to remove stores (experimental)"), 48a34c753fSRafael Auler cl::init(false), 49a34c753fSRafael Auler cl::ZeroOrMore, 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) { 60*60b09997SMaksim 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(); 67*60b09997SMaksim 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 108*60b09997SMaksim Panchenko if (MIB->isPop(Inst)) 109a34c753fSRafael Auler continue; 110a34c753fSRafael Auler 111a34c753fSRafael Auler ++NumRedundantLoads; 112a34c753fSRafael Auler Changed = true; 113a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Redundant load instruction: "); 114a34c753fSRafael Auler LLVM_DEBUG(Inst.dump()); 115a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Related store instruction: "); 116a34c753fSRafael Auler LLVM_DEBUG(AvailableInst->dump()); 117a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n"); 118a34c753fSRafael Auler // Replace load 119a34c753fSRafael Auler if (FIEY->IsStoreFromReg) { 120*60b09997SMaksim Panchenko if (!MIB->replaceMemOperandWithReg(Inst, FIEY->RegOrImm)) { 121a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FAILED to change operand to a reg\n"); 122a34c753fSRafael Auler break; 123a34c753fSRafael Auler } 124a34c753fSRafael Auler ++NumLoadsChangedToReg; 125*60b09997SMaksim Panchenko MIB->removeAnnotation(Inst, "FrameAccessEntry"); 126a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changed operand to a reg\n"); 127*60b09997SMaksim Panchenko if (MIB->isRedundantMove(Inst)) { 128a34c753fSRafael Auler ++NumLoadsDeleted; 129a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Created a redundant move\n"); 130a34c753fSRafael Auler // Delete it! 131a34c753fSRafael Auler ToErase.push_front(std::make_pair(&BB, &Inst)); 132a34c753fSRafael Auler } 133a34c753fSRafael Auler } else { 134a34c753fSRafael Auler char Buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 135a34c753fSRafael Auler support::ulittle64_t::ref(Buf + 0) = FIEY->RegOrImm; 136a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changing operand to an imm... "); 137*60b09997SMaksim Panchenko if (!MIB->replaceMemOperandWithImm(Inst, StringRef(Buf, 8), 0)) { 138a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FAILED\n"); 139a34c753fSRafael Auler } else { 140a34c753fSRafael Auler ++NumLoadsChangedToImm; 141*60b09997SMaksim Panchenko MIB->removeAnnotation(Inst, "FrameAccessEntry"); 142a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Ok\n"); 143a34c753fSRafael Auler } 144a34c753fSRafael Auler } 145a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changed to: "); 146a34c753fSRafael Auler LLVM_DEBUG(Inst.dump()); 147a34c753fSRafael Auler break; 148a34c753fSRafael Auler } 149a34c753fSRafael Auler Prev = &Inst; 150a34c753fSRafael Auler } 151a34c753fSRafael Auler } 152a34c753fSRafael Auler if (Changed) { 153a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n"); 154a34c753fSRafael Auler } 155a34c753fSRafael Auler // TODO: Implement an interface of eraseInstruction that works out the 156a34c753fSRafael Auler // complete list of elements to remove. 157a34c753fSRafael Auler for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase) { 158a34c753fSRafael Auler I.first->eraseInstruction(I.first->findInstruction(I.second)); 159a34c753fSRafael Auler } 160a34c753fSRafael Auler } 161a34c753fSRafael Auler 162a34c753fSRafael Auler void FrameOptimizerPass::removeUnusedStores(const FrameAnalysis &FA, 163a34c753fSRafael Auler BinaryFunction &BF) { 164*60b09997SMaksim Panchenko StackReachingUses SRU(FA, BF); 165a34c753fSRafael Auler SRU.run(); 166a34c753fSRafael Auler 167a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Performing unused stores removal\n"); 168a34c753fSRafael Auler std::vector<std::pair<BinaryBasicBlock *, MCInst *>> ToErase; 169a34c753fSRafael Auler bool Changed = false; 170a34c753fSRafael Auler for (BinaryBasicBlock &BB : BF) { 171a34c753fSRafael Auler LLVM_DEBUG(dbgs() <<"\tNow at BB " << BB.getName() << "\n"); 172a34c753fSRafael Auler const MCInst *Prev = nullptr; 173a34c753fSRafael Auler for (auto I = BB.rbegin(), E = BB.rend(); I != E; ++I) { 174a34c753fSRafael Auler MCInst &Inst = *I; 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 200*60b09997SMaksim Panchenko if (BF.getBinaryContext().MIB->isPush(Inst)) 201a34c753fSRafael Auler continue; 202a34c753fSRafael Auler 203a34c753fSRafael Auler ++NumRedundantStores; 204a34c753fSRafael Auler Changed = true; 205a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Unused store instruction: "); 206a34c753fSRafael Auler LLVM_DEBUG(Inst.dump()); 207a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n"); 208a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FIE offset = " << FIEX->StackOffset 209a34c753fSRafael Auler << " size = " << (int)FIEX->Size << "\n"); 210a34c753fSRafael Auler // Delete it! 211a34c753fSRafael Auler ToErase.emplace_back(&BB, &Inst); 212a34c753fSRafael Auler Prev = &Inst; 213a34c753fSRafael Auler } 214a34c753fSRafael Auler } 215a34c753fSRafael Auler 216a34c753fSRafael Auler for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase) { 217a34c753fSRafael Auler I.first->eraseInstruction(I.first->findInstruction(I.second)); 218a34c753fSRafael Auler } 219a34c753fSRafael Auler if (Changed) { 220a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n"); 221a34c753fSRafael Auler } 222a34c753fSRafael Auler } 223a34c753fSRafael Auler 224a34c753fSRafael Auler void FrameOptimizerPass::runOnFunctions(BinaryContext &BC) { 225a34c753fSRafael Auler if (opts::FrameOptimization == FOP_NONE) 226a34c753fSRafael Auler return; 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 { 245a34c753fSRafael Auler NamedRegionTimer T1("reganalysis", "reg analysis", "FOP", 246a34c753fSRafael Auler "FOP breakdown", 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); 270*60b09997SMaksim Panchenko removeUnnecessaryLoads(*RA, *FA, I.second); 271a34c753fSRafael Auler } 272a34c753fSRafael Auler 273a34c753fSRafael Auler if (opts::RemoveStores) { 274a34c753fSRafael Auler NamedRegionTimer T1("removestores", "remove stores", "FOP", 275a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts); 276*60b09997SMaksim Panchenko removeUnusedStores(*FA, I.second); 277a34c753fSRafael Auler } 278a34c753fSRafael Auler // Don't even start shrink wrapping if no profiling info is available 279a34c753fSRafael Auler if (I.second.getKnownExecutionCount() == 0) 280a34c753fSRafael Auler continue; 281a34c753fSRafael Auler 282a34c753fSRafael Auler } 283a34c753fSRafael Auler 284a34c753fSRafael Auler { 285a34c753fSRafael Auler NamedRegionTimer T1("shrinkwrapping", "shrink wrapping", "FOP", 286a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts); 287a34c753fSRafael Auler performShrinkWrapping(*RA, *FA, BC); 288a34c753fSRafael Auler } 289a34c753fSRafael Auler 290a34c753fSRafael Auler outs() << "BOLT-INFO: FOP optimized " << NumRedundantLoads 291a34c753fSRafael Auler << " redundant load(s) and " << NumRedundantStores 292a34c753fSRafael Auler << " unused store(s)\n"; 293a34c753fSRafael Auler outs() << "BOLT-INFO: FOP changed " << NumLoadsChangedToReg 294a34c753fSRafael Auler << " load(s) to use a register instead of a stack access, and " 295a34c753fSRafael Auler << NumLoadsChangedToImm << " to use an immediate.\n" 296a34c753fSRafael Auler << "BOLT-INFO: FOP deleted " << NumLoadsDeleted << " load(s) and " 297a34c753fSRafael Auler << NumRedundantStores << " store(s).\n"; 298a34c753fSRafael Auler FA->printStats(); 299a34c753fSRafael Auler ShrinkWrapping::printStats(); 300a34c753fSRafael Auler } 301a34c753fSRafael Auler 302a34c753fSRafael Auler void FrameOptimizerPass::performShrinkWrapping(const RegAnalysis &RA, 303a34c753fSRafael Auler const FrameAnalysis &FA, 304a34c753fSRafael Auler BinaryContext &BC) { 305a34c753fSRafael Auler // Initialize necessary annotations to allow safe parallel accesses to 306a34c753fSRafael Auler // annotation index in MIB 307a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex(CalleeSavedAnalysis::getSaveTagName()); 308a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex(CalleeSavedAnalysis::getRestoreTagName()); 309a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex(StackLayoutModifier::getTodoTagName()); 310a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex(StackLayoutModifier::getSlotTagName()); 311a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex( 312a34c753fSRafael Auler StackLayoutModifier::getOffsetCFIRegTagName()); 313a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ReachingDefs"); 314a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ReachingUses"); 315a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("LivenessAnalysis"); 316a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackReachingUses"); 317a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("PostDominatorAnalysis"); 318a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("DominatorAnalysis"); 319a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackPointerTracking"); 320a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackPointerTrackingForInternalCalls"); 321a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackAvailableExpressions"); 322a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("StackAllocationAnalysis"); 323a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ShrinkWrap-Todo"); 324a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("PredictiveStackPointerTracking"); 325a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ReachingInsnsBackward"); 326a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("ReachingInsns"); 327a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("AccessesDeletedPos"); 328a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationIndex("DeleteMe"); 329a34c753fSRafael Auler 330a34c753fSRafael Auler ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) { 331a34c753fSRafael Auler if (!FA.hasFrameInfo(BF)) 332a34c753fSRafael Auler return true; 333a34c753fSRafael Auler 334a34c753fSRafael Auler if (opts::FrameOptimization == FOP_HOT && 335a34c753fSRafael Auler (BF.getKnownExecutionCount() < BC.getHotThreshold())) 336a34c753fSRafael Auler return true; 337a34c753fSRafael Auler 338a34c753fSRafael Auler if (BF.getKnownExecutionCount() == 0) 339a34c753fSRafael Auler return true; 340a34c753fSRafael Auler 341a34c753fSRafael Auler return false; 342a34c753fSRafael Auler }; 343a34c753fSRafael Auler 344a34c753fSRafael Auler ParallelUtilities::WorkFuncWithAllocTy WorkFunction = 345a34c753fSRafael Auler [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) { 346*60b09997SMaksim Panchenko DataflowInfoManager Info(BF, &RA, &FA, AllocatorId); 347*60b09997SMaksim Panchenko ShrinkWrapping SW(FA, BF, Info, AllocatorId); 348a34c753fSRafael Auler 349a34c753fSRafael Auler if (SW.perform()) { 350a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(FuncsChangedMutex); 351a34c753fSRafael Auler FuncsChanged.insert(&BF); 352a34c753fSRafael Auler } 353a34c753fSRafael Auler }; 354a34c753fSRafael Auler 355a34c753fSRafael Auler ParallelUtilities::runOnEachFunctionWithUniqueAllocId( 356a34c753fSRafael Auler BC, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC, WorkFunction, 357a34c753fSRafael Auler SkipPredicate, "shrink-wrapping"); 358a34c753fSRafael Auler } 359a34c753fSRafael Auler 360a34c753fSRafael Auler } // namespace bolt 361a34c753fSRafael Auler } // namespace llvm 362