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 | static bool getStackAdjustmentSize(const BinaryContext &BC, const MCInst &Inst, |
29 | int64_t &Adjustment) { |
30 | return BC.MIB->evaluateStackOffsetExpr( |
31 | Inst, Output&: Adjustment, Input1: std::make_pair(x: BC.MIB->getStackPointer(), y: 0LL), |
32 | Input2: std::make_pair(x: 0, y: 0LL)); |
33 | } |
34 | |
35 | static bool isIndifferentToSP(const MCInst &Inst, const BinaryContext &BC) { |
36 | if (BC.MIB->isCFI(Inst)) |
37 | return true; |
38 | |
39 | const MCInstrDesc &II = BC.MII->get(Opcode: Inst.getOpcode()); |
40 | if (BC.MIB->isTerminator(Inst) || |
41 | II.hasImplicitDefOfPhysReg(Reg: BC.MIB->getStackPointer(), MRI: BC.MRI.get()) || |
42 | II.hasImplicitUseOfPhysReg(Reg: BC.MIB->getStackPointer())) |
43 | return false; |
44 | |
45 | for (const MCOperand &Operand : MCPlus::primeOperands(Inst)) |
46 | if (Operand.isReg() && Operand.getReg() == BC.MIB->getStackPointer()) |
47 | return false; |
48 | return true; |
49 | } |
50 | |
51 | static bool shouldProcess(const BinaryFunction &Function) { |
52 | return Function.isSimple() && Function.hasCFG() && !Function.isIgnored(); |
53 | } |
54 | |
55 | static void runForAllWeCare(std::map<uint64_t, BinaryFunction> &BFs, |
56 | std::function<void(BinaryFunction &)> Task) { |
57 | for (auto &It : BFs) { |
58 | BinaryFunction &Function = It.second; |
59 | if (shouldProcess(Function)) |
60 | Task(Function); |
61 | } |
62 | } |
63 | |
64 | void AllocCombinerPass::combineAdjustments(BinaryFunction &BF) { |
65 | BinaryContext &BC = BF.getBinaryContext(); |
66 | for (BinaryBasicBlock &BB : BF) { |
67 | MCInst *Prev = nullptr; |
68 | for (MCInst &Inst : llvm::reverse(C&: BB)) { |
69 | if (isIndifferentToSP(Inst, BC)) |
70 | continue; // Skip updating Prev |
71 | |
72 | int64_t Adjustment = 0LL; |
73 | if (!Prev || !BC.MIB->isStackAdjustment(Inst) || |
74 | !BC.MIB->isStackAdjustment(Inst: *Prev) || |
75 | !getStackAdjustmentSize(BC, Inst: *Prev, Adjustment)) { |
76 | Prev = &Inst; |
77 | continue; |
78 | } |
79 | |
80 | LLVM_DEBUG({ |
81 | dbgs() << "At \"" << BF.getPrintName() << "\", combining: \n" ; |
82 | Inst.dump(); |
83 | Prev->dump(); |
84 | dbgs() << "Adjustment: " << Adjustment << "\n" ; |
85 | }); |
86 | |
87 | if (BC.MIB->isSUB(Inst)) |
88 | Adjustment = -Adjustment; |
89 | |
90 | BC.MIB->addToImm(Inst, Amt&: Adjustment, Ctx: BC.Ctx.get()); |
91 | |
92 | LLVM_DEBUG({ |
93 | dbgs() << "After adjustment:\n" ; |
94 | Inst.dump(); |
95 | }); |
96 | |
97 | BB.eraseInstruction(II: BB.findInstruction(Inst: Prev)); |
98 | ++NumCombined; |
99 | DynamicCountCombined += BB.getKnownExecutionCount(); |
100 | FuncsChanged.insert(V: &BF); |
101 | Prev = &Inst; |
102 | } |
103 | } |
104 | } |
105 | |
106 | Error AllocCombinerPass::runOnFunctions(BinaryContext &BC) { |
107 | if (opts::FrameOptimization == FOP_NONE) |
108 | return Error::success(); |
109 | |
110 | runForAllWeCare(BFs&: BC.getBinaryFunctions(), Task: [&](BinaryFunction &Function) { |
111 | combineAdjustments(BF&: Function); |
112 | }); |
113 | |
114 | BC.outs() << "BOLT-INFO: Allocation combiner: " << NumCombined |
115 | << " empty spaces coalesced (dyn count: " << DynamicCountCombined |
116 | << ").\n" ; |
117 | return Error::success(); |
118 | } |
119 | |
120 | } // end namespace bolt |
121 | } // end namespace llvm |
122 | |