| //===- bolt/Passes/AllocCombiner.cpp --------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the AllocCombinerPass class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "bolt/Passes/AllocCombiner.h" | |
| #define DEBUG_TYPE "alloccombiner" | |
| using namespace llvm; | |
| namespace opts { | |
| extern cl::opt<bolt::FrameOptimizationType> FrameOptimization; | |
| } // end namespace opts | |
| namespace llvm { | |
| namespace bolt { | |
| static bool getStackAdjustmentSize(const BinaryContext &BC, const MCInst &Inst, | |
| int64_t &Adjustment) { | |
| return BC.MIB->evaluateStackOffsetExpr( | |
| Inst, Adjustment, std::make_pair(BC.MIB->getStackPointer(), 0LL), | |
| std::make_pair(0, 0LL)); | |
| } | |
| static bool isIndifferentToSP(const MCInst &Inst, const BinaryContext &BC) { | |
| if (BC.MIB->isCFI(Inst)) | |
| return true; | |
| const MCInstrDesc &II = BC.MII->get(Inst.getOpcode()); | |
| if (BC.MIB->isTerminator(Inst) || | |
| II.hasImplicitDefOfPhysReg(BC.MIB->getStackPointer(), BC.MRI.get()) || | |
| II.hasImplicitUseOfPhysReg(BC.MIB->getStackPointer())) | |
| return false; | |
| for (const MCOperand &Operand : MCPlus::primeOperands(Inst)) | |
| if (Operand.isReg() && Operand.getReg() == BC.MIB->getStackPointer()) | |
| return false; | |
| return true; | |
| } | |
| static bool shouldProcess(const BinaryFunction &Function) { | |
| return Function.isSimple() && Function.hasCFG() && !Function.isIgnored(); | |
| } | |
| static void runForAllWeCare(std::map<uint64_t, BinaryFunction> &BFs, | |
| std::function<void(BinaryFunction &)> Task) { | |
| for (auto &It : BFs) { | |
| BinaryFunction &Function = It.second; | |
| if (shouldProcess(Function)) | |
| Task(Function); | |
| } | |
| } | |
| void AllocCombinerPass::combineAdjustments(BinaryFunction &BF) { | |
| BinaryContext &BC = BF.getBinaryContext(); | |
| for (BinaryBasicBlock &BB : BF) { | |
| MCInst *Prev = nullptr; | |
| for (MCInst &Inst : llvm::reverse(BB)) { | |
| if (isIndifferentToSP(Inst, BC)) | |
| continue; // Skip updating Prev | |
| int64_t Adjustment = 0LL; | |
| if (!Prev || !BC.MIB->isStackAdjustment(Inst) || | |
| !BC.MIB->isStackAdjustment(*Prev) || | |
| !getStackAdjustmentSize(BC, *Prev, Adjustment)) { | |
| Prev = &Inst; | |
| continue; | |
| } | |
| LLVM_DEBUG({ | |
| dbgs() << "At \"" << BF.getPrintName() << "\", combining: \n"; | |
| Inst.dump(); | |
| Prev->dump(); | |
| dbgs() << "Adjustment: " << Adjustment << "\n"; | |
| }); | |
| if (BC.MIB->isSUB(Inst)) | |
| Adjustment = -Adjustment; | |
| BC.MIB->addToImm(Inst, Adjustment, BC.Ctx.get()); | |
| LLVM_DEBUG({ | |
| dbgs() << "After adjustment:\n"; | |
| Inst.dump(); | |
| }); | |
| BB.eraseInstruction(BB.findInstruction(Prev)); | |
| ++NumCombined; | |
| DynamicCountCombined += BB.getKnownExecutionCount(); | |
| FuncsChanged.insert(&BF); | |
| Prev = &Inst; | |
| } | |
| } | |
| } | |
| Error AllocCombinerPass::runOnFunctions(BinaryContext &BC) { | |
| if (opts::FrameOptimization == FOP_NONE) | |
| return Error::success(); | |
| runForAllWeCare(BC.getBinaryFunctions(), [&](BinaryFunction &Function) { | |
| combineAdjustments(Function); | |
| }); | |
| BC.outs() << "BOLT-INFO: Allocation combiner: " << NumCombined | |
| << " empty spaces coalesced (dyn count: " << DynamicCountCombined | |
| << ").\n"; | |
| return Error::success(); | |
| } | |
| } // end namespace bolt | |
| } // end namespace llvm |