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