xref: /src/contrib/llvm-project/llvm/lib/CodeGen/RemoveRedundantDebugValues.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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