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