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