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