1 //===- bolt/Passes/AllocCombiner.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 AllocCombinerPass class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "bolt/Passes/AllocCombiner.h" 14 15 #define DEBUG_TYPE "alloccombiner" 16 17 using namespace llvm; 18 19 namespace opts { 20 21 extern cl::opt<bolt::FrameOptimizationType> FrameOptimization; 22 23 } // end namespace opts 24 25 namespace llvm { 26 namespace bolt { 27 28 namespace { 29 30 bool getStackAdjustmentSize(const BinaryContext &BC, const MCInst &Inst, 31 int64_t &Adjustment) { 32 return BC.MIB->evaluateStackOffsetExpr( 33 Inst, Adjustment, std::make_pair(BC.MIB->getStackPointer(), 0LL), 34 std::make_pair(0, 0LL)); 35 } 36 37 bool isIndifferentToSP(const MCInst &Inst, const BinaryContext &BC) { 38 if (BC.MIB->isCFI(Inst)) 39 return true; 40 41 const MCInstrDesc II = BC.MII->get(Inst.getOpcode()); 42 if (BC.MIB->isTerminator(Inst) || 43 II.hasImplicitDefOfPhysReg(BC.MIB->getStackPointer(), BC.MRI.get()) || 44 II.hasImplicitUseOfPhysReg(BC.MIB->getStackPointer())) 45 return false; 46 47 for (const MCOperand &Operand : MCPlus::primeOperands(Inst)) 48 if (Operand.isReg() && Operand.getReg() == BC.MIB->getStackPointer()) 49 return false; 50 return true; 51 } 52 53 bool shouldProcess(const BinaryFunction &Function) { 54 return Function.isSimple() && Function.hasCFG() && !Function.isIgnored(); 55 } 56 57 void runForAllWeCare(std::map<uint64_t, BinaryFunction> &BFs, 58 std::function<void(BinaryFunction &)> Task) { 59 for (auto &It : BFs) { 60 BinaryFunction &Function = It.second; 61 if (shouldProcess(Function)) 62 Task(Function); 63 } 64 } 65 66 } // end anonymous namespace 67 68 void AllocCombinerPass::combineAdjustments(BinaryFunction &BF) { 69 BinaryContext &BC = BF.getBinaryContext(); 70 for (BinaryBasicBlock &BB : BF) { 71 MCInst *Prev = nullptr; 72 for (auto I = BB.rbegin(), E = BB.rend(); I != E; ++I) { 73 MCInst &Inst = *I; 74 if (isIndifferentToSP(Inst, BC)) 75 continue; // Skip updating Prev 76 77 int64_t Adjustment = 0LL; 78 if (!Prev || !BC.MIB->isStackAdjustment(Inst) || 79 !BC.MIB->isStackAdjustment(*Prev) || 80 !getStackAdjustmentSize(BC, *Prev, Adjustment)) { 81 Prev = &Inst; 82 continue; 83 } 84 85 LLVM_DEBUG({ 86 dbgs() << "At \"" << BF.getPrintName() << "\", combining: \n"; 87 Inst.dump(); 88 Prev->dump(); 89 dbgs() << "Adjustment: " << Adjustment << "\n"; 90 }); 91 92 if (BC.MIB->isSUB(Inst)) 93 Adjustment = -Adjustment; 94 95 BC.MIB->addToImm(Inst, Adjustment, BC.Ctx.get()); 96 97 LLVM_DEBUG({ 98 dbgs() << "After adjustment:\n"; 99 Inst.dump(); 100 }); 101 102 BB.eraseInstruction(BB.findInstruction(Prev)); 103 ++NumCombined; 104 DynamicCountCombined += BB.getKnownExecutionCount(); 105 FuncsChanged.insert(&BF); 106 Prev = &Inst; 107 } 108 } 109 } 110 111 void AllocCombinerPass::runOnFunctions(BinaryContext &BC) { 112 if (opts::FrameOptimization == FOP_NONE) 113 return; 114 115 runForAllWeCare(BC.getBinaryFunctions(), [&](BinaryFunction &Function) { 116 combineAdjustments(Function); 117 }); 118 119 outs() << "BOLT-INFO: Allocation combiner: " << NumCombined 120 << " empty spaces coalesced (dyn count: " << DynamicCountCombined 121 << ").\n"; 122 } 123 124 } // end namespace bolt 125 } // end namespace llvm 126