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