forked from OSchip/llvm-project
228 lines
7.3 KiB
C++
228 lines
7.3 KiB
C++
//===- 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/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 {
|
|
|
|
class RemoveRedundantDebugValues : public MachineFunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
RemoveRedundantDebugValues();
|
|
|
|
bool reduceDbgValues(MachineFunction &MF);
|
|
|
|
/// 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 RemoveRedundantDebugValues::ID = 0;
|
|
|
|
char &llvm::RemoveRedundantDebugValuesID = RemoveRedundantDebugValues::ID;
|
|
|
|
INITIALIZE_PASS(RemoveRedundantDebugValues, DEBUG_TYPE,
|
|
"Remove Redundant DEBUG_VALUE analysis", false, false)
|
|
|
|
/// Default construct and initialize the pass.
|
|
RemoveRedundantDebugValues::RemoveRedundantDebugValues()
|
|
: MachineFunctionPass(ID) {
|
|
initializeRemoveRedundantDebugValuesPass(*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(), NoneType(),
|
|
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 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 RemoveRedundantDebugValues::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 RemoveRedundantDebugValues::runOnMachineFunction(MachineFunction &MF) {
|
|
// Skip functions without debugging information.
|
|
if (!MF.getFunction().getSubprogram())
|
|
return false;
|
|
|
|
// Skip functions from NoDebug compilation units.
|
|
if (MF.getFunction().getSubprogram()->getUnit()->getEmissionKind() ==
|
|
DICompileUnit::NoDebug)
|
|
return false;
|
|
|
|
bool Changed = reduceDbgValues(MF);
|
|
return Changed;
|
|
}
|