Skip to content

Commit

Permalink
[LiveDebugValues] Tracking copying value between registers
Browse files Browse the repository at this point in the history
During the execution of long functions or functions that have a lot of
inlined code it could come to the situation where tracked value could be
transferred from one register to another. The transfer is recognized only if
destination register is a callee saved register and if source register is
killed. We do not salvage caller-saved registers since there is a great
chance that killed register would outlive it.

Patch by Nikola Prica.

Differential Revision: https://reviews.llvm.org/D44016

llvm-svn: 336978
  • Loading branch information
petar-jovanovic committed Jul 13, 2018
1 parent 95d9d22 commit be2e80a
Show file tree
Hide file tree
Showing 4 changed files with 705 additions and 52 deletions.
179 changes: 127 additions & 52 deletions llvm/lib/CodeGen/LiveDebugValues.cpp
Expand Up @@ -40,6 +40,7 @@
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
Expand Down Expand Up @@ -82,6 +83,7 @@ class LiveDebugValues : public MachineFunctionPass {
const TargetRegisterInfo *TRI;
const TargetInstrInfo *TII;
const TargetFrameLowering *TFI;
BitVector CalleeSavedRegs;
LexicalScopes LS;

/// Keeps track of lexical scopes associated with a user value's source
Expand Down Expand Up @@ -179,11 +181,11 @@ class LiveDebugValues : public MachineFunctionPass {
using VarLocMap = UniqueVector<VarLoc>;
using VarLocSet = SparseBitVector<>;
using VarLocInMBB = SmallDenseMap<const MachineBasicBlock *, VarLocSet>;
struct SpillDebugPair {
MachineInstr *SpillInst;
struct TransferDebugPair {
MachineInstr *TransferInst;
MachineInstr *DebugInst;
};
using SpillMap = SmallVector<SpillDebugPair, 4>;
using TransferMap = SmallVector<TransferDebugPair, 4>;

/// This holds the working set of currently open ranges. For fast
/// access, this is done both as a set of VarLocIDs, and a map of
Expand Down Expand Up @@ -236,18 +238,23 @@ class LiveDebugValues : public MachineFunctionPass {
bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF,
unsigned &Reg);
int extractSpillBaseRegAndOffset(const MachineInstr &MI, unsigned &Reg);
void insertTransferDebugPair(MachineInstr &MI, OpenRangesSet &OpenRanges,
TransferMap &Transfers, VarLocMap &VarLocIDs,
unsigned OldVarID, unsigned NewReg = 0);

void transferDebugValue(const MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs);
void transferSpillInst(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs, SpillMap &Spills);
VarLocMap &VarLocIDs, TransferMap &Transfers);
void transferRegisterCopy(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs, TransferMap &Transfers);
void transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges,
const VarLocMap &VarLocIDs);
bool transferTerminatorInst(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocInMBB &OutLocs, const VarLocMap &VarLocIDs);
bool transfer(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs, SpillMap &Spills,
bool transferSpills);
bool process(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs,
TransferMap &Transfers, bool transferChanges);

bool join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs,
const VarLocMap &VarLocIDs,
Expand Down Expand Up @@ -370,6 +377,54 @@ void LiveDebugValues::transferDebugValue(const MachineInstr &MI,
}
}

/// Create new TransferDebugPair and insert it in \p Transfers. The VarLoc
/// with \p OldVarID should be deleted form \p OpenRanges and replaced with
/// new VarLoc. If \p NewReg is different than default zero value then the
/// new location will be register location created by the copy like instruction,
/// otherwise it is variable's location on the stack.
void LiveDebugValues::insertTransferDebugPair(
MachineInstr &MI, OpenRangesSet &OpenRanges, TransferMap &Transfers,
VarLocMap &VarLocIDs, unsigned OldVarID, unsigned NewReg) {
const MachineInstr *DMI = &VarLocIDs[OldVarID].MI;
MachineFunction *MF = MI.getParent()->getParent();
MachineInstr *NewDMI;
if (NewReg) {
// Create a DBG_VALUE instruction to describe the Var in its new
// register location.
NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(),
DMI->isIndirectDebugValue(), NewReg,
DMI->getDebugVariable(), DMI->getDebugExpression());
if (DMI->isIndirectDebugValue())
NewDMI->getOperand(1).setImm(DMI->getOperand(1).getImm());
LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register copy: ";
NewDMI->print(dbgs(), false, false, false, TII));
} else {
// Create a DBG_VALUE instruction to describe the Var in its spilled
// location.
unsigned SpillBase;
int SpillOffset = extractSpillBaseRegAndOffset(MI, SpillBase);
auto *SpillExpr = DIExpression::prepend(DMI->getDebugExpression(),
DIExpression::NoDeref, SpillOffset);
NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, SpillBase,
DMI->getDebugVariable(), SpillExpr);
LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: ";
NewDMI->print(dbgs(), false, false, false, TII));
}

// The newly created DBG_VALUE instruction NewDMI must be inserted after
// MI. Keep track of the pairing.
TransferDebugPair MIP = {&MI, NewDMI};
Transfers.push_back(MIP);

// End all previous ranges of Var.
OpenRanges.erase(VarLocIDs[OldVarID].Var);

// Add the VarLoc to OpenRanges.
VarLoc VL(*NewDMI, LS);
unsigned LocID = VarLocIDs.insert(VL);
OpenRanges.insert(LocID, VL.Var);
}

/// A definition of a register may mark the end of a range.
void LiveDebugValues::transferRegisterDef(MachineInstr &MI,
OpenRangesSet &OpenRanges,
Expand Down Expand Up @@ -464,14 +519,14 @@ bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI,

/// A spilled register may indicate that we have to end the current range of
/// a variable and create a new one for the spill location.
/// We don't want to insert any instructions in transfer(), so we just create
/// the DBG_VALUE witout inserting it and keep track of it in @Spills.
/// We don't want to insert any instructions in process(), so we just create
/// the DBG_VALUE without inserting it and keep track of it in \p Transfers.
/// It will be inserted into the BB when we're done iterating over the
/// instructions.
void LiveDebugValues::transferSpillInst(MachineInstr &MI,
OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs,
SpillMap &Spills) {
TransferMap &Transfers) {
unsigned Reg;
MachineFunction *MF = MI.getMF();
if (!isSpillInstruction(MI, MF, Reg))
Expand All @@ -482,33 +537,47 @@ void LiveDebugValues::transferSpillInst(MachineInstr &MI,
if (VarLocIDs[ID].isDescribedByReg() == Reg) {
LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '('
<< VarLocIDs[ID].Var.getVar()->getName() << ")\n");
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID);
return;
}
}
}

// Create a DBG_VALUE instruction to describe the Var in its spilled
// location, but don't insert it yet to avoid invalidating the
// iterator in our caller.
unsigned SpillBase;
int SpillOffset = extractSpillBaseRegAndOffset(MI, SpillBase);
const MachineInstr *DMI = &VarLocIDs[ID].MI;
auto *SpillExpr = DIExpression::prepend(
DMI->getDebugExpression(), DIExpression::NoDeref, SpillOffset);
MachineInstr *SpDMI =
BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, SpillBase,
DMI->getDebugVariable(), SpillExpr);
LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: ";
SpDMI->print(dbgs(), false, TII));

// The newly created DBG_VALUE instruction SpDMI must be inserted after
// MI. Keep track of the pairing.
SpillDebugPair MIP = {&MI, SpDMI};
Spills.push_back(MIP);

// End all previous ranges of Var.
OpenRanges.erase(VarLocIDs[ID].Var);

// Add the VarLoc to OpenRanges.
VarLoc VL(*SpDMI, LS);
unsigned SpillLocID = VarLocIDs.insert(VL);
OpenRanges.insert(SpillLocID, VL.Var);
/// If \p MI is a register copy instruction, that copies a previously tracked
/// value from one register to another register that is callee saved, we
/// create new DBG_VALUE instruction described with copy destination register.
void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs,
TransferMap &Transfers) {
const MachineOperand *SrcRegOp, *DestRegOp;

if (!TII->isCopyInstr(MI, SrcRegOp, DestRegOp) || !SrcRegOp->isKill() ||
!DestRegOp->isDef())
return;

auto isCalleSavedReg = [&](unsigned Reg) {
for (MCRegAliasIterator RAI(Reg, TRI, true); RAI.isValid(); ++RAI)
if (CalleeSavedRegs.test(*RAI))
return true;
return false;
};

unsigned SrcReg = SrcRegOp->getReg();
unsigned DestReg = DestRegOp->getReg();

// We want to recognize instructions where destination register is callee
// saved register. If register that could be clobbered by the call is
// included, there would be a great chance that it is going to be clobbered
// soon. It is more likely that previous register location, which is callee
// saved, is going to stay unclobbered longer, even if it is killed.
if (!isCalleSavedReg(DestReg))
return;

for (unsigned ID : OpenRanges.getVarLocs()) {
if (VarLocIDs[ID].isDescribedByReg() == SrcReg) {
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID,
DestReg);
return;
}
}
Expand Down Expand Up @@ -540,14 +609,16 @@ bool LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
}

/// This routine creates OpenRanges and OutLocs.
bool LiveDebugValues::transfer(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs,
SpillMap &Spills, bool transferSpills) {
bool LiveDebugValues::process(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs,
TransferMap &Transfers, bool transferChanges) {
bool Changed = false;
transferDebugValue(MI, OpenRanges, VarLocIDs);
transferRegisterDef(MI, OpenRanges, VarLocIDs);
if (transferSpills)
transferSpillInst(MI, OpenRanges, VarLocIDs, Spills);
if (transferChanges) {
transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers);
transferSpillInst(MI, OpenRanges, VarLocIDs, Transfers);
}
Changed = transferTerminatorInst(MI, OpenRanges, OutLocs, VarLocIDs);
return Changed;
}
Expand Down Expand Up @@ -609,7 +680,7 @@ bool LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
for (auto ID : Diff) {
// This VarLoc is not found in InLocs i.e. it is not yet inserted. So, a
// new range is started for the var from the mbb's beginning by inserting
// a new DBG_VALUE. transfer() will end this range however appropriate.
// a new DBG_VALUE. process() will end this range however appropriate.
const VarLoc &DiffIt = VarLocIDs[ID];
const MachineInstr *DMI = &DiffIt.MI;
MachineInstr *MI =
Expand Down Expand Up @@ -639,7 +710,7 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
OpenRangesSet OpenRanges; // Ranges that are open until end of bb.
VarLocInMBB OutLocs; // Ranges that exist beyond bb.
VarLocInMBB InLocs; // Ranges that are incoming after joining.
SpillMap Spills; // DBG_VALUEs associated with spills.
TransferMap Transfers; // DBG_VALUEs associated with spills.

DenseMap<unsigned int, MachineBasicBlock *> OrderToBB;
DenseMap<MachineBasicBlock *, unsigned int> BBToOrder;
Expand All @@ -650,15 +721,17 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
std::greater<unsigned int>>
Pending;

enum : bool { dontTransferChanges = false, transferChanges = true };

// Initialize every mbb with OutLocs.
// We are not looking at any spill instructions during the initial pass
// over the BBs. The LiveDebugVariables pass has already created DBG_VALUE
// instructions for spills of registers that are known to be user variables
// within the BB in which the spill occurs.
for (auto &MBB : MF)
for (auto &MI : MBB)
transfer(MI, OpenRanges, OutLocs, VarLocIDs, Spills,
/*transferSpills=*/false);
process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers,
dontTransferChanges);

LLVM_DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs,
"OutLocs after initialization", dbgs()));
Expand All @@ -672,7 +745,7 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
++RPONumber;
}
// This is a standard "union of predecessor outs" dataflow problem.
// To solve it, we perform join() and transfer() using the two worklist method
// To solve it, we perform join() and process() using the two worklist method
// until the ranges converge.
// Ranges have converged when both worklists are empty.
SmallPtrSet<const MachineBasicBlock *, 16> Visited;
Expand All @@ -694,14 +767,14 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
// examine spill instructions to see whether they spill registers that
// correspond to user variables.
for (auto &MI : *MBB)
OLChanged |= transfer(MI, OpenRanges, OutLocs, VarLocIDs, Spills,
/*transferSpills=*/true);
OLChanged |= process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers,
transferChanges);

// Add any DBG_VALUE instructions necessitated by spills.
for (auto &SP : Spills)
MBB->insertAfter(MachineBasicBlock::iterator(*SP.SpillInst),
SP.DebugInst);
Spills.clear();
for (auto &TR : Transfers)
MBB->insertAfter(MachineBasicBlock::iterator(*TR.TransferInst),
TR.DebugInst);
Transfers.clear();

LLVM_DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs,
"OutLocs after propagating", dbgs()));
Expand Down Expand Up @@ -741,6 +814,8 @@ bool LiveDebugValues::runOnMachineFunction(MachineFunction &MF) {
TRI = MF.getSubtarget().getRegisterInfo();
TII = MF.getSubtarget().getInstrInfo();
TFI = MF.getSubtarget().getFrameLowering();
TFI->determineCalleeSaves(MF, CalleeSavedRegs,
make_unique<RegScavenger>().get());
LS.initialize(MF);

bool Changed = ExtendRanges(MF);
Expand Down

0 comments on commit be2e80a

Please sign in to comment.