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