[DEBUGINFO] Reposting r352642: Handle restore instructions in LiveDebugValues

The LiveDebugValues pass recognizes spills but not restores, which can
cause large gaps in location information for some variables, depending
on control flow. This patch make LiveDebugValues recognize restores and
generate appropriate DBG_VALUE instructions.

This patch was posted previously with r352642 and reverted in r352666 due
to buildbot errors. A missing return statement was the cause for the 
failures.

Reviewers: aprantl, NicolaPrica

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

llvm-svn: 353089
This commit is contained in:
Wolfgang Pieb 2019-02-04 20:42:45 +00:00
parent 690a20467b
commit 90d856cd5f
5 changed files with 418 additions and 92 deletions

View File

@ -1399,6 +1399,19 @@ public:
/// Return true if all the defs of this instruction are dead. /// Return true if all the defs of this instruction are dead.
bool allDefsAreDead() const; bool allDefsAreDead() const;
/// Return a valid size if the instruction is a spill instruction.
Optional<unsigned> getSpillSize(const TargetInstrInfo *TII) const;
/// Return a valid size if the instruction is a folded spill instruction.
Optional<unsigned> getFoldedSpillSize(const TargetInstrInfo *TII) const;
/// Return a valid size if the instruction is a restore instruction.
Optional<unsigned> getRestoreSize(const TargetInstrInfo *TII) const;
/// Return a valid size if the instruction is a folded restore instruction.
Optional<unsigned>
getFoldedRestoreSize(const TargetInstrInfo *TII) const;
/// Copy implicit register operands from specified /// Copy implicit register operands from specified
/// instruction to this instruction. /// instruction to this instruction.
void copyImplicitOps(MachineFunction &MF, const MachineInstr &MI); void copyImplicitOps(MachineFunction &MF, const MachineInstr &MI);

View File

@ -746,41 +746,20 @@ static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) {
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
// Check for spills and reloads // Check for spills and reloads
int FI;
const MachineFrameInfo &MFI = MF->getFrameInfo();
auto getSize =
[&MFI](const SmallVectorImpl<const MachineMemOperand *> &Accesses) {
unsigned Size = 0;
for (auto A : Accesses)
if (MFI.isSpillSlotObjectIndex(
cast<FixedStackPseudoSourceValue>(A->getPseudoValue())
->getFrameIndex()))
Size += A->getSize();
return Size;
};
// We assume a single instruction only has a spill or reload, not // We assume a single instruction only has a spill or reload, not
// both. // both.
const MachineMemOperand *MMO; Optional<unsigned> Size;
SmallVector<const MachineMemOperand *, 2> Accesses; if ((Size = MI.getRestoreSize(TII))) {
if (TII->isLoadFromStackSlotPostFE(MI, FI)) { CommentOS << *Size << "-byte Reload\n";
if (MFI.isSpillSlotObjectIndex(FI)) { } else if ((Size = MI.getFoldedRestoreSize(TII))) {
MMO = *MI.memoperands_begin(); if (*Size)
CommentOS << MMO->getSize() << "-byte Reload\n"; CommentOS << *Size << "-byte Folded Reload\n";
} } else if ((Size = MI.getSpillSize(TII))) {
} else if (TII->hasLoadFromStackSlot(MI, Accesses)) { CommentOS << *Size << "-byte Spill\n";
if (auto Size = getSize(Accesses)) } else if ((Size = MI.getFoldedSpillSize(TII))) {
CommentOS << Size << "-byte Folded Reload\n"; if (*Size)
} else if (TII->isStoreToStackSlotPostFE(MI, FI)) { CommentOS << *Size << "-byte Folded Spill\n";
if (MFI.isSpillSlotObjectIndex(FI)) {
MMO = *MI.memoperands_begin();
CommentOS << MMO->getSize() << "-byte Spill\n";
}
} else if (TII->hasStoreToStackSlot(MI, Accesses)) {
if (auto Size = getSize(Accesses))
CommentOS << Size << "-byte Folded Spill\n";
} }
// Check for spill-induced copies // Check for spill-induced copies

View File

@ -34,13 +34,14 @@
#include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Config/llvm-config.h" #include "llvm/Config/llvm-config.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h" #include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Function.h" #include "llvm/IR/Function.h"
@ -85,6 +86,8 @@ private:
BitVector CalleeSavedRegs; BitVector CalleeSavedRegs;
LexicalScopes LS; LexicalScopes LS;
enum struct TransferKind { TransferCopy, TransferSpill, TransferRestore };
/// Keeps track of lexical scopes associated with a user value's source /// Keeps track of lexical scopes associated with a user value's source
/// location. /// location.
class UserValueScopes { class UserValueScopes {
@ -124,15 +127,30 @@ private:
/// A pair of debug variable and value location. /// A pair of debug variable and value location.
struct VarLoc { struct VarLoc {
// The location at which a spilled variable resides. It consists of a
// register and an offset.
struct SpillLoc {
unsigned SpillBase;
int SpillOffset;
bool operator==(const SpillLoc &Other) const {
return SpillBase == Other.SpillBase && SpillOffset == Other.SpillOffset;
}
};
const DebugVariable Var; const DebugVariable Var;
const MachineInstr &MI; ///< Only used for cloning a new DBG_VALUE. const MachineInstr &MI; ///< Only used for cloning a new DBG_VALUE.
mutable UserValueScopes UVS; mutable UserValueScopes UVS;
enum { InvalidKind = 0, RegisterKind } Kind = InvalidKind; enum VarLocKind {
InvalidKind = 0,
RegisterKind,
SpillLocKind
} Kind = InvalidKind;
/// The value location. Stored separately to avoid repeatedly /// The value location. Stored separately to avoid repeatedly
/// extracting it from MI. /// extracting it from MI.
union { union {
uint64_t RegNo; uint64_t RegNo;
SpillLoc SpillLocation;
uint64_t Hash; uint64_t Hash;
} Loc; } Loc;
@ -149,6 +167,17 @@ private:
} }
} }
/// The constructor for spill locations.
VarLoc(const MachineInstr &MI, unsigned SpillBase, int SpillOffset,
LexicalScopes &LS)
: Var(MI.getDebugVariable(), MI.getDebugLoc()->getInlinedAt()), MI(MI),
UVS(MI.getDebugLoc(), LS) {
assert(MI.isDebugValue() && "not a DBG_VALUE");
assert(MI.getNumOperands() == 4 && "malformed DBG_VALUE");
Kind = SpillLocKind;
Loc.SpillLocation = {SpillBase, SpillOffset};
}
/// If this variable is described by a register, return it, /// If this variable is described by a register, return it,
/// otherwise return 0. /// otherwise return 0.
unsigned isDescribedByReg() const { unsigned isDescribedByReg() const {
@ -236,15 +265,23 @@ private:
bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF, bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF,
unsigned &Reg); unsigned &Reg);
int extractSpillBaseRegAndOffset(const MachineInstr &MI, unsigned &Reg); /// If a given instruction is identified as a spill, return the spill location
/// and set \p Reg to the spilled register.
Optional<VarLoc::SpillLoc> isRestoreInstruction(const MachineInstr &MI,
MachineFunction *MF,
unsigned &Reg);
/// Given a spill instruction, extract the register and offset used to
/// address the spill location in a target independent way.
VarLoc::SpillLoc extractSpillBaseRegAndOffset(const MachineInstr &MI);
void insertTransferDebugPair(MachineInstr &MI, OpenRangesSet &OpenRanges, void insertTransferDebugPair(MachineInstr &MI, OpenRangesSet &OpenRanges,
TransferMap &Transfers, VarLocMap &VarLocIDs, TransferMap &Transfers, VarLocMap &VarLocIDs,
unsigned OldVarID, unsigned NewReg = 0); unsigned OldVarID, TransferKind Kind,
unsigned NewReg = 0);
void transferDebugValue(const MachineInstr &MI, OpenRangesSet &OpenRanges, void transferDebugValue(const MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs); VarLocMap &VarLocIDs);
void transferSpillInst(MachineInstr &MI, OpenRangesSet &OpenRanges, void transferSpillOrRestoreInst(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs, TransferMap &Transfers); VarLocMap &VarLocIDs, TransferMap &Transfers);
void transferRegisterCopy(MachineInstr &MI, OpenRangesSet &OpenRanges, void transferRegisterCopy(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs, TransferMap &Transfers); VarLocMap &VarLocIDs, TransferMap &Transfers);
void transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges, void transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges,
@ -338,10 +375,8 @@ void LiveDebugValues::printVarLocInMBB(const MachineFunction &MF,
} }
#endif #endif
/// Given a spill instruction, extract the register and offset used to LiveDebugValues::VarLoc::SpillLoc
/// address the spill location in a target independent way. LiveDebugValues::extractSpillBaseRegAndOffset(const MachineInstr &MI) {
int LiveDebugValues::extractSpillBaseRegAndOffset(const MachineInstr &MI,
unsigned &Reg) {
assert(MI.hasOneMemOperand() && assert(MI.hasOneMemOperand() &&
"Spill instruction does not have exactly one memory operand?"); "Spill instruction does not have exactly one memory operand?");
auto MMOI = MI.memoperands_begin(); auto MMOI = MI.memoperands_begin();
@ -350,7 +385,9 @@ int LiveDebugValues::extractSpillBaseRegAndOffset(const MachineInstr &MI,
"Inconsistent memory operand in spill instruction"); "Inconsistent memory operand in spill instruction");
int FI = cast<FixedStackPseudoSourceValue>(PVal)->getFrameIndex(); int FI = cast<FixedStackPseudoSourceValue>(PVal)->getFrameIndex();
const MachineBasicBlock *MBB = MI.getParent(); const MachineBasicBlock *MBB = MI.getParent();
return TFI->getFrameIndexReference(*MBB->getParent(), FI, Reg); unsigned Reg;
int Offset = TFI->getFrameIndexReference(*MBB->getParent(), FI, Reg);
return {Reg, Offset};
} }
/// End all previous ranges related to @MI and start a new range from @MI /// End all previous ranges related to @MI and start a new range from @MI
@ -386,11 +423,28 @@ void LiveDebugValues::transferDebugValue(const MachineInstr &MI,
/// otherwise it is variable's location on the stack. /// otherwise it is variable's location on the stack.
void LiveDebugValues::insertTransferDebugPair( void LiveDebugValues::insertTransferDebugPair(
MachineInstr &MI, OpenRangesSet &OpenRanges, TransferMap &Transfers, MachineInstr &MI, OpenRangesSet &OpenRanges, TransferMap &Transfers,
VarLocMap &VarLocIDs, unsigned OldVarID, unsigned NewReg) { VarLocMap &VarLocIDs, unsigned OldVarID, TransferKind Kind,
unsigned NewReg) {
const MachineInstr *DMI = &VarLocIDs[OldVarID].MI; const MachineInstr *DMI = &VarLocIDs[OldVarID].MI;
MachineFunction *MF = MI.getParent()->getParent(); MachineFunction *MF = MI.getParent()->getParent();
MachineInstr *NewDMI; MachineInstr *NewDMI;
if (NewReg) {
auto ProcessVarLoc = [&MI, &OpenRanges, &Transfers,
&VarLocIDs](VarLoc &VL, MachineInstr *NewDMI) {
unsigned LocId = VarLocIDs.insert(VL);
OpenRanges.insert(LocId, VL.Var);
// 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);
switch (Kind) {
case TransferKind::TransferCopy: {
assert(NewReg &&
"No register supplied when handling a copy of a debug value");
// Create a DBG_VALUE instruction to describe the Var in its new // Create a DBG_VALUE instruction to describe the Var in its new
// register location. // register location.
NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(),
@ -398,33 +452,43 @@ void LiveDebugValues::insertTransferDebugPair(
DMI->getDebugVariable(), DMI->getDebugExpression()); DMI->getDebugVariable(), DMI->getDebugExpression());
if (DMI->isIndirectDebugValue()) if (DMI->isIndirectDebugValue())
NewDMI->getOperand(1).setImm(DMI->getOperand(1).getImm()); NewDMI->getOperand(1).setImm(DMI->getOperand(1).getImm());
VarLoc VL(*NewDMI, LS);
ProcessVarLoc(VL, NewDMI);
LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register copy: "; LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register copy: ";
NewDMI->print(dbgs(), false, false, false, TII)); NewDMI->print(dbgs(), false, false, false, TII));
} else { return;
}
case TransferKind::TransferSpill: {
// Create a DBG_VALUE instruction to describe the Var in its spilled // Create a DBG_VALUE instruction to describe the Var in its spilled
// location. // location.
unsigned SpillBase; VarLoc::SpillLoc SpillLocation = extractSpillBaseRegAndOffset(MI);
int SpillOffset = extractSpillBaseRegAndOffset(MI, SpillBase); auto *SpillExpr =
auto *SpillExpr = DIExpression::prepend(DMI->getDebugExpression(), DIExpression::prepend(DMI->getDebugExpression(), DIExpression::NoDeref,
DIExpression::NoDeref, SpillOffset); SpillLocation.SpillOffset);
NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true, SpillBase, NewDMI =
DMI->getDebugVariable(), SpillExpr); BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), true,
SpillLocation.SpillBase, DMI->getDebugVariable(), SpillExpr);
VarLoc VL(*NewDMI, SpillLocation.SpillBase, SpillLocation.SpillOffset, LS);
ProcessVarLoc(VL, NewDMI);
LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: "; LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: ";
NewDMI->print(dbgs(), false, false, false, TII)); NewDMI->print(dbgs(), false, false, false, TII));
return;
} }
case TransferKind::TransferRestore: {
// The newly created DBG_VALUE instruction NewDMI must be inserted after assert(NewReg &&
// MI. Keep track of the pairing. "No register supplied when handling a restore of a debug value");
TransferDebugPair MIP = {&MI, NewDMI}; MachineFunction *MF = MI.getMF();
Transfers.push_back(MIP); DIBuilder DIB(*const_cast<Function &>(MF->getFunction()).getParent());
NewDMI = BuildMI(*MF, DMI->getDebugLoc(), DMI->getDesc(), false, NewReg,
// End all previous ranges of Var. DMI->getDebugVariable(), DIB.createExpression());
OpenRanges.erase(VarLocIDs[OldVarID].Var); VarLoc VL(*NewDMI, LS);
ProcessVarLoc(VL, NewDMI);
// Add the VarLoc to OpenRanges. LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register restore: ";
VarLoc VL(*NewDMI, LS); NewDMI->print(dbgs(), false, false, false, TII));
unsigned LocID = VarLocIDs.insert(VL); return;
OpenRanges.insert(LocID, VL.Var); }
}
llvm_unreachable("Invalid transfer kind");
} }
/// A definition of a register may mark the end of a range. /// A definition of a register may mark the end of a range.
@ -470,24 +534,15 @@ void LiveDebugValues::transferRegisterDef(MachineInstr &MI,
/// other spills). We do not handle this yet (more than one memory operand). /// other spills). We do not handle this yet (more than one memory operand).
bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI, bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI,
MachineFunction *MF, unsigned &Reg) { MachineFunction *MF, unsigned &Reg) {
const MachineFrameInfo &FrameInfo = MF->getFrameInfo();
int FI;
SmallVector<const MachineMemOperand*, 1> Accesses; SmallVector<const MachineMemOperand*, 1> Accesses;
// TODO: Handle multiple stores folded into one. // TODO: Handle multiple stores folded into one.
if (!MI.hasOneMemOperand()) if (!MI.hasOneMemOperand())
return false; return false;
// To identify a spill instruction, use the same criteria as in AsmPrinter. if (!MI.getSpillSize(TII) && !MI.getFoldedSpillSize(TII))
if (!((TII->isStoreToStackSlotPostFE(MI, FI) && return false; // This is not a spill instruction, since no valid size was
FrameInfo.isSpillSlotObjectIndex(FI)) || // returned from either function.
(TII->hasStoreToStackSlot(MI, Accesses) &&
llvm::any_of(Accesses, [&FrameInfo](const MachineMemOperand *MMO) {
return FrameInfo.isSpillSlotObjectIndex(
cast<FixedStackPseudoSourceValue>(MMO->getPseudoValue())
->getFrameIndex());
}))))
return false;
auto isKilledReg = [&](const MachineOperand MO, unsigned &Reg) { auto isKilledReg = [&](const MachineOperand MO, unsigned &Reg) {
if (!MO.isReg() || !MO.isUse()) { if (!MO.isReg() || !MO.isUse()) {
@ -524,29 +579,67 @@ bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI,
return false; return false;
} }
Optional<LiveDebugValues::VarLoc::SpillLoc>
LiveDebugValues::isRestoreInstruction(const MachineInstr &MI,
MachineFunction *MF, unsigned &Reg) {
if (!MI.hasOneMemOperand())
return None;
// FIXME: Handle folded restore instructions with more than one memory
// operand.
if (MI.getRestoreSize(TII)) {
Reg = MI.getOperand(0).getReg();
return extractSpillBaseRegAndOffset(MI);
}
return None;
}
/// A spilled register may indicate that we have to end the current range of /// 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. /// a variable and create a new one for the spill location.
/// A restored register may indicate the reverse situation.
/// We don't want to insert any instructions in process(), so we just create /// 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. /// 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 /// It will be inserted into the BB when we're done iterating over the
/// instructions. /// instructions.
void LiveDebugValues::transferSpillInst(MachineInstr &MI, void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI,
OpenRangesSet &OpenRanges, OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs, VarLocMap &VarLocIDs,
TransferMap &Transfers) { TransferMap &Transfers) {
unsigned Reg;
MachineFunction *MF = MI.getMF(); MachineFunction *MF = MI.getMF();
if (!isSpillInstruction(MI, MF, Reg)) TransferKind TKind;
return; unsigned Reg;
Optional<VarLoc::SpillLoc> Loc;
// Check if the register is the location of a debug value. LLVM_DEBUG(dbgs() << "Examining instruction: "; MI.dump(););
if (isSpillInstruction(MI, MF, Reg)) {
TKind = TransferKind::TransferSpill;
LLVM_DEBUG(dbgs() << "Recognized as spill: "; MI.dump(););
LLVM_DEBUG(dbgs() << "Register: " << Reg << " " << printReg(Reg, TRI)
<< "\n");
} else {
if (!(Loc = isRestoreInstruction(MI, MF, Reg)))
return;
TKind = TransferKind::TransferRestore;
LLVM_DEBUG(dbgs() << "Recognized as restore: "; MI.dump(););
LLVM_DEBUG(dbgs() << "Register: " << Reg << " " << printReg(Reg, TRI)
<< "\n");
}
// Check if the register or spill location is the location of a debug value.
for (unsigned ID : OpenRanges.getVarLocs()) { for (unsigned ID : OpenRanges.getVarLocs()) {
if (VarLocIDs[ID].isDescribedByReg() == Reg) { if (TKind == TransferKind::TransferSpill &&
VarLocIDs[ID].isDescribedByReg() == Reg) {
LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '(' LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '('
<< VarLocIDs[ID].Var.getVar()->getName() << ")\n"); << VarLocIDs[ID].Var.getVar()->getName() << ")\n");
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID); } else if (TKind == TransferKind::TransferRestore &&
return; VarLocIDs[ID].Loc.SpillLocation == *Loc) {
} LLVM_DEBUG(dbgs() << "Restoring Register " << printReg(Reg, TRI) << '('
<< VarLocIDs[ID].Var.getVar()->getName() << ")\n");
} else
continue;
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID, TKind,
Reg);
return;
} }
} }
@ -584,7 +677,7 @@ void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
for (unsigned ID : OpenRanges.getVarLocs()) { for (unsigned ID : OpenRanges.getVarLocs()) {
if (VarLocIDs[ID].isDescribedByReg() == SrcReg) { if (VarLocIDs[ID].isDescribedByReg() == SrcReg) {
insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID, insertTransferDebugPair(MI, OpenRanges, Transfers, VarLocIDs, ID,
DestReg); TransferKind::TransferCopy, DestReg);
return; return;
} }
} }
@ -624,7 +717,7 @@ bool LiveDebugValues::process(MachineInstr &MI, OpenRangesSet &OpenRanges,
transferRegisterDef(MI, OpenRanges, VarLocIDs); transferRegisterDef(MI, OpenRanges, VarLocIDs);
if (transferChanges) { if (transferChanges) {
transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers); transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers);
transferSpillInst(MI, OpenRanges, VarLocIDs, Transfers); transferSpillOrRestoreInst(MI, OpenRanges, VarLocIDs, Transfers);
} }
Changed = transferTerminatorInst(MI, OpenRanges, OutLocs, VarLocIDs); Changed = transferTerminatorInst(MI, OpenRanges, OutLocs, VarLocIDs);
return Changed; return Changed;

View File

@ -25,6 +25,7 @@
#include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/MemoryLocation.h"
#include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h"
#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineInstrBundle.h" #include "llvm/CodeGen/MachineInstrBundle.h"
@ -49,9 +50,9 @@
#include "llvm/IR/Metadata.h" #include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSlotTracker.h" #include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h" #include "llvm/IR/Type.h"
#include "llvm/IR/Value.h" #include "llvm/IR/Value.h"
#include "llvm/IR/Operator.h"
#include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbol.h"
@ -2102,3 +2103,54 @@ void MachineInstr::changeDebugValuesDefReg(unsigned Reg) {
for (auto *DBI : DbgValues) for (auto *DBI : DbgValues)
DBI->getOperand(0).setReg(Reg); DBI->getOperand(0).setReg(Reg);
} }
using MMOList = SmallVector<const MachineMemOperand *, 2>;
static unsigned getSpillSlotSize(MMOList &Accesses,
const MachineFrameInfo &MFI) {
unsigned Size = 0;
for (auto A : Accesses)
if (MFI.isSpillSlotObjectIndex(
cast<FixedStackPseudoSourceValue>(A->getPseudoValue())
->getFrameIndex()))
Size += A->getSize();
return Size;
}
Optional<unsigned>
MachineInstr::getSpillSize(const TargetInstrInfo *TII) const {
int FI;
if (TII->isStoreToStackSlotPostFE(*this, FI)) {
const MachineFrameInfo &MFI = getMF()->getFrameInfo();
if (MFI.isSpillSlotObjectIndex(FI))
return (*memoperands_begin())->getSize();
}
return None;
}
Optional<unsigned>
MachineInstr::getFoldedSpillSize(const TargetInstrInfo *TII) const {
MMOList Accesses;
if (TII->hasStoreToStackSlot(*this, Accesses))
return getSpillSlotSize(Accesses, getMF()->getFrameInfo());
return None;
}
Optional<unsigned>
MachineInstr::getRestoreSize(const TargetInstrInfo *TII) const {
int FI;
if (TII->isLoadFromStackSlotPostFE(*this, FI)) {
const MachineFrameInfo &MFI = getMF()->getFrameInfo();
if (MFI.isSpillSlotObjectIndex(FI))
return (*memoperands_begin())->getSize();
}
return None;
}
Optional<unsigned>
MachineInstr::getFoldedRestoreSize(const TargetInstrInfo *TII) const {
MMOList Accesses;
if (TII->hasLoadFromStackSlot(*this, Accesses))
return getSpillSlotSize(Accesses, getMF()->getFrameInfo());
return None;
}

View File

@ -0,0 +1,189 @@
# RUN: llc -run-pass livedebugvalues -march=x86-64 -o - %s | FileCheck %s
# Generated from the following source with:
# clang -g -mllvm -stop-before=livedebugvalues -S -O2 test.c -o test.mir
# #define FORCE_SPILL() \
# __asm volatile("" : : : \
# "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "r8", \
# "r9", "r10", "r11", "r12", "r13", "r14", "r15")
# int f(int *p) {
# if (p) {
# FORCE_SPILL();
# }
# return *(p + 1);
# }
# Ascertain that the spill has been recognized and manifested in a DBG_VALUE.
# CHECK: MOV64mr $rsp,{{.*-8.*}}killed{{.*}}$rdi :: (store 8 into %stack.0)
# CHECK-NEXT: DBG_VALUE $rsp,{{.*}}![[MDIX:[0-9]+]],{{.*}}!DIExpression(DW_OP_constu, 8, DW_OP_minus)
# Check for the restore.
# CHECK: $rdi = MOV64rm $rsp,{{.*-8.*}}:: (load 8 from %stack.0)
# CHECK-NEXT: DBG_VALUE $rdi,{{.*}}![[MDIX]], !DIExpression()
--- |
define dso_local i32 @f(i32* readonly %p) local_unnamed_addr !dbg !7 {
entry:
call void @llvm.dbg.value(metadata i32* %p, metadata !13, metadata !DIExpression()), !dbg !14
%tobool = icmp eq i32* %p, null, !dbg !15
br i1 %tobool, label %if.end, label %if.then, !dbg !17
if.then: ; preds = %entry
tail call void asm sideeffect "", "~{rax},~{rbx},~{rcx},~{rdx},~{rsi},~{rdi},~{rbp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{dirflag},~{fpsr},~{flags}"(), !dbg !18, !srcloc !20
br label %if.end, !dbg !21
if.end: ; preds = %entry, %if.then
%add.ptr = getelementptr inbounds i32, i32* %p, i64 1, !dbg !22
%0 = load i32, i32* %add.ptr, align 4, !dbg !23, !tbaa !24
ret i32 %0, !dbg !28
}
declare void @llvm.dbg.value(metadata, metadata, metadata)
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (https://git.llvm.org/git/clang.git/ 57a6ce7ac318de98e3e777e09cb9ed8282b5cc03) (https://git.llvm.org/git/llvm.git/ ff54a19e4912d7f15cb02798a7f2048441bff751)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
!1 = !DIFile(filename: "test2.c", directory: "/home/test")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 9.0.0 (https://git.llvm.org/git/clang.git/ 57a6ce7ac318de98e3e777e09cb9ed8282b5cc03) (https://git.llvm.org/git/llvm.git/ ff54a19e4912d7f15cb02798a7f2048441bff751)"}
!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
!8 = !DISubroutineType(types: !9)
!9 = !{!10, !11}
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
!12 = !{!13}
!13 = !DILocalVariable(name: "p", arg: 1, scope: !7, file: !1, line: 5, type: !11)
!14 = !DILocation(line: 5, column: 12, scope: !7)
!15 = !DILocation(line: 6, column: 7, scope: !16)
!16 = distinct !DILexicalBlock(scope: !7, file: !1, line: 6, column: 7)
!17 = !DILocation(line: 6, column: 7, scope: !7)
!18 = !DILocation(line: 7, column: 5, scope: !19)
!19 = distinct !DILexicalBlock(scope: !16, file: !1, line: 6, column: 10)
!20 = !{i32 -2147471544}
!21 = !DILocation(line: 8, column: 3, scope: !19)
!22 = !DILocation(line: 9, column: 14, scope: !7)
!23 = !DILocation(line: 9, column: 10, scope: !7)
!24 = !{!25, !25, i64 0}
!25 = !{!"int", !26, i64 0}
!26 = !{!"omnipotent char", !27, i64 0}
!27 = !{!"Simple C/C++ TBAA"}
!28 = !DILocation(line: 9, column: 3, scope: !7)
...
---
name: f
alignment: 4
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
failedISel: false
tracksRegLiveness: true
hasWinCFI: false
registers: []
liveins:
- { reg: '$rdi', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 48
offsetAdjustment: -48
maxAlignment: 8
adjustsStack: false
hasCalls: false
stackProtector: ''
maxCallFrameSize: 0
cvBytesOfCalleeSavedRegisters: 48
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
localFrameSize: 0
savePoint: ''
restorePoint: ''
fixedStack:
- { id: 0, type: spill-slot, offset: -56, size: 8, alignment: 8, stack-id: 0,
callee-saved-register: '$rbx', callee-saved-restored: true, debug-info-variable: '',
debug-info-expression: '', debug-info-location: '' }
- { id: 1, type: spill-slot, offset: -48, size: 8, alignment: 16, stack-id: 0,
callee-saved-register: '$r12', callee-saved-restored: true, debug-info-variable: '',
debug-info-expression: '', debug-info-location: '' }
- { id: 2, type: spill-slot, offset: -40, size: 8, alignment: 8, stack-id: 0,
callee-saved-register: '$r13', callee-saved-restored: true, debug-info-variable: '',
debug-info-expression: '', debug-info-location: '' }
- { id: 3, type: spill-slot, offset: -32, size: 8, alignment: 16, stack-id: 0,
callee-saved-register: '$r14', callee-saved-restored: true, debug-info-variable: '',
debug-info-expression: '', debug-info-location: '' }
- { id: 4, type: spill-slot, offset: -24, size: 8, alignment: 8, stack-id: 0,
callee-saved-register: '$r15', callee-saved-restored: true, debug-info-variable: '',
debug-info-expression: '', debug-info-location: '' }
- { id: 5, type: spill-slot, offset: -16, size: 8, alignment: 16, stack-id: 0,
callee-saved-register: '$rbp', callee-saved-restored: true, debug-info-variable: '',
debug-info-expression: '', debug-info-location: '' }
stack:
- { id: 0, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8,
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants: []
body: |
bb.0.entry:
successors: %bb.2(0x30000000), %bb.1(0x50000000)
liveins: $rdi, $rbx, $r12, $r13, $r14, $r15, $rbp
DBG_VALUE $rdi, $noreg, !13, !DIExpression(), debug-location !14
DBG_VALUE $rdi, $noreg, !13, !DIExpression(), debug-location !14
TEST64rr renamable $rdi, renamable $rdi, implicit-def $eflags, debug-location !15
JE_1 %bb.2, implicit $eflags, debug-location !17
bb.1.if.then:
successors: %bb.2(0x80000000)
liveins: $rdi, $rbp, $r15, $r14, $r13, $r12, $rbx
frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 16
frame-setup PUSH64r killed $r15, implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 24
frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 32
frame-setup PUSH64r killed $r13, implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 40
frame-setup PUSH64r killed $r12, implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 48
frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 56
CFI_INSTRUCTION offset $rbx, -56
CFI_INSTRUCTION offset $r12, -48
CFI_INSTRUCTION offset $r13, -40
CFI_INSTRUCTION offset $r14, -32
CFI_INSTRUCTION offset $r15, -24
CFI_INSTRUCTION offset $rbp, -16
MOV64mr $rsp, 1, $noreg, -8, $noreg, killed renamable $rdi :: (store 8 into %stack.0)
INLINEASM &"", 1, 12, implicit-def dead early-clobber $rax, 12, implicit-def dead early-clobber $rbx, 12, implicit-def dead early-clobber $rcx, 12, implicit-def dead early-clobber $rdx, 12, implicit-def dead early-clobber $rsi, 12, implicit-def dead early-clobber $rdi, 12, implicit-def dead early-clobber $rbp, 12, implicit-def dead early-clobber $r8, 12, implicit-def dead early-clobber $r9, 12, implicit-def dead early-clobber $r10, 12, implicit-def dead early-clobber $r11, 12, implicit-def dead early-clobber $r12, 12, implicit-def dead early-clobber $r13, 12, implicit-def dead early-clobber $r14, 12, implicit-def dead early-clobber $r15, 12, implicit-def dead early-clobber $eflags, !20, debug-location !18
renamable $rdi = MOV64rm $rsp, 1, $noreg, -8, $noreg :: (load 8 from %stack.0)
$rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 48
$r12 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 40
$r13 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 32
$r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 24
$r15 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 16
$rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
CFI_INSTRUCTION def_cfa_offset 8
bb.2.if.end:
liveins: $rdi, $rbx, $r12, $r13, $r14, $r15, $rbp
renamable $eax = MOV32rm killed renamable $rdi, 1, $noreg, 4, $noreg, debug-location !23 :: (load 4 from %ir.add.ptr, !tbaa !24)
RETQ $eax, debug-location !28
...