mirror of
https://github.com/RPCS3/llvm.git
synced 2026-07-21 03:05:26 -04:00
[LiveDebugValues] Tracking copying value between registers
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336978 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
+124
-49
@@ -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"
|
||||
@@ -82,6 +83,7 @@ private:
|
||||
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
|
||||
@@ -179,11 +181,11 @@ private:
|
||||
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
|
||||
@@ -236,18 +238,23 @@ private:
|
||||
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,
|
||||
@@ -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,
|
||||
@@ -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))
|
||||
@@ -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));
|
||||
/// 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;
|
||||
|
||||
// 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);
|
||||
if (!TII->isCopyInstr(MI, SrcRegOp, DestRegOp) || !SrcRegOp->isKill() ||
|
||||
!DestRegOp->isDef())
|
||||
return;
|
||||
|
||||
// End all previous ranges of Var.
|
||||
OpenRanges.erase(VarLocIDs[ID].Var);
|
||||
auto isCalleSavedReg = [&](unsigned Reg) {
|
||||
for (MCRegAliasIterator RAI(Reg, TRI, true); RAI.isValid(); ++RAI)
|
||||
if (CalleeSavedRegs.test(*RAI))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
// Add the VarLoc to OpenRanges.
|
||||
VarLoc VL(*SpDMI, LS);
|
||||
unsigned SpillLocID = VarLocIDs.insert(VL);
|
||||
OpenRanges.insert(SpillLocID, VL.Var);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 =
|
||||
@@ -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;
|
||||
@@ -650,6 +721,8 @@ 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
|
||||
@@ -657,8 +730,8 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
|
||||
// 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()));
|
||||
@@ -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;
|
||||
@@ -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()));
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user