|  | //===- RemoveRedundantDebugValues.cpp - Remove Redundant Debug Value MIs --===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/CodeGen/RemoveRedundantDebugValues.h" | 
|  | #include "llvm/ADT/DenseMap.h" | 
|  | #include "llvm/ADT/DenseSet.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/CodeGen/MachineBasicBlock.h" | 
|  | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | #include "llvm/CodeGen/TargetSubtargetInfo.h" | 
|  | #include "llvm/IR/DebugInfoMetadata.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/InitializePasses.h" | 
|  | #include "llvm/Pass.h" | 
|  | #include "llvm/PassRegistry.h" | 
|  |  | 
|  | /// \file RemoveRedundantDebugValues.cpp | 
|  | /// | 
|  | /// The RemoveRedundantDebugValues pass removes redundant DBG_VALUEs that | 
|  | /// appear in MIR after the register allocator. | 
|  |  | 
|  | #define DEBUG_TYPE "removeredundantdebugvalues" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | STATISTIC(NumRemovedBackward, "Number of DBG_VALUEs removed (backward scan)"); | 
|  | STATISTIC(NumRemovedForward, "Number of DBG_VALUEs removed (forward scan)"); | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct RemoveRedundantDebugValuesImpl { | 
|  | bool reduceDbgValues(MachineFunction &MF); | 
|  | }; | 
|  |  | 
|  | class RemoveRedundantDebugValuesLegacy : public MachineFunctionPass { | 
|  | public: | 
|  | static char ID; | 
|  |  | 
|  | RemoveRedundantDebugValuesLegacy(); | 
|  | /// Remove redundant debug value MIs for the given machine function. | 
|  | bool runOnMachineFunction(MachineFunction &MF) override; | 
|  |  | 
|  | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
|  | AU.setPreservesCFG(); | 
|  | MachineFunctionPass::getAnalysisUsage(AU); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //            Implementation | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | char RemoveRedundantDebugValuesLegacy::ID = 0; | 
|  |  | 
|  | char &llvm::RemoveRedundantDebugValuesID = RemoveRedundantDebugValuesLegacy::ID; | 
|  |  | 
|  | INITIALIZE_PASS(RemoveRedundantDebugValuesLegacy, DEBUG_TYPE, | 
|  | "Remove Redundant DEBUG_VALUE analysis", false, false) | 
|  |  | 
|  | /// Default construct and initialize the pass. | 
|  | RemoveRedundantDebugValuesLegacy::RemoveRedundantDebugValuesLegacy() | 
|  | : MachineFunctionPass(ID) { | 
|  | initializeRemoveRedundantDebugValuesLegacyPass( | 
|  | *PassRegistry::getPassRegistry()); | 
|  | } | 
|  |  | 
|  | // This analysis aims to remove redundant DBG_VALUEs by going forward | 
|  | // in the basic block by considering the first DBG_VALUE as a valid | 
|  | // until its first (location) operand is not clobbered/modified. | 
|  | // For example: | 
|  | //   (1) DBG_VALUE $edi, !"var1", ... | 
|  | //   (2) <block of code that does affect $edi> | 
|  | //   (3) DBG_VALUE $edi, !"var1", ... | 
|  | //   ... | 
|  | // in this case, we can remove (3). | 
|  | // TODO: Support DBG_VALUE_LIST and other debug instructions. | 
|  | static bool reduceDbgValsForwardScan(MachineBasicBlock &MBB) { | 
|  | LLVM_DEBUG(dbgs() << "\n == Forward Scan == \n"); | 
|  |  | 
|  | SmallVector<MachineInstr *, 8> DbgValsToBeRemoved; | 
|  | DenseMap<DebugVariable, std::pair<MachineOperand *, const DIExpression *>> | 
|  | VariableMap; | 
|  | const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo(); | 
|  |  | 
|  | for (auto &MI : MBB) { | 
|  | if (MI.isDebugValue()) { | 
|  | DebugVariable Var(MI.getDebugVariable(), std::nullopt, | 
|  | MI.getDebugLoc()->getInlinedAt()); | 
|  | auto VMI = VariableMap.find(Var); | 
|  | // Just stop tracking this variable, until we cover DBG_VALUE_LIST. | 
|  | // 1  DBG_VALUE $rax, "x", DIExpression() | 
|  | // ... | 
|  | // 2  DBG_VALUE_LIST "x", DIExpression(...), $rax, $rbx | 
|  | // ... | 
|  | // 3  DBG_VALUE $rax, "x", DIExpression() | 
|  | if (MI.isDebugValueList() && VMI != VariableMap.end()) { | 
|  | VariableMap.erase(VMI); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | MachineOperand &Loc = MI.getDebugOperand(0); | 
|  | if (!Loc.isReg()) { | 
|  | // If it's not a register, just stop tracking such variable. | 
|  | if (VMI != VariableMap.end()) | 
|  | VariableMap.erase(VMI); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // We have found a new value for a variable. | 
|  | if (VMI == VariableMap.end() || | 
|  | VMI->second.first->getReg() != Loc.getReg() || | 
|  | VMI->second.second != MI.getDebugExpression()) { | 
|  | VariableMap[Var] = {&Loc, MI.getDebugExpression()}; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Found an identical DBG_VALUE, so it can be considered | 
|  | // for later removal. | 
|  | DbgValsToBeRemoved.push_back(&MI); | 
|  | } | 
|  |  | 
|  | if (MI.isMetaInstruction()) | 
|  | continue; | 
|  |  | 
|  | // Stop tracking any location that is clobbered by this instruction. | 
|  | for (auto &Var : VariableMap) { | 
|  | auto &LocOp = Var.second.first; | 
|  | if (MI.modifiesRegister(LocOp->getReg(), TRI)) | 
|  | VariableMap.erase(Var.first); | 
|  | } | 
|  | } | 
|  |  | 
|  | for (auto &Instr : DbgValsToBeRemoved) { | 
|  | LLVM_DEBUG(dbgs() << "removing "; Instr->dump()); | 
|  | Instr->eraseFromParent(); | 
|  | ++NumRemovedForward; | 
|  | } | 
|  |  | 
|  | return !DbgValsToBeRemoved.empty(); | 
|  | } | 
|  |  | 
|  | // This analysis aims to remove redundant DBG_VALUEs by going backward | 
|  | // in the basic block and removing all but the last DBG_VALUE for any | 
|  | // given variable in a set of consecutive DBG_VALUE instructions. | 
|  | // For example: | 
|  | //   (1) DBG_VALUE $edi, !"var1", ... | 
|  | //   (2) DBG_VALUE $esi, !"var2", ... | 
|  | //   (3) DBG_VALUE $edi, !"var1", ... | 
|  | //   ... | 
|  | // in this case, we can remove (1). | 
|  | static bool reduceDbgValsBackwardScan(MachineBasicBlock &MBB) { | 
|  | LLVM_DEBUG(dbgs() << "\n == Backward Scan == \n"); | 
|  | SmallVector<MachineInstr *, 8> DbgValsToBeRemoved; | 
|  | SmallDenseSet<DebugVariable> VariableSet; | 
|  |  | 
|  | for (MachineInstr &MI : llvm::reverse(MBB)) { | 
|  | if (MI.isDebugValue()) { | 
|  | DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(), | 
|  | MI.getDebugLoc()->getInlinedAt()); | 
|  | auto R = VariableSet.insert(Var); | 
|  | // If it is a DBG_VALUE describing a constant as: | 
|  | //   DBG_VALUE 0, ... | 
|  | // we just don't consider such instructions as candidates | 
|  | // for redundant removal. | 
|  | if (MI.isNonListDebugValue()) { | 
|  | MachineOperand &Loc = MI.getDebugOperand(0); | 
|  | if (!Loc.isReg()) { | 
|  | // If we have already encountered this variable, just stop | 
|  | // tracking it. | 
|  | if (!R.second) | 
|  | VariableSet.erase(Var); | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | // We have already encountered the value for this variable, | 
|  | // so this one can be deleted. | 
|  | if (!R.second) | 
|  | DbgValsToBeRemoved.push_back(&MI); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // If we encountered a non-DBG_VALUE, try to find the next | 
|  | // sequence with consecutive DBG_VALUE instructions. | 
|  | VariableSet.clear(); | 
|  | } | 
|  |  | 
|  | for (auto &Instr : DbgValsToBeRemoved) { | 
|  | LLVM_DEBUG(dbgs() << "removing "; Instr->dump()); | 
|  | Instr->eraseFromParent(); | 
|  | ++NumRemovedBackward; | 
|  | } | 
|  |  | 
|  | return !DbgValsToBeRemoved.empty(); | 
|  | } | 
|  |  | 
|  | bool RemoveRedundantDebugValuesImpl::reduceDbgValues(MachineFunction &MF) { | 
|  | LLVM_DEBUG(dbgs() << "\nDebug Value Reduction\n"); | 
|  |  | 
|  | bool Changed = false; | 
|  |  | 
|  | for (auto &MBB : MF) { | 
|  | Changed |= reduceDbgValsBackwardScan(MBB); | 
|  | Changed |= reduceDbgValsForwardScan(MBB); | 
|  | } | 
|  |  | 
|  | return Changed; | 
|  | } | 
|  |  | 
|  | bool RemoveRedundantDebugValuesLegacy::runOnMachineFunction( | 
|  | MachineFunction &MF) { | 
|  | // Skip functions without debugging information or functions from NoDebug | 
|  | // compilation units. | 
|  | if (!MF.getFunction().getSubprogram() || | 
|  | (MF.getFunction().getSubprogram()->getUnit()->getEmissionKind() == | 
|  | DICompileUnit::NoDebug)) | 
|  | return false; | 
|  |  | 
|  | return RemoveRedundantDebugValuesImpl().reduceDbgValues(MF); | 
|  | } | 
|  |  | 
|  | PreservedAnalyses | 
|  | RemoveRedundantDebugValuesPass::run(MachineFunction &MF, | 
|  | MachineFunctionAnalysisManager &MFAM) { | 
|  | // Skip functions without debugging information or functions from NoDebug | 
|  | // compilation units. | 
|  | if (!MF.getFunction().getSubprogram() || | 
|  | (MF.getFunction().getSubprogram()->getUnit()->getEmissionKind() == | 
|  | DICompileUnit::NoDebug)) | 
|  | return PreservedAnalyses::all(); | 
|  |  | 
|  | if (!RemoveRedundantDebugValuesImpl().reduceDbgValues(MF)) | 
|  | return PreservedAnalyses::all(); | 
|  |  | 
|  | auto PA = getMachineFunctionPassPreservedAnalyses(); | 
|  | PA.preserveSet<CFGAnalyses>(); | 
|  | return PA; | 
|  | } |