1344a3780SDimitry Andric //===- RemoveRedundantDebugValues.cpp - Remove Redundant Debug Value MIs --===//
2344a3780SDimitry Andric //
3344a3780SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4344a3780SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5344a3780SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6344a3780SDimitry Andric //
7344a3780SDimitry Andric //===----------------------------------------------------------------------===//
8344a3780SDimitry Andric
9344a3780SDimitry Andric #include "llvm/ADT/DenseMap.h"
10344a3780SDimitry Andric #include "llvm/ADT/DenseSet.h"
11344a3780SDimitry Andric #include "llvm/ADT/SmallVector.h"
12344a3780SDimitry Andric #include "llvm/ADT/Statistic.h"
13344a3780SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
14344a3780SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
15344a3780SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
16344a3780SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
17344a3780SDimitry Andric #include "llvm/IR/Function.h"
18344a3780SDimitry Andric #include "llvm/InitializePasses.h"
19344a3780SDimitry Andric #include "llvm/Pass.h"
20145449b1SDimitry Andric #include "llvm/PassRegistry.h"
21344a3780SDimitry Andric
22344a3780SDimitry Andric /// \file RemoveRedundantDebugValues.cpp
23344a3780SDimitry Andric ///
24344a3780SDimitry Andric /// The RemoveRedundantDebugValues pass removes redundant DBG_VALUEs that
25344a3780SDimitry Andric /// appear in MIR after the register allocator.
26344a3780SDimitry Andric
27344a3780SDimitry Andric #define DEBUG_TYPE "removeredundantdebugvalues"
28344a3780SDimitry Andric
29344a3780SDimitry Andric using namespace llvm;
30344a3780SDimitry Andric
31344a3780SDimitry Andric STATISTIC(NumRemovedBackward, "Number of DBG_VALUEs removed (backward scan)");
32344a3780SDimitry Andric STATISTIC(NumRemovedForward, "Number of DBG_VALUEs removed (forward scan)");
33344a3780SDimitry Andric
34344a3780SDimitry Andric namespace {
35344a3780SDimitry Andric
36344a3780SDimitry Andric class RemoveRedundantDebugValues : public MachineFunctionPass {
37344a3780SDimitry Andric public:
38344a3780SDimitry Andric static char ID;
39344a3780SDimitry Andric
40344a3780SDimitry Andric RemoveRedundantDebugValues();
41344a3780SDimitry Andric
42344a3780SDimitry Andric bool reduceDbgValues(MachineFunction &MF);
43344a3780SDimitry Andric
44344a3780SDimitry Andric /// Remove redundant debug value MIs for the given machine function.
45344a3780SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
46344a3780SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const47344a3780SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
48344a3780SDimitry Andric AU.setPreservesCFG();
49344a3780SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
50344a3780SDimitry Andric }
51344a3780SDimitry Andric };
52344a3780SDimitry Andric
53344a3780SDimitry Andric } // namespace
54344a3780SDimitry Andric
55344a3780SDimitry Andric //===----------------------------------------------------------------------===//
56344a3780SDimitry Andric // Implementation
57344a3780SDimitry Andric //===----------------------------------------------------------------------===//
58344a3780SDimitry Andric
59344a3780SDimitry Andric char RemoveRedundantDebugValues::ID = 0;
60344a3780SDimitry Andric
61344a3780SDimitry Andric char &llvm::RemoveRedundantDebugValuesID = RemoveRedundantDebugValues::ID;
62344a3780SDimitry Andric
63344a3780SDimitry Andric INITIALIZE_PASS(RemoveRedundantDebugValues, DEBUG_TYPE,
64344a3780SDimitry Andric "Remove Redundant DEBUG_VALUE analysis", false, false)
65344a3780SDimitry Andric
66344a3780SDimitry Andric /// Default construct and initialize the pass.
RemoveRedundantDebugValues()67344a3780SDimitry Andric RemoveRedundantDebugValues::RemoveRedundantDebugValues()
68344a3780SDimitry Andric : MachineFunctionPass(ID) {
69344a3780SDimitry Andric initializeRemoveRedundantDebugValuesPass(*PassRegistry::getPassRegistry());
70344a3780SDimitry Andric }
71344a3780SDimitry Andric
72344a3780SDimitry Andric // This analysis aims to remove redundant DBG_VALUEs by going forward
73344a3780SDimitry Andric // in the basic block by considering the first DBG_VALUE as a valid
74344a3780SDimitry Andric // until its first (location) operand is not clobbered/modified.
75344a3780SDimitry Andric // For example:
76344a3780SDimitry Andric // (1) DBG_VALUE $edi, !"var1", ...
77344a3780SDimitry Andric // (2) <block of code that does affect $edi>
78344a3780SDimitry Andric // (3) DBG_VALUE $edi, !"var1", ...
79344a3780SDimitry Andric // ...
80344a3780SDimitry Andric // in this case, we can remove (3).
81344a3780SDimitry Andric // TODO: Support DBG_VALUE_LIST and other debug instructions.
reduceDbgValsForwardScan(MachineBasicBlock & MBB)82344a3780SDimitry Andric static bool reduceDbgValsForwardScan(MachineBasicBlock &MBB) {
83344a3780SDimitry Andric LLVM_DEBUG(dbgs() << "\n == Forward Scan == \n");
84344a3780SDimitry Andric
85344a3780SDimitry Andric SmallVector<MachineInstr *, 8> DbgValsToBeRemoved;
86344a3780SDimitry Andric DenseMap<DebugVariable, std::pair<MachineOperand *, const DIExpression *>>
87344a3780SDimitry Andric VariableMap;
88344a3780SDimitry Andric const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();
89344a3780SDimitry Andric
90344a3780SDimitry Andric for (auto &MI : MBB) {
91344a3780SDimitry Andric if (MI.isDebugValue()) {
92e3b55780SDimitry Andric DebugVariable Var(MI.getDebugVariable(), std::nullopt,
93344a3780SDimitry Andric MI.getDebugLoc()->getInlinedAt());
94344a3780SDimitry Andric auto VMI = VariableMap.find(Var);
95344a3780SDimitry Andric // Just stop tracking this variable, until we cover DBG_VALUE_LIST.
96344a3780SDimitry Andric // 1 DBG_VALUE $rax, "x", DIExpression()
97344a3780SDimitry Andric // ...
98344a3780SDimitry Andric // 2 DBG_VALUE_LIST "x", DIExpression(...), $rax, $rbx
99344a3780SDimitry Andric // ...
100344a3780SDimitry Andric // 3 DBG_VALUE $rax, "x", DIExpression()
101344a3780SDimitry Andric if (MI.isDebugValueList() && VMI != VariableMap.end()) {
102344a3780SDimitry Andric VariableMap.erase(VMI);
103344a3780SDimitry Andric continue;
104344a3780SDimitry Andric }
105344a3780SDimitry Andric
106344a3780SDimitry Andric MachineOperand &Loc = MI.getDebugOperand(0);
107344a3780SDimitry Andric if (!Loc.isReg()) {
108b1c73532SDimitry Andric // If it's not a register, just stop tracking such variable.
109344a3780SDimitry Andric if (VMI != VariableMap.end())
110344a3780SDimitry Andric VariableMap.erase(VMI);
111344a3780SDimitry Andric continue;
112344a3780SDimitry Andric }
113344a3780SDimitry Andric
114344a3780SDimitry Andric // We have found a new value for a variable.
115344a3780SDimitry Andric if (VMI == VariableMap.end() ||
116344a3780SDimitry Andric VMI->second.first->getReg() != Loc.getReg() ||
117344a3780SDimitry Andric VMI->second.second != MI.getDebugExpression()) {
118344a3780SDimitry Andric VariableMap[Var] = {&Loc, MI.getDebugExpression()};
119344a3780SDimitry Andric continue;
120344a3780SDimitry Andric }
121344a3780SDimitry Andric
122344a3780SDimitry Andric // Found an identical DBG_VALUE, so it can be considered
123344a3780SDimitry Andric // for later removal.
124344a3780SDimitry Andric DbgValsToBeRemoved.push_back(&MI);
125344a3780SDimitry Andric }
126344a3780SDimitry Andric
127344a3780SDimitry Andric if (MI.isMetaInstruction())
128344a3780SDimitry Andric continue;
129344a3780SDimitry Andric
130344a3780SDimitry Andric // Stop tracking any location that is clobbered by this instruction.
131344a3780SDimitry Andric for (auto &Var : VariableMap) {
132344a3780SDimitry Andric auto &LocOp = Var.second.first;
133344a3780SDimitry Andric if (MI.modifiesRegister(LocOp->getReg(), TRI))
134344a3780SDimitry Andric VariableMap.erase(Var.first);
135344a3780SDimitry Andric }
136344a3780SDimitry Andric }
137344a3780SDimitry Andric
138344a3780SDimitry Andric for (auto &Instr : DbgValsToBeRemoved) {
139344a3780SDimitry Andric LLVM_DEBUG(dbgs() << "removing "; Instr->dump());
140344a3780SDimitry Andric Instr->eraseFromParent();
141344a3780SDimitry Andric ++NumRemovedForward;
142344a3780SDimitry Andric }
143344a3780SDimitry Andric
144344a3780SDimitry Andric return !DbgValsToBeRemoved.empty();
145344a3780SDimitry Andric }
146344a3780SDimitry Andric
147344a3780SDimitry Andric // This analysis aims to remove redundant DBG_VALUEs by going backward
148344a3780SDimitry Andric // in the basic block and removing all but the last DBG_VALUE for any
149344a3780SDimitry Andric // given variable in a set of consecutive DBG_VALUE instructions.
150344a3780SDimitry Andric // For example:
151344a3780SDimitry Andric // (1) DBG_VALUE $edi, !"var1", ...
152344a3780SDimitry Andric // (2) DBG_VALUE $esi, !"var2", ...
153344a3780SDimitry Andric // (3) DBG_VALUE $edi, !"var1", ...
154344a3780SDimitry Andric // ...
155344a3780SDimitry Andric // in this case, we can remove (1).
reduceDbgValsBackwardScan(MachineBasicBlock & MBB)156344a3780SDimitry Andric static bool reduceDbgValsBackwardScan(MachineBasicBlock &MBB) {
157344a3780SDimitry Andric LLVM_DEBUG(dbgs() << "\n == Backward Scan == \n");
158344a3780SDimitry Andric SmallVector<MachineInstr *, 8> DbgValsToBeRemoved;
159344a3780SDimitry Andric SmallDenseSet<DebugVariable> VariableSet;
160344a3780SDimitry Andric
16177fc4c14SDimitry Andric for (MachineInstr &MI : llvm::reverse(MBB)) {
16277fc4c14SDimitry Andric if (MI.isDebugValue()) {
16377fc4c14SDimitry Andric DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
16477fc4c14SDimitry Andric MI.getDebugLoc()->getInlinedAt());
165344a3780SDimitry Andric auto R = VariableSet.insert(Var);
166344a3780SDimitry Andric // If it is a DBG_VALUE describing a constant as:
167344a3780SDimitry Andric // DBG_VALUE 0, ...
168344a3780SDimitry Andric // we just don't consider such instructions as candidates
169344a3780SDimitry Andric // for redundant removal.
17077fc4c14SDimitry Andric if (MI.isNonListDebugValue()) {
17177fc4c14SDimitry Andric MachineOperand &Loc = MI.getDebugOperand(0);
172344a3780SDimitry Andric if (!Loc.isReg()) {
173344a3780SDimitry Andric // If we have already encountered this variable, just stop
174344a3780SDimitry Andric // tracking it.
175344a3780SDimitry Andric if (!R.second)
176344a3780SDimitry Andric VariableSet.erase(Var);
177344a3780SDimitry Andric continue;
178344a3780SDimitry Andric }
179344a3780SDimitry Andric }
180344a3780SDimitry Andric
181344a3780SDimitry Andric // We have already encountered the value for this variable,
182344a3780SDimitry Andric // so this one can be deleted.
183344a3780SDimitry Andric if (!R.second)
18477fc4c14SDimitry Andric DbgValsToBeRemoved.push_back(&MI);
185344a3780SDimitry Andric continue;
186344a3780SDimitry Andric }
187344a3780SDimitry Andric
188344a3780SDimitry Andric // If we encountered a non-DBG_VALUE, try to find the next
189344a3780SDimitry Andric // sequence with consecutive DBG_VALUE instructions.
190344a3780SDimitry Andric VariableSet.clear();
191344a3780SDimitry Andric }
192344a3780SDimitry Andric
193344a3780SDimitry Andric for (auto &Instr : DbgValsToBeRemoved) {
194344a3780SDimitry Andric LLVM_DEBUG(dbgs() << "removing "; Instr->dump());
195344a3780SDimitry Andric Instr->eraseFromParent();
196344a3780SDimitry Andric ++NumRemovedBackward;
197344a3780SDimitry Andric }
198344a3780SDimitry Andric
199344a3780SDimitry Andric return !DbgValsToBeRemoved.empty();
200344a3780SDimitry Andric }
201344a3780SDimitry Andric
reduceDbgValues(MachineFunction & MF)202344a3780SDimitry Andric bool RemoveRedundantDebugValues::reduceDbgValues(MachineFunction &MF) {
203344a3780SDimitry Andric LLVM_DEBUG(dbgs() << "\nDebug Value Reduction\n");
204344a3780SDimitry Andric
205344a3780SDimitry Andric bool Changed = false;
206344a3780SDimitry Andric
207344a3780SDimitry Andric for (auto &MBB : MF) {
208344a3780SDimitry Andric Changed |= reduceDbgValsBackwardScan(MBB);
209344a3780SDimitry Andric Changed |= reduceDbgValsForwardScan(MBB);
210344a3780SDimitry Andric }
211344a3780SDimitry Andric
212344a3780SDimitry Andric return Changed;
213344a3780SDimitry Andric }
214344a3780SDimitry Andric
runOnMachineFunction(MachineFunction & MF)215344a3780SDimitry Andric bool RemoveRedundantDebugValues::runOnMachineFunction(MachineFunction &MF) {
216344a3780SDimitry Andric // Skip functions without debugging information.
217344a3780SDimitry Andric if (!MF.getFunction().getSubprogram())
218344a3780SDimitry Andric return false;
219344a3780SDimitry Andric
220344a3780SDimitry Andric // Skip functions from NoDebug compilation units.
221344a3780SDimitry Andric if (MF.getFunction().getSubprogram()->getUnit()->getEmissionKind() ==
222344a3780SDimitry Andric DICompileUnit::NoDebug)
223344a3780SDimitry Andric return false;
224344a3780SDimitry Andric
225344a3780SDimitry Andric bool Changed = reduceDbgValues(MF);
226344a3780SDimitry Andric return Changed;
227344a3780SDimitry Andric }
228