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