1*5f7ddb14SDimitry Andric //===- RemoveRedundantDebugValues.cpp - Remove Redundant Debug Value MIs --===//
2*5f7ddb14SDimitry Andric //
3*5f7ddb14SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f7ddb14SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f7ddb14SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f7ddb14SDimitry Andric //
7*5f7ddb14SDimitry Andric //===----------------------------------------------------------------------===//
8*5f7ddb14SDimitry Andric
9*5f7ddb14SDimitry Andric #include "llvm/ADT/DenseMap.h"
10*5f7ddb14SDimitry Andric #include "llvm/ADT/DenseSet.h"
11*5f7ddb14SDimitry Andric #include "llvm/ADT/SmallVector.h"
12*5f7ddb14SDimitry Andric #include "llvm/ADT/Statistic.h"
13*5f7ddb14SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
14*5f7ddb14SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
15*5f7ddb14SDimitry Andric #include "llvm/CodeGen/Passes.h"
16*5f7ddb14SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
17*5f7ddb14SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
18*5f7ddb14SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
19*5f7ddb14SDimitry Andric #include "llvm/IR/Function.h"
20*5f7ddb14SDimitry Andric #include "llvm/InitializePasses.h"
21*5f7ddb14SDimitry Andric #include "llvm/Pass.h"
22*5f7ddb14SDimitry Andric
23*5f7ddb14SDimitry Andric /// \file RemoveRedundantDebugValues.cpp
24*5f7ddb14SDimitry Andric ///
25*5f7ddb14SDimitry Andric /// The RemoveRedundantDebugValues pass removes redundant DBG_VALUEs that
26*5f7ddb14SDimitry Andric /// appear in MIR after the register allocator.
27*5f7ddb14SDimitry Andric
28*5f7ddb14SDimitry Andric #define DEBUG_TYPE "removeredundantdebugvalues"
29*5f7ddb14SDimitry Andric
30*5f7ddb14SDimitry Andric using namespace llvm;
31*5f7ddb14SDimitry Andric
32*5f7ddb14SDimitry Andric STATISTIC(NumRemovedBackward, "Number of DBG_VALUEs removed (backward scan)");
33*5f7ddb14SDimitry Andric STATISTIC(NumRemovedForward, "Number of DBG_VALUEs removed (forward scan)");
34*5f7ddb14SDimitry Andric
35*5f7ddb14SDimitry Andric namespace {
36*5f7ddb14SDimitry Andric
37*5f7ddb14SDimitry Andric class RemoveRedundantDebugValues : public MachineFunctionPass {
38*5f7ddb14SDimitry Andric public:
39*5f7ddb14SDimitry Andric static char ID;
40*5f7ddb14SDimitry Andric
41*5f7ddb14SDimitry Andric RemoveRedundantDebugValues();
42*5f7ddb14SDimitry Andric
43*5f7ddb14SDimitry Andric bool reduceDbgValues(MachineFunction &MF);
44*5f7ddb14SDimitry Andric
45*5f7ddb14SDimitry Andric /// Remove redundant debug value MIs for the given machine function.
46*5f7ddb14SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
47*5f7ddb14SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const48*5f7ddb14SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
49*5f7ddb14SDimitry Andric AU.setPreservesCFG();
50*5f7ddb14SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
51*5f7ddb14SDimitry Andric }
52*5f7ddb14SDimitry Andric };
53*5f7ddb14SDimitry Andric
54*5f7ddb14SDimitry Andric } // namespace
55*5f7ddb14SDimitry Andric
56*5f7ddb14SDimitry Andric //===----------------------------------------------------------------------===//
57*5f7ddb14SDimitry Andric // Implementation
58*5f7ddb14SDimitry Andric //===----------------------------------------------------------------------===//
59*5f7ddb14SDimitry Andric
60*5f7ddb14SDimitry Andric char RemoveRedundantDebugValues::ID = 0;
61*5f7ddb14SDimitry Andric
62*5f7ddb14SDimitry Andric char &llvm::RemoveRedundantDebugValuesID = RemoveRedundantDebugValues::ID;
63*5f7ddb14SDimitry Andric
64*5f7ddb14SDimitry Andric INITIALIZE_PASS(RemoveRedundantDebugValues, DEBUG_TYPE,
65*5f7ddb14SDimitry Andric "Remove Redundant DEBUG_VALUE analysis", false, false)
66*5f7ddb14SDimitry Andric
67*5f7ddb14SDimitry Andric /// Default construct and initialize the pass.
RemoveRedundantDebugValues()68*5f7ddb14SDimitry Andric RemoveRedundantDebugValues::RemoveRedundantDebugValues()
69*5f7ddb14SDimitry Andric : MachineFunctionPass(ID) {
70*5f7ddb14SDimitry Andric initializeRemoveRedundantDebugValuesPass(*PassRegistry::getPassRegistry());
71*5f7ddb14SDimitry Andric }
72*5f7ddb14SDimitry Andric
73*5f7ddb14SDimitry Andric // This analysis aims to remove redundant DBG_VALUEs by going forward
74*5f7ddb14SDimitry Andric // in the basic block by considering the first DBG_VALUE as a valid
75*5f7ddb14SDimitry Andric // until its first (location) operand is not clobbered/modified.
76*5f7ddb14SDimitry Andric // For example:
77*5f7ddb14SDimitry Andric // (1) DBG_VALUE $edi, !"var1", ...
78*5f7ddb14SDimitry Andric // (2) <block of code that does affect $edi>
79*5f7ddb14SDimitry Andric // (3) DBG_VALUE $edi, !"var1", ...
80*5f7ddb14SDimitry Andric // ...
81*5f7ddb14SDimitry Andric // in this case, we can remove (3).
82*5f7ddb14SDimitry Andric // TODO: Support DBG_VALUE_LIST and other debug instructions.
reduceDbgValsForwardScan(MachineBasicBlock & MBB)83*5f7ddb14SDimitry Andric static bool reduceDbgValsForwardScan(MachineBasicBlock &MBB) {
84*5f7ddb14SDimitry Andric LLVM_DEBUG(dbgs() << "\n == Forward Scan == \n");
85*5f7ddb14SDimitry Andric
86*5f7ddb14SDimitry Andric SmallVector<MachineInstr *, 8> DbgValsToBeRemoved;
87*5f7ddb14SDimitry Andric DenseMap<DebugVariable, std::pair<MachineOperand *, const DIExpression *>>
88*5f7ddb14SDimitry Andric VariableMap;
89*5f7ddb14SDimitry Andric const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();
90*5f7ddb14SDimitry Andric
91*5f7ddb14SDimitry Andric for (auto &MI : MBB) {
92*5f7ddb14SDimitry Andric if (MI.isDebugValue()) {
93*5f7ddb14SDimitry Andric DebugVariable Var(MI.getDebugVariable(), NoneType(),
94*5f7ddb14SDimitry Andric MI.getDebugLoc()->getInlinedAt());
95*5f7ddb14SDimitry Andric auto VMI = VariableMap.find(Var);
96*5f7ddb14SDimitry Andric // Just stop tracking this variable, until we cover DBG_VALUE_LIST.
97*5f7ddb14SDimitry Andric // 1 DBG_VALUE $rax, "x", DIExpression()
98*5f7ddb14SDimitry Andric // ...
99*5f7ddb14SDimitry Andric // 2 DBG_VALUE_LIST "x", DIExpression(...), $rax, $rbx
100*5f7ddb14SDimitry Andric // ...
101*5f7ddb14SDimitry Andric // 3 DBG_VALUE $rax, "x", DIExpression()
102*5f7ddb14SDimitry Andric if (MI.isDebugValueList() && VMI != VariableMap.end()) {
103*5f7ddb14SDimitry Andric VariableMap.erase(VMI);
104*5f7ddb14SDimitry Andric continue;
105*5f7ddb14SDimitry Andric }
106*5f7ddb14SDimitry Andric
107*5f7ddb14SDimitry Andric MachineOperand &Loc = MI.getDebugOperand(0);
108*5f7ddb14SDimitry Andric if (!Loc.isReg()) {
109*5f7ddb14SDimitry Andric // If it it's not a register, just stop tracking such variable.
110*5f7ddb14SDimitry Andric if (VMI != VariableMap.end())
111*5f7ddb14SDimitry Andric VariableMap.erase(VMI);
112*5f7ddb14SDimitry Andric continue;
113*5f7ddb14SDimitry Andric }
114*5f7ddb14SDimitry Andric
115*5f7ddb14SDimitry Andric // We have found a new value for a variable.
116*5f7ddb14SDimitry Andric if (VMI == VariableMap.end() ||
117*5f7ddb14SDimitry Andric VMI->second.first->getReg() != Loc.getReg() ||
118*5f7ddb14SDimitry Andric VMI->second.second != MI.getDebugExpression()) {
119*5f7ddb14SDimitry Andric VariableMap[Var] = {&Loc, MI.getDebugExpression()};
120*5f7ddb14SDimitry Andric continue;
121*5f7ddb14SDimitry Andric }
122*5f7ddb14SDimitry Andric
123*5f7ddb14SDimitry Andric // Found an identical DBG_VALUE, so it can be considered
124*5f7ddb14SDimitry Andric // for later removal.
125*5f7ddb14SDimitry Andric DbgValsToBeRemoved.push_back(&MI);
126*5f7ddb14SDimitry Andric }
127*5f7ddb14SDimitry Andric
128*5f7ddb14SDimitry Andric if (MI.isMetaInstruction())
129*5f7ddb14SDimitry Andric continue;
130*5f7ddb14SDimitry Andric
131*5f7ddb14SDimitry Andric // Stop tracking any location that is clobbered by this instruction.
132*5f7ddb14SDimitry Andric for (auto &Var : VariableMap) {
133*5f7ddb14SDimitry Andric auto &LocOp = Var.second.first;
134*5f7ddb14SDimitry Andric if (MI.modifiesRegister(LocOp->getReg(), TRI))
135*5f7ddb14SDimitry Andric VariableMap.erase(Var.first);
136*5f7ddb14SDimitry Andric }
137*5f7ddb14SDimitry Andric }
138*5f7ddb14SDimitry Andric
139*5f7ddb14SDimitry Andric for (auto &Instr : DbgValsToBeRemoved) {
140*5f7ddb14SDimitry Andric LLVM_DEBUG(dbgs() << "removing "; Instr->dump());
141*5f7ddb14SDimitry Andric Instr->eraseFromParent();
142*5f7ddb14SDimitry Andric ++NumRemovedForward;
143*5f7ddb14SDimitry Andric }
144*5f7ddb14SDimitry Andric
145*5f7ddb14SDimitry Andric return !DbgValsToBeRemoved.empty();
146*5f7ddb14SDimitry Andric }
147*5f7ddb14SDimitry Andric
148*5f7ddb14SDimitry Andric // This analysis aims to remove redundant DBG_VALUEs by going backward
149*5f7ddb14SDimitry Andric // in the basic block and removing all but the last DBG_VALUE for any
150*5f7ddb14SDimitry Andric // given variable in a set of consecutive DBG_VALUE instructions.
151*5f7ddb14SDimitry Andric // For example:
152*5f7ddb14SDimitry Andric // (1) DBG_VALUE $edi, !"var1", ...
153*5f7ddb14SDimitry Andric // (2) DBG_VALUE $esi, !"var2", ...
154*5f7ddb14SDimitry Andric // (3) DBG_VALUE $edi, !"var1", ...
155*5f7ddb14SDimitry Andric // ...
156*5f7ddb14SDimitry Andric // in this case, we can remove (1).
reduceDbgValsBackwardScan(MachineBasicBlock & MBB)157*5f7ddb14SDimitry Andric static bool reduceDbgValsBackwardScan(MachineBasicBlock &MBB) {
158*5f7ddb14SDimitry Andric LLVM_DEBUG(dbgs() << "\n == Backward Scan == \n");
159*5f7ddb14SDimitry Andric SmallVector<MachineInstr *, 8> DbgValsToBeRemoved;
160*5f7ddb14SDimitry Andric SmallDenseSet<DebugVariable> VariableSet;
161*5f7ddb14SDimitry Andric
162*5f7ddb14SDimitry Andric for (MachineBasicBlock::reverse_iterator I = MBB.rbegin(), E = MBB.rend();
163*5f7ddb14SDimitry Andric I != E; ++I) {
164*5f7ddb14SDimitry Andric MachineInstr *MI = &*I;
165*5f7ddb14SDimitry Andric
166*5f7ddb14SDimitry Andric if (MI->isDebugValue()) {
167*5f7ddb14SDimitry Andric DebugVariable Var(MI->getDebugVariable(), MI->getDebugExpression(),
168*5f7ddb14SDimitry Andric MI->getDebugLoc()->getInlinedAt());
169*5f7ddb14SDimitry Andric auto R = VariableSet.insert(Var);
170*5f7ddb14SDimitry Andric // If it is a DBG_VALUE describing a constant as:
171*5f7ddb14SDimitry Andric // DBG_VALUE 0, ...
172*5f7ddb14SDimitry Andric // we just don't consider such instructions as candidates
173*5f7ddb14SDimitry Andric // for redundant removal.
174*5f7ddb14SDimitry Andric if (MI->isNonListDebugValue()) {
175*5f7ddb14SDimitry Andric MachineOperand &Loc = MI->getDebugOperand(0);
176*5f7ddb14SDimitry Andric if (!Loc.isReg()) {
177*5f7ddb14SDimitry Andric // If we have already encountered this variable, just stop
178*5f7ddb14SDimitry Andric // tracking it.
179*5f7ddb14SDimitry Andric if (!R.second)
180*5f7ddb14SDimitry Andric VariableSet.erase(Var);
181*5f7ddb14SDimitry Andric continue;
182*5f7ddb14SDimitry Andric }
183*5f7ddb14SDimitry Andric }
184*5f7ddb14SDimitry Andric
185*5f7ddb14SDimitry Andric // We have already encountered the value for this variable,
186*5f7ddb14SDimitry Andric // so this one can be deleted.
187*5f7ddb14SDimitry Andric if (!R.second)
188*5f7ddb14SDimitry Andric DbgValsToBeRemoved.push_back(MI);
189*5f7ddb14SDimitry Andric continue;
190*5f7ddb14SDimitry Andric }
191*5f7ddb14SDimitry Andric
192*5f7ddb14SDimitry Andric // If we encountered a non-DBG_VALUE, try to find the next
193*5f7ddb14SDimitry Andric // sequence with consecutive DBG_VALUE instructions.
194*5f7ddb14SDimitry Andric VariableSet.clear();
195*5f7ddb14SDimitry Andric }
196*5f7ddb14SDimitry Andric
197*5f7ddb14SDimitry Andric for (auto &Instr : DbgValsToBeRemoved) {
198*5f7ddb14SDimitry Andric LLVM_DEBUG(dbgs() << "removing "; Instr->dump());
199*5f7ddb14SDimitry Andric Instr->eraseFromParent();
200*5f7ddb14SDimitry Andric ++NumRemovedBackward;
201*5f7ddb14SDimitry Andric }
202*5f7ddb14SDimitry Andric
203*5f7ddb14SDimitry Andric return !DbgValsToBeRemoved.empty();
204*5f7ddb14SDimitry Andric }
205*5f7ddb14SDimitry Andric
reduceDbgValues(MachineFunction & MF)206*5f7ddb14SDimitry Andric bool RemoveRedundantDebugValues::reduceDbgValues(MachineFunction &MF) {
207*5f7ddb14SDimitry Andric LLVM_DEBUG(dbgs() << "\nDebug Value Reduction\n");
208*5f7ddb14SDimitry Andric
209*5f7ddb14SDimitry Andric bool Changed = false;
210*5f7ddb14SDimitry Andric
211*5f7ddb14SDimitry Andric for (auto &MBB : MF) {
212*5f7ddb14SDimitry Andric Changed |= reduceDbgValsBackwardScan(MBB);
213*5f7ddb14SDimitry Andric Changed |= reduceDbgValsForwardScan(MBB);
214*5f7ddb14SDimitry Andric }
215*5f7ddb14SDimitry Andric
216*5f7ddb14SDimitry Andric return Changed;
217*5f7ddb14SDimitry Andric }
218*5f7ddb14SDimitry Andric
runOnMachineFunction(MachineFunction & MF)219*5f7ddb14SDimitry Andric bool RemoveRedundantDebugValues::runOnMachineFunction(MachineFunction &MF) {
220*5f7ddb14SDimitry Andric // Skip functions without debugging information.
221*5f7ddb14SDimitry Andric if (!MF.getFunction().getSubprogram())
222*5f7ddb14SDimitry Andric return false;
223*5f7ddb14SDimitry Andric
224*5f7ddb14SDimitry Andric // Skip functions from NoDebug compilation units.
225*5f7ddb14SDimitry Andric if (MF.getFunction().getSubprogram()->getUnit()->getEmissionKind() ==
226*5f7ddb14SDimitry Andric DICompileUnit::NoDebug)
227*5f7ddb14SDimitry Andric return false;
228*5f7ddb14SDimitry Andric
229*5f7ddb14SDimitry Andric bool Changed = reduceDbgValues(MF);
230*5f7ddb14SDimitry Andric return Changed;
231*5f7ddb14SDimitry Andric }
232