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