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(Registry&: *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(Val: 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(I: VMI); |
103 | continue; |
104 | } |
105 | |
106 | MachineOperand &Loc = MI.getDebugOperand(Index: 0); |
107 | if (!Loc.isReg()) { |
108 | // If it's not a register, just stop tracking such variable. |
109 | if (VMI != VariableMap.end()) |
110 | VariableMap.erase(I: 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(Elt: &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(Reg: LocOp->getReg(), TRI)) |
134 | VariableMap.erase(Val: 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(C&: MBB)) { |
162 | if (MI.isDebugValue()) { |
163 | DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(), |
164 | MI.getDebugLoc()->getInlinedAt()); |
165 | auto R = VariableSet.insert(V: 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(Index: 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(V: 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(Elt: &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 | |