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