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