aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/LiveDebugValues.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/LiveDebugValues.cpp')
-rw-r--r--lib/CodeGen/LiveDebugValues.cpp510
1 files changed, 321 insertions, 189 deletions
diff --git a/lib/CodeGen/LiveDebugValues.cpp b/lib/CodeGen/LiveDebugValues.cpp
index a669e64692b9..f1b237d83e8c 100644
--- a/lib/CodeGen/LiveDebugValues.cpp
+++ b/lib/CodeGen/LiveDebugValues.cpp
@@ -7,14 +7,23 @@
//===----------------------------------------------------------------------===//
///
/// This pass implements a data flow analysis that propagates debug location
-/// information by inserting additional DBG_VALUE instructions into the machine
-/// instruction stream. The pass internally builds debug location liveness
-/// ranges to determine the points where additional DBG_VALUEs need to be
-/// inserted.
+/// information by inserting additional DBG_VALUE insts into the machine
+/// instruction stream. Before running, each DBG_VALUE inst corresponds to a
+/// source assignment of a variable. Afterwards, a DBG_VALUE inst specifies a
+/// variable location for the current basic block (see SourceLevelDebugging.rst).
///
/// This is a separate pass from DbgValueHistoryCalculator to facilitate
/// testing and improve modularity.
///
+/// Each variable location is represented by a VarLoc object that identifies the
+/// source variable, its current machine-location, and the DBG_VALUE inst that
+/// specifies the location. Each VarLoc is indexed in the (function-scope)
+/// VarLocMap, giving each VarLoc a unique index. Rather than operate directly
+/// on machine locations, the dataflow analysis in this pass identifies
+/// locations by their index in the VarLocMap, meaning all the variable
+/// locations in a block can be described by a sparse vector of VarLocMap
+/// indexes.
+///
//===----------------------------------------------------------------------===//
#include "llvm/ADT/DenseMap.h"
@@ -68,6 +77,7 @@ using namespace llvm;
#define DEBUG_TYPE "livedebugvalues"
STATISTIC(NumInserted, "Number of DBG_VALUE instructions inserted");
+STATISTIC(NumRemoved, "Number of DBG_VALUE instructions removed");
// If @MI is a DBG_VALUE with debug value described by a defined
// register, returns the number of this register. In the other case, returns 0.
@@ -179,8 +189,16 @@ private:
}
};
+ /// Identity of the variable at this location.
const DebugVariable Var;
- const MachineInstr &MI; ///< Only used for cloning a new DBG_VALUE.
+
+ /// The expression applied to this location.
+ const DIExpression *Expr;
+
+ /// DBG_VALUE to clone var/expr information from if this location
+ /// is moved.
+ const MachineInstr &MI;
+
mutable UserValueScopes UVS;
enum VarLocKind {
InvalidKind = 0,
@@ -201,9 +219,9 @@ private:
const ConstantInt *CImm;
} Loc;
- VarLoc(const MachineInstr &MI, LexicalScopes &LS,
- VarLocKind K = InvalidKind)
- : Var(MI), MI(MI), UVS(MI.getDebugLoc(), LS){
+ VarLoc(const MachineInstr &MI, LexicalScopes &LS)
+ : Var(MI), Expr(MI.getDebugExpression()), MI(MI),
+ UVS(MI.getDebugLoc(), LS) {
static_assert((sizeof(Loc) == sizeof(uint64_t)),
"hash does not cover all members of Loc");
assert(MI.isDebugValue() && "not a DBG_VALUE");
@@ -225,17 +243,78 @@ private:
"entry values must be register locations");
}
- /// The constructor for spill locations.
- VarLoc(const MachineInstr &MI, unsigned SpillBase, int SpillOffset,
- LexicalScopes &LS)
- : Var(MI), 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};
+ /// Take the variable and machine-location in DBG_VALUE MI, and build an
+ /// entry location using the given expression.
+ static VarLoc CreateEntryLoc(const MachineInstr &MI, LexicalScopes &LS,
+ const DIExpression *EntryExpr) {
+ VarLoc VL(MI, LS);
+ VL.Kind = EntryValueKind;
+ VL.Expr = EntryExpr;
+ return VL;
+ }
+
+ /// Copy the register location in DBG_VALUE MI, updating the register to
+ /// be NewReg.
+ static VarLoc CreateCopyLoc(const MachineInstr &MI, LexicalScopes &LS,
+ unsigned NewReg) {
+ VarLoc VL(MI, LS);
+ assert(VL.Kind == RegisterKind);
+ VL.Loc.RegNo = NewReg;
+ return VL;
+ }
+
+ /// Take the variable described by DBG_VALUE MI, and create a VarLoc
+ /// locating it in the specified spill location.
+ static VarLoc CreateSpillLoc(const MachineInstr &MI, unsigned SpillBase,
+ int SpillOffset, LexicalScopes &LS) {
+ VarLoc VL(MI, LS);
+ assert(VL.Kind == RegisterKind);
+ VL.Kind = SpillLocKind;
+ VL.Loc.SpillLocation = {SpillBase, SpillOffset};
+ return VL;
}
- // Is the Loc field a constant or constant object?
+ /// Create a DBG_VALUE representing this VarLoc in the given function.
+ /// Copies variable-specific information such as DILocalVariable and
+ /// inlining information from the original DBG_VALUE instruction, which may
+ /// have been several transfers ago.
+ MachineInstr *BuildDbgValue(MachineFunction &MF) const {
+ const DebugLoc &DbgLoc = MI.getDebugLoc();
+ bool Indirect = MI.isIndirectDebugValue();
+ const auto &IID = MI.getDesc();
+ const DILocalVariable *Var = MI.getDebugVariable();
+ const DIExpression *DIExpr = MI.getDebugExpression();
+
+ switch (Kind) {
+ case EntryValueKind:
+ // An entry value is a register location -- but with an updated
+ // expression.
+ return BuildMI(MF, DbgLoc, IID, Indirect, Loc.RegNo, Var, Expr);
+ case RegisterKind:
+ // Register locations are like the source DBG_VALUE, but with the
+ // register number from this VarLoc.
+ return BuildMI(MF, DbgLoc, IID, Indirect, Loc.RegNo, Var, DIExpr);
+ case SpillLocKind: {
+ // Spills are indirect DBG_VALUEs, with a base register and offset.
+ // Use the original DBG_VALUEs expression to build the spilt location
+ // on top of. FIXME: spill locations created before this pass runs
+ // are not recognized, and not handled here.
+ auto *SpillExpr = DIExpression::prepend(
+ DIExpr, DIExpression::ApplyOffset, Loc.SpillLocation.SpillOffset);
+ unsigned Base = Loc.SpillLocation.SpillBase;
+ return BuildMI(MF, DbgLoc, IID, true, Base, Var, SpillExpr);
+ }
+ case ImmediateKind: {
+ MachineOperand MO = MI.getOperand(0);
+ return BuildMI(MF, DbgLoc, IID, Indirect, MO, Var, DIExpr);
+ }
+ case InvalidKind:
+ llvm_unreachable("Tried to produce DBG_VALUE for invalid VarLoc");
+ }
+ llvm_unreachable("Unrecognized LiveDebugValues.VarLoc.Kind enum");
+ }
+
+ /// Is the Loc field a constant or constant object?
bool isConstant() const { return Kind == ImmediateKind; }
/// If this variable is described by a register, return it,
@@ -251,18 +330,42 @@ private:
bool dominates(MachineBasicBlock &MBB) const { return UVS.dominates(&MBB); }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- LLVM_DUMP_METHOD void dump() const { MI.dump(); }
+ // TRI can be null.
+ void dump(const TargetRegisterInfo *TRI, raw_ostream &Out = dbgs()) const {
+ dbgs() << "VarLoc(";
+ switch (Kind) {
+ case RegisterKind:
+ case EntryValueKind:
+ dbgs() << printReg(Loc.RegNo, TRI);
+ break;
+ case SpillLocKind:
+ dbgs() << printReg(Loc.SpillLocation.SpillBase, TRI);
+ dbgs() << "[" << Loc.SpillLocation.SpillOffset << "]";
+ break;
+ case ImmediateKind:
+ dbgs() << Loc.Immediate;
+ break;
+ case InvalidKind:
+ llvm_unreachable("Invalid VarLoc in dump method");
+ }
+
+ dbgs() << ", \"" << Var.getVar()->getName() << "\", " << *Expr << ", ";
+ if (Var.getInlinedAt())
+ dbgs() << "!" << Var.getInlinedAt()->getMetadataID() << ")\n";
+ else
+ dbgs() << "(null))\n";
+ }
#endif
bool operator==(const VarLoc &Other) const {
return Kind == Other.Kind && Var == Other.Var &&
- Loc.Hash == Other.Loc.Hash;
+ Loc.Hash == Other.Loc.Hash && Expr == Other.Expr;
}
/// This operator guarantees that VarLocs are sorted by Variable first.
bool operator<(const VarLoc &Other) const {
- return std::tie(Var, Kind, Loc.Hash) <
- std::tie(Other.Var, Other.Kind, Other.Loc.Hash);
+ return std::tie(Var, Kind, Loc.Hash, Expr) <
+ std::tie(Other.Var, Other.Kind, Other.Loc.Hash, Other.Expr);
}
};
@@ -271,8 +374,8 @@ private:
using VarLocSet = SparseBitVector<>;
using VarLocInMBB = SmallDenseMap<const MachineBasicBlock *, VarLocSet>;
struct TransferDebugPair {
- MachineInstr *TransferInst;
- MachineInstr *DebugInst;
+ MachineInstr *TransferInst; /// Instruction where this transfer occurs.
+ unsigned LocationID; /// Location number for the transfer dest.
};
using TransferMap = SmallVector<TransferDebugPair, 4>;
@@ -320,6 +423,14 @@ private:
Vars.insert({Var, VarLocID});
}
+ /// Insert a set of ranges.
+ void insertFromLocSet(const VarLocSet &ToLoad, const VarLocMap &Map) {
+ for (unsigned Id : ToLoad) {
+ const VarLoc &Var = Map[Id];
+ insert(Id, Var.Var);
+ }
+ }
+
/// Empty the set.
void clear() {
VarLocs.clear();
@@ -333,8 +444,18 @@ private:
}
};
- bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF,
- unsigned &Reg);
+ /// Tests whether this instruction is a spill to a stack location.
+ bool isSpillInstruction(const MachineInstr &MI, MachineFunction *MF);
+
+ /// Decide if @MI is a spill instruction and return true if it is. We use 2
+ /// criteria to make this decision:
+ /// - Is this instruction a store to a spill slot?
+ /// - Is there a register operand that is both used and killed?
+ /// TODO: Store optimization can fold spills into other stores (including
+ /// other spills). We do not handle this yet (more than one memory operand).
+ bool isLocationSpill(const MachineInstr &MI, MachineFunction *MF,
+ 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,
@@ -361,13 +482,13 @@ private:
void transferRegisterDef(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocMap &VarLocIDs, TransferMap &Transfers,
DebugParamMap &DebugEntryVals);
- bool transferTerminatorInst(MachineInstr &MI, OpenRangesSet &OpenRanges,
- VarLocInMBB &OutLocs, const VarLocMap &VarLocIDs);
+ bool transferTerminator(MachineBasicBlock *MBB, OpenRangesSet &OpenRanges,
+ VarLocInMBB &OutLocs, const VarLocMap &VarLocIDs);
- bool process(MachineInstr &MI, OpenRangesSet &OpenRanges,
+ void process(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs,
TransferMap &Transfers, DebugParamMap &DebugEntryVals,
- bool transferChanges, OverlapMap &OverlapFragments,
+ OverlapMap &OverlapFragments,
VarToFragments &SeenFragments);
void accumulateFragmentMap(MachineInstr &MI, VarToFragments &SeenFragments,
@@ -376,7 +497,12 @@ private:
bool join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs,
const VarLocMap &VarLocIDs,
SmallPtrSet<const MachineBasicBlock *, 16> &Visited,
- SmallPtrSetImpl<const MachineBasicBlock *> &ArtificialBlocks);
+ SmallPtrSetImpl<const MachineBasicBlock *> &ArtificialBlocks,
+ VarLocInMBB &PendingInLocs);
+
+ /// Create DBG_VALUE insts for inlocs that have been propagated but
+ /// had their instruction creation deferred.
+ void flushPendingLocs(VarLocInMBB &PendingInLocs, VarLocMap &VarLocIDs);
bool ExtendRanges(MachineFunction &MF);
@@ -518,7 +644,7 @@ void LiveDebugValues::printVarLocInMBB(const MachineFunction &MF,
const VarLoc &VL = VarLocIDs[VLL];
Out << " Var: " << VL.Var.getVar()->getName();
Out << " MI: ";
- VL.dump();
+ VL.dump(TRI, Out);
}
}
Out << "\n";
@@ -567,11 +693,7 @@ void LiveDebugValues::transferDebugValue(const MachineInstr &MI,
ID = VarLocIDs.insert(VL);
OpenRanges.insert(ID, VL.Var);
} else if (MI.hasOneMemOperand()) {
- // It's a stack spill -- fetch spill base and offset.
- VarLoc::SpillLoc SpillLocation = extractSpillBaseRegAndOffset(MI);
- VarLoc VL(MI, SpillLocation.SpillBase, SpillLocation.SpillOffset, LS);
- ID = VarLocIDs.insert(VL);
- OpenRanges.insert(ID, VL.Var);
+ llvm_unreachable("DBG_VALUE with mem operand encountered after regalloc?");
} else {
// This must be an undefined location. We should leave OpenRanges closed.
assert(MI.getOperand(0).isReg() && MI.getOperand(0).getReg() == 0 &&
@@ -585,7 +707,6 @@ void LiveDebugValues::emitEntryValues(MachineInstr &MI,
TransferMap &Transfers,
DebugParamMap &DebugEntryVals,
SparseBitVector<> &KillSet) {
- MachineFunction *MF = MI.getParent()->getParent();
for (unsigned ID : KillSet) {
if (!VarLocIDs[ID].Var.getVar()->isParameter())
continue;
@@ -600,20 +721,12 @@ void LiveDebugValues::emitEntryValues(MachineInstr &MI,
auto ParamDebugInstr = DebugEntryVals[CurrDebugInstr->getDebugVariable()];
DIExpression *NewExpr = DIExpression::prepend(
ParamDebugInstr->getDebugExpression(), DIExpression::EntryValue);
- MachineInstr *EntryValDbgMI =
- BuildMI(*MF, ParamDebugInstr->getDebugLoc(), ParamDebugInstr->getDesc(),
- ParamDebugInstr->isIndirectDebugValue(),
- ParamDebugInstr->getOperand(0).getReg(),
- ParamDebugInstr->getDebugVariable(), NewExpr);
-
- if (ParamDebugInstr->isIndirectDebugValue())
- EntryValDbgMI->getOperand(1).setImm(
- ParamDebugInstr->getOperand(1).getImm());
-
- Transfers.push_back({&MI, EntryValDbgMI});
- VarLoc VL(*EntryValDbgMI, LS);
- unsigned EntryValLocID = VarLocIDs.insert(VL);
- OpenRanges.insert(EntryValLocID, VL.Var);
+
+ VarLoc EntryLoc = VarLoc::CreateEntryLoc(*ParamDebugInstr, LS, NewExpr);
+
+ unsigned EntryValLocID = VarLocIDs.insert(EntryLoc);
+ Transfers.push_back({&MI, EntryValLocID});
+ OpenRanges.insert(EntryValLocID, EntryLoc.Var);
}
}
@@ -627,21 +740,19 @@ void LiveDebugValues::insertTransferDebugPair(
VarLocMap &VarLocIDs, unsigned OldVarID, TransferKind Kind,
unsigned NewReg) {
const MachineInstr *DebugInstr = &VarLocIDs[OldVarID].MI;
- MachineFunction *MF = MI.getParent()->getParent();
- MachineInstr *NewDebugInstr;
auto ProcessVarLoc = [&MI, &OpenRanges, &Transfers, &DebugInstr,
- &VarLocIDs](VarLoc &VL, MachineInstr *NewDebugInstr) {
+ &VarLocIDs](VarLoc &VL) {
unsigned LocId = VarLocIDs.insert(VL);
// Close this variable's previous location range.
DebugVariable V(*DebugInstr);
OpenRanges.erase(V);
+ // Record the new location as an open range, and a postponed transfer
+ // inserting a DBG_VALUE for this location.
OpenRanges.insert(LocId, VL.Var);
- // The newly created DBG_VALUE instruction NewDebugInstr must be inserted
- // after MI. Keep track of the pairing.
- TransferDebugPair MIP = {&MI, NewDebugInstr};
+ TransferDebugPair MIP = {&MI, LocId};
Transfers.push_back(MIP);
};
@@ -653,37 +764,25 @@ void LiveDebugValues::insertTransferDebugPair(
"No register supplied when handling a copy of a debug value");
// Create a DBG_VALUE instruction to describe the Var in its new
// register location.
- NewDebugInstr = BuildMI(
- *MF, DebugInstr->getDebugLoc(), DebugInstr->getDesc(),
- DebugInstr->isIndirectDebugValue(), NewReg,
- DebugInstr->getDebugVariable(), DebugInstr->getDebugExpression());
- if (DebugInstr->isIndirectDebugValue())
- NewDebugInstr->getOperand(1).setImm(DebugInstr->getOperand(1).getImm());
- VarLoc VL(*NewDebugInstr, LS);
- ProcessVarLoc(VL, NewDebugInstr);
- LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register copy: ";
- NewDebugInstr->print(dbgs(), /*IsStandalone*/false,
- /*SkipOpers*/false, /*SkipDebugLoc*/false,
- /*AddNewLine*/true, TII));
+ VarLoc VL = VarLoc::CreateCopyLoc(*DebugInstr, LS, NewReg);
+ ProcessVarLoc(VL);
+ LLVM_DEBUG({
+ dbgs() << "Creating VarLoc for register copy:";
+ VL.dump(TRI);
+ });
return;
}
case TransferKind::TransferSpill: {
// Create a DBG_VALUE instruction to describe the Var in its spilled
// location.
VarLoc::SpillLoc SpillLocation = extractSpillBaseRegAndOffset(MI);
- auto *SpillExpr = DIExpression::prepend(DebugInstr->getDebugExpression(),
- DIExpression::ApplyOffset,
- SpillLocation.SpillOffset);
- NewDebugInstr = BuildMI(
- *MF, DebugInstr->getDebugLoc(), DebugInstr->getDesc(), true,
- SpillLocation.SpillBase, DebugInstr->getDebugVariable(), SpillExpr);
- VarLoc VL(*NewDebugInstr, SpillLocation.SpillBase,
- SpillLocation.SpillOffset, LS);
- ProcessVarLoc(VL, NewDebugInstr);
- LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for spill: ";
- NewDebugInstr->print(dbgs(), /*IsStandalone*/false,
- /*SkipOpers*/false, /*SkipDebugLoc*/false,
- /*AddNewLine*/true, TII));
+ VarLoc VL = VarLoc::CreateSpillLoc(*DebugInstr, SpillLocation.SpillBase,
+ SpillLocation.SpillOffset, LS);
+ ProcessVarLoc(VL);
+ LLVM_DEBUG({
+ dbgs() << "Creating VarLoc for spill:";
+ VL.dump(TRI);
+ });
return;
}
case TransferKind::TransferRestore: {
@@ -691,15 +790,14 @@ void LiveDebugValues::insertTransferDebugPair(
"No register supplied when handling a restore of a debug value");
MachineFunction *MF = MI.getMF();
DIBuilder DIB(*const_cast<Function &>(MF->getFunction()).getParent());
- NewDebugInstr =
- BuildMI(*MF, DebugInstr->getDebugLoc(), DebugInstr->getDesc(), false,
- NewReg, DebugInstr->getDebugVariable(), DIB.createExpression());
- VarLoc VL(*NewDebugInstr, LS);
- ProcessVarLoc(VL, NewDebugInstr);
- LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register restore: ";
- NewDebugInstr->print(dbgs(), /*IsStandalone*/false,
- /*SkipOpers*/false, /*SkipDebugLoc*/false,
- /*AddNewLine*/true, TII));
+ // DebugInstr refers to the pre-spill location, therefore we can reuse
+ // its expression.
+ VarLoc VL = VarLoc::CreateCopyLoc(*DebugInstr, LS, NewReg);
+ ProcessVarLoc(VL);
+ LLVM_DEBUG({
+ dbgs() << "Creating VarLoc for restore:";
+ VL.dump(TRI);
+ });
return;
}
}
@@ -719,7 +817,7 @@ void LiveDebugValues::transferRegisterDef(
// instructions never clobber SP, because some backends (e.g., AArch64)
// never list SP in the regmask.
if (MO.isReg() && MO.isDef() && MO.getReg() &&
- TRI->isPhysicalRegister(MO.getReg()) &&
+ Register::isPhysicalRegister(MO.getReg()) &&
!(MI.isCall() && MO.getReg() == SP)) {
// Remove ranges of all aliased registers.
for (MCRegAliasIterator RAI(MO.getReg(), TRI, true); RAI.isValid(); ++RAI)
@@ -748,16 +846,8 @@ void LiveDebugValues::transferRegisterDef(
}
}
-/// Decide if @MI is a spill instruction and return true if it is. We use 2
-/// criteria to make this decision:
-/// - Is this instruction a store to a spill slot?
-/// - Is there a register operand that is both used and killed?
-/// TODO: Store optimization can fold spills into other stores (including
-/// other spills). We do not handle this yet (more than one memory operand).
bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI,
- MachineFunction *MF, unsigned &Reg) {
- SmallVector<const MachineMemOperand*, 1> Accesses;
-
+ MachineFunction *MF) {
// TODO: Handle multiple stores folded into one.
if (!MI.hasOneMemOperand())
return false;
@@ -766,6 +856,14 @@ bool LiveDebugValues::isSpillInstruction(const MachineInstr &MI,
return false; // This is not a spill instruction, since no valid size was
// returned from either function.
+ return true;
+}
+
+bool LiveDebugValues::isLocationSpill(const MachineInstr &MI,
+ MachineFunction *MF, unsigned &Reg) {
+ if (!isSpillInstruction(MI, MF))
+ return false;
+
auto isKilledReg = [&](const MachineOperand MO, unsigned &Reg) {
if (!MO.isReg() || !MO.isUse()) {
Reg = 0;
@@ -834,7 +932,37 @@ void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI,
LLVM_DEBUG(dbgs() << "Examining instruction: "; MI.dump(););
- if (isSpillInstruction(MI, MF, Reg)) {
+ // First, if there are any DBG_VALUEs pointing at a spill slot that is
+ // written to, then close the variable location. The value in memory
+ // will have changed.
+ VarLocSet KillSet;
+ if (isSpillInstruction(MI, MF)) {
+ Loc = extractSpillBaseRegAndOffset(MI);
+ for (unsigned ID : OpenRanges.getVarLocs()) {
+ const VarLoc &VL = VarLocIDs[ID];
+ if (VL.Kind == VarLoc::SpillLocKind && VL.Loc.SpillLocation == *Loc) {
+ // This location is overwritten by the current instruction -- terminate
+ // the open range, and insert an explicit DBG_VALUE $noreg.
+ //
+ // Doing this at a later stage would require re-interpreting all
+ // DBG_VALUes and DIExpressions to identify whether they point at
+ // memory, and then analysing all memory writes to see if they
+ // overwrite that memory, which is expensive.
+ //
+ // At this stage, we already know which DBG_VALUEs are for spills and
+ // where they are located; it's best to fix handle overwrites now.
+ KillSet.set(ID);
+ VarLoc UndefVL = VarLoc::CreateCopyLoc(VL.MI, LS, 0);
+ unsigned UndefLocID = VarLocIDs.insert(UndefVL);
+ Transfers.push_back({&MI, UndefLocID});
+ }
+ }
+ OpenRanges.erase(KillSet, VarLocIDs);
+ }
+
+ // Try to recognise spill and restore instructions that may create a new
+ // variable location.
+ if (isLocationSpill(MI, MF, Reg)) {
TKind = TransferKind::TransferSpill;
LLVM_DEBUG(dbgs() << "Recognized as spill: "; MI.dump(););
LLVM_DEBUG(dbgs() << "Register: " << Reg << " " << printReg(Reg, TRI)
@@ -854,6 +982,7 @@ void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI,
LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '('
<< VarLocIDs[ID].Var.getVar()->getName() << ")\n");
} else if (TKind == TransferKind::TransferRestore &&
+ VarLocIDs[ID].Kind == VarLoc::SpillLocKind &&
VarLocIDs[ID].Loc.SpillLocation == *Loc) {
LLVM_DEBUG(dbgs() << "Restoring Register " << printReg(Reg, TRI) << '('
<< VarLocIDs[ID].Var.getVar()->getName() << ")\n");
@@ -885,8 +1014,8 @@ void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
return false;
};
- unsigned SrcReg = SrcRegOp->getReg();
- unsigned DestReg = DestRegOp->getReg();
+ Register SrcReg = SrcRegOp->getReg();
+ Register 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
@@ -906,26 +1035,20 @@ void LiveDebugValues::transferRegisterCopy(MachineInstr &MI,
}
/// Terminate all open ranges at the end of the current basic block.
-bool LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
- OpenRangesSet &OpenRanges,
- VarLocInMBB &OutLocs,
- const VarLocMap &VarLocIDs) {
+bool LiveDebugValues::transferTerminator(MachineBasicBlock *CurMBB,
+ OpenRangesSet &OpenRanges,
+ VarLocInMBB &OutLocs,
+ const VarLocMap &VarLocIDs) {
bool Changed = false;
- const MachineBasicBlock *CurMBB = MI.getParent();
- if (!(MI.isTerminator() || (&MI == &CurMBB->back())))
- return false;
-
- if (OpenRanges.empty())
- return false;
LLVM_DEBUG(for (unsigned ID
: OpenRanges.getVarLocs()) {
// Copy OpenRanges to OutLocs, if not already present.
dbgs() << "Add to OutLocs in MBB #" << CurMBB->getNumber() << ": ";
- VarLocIDs[ID].dump();
+ VarLocIDs[ID].dump(TRI);
});
VarLocSet &VLS = OutLocs[CurMBB];
- Changed = VLS |= OpenRanges.getVarLocs();
+ Changed = VLS != OpenRanges.getVarLocs();
// New OutLocs set may be different due to spill, restore or register
// copy instruction processing.
if (Changed)
@@ -995,26 +1118,17 @@ void LiveDebugValues::accumulateFragmentMap(MachineInstr &MI,
}
/// This routine creates OpenRanges and OutLocs.
-bool LiveDebugValues::process(MachineInstr &MI, OpenRangesSet &OpenRanges,
+void LiveDebugValues::process(MachineInstr &MI, OpenRangesSet &OpenRanges,
VarLocInMBB &OutLocs, VarLocMap &VarLocIDs,
- TransferMap &Transfers, DebugParamMap &DebugEntryVals,
- bool transferChanges,
+ TransferMap &Transfers,
+ DebugParamMap &DebugEntryVals,
OverlapMap &OverlapFragments,
VarToFragments &SeenFragments) {
- bool Changed = false;
transferDebugValue(MI, OpenRanges, VarLocIDs);
transferRegisterDef(MI, OpenRanges, VarLocIDs, Transfers,
DebugEntryVals);
- if (transferChanges) {
- transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers);
- transferSpillOrRestoreInst(MI, OpenRanges, VarLocIDs, Transfers);
- } else {
- // Build up a map of overlapping fragments on the first run through.
- if (MI.isDebugValue())
- accumulateFragmentMap(MI, SeenFragments, OverlapFragments);
- }
- Changed = transferTerminatorInst(MI, OpenRanges, OutLocs, VarLocIDs);
- return Changed;
+ transferRegisterCopy(MI, OpenRanges, VarLocIDs, Transfers);
+ transferSpillOrRestoreInst(MI, OpenRanges, VarLocIDs, Transfers);
}
/// This routine joins the analysis results of all incoming edges in @MBB by
@@ -1024,7 +1138,8 @@ bool LiveDebugValues::join(
MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs,
const VarLocMap &VarLocIDs,
SmallPtrSet<const MachineBasicBlock *, 16> &Visited,
- SmallPtrSetImpl<const MachineBasicBlock *> &ArtificialBlocks) {
+ SmallPtrSetImpl<const MachineBasicBlock *> &ArtificialBlocks,
+ VarLocInMBB &PendingInLocs) {
LLVM_DEBUG(dbgs() << "join MBB: " << MBB.getNumber() << "\n");
bool Changed = false;
@@ -1034,9 +1149,11 @@ bool LiveDebugValues::join(
// can be joined.
int NumVisited = 0;
for (auto p : MBB.predecessors()) {
- // Ignore unvisited predecessor blocks. As we are processing
- // the blocks in reverse post-order any unvisited block can
- // be considered to not remove any incoming values.
+ // Ignore backedges if we have not visited the predecessor yet. As the
+ // predecessor hasn't yet had locations propagated into it, most locations
+ // will not yet be valid, so treat them as all being uninitialized and
+ // potentially valid. If a location guessed to be correct here is
+ // invalidated later, we will remove it when we revisit this block.
if (!Visited.count(p)) {
LLVM_DEBUG(dbgs() << " ignoring unvisited pred MBB: " << p->getNumber()
<< "\n");
@@ -1086,44 +1203,59 @@ bool LiveDebugValues::join(
// is the entry block which has no predecessor.
assert((NumVisited || MBB.pred_empty()) &&
"Should have processed at least one predecessor");
- if (InLocsT.empty())
- return false;
VarLocSet &ILS = InLocs[&MBB];
+ VarLocSet &Pending = PendingInLocs[&MBB];
- // Insert DBG_VALUE instructions, if not already inserted.
+ // New locations will have DBG_VALUE insts inserted at the start of the
+ // block, after location propagation has finished. Record the insertions
+ // that we need to perform in the Pending set.
VarLocSet Diff = InLocsT;
Diff.intersectWithComplement(ILS);
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. process() will end this range however appropriate.
- const VarLoc &DiffIt = VarLocIDs[ID];
- const MachineInstr *DebugInstr = &DiffIt.MI;
- MachineInstr *MI = nullptr;
- if (DiffIt.isConstant()) {
- MachineOperand MO(DebugInstr->getOperand(0));
- MI = BuildMI(MBB, MBB.instr_begin(), DebugInstr->getDebugLoc(),
- DebugInstr->getDesc(), false, MO,
- DebugInstr->getDebugVariable(),
- DebugInstr->getDebugExpression());
- } else {
- MI = BuildMI(MBB, MBB.instr_begin(), DebugInstr->getDebugLoc(),
- DebugInstr->getDesc(), DebugInstr->isIndirectDebugValue(),
- DebugInstr->getOperand(0).getReg(),
- DebugInstr->getDebugVariable(),
- DebugInstr->getDebugExpression());
- if (DebugInstr->isIndirectDebugValue())
- MI->getOperand(1).setImm(DebugInstr->getOperand(1).getImm());
- }
- LLVM_DEBUG(dbgs() << "Inserted: "; MI->dump(););
+ Pending.set(ID);
ILS.set(ID);
++NumInserted;
Changed = true;
}
+
+ // We may have lost locations by learning about a predecessor that either
+ // loses or moves a variable. Find any locations in ILS that are not in the
+ // new in-locations, and delete those.
+ VarLocSet Removed = ILS;
+ Removed.intersectWithComplement(InLocsT);
+ for (auto ID : Removed) {
+ Pending.reset(ID);
+ ILS.reset(ID);
+ ++NumRemoved;
+ Changed = true;
+ }
+
return Changed;
}
+void LiveDebugValues::flushPendingLocs(VarLocInMBB &PendingInLocs,
+ VarLocMap &VarLocIDs) {
+ // PendingInLocs records all locations propagated into blocks, which have
+ // not had DBG_VALUE insts created. Go through and create those insts now.
+ for (auto &Iter : PendingInLocs) {
+ // Map is keyed on a constant pointer, unwrap it so we can insert insts.
+ auto &MBB = const_cast<MachineBasicBlock &>(*Iter.first);
+ VarLocSet &Pending = Iter.second;
+
+ for (unsigned ID : Pending) {
+ // The ID location is live-in to MBB -- work out what kind of machine
+ // location it is and create a DBG_VALUE.
+ const VarLoc &DiffIt = VarLocIDs[ID];
+ MachineInstr *MI = DiffIt.BuildDbgValue(*MBB.getParent());
+ MBB.insert(MBB.instr_begin(), MI);
+
+ (void)MI;
+ LLVM_DEBUG(dbgs() << "Inserted: "; MI->dump(););
+ }
+ }
+}
+
/// Calculate the liveness information for the given machine function and
/// extend ranges across basic blocks.
bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
@@ -1140,6 +1272,9 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
VarLocInMBB OutLocs; // Ranges that exist beyond bb.
VarLocInMBB InLocs; // Ranges that are incoming after joining.
TransferMap Transfers; // DBG_VALUEs associated with spills.
+ VarLocInMBB PendingInLocs; // Ranges that are incoming after joining, but
+ // that we have deferred creating DBG_VALUE insts
+ // for immediately.
VarToFragments SeenFragments;
@@ -1156,8 +1291,6 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
std::greater<unsigned int>>
Pending;
- enum : bool { dontTransferChanges = false, transferChanges = true };
-
// Besides parameter's modification, check whether a DBG_VALUE is inlined
// in order to deduce whether the variable that it tracks comes from
// a different function. If that is the case we can't track its entry value.
@@ -1169,7 +1302,7 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
unsigned SP = TLI->getStackPointerRegisterToSaveRestore();
- unsigned FP = TRI->getFrameRegister(MF);
+ Register FP = TRI->getFrameRegister(MF);
auto IsRegOtherThanSPAndFP = [&](const MachineOperand &Op) -> bool {
return Op.isReg() && Op.getReg() != SP && Op.getReg() != FP;
};
@@ -1195,23 +1328,14 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
!MI.getDebugExpression()->isFragment())
DebugEntryVals[MI.getDebugVariable()] = &MI;
- // 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.
+ // Initialize per-block structures and scan for fragment overlaps.
for (auto &MBB : MF) {
+ PendingInLocs[&MBB] = VarLocSet();
+
for (auto &MI : MBB) {
- process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers, DebugEntryVals,
- dontTransferChanges, OverlapFragments, SeenFragments);
- }
- // Add any entry DBG_VALUE instructions necessitated by parameter
- // clobbering.
- for (auto &TR : Transfers) {
- MBB.insertAfter(MachineBasicBlock::iterator(*TR.TransferInst),
- TR.DebugInst);
+ if (MI.isDebugValue())
+ accumulateFragmentMap(MI, SeenFragments, OverlapFragments);
}
- Transfers.clear();
}
auto hasNonArtificialLocation = [](const MachineInstr &MI) -> bool {
@@ -1248,26 +1372,21 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
while (!Worklist.empty()) {
MachineBasicBlock *MBB = OrderToBB[Worklist.top()];
Worklist.pop();
- MBBJoined =
- join(*MBB, OutLocs, InLocs, VarLocIDs, Visited, ArtificialBlocks);
- Visited.insert(MBB);
+ MBBJoined = join(*MBB, OutLocs, InLocs, VarLocIDs, Visited,
+ ArtificialBlocks, PendingInLocs);
+ MBBJoined |= Visited.insert(MBB).second;
if (MBBJoined) {
MBBJoined = false;
Changed = true;
// Now that we have started to extend ranges across BBs we need to
// examine spill instructions to see whether they spill registers that
// correspond to user variables.
+ // First load any pending inlocs.
+ OpenRanges.insertFromLocSet(PendingInLocs[MBB], VarLocIDs);
for (auto &MI : *MBB)
- OLChanged |=
process(MI, OpenRanges, OutLocs, VarLocIDs, Transfers,
- DebugEntryVals, transferChanges, OverlapFragments,
- SeenFragments);
-
- // Add any DBG_VALUE instructions necessitated by spills.
- for (auto &TR : Transfers)
- MBB->insertAfter(MachineBasicBlock::iterator(*TR.TransferInst),
- TR.DebugInst);
- Transfers.clear();
+ DebugEntryVals, OverlapFragments, SeenFragments);
+ OLChanged |= transferTerminator(MBB, OpenRanges, OutLocs, VarLocIDs);
LLVM_DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs,
"OutLocs after propagating", dbgs()));
@@ -1289,6 +1408,19 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
assert(Pending.empty() && "Pending should be empty");
}
+ // Add any DBG_VALUE instructions created by location transfers.
+ for (auto &TR : Transfers) {
+ MachineBasicBlock *MBB = TR.TransferInst->getParent();
+ const VarLoc &VL = VarLocIDs[TR.LocationID];
+ MachineInstr *MI = VL.BuildDbgValue(MF);
+ MBB->insertAfterBundle(TR.TransferInst->getIterator(), MI);
+ }
+ Transfers.clear();
+
+ // Deferred inlocs will not have had any DBG_VALUE insts created; do
+ // that now.
+ flushPendingLocs(PendingInLocs, VarLocIDs);
+
LLVM_DEBUG(printVarLocInMBB(MF, OutLocs, VarLocIDs, "Final OutLocs", dbgs()));
LLVM_DEBUG(printVarLocInMBB(MF, InLocs, VarLocIDs, "Final InLocs", dbgs()));
return Changed;
@@ -1308,7 +1440,7 @@ bool LiveDebugValues::runOnMachineFunction(MachineFunction &MF) {
TII = MF.getSubtarget().getInstrInfo();
TFI = MF.getSubtarget().getFrameLowering();
TFI->determineCalleeSaves(MF, CalleeSavedRegs,
- make_unique<RegScavenger>().get());
+ std::make_unique<RegScavenger>().get());
LS.initialize(MF);
bool Changed = ExtendRanges(MF);