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