aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
diff options
context:
space:
mode:
authorJeremy Morse <jeremy.morse@sony.com>2020-10-23 14:06:39 +0100
committerJeremy Morse <jeremy.morse@sony.com>2020-10-23 14:50:02 +0100
commit68f47157164e0513fb5bf3a4639884c85b8a1308 (patch)
tree570195c294719876d91faa1097264fdf74f21084 /llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
parent13aff21f0da7007c42d407b4ec5c1f6b24cb6831 (diff)
downloadllvm-68f47157164e0513fb5bf3a4639884c85b8a1308.zip
llvm-68f47157164e0513fb5bf3a4639884c85b8a1308.tar.gz
llvm-68f47157164e0513fb5bf3a4639884c85b8a1308.tar.bz2
[DebugInstrRef] Convert DBG_INSTR_REFs into variable locations
Handle DBG_INSTR_REF instructions in LiveDebugValues, to determine and propagate variable locations. The logic is fairly straight forwards: Collect a map of debug-instruction-number to the machine value numbers generated in the first walk through the function. When building the variable value transfer function and we see a DBG_INSTR_REF, look up the instruction it refers to, and pick the machine value number it generates, That's it; the rest of LiveDebugValues continues as normal. Awkwardly, there are two kinds of instruction numbering happening here: the offset into the block (which is how machine value numbers are determined), and the numbers that we label instructions with when generating DBG_INSTR_REFs. I've also restructured the TransferTracker redefVar code a little, to separate some DBG_VALUE specific operations into its own method. The changes around redefVar should be largely NFC, while allowing DBG_INSTR_REFs to specify a value number rather than just a location. Differential Revision: https://reviews.llvm.org/D85771
Diffstat (limited to 'llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp')
-rw-r--r--llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp212
1 files changed, 182 insertions, 30 deletions
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
index 0d10c7c..32cccc1 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
@@ -900,12 +900,11 @@ public:
public:
VLocTracker() {}
- void defVar(const MachineInstr &MI, Optional<ValueIDNum> ID) {
- // XXX skipping overlapping fragments for now.
- assert(MI.isDebugValue());
+ void defVar(const MachineInstr &MI, const DbgValueProperties &Properties,
+ Optional<ValueIDNum> ID) {
+ assert(MI.isDebugValue() || MI.isDebugRef());
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt());
- DbgValueProperties Properties(MI);
DbgValue Rec = (ID) ? DbgValue(*ID, Properties, DbgValue::Def)
: DbgValue(Properties, DbgValue::Undef);
@@ -917,7 +916,7 @@ public:
}
void defVar(const MachineInstr &MI, const MachineOperand &MO) {
- // XXX skipping overlapping fragments for now.
+ // Only DBG_VALUEs can define constant-valued variables.
assert(MI.isDebugValue());
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt());
@@ -1083,50 +1082,64 @@ public:
}
}
- /// Handle a DBG_VALUE within a block. Terminate the variables current
- /// location, and record the value its DBG_VALUE refers to, so that we can
- /// detect location transfers later on.
+ /// Change a variable value after encountering a DBG_VALUE inside a block.
void redefVar(const MachineInstr &MI) {
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt());
- const MachineOperand &MO = MI.getOperand(0);
+ DbgValueProperties Properties(MI);
- // Erase any previous location,
- auto It = ActiveVLocs.find(Var);
- if (It != ActiveVLocs.end()) {
- ActiveMLocs[It->second.Loc].erase(Var);
- }
+ const MachineOperand &MO = MI.getOperand(0);
- // Insert a new variable location. Ignore non-register locations, we don't
- // transfer those, and can't currently describe spill locs independently of
- // regs.
- // (This is because a spill location is a DBG_VALUE of the stack pointer).
+ // Ignore non-register locations, we don't transfer those.
if (!MO.isReg() || MO.getReg() == 0) {
- if (It != ActiveVLocs.end())
+ auto It = ActiveVLocs.find(Var);
+ if (It != ActiveVLocs.end()) {
+ ActiveMLocs[It->second.Loc].erase(Var);
ActiveVLocs.erase(It);
+ }
return;
}
Register Reg = MO.getReg();
- LocIdx MLoc = MTracker->getRegMLoc(Reg);
- DbgValueProperties Properties(MI);
+ LocIdx NewLoc = MTracker->getRegMLoc(Reg);
+ redefVar(MI, Properties, NewLoc);
+ }
+
+ /// Handle a change in variable location within a block. Terminate the
+ /// variables current location, and record the value it now refers to, so
+ /// that we can detect location transfers later on.
+ void redefVar(const MachineInstr &MI, const DbgValueProperties &Properties,
+ Optional<LocIdx> OptNewLoc) {
+ DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
+ MI.getDebugLoc()->getInlinedAt());
+
+ // Erase any previous location,
+ auto It = ActiveVLocs.find(Var);
+ if (It != ActiveVLocs.end())
+ ActiveMLocs[It->second.Loc].erase(Var);
+
+ // If there _is_ no new location, all we had to do was erase.
+ if (!OptNewLoc)
+ return;
+ LocIdx NewLoc = *OptNewLoc;
// Check whether our local copy of values-by-location in #VarLocs is out of
// date. Wipe old tracking data for the location if it's been clobbered in
// the meantime.
- if (MTracker->getNumAtPos(MLoc) != VarLocs[MLoc.asU64()]) {
- for (auto &P : ActiveMLocs[MLoc.asU64()]) {
+ if (MTracker->getNumAtPos(NewLoc) != VarLocs[NewLoc.asU64()]) {
+ for (auto &P : ActiveMLocs[NewLoc]) {
ActiveVLocs.erase(P);
}
- ActiveMLocs[MLoc].clear();
- VarLocs[MLoc.asU64()] = MTracker->getNumAtPos(MLoc);
+ ActiveMLocs[NewLoc.asU64()].clear();
+ VarLocs[NewLoc.asU64()] = MTracker->getNumAtPos(NewLoc);
}
- ActiveMLocs[MLoc].insert(Var);
+ ActiveMLocs[NewLoc].insert(Var);
if (It == ActiveVLocs.end()) {
- ActiveVLocs.insert(std::make_pair(Var, LocAndProperties{MLoc, Properties}));
+ ActiveVLocs.insert(
+ std::make_pair(Var, LocAndProperties{NewLoc, Properties}));
} else {
- It->second.Loc = MLoc;
+ It->second.Loc = NewLoc;
It->second.Properties = Properties;
}
}
@@ -1272,6 +1285,13 @@ private:
DenseMap<MachineBasicBlock *, unsigned int> BBToOrder;
DenseMap<unsigned, unsigned> BBNumToRPO;
+ /// Pair of MachineInstr, and its 1-based offset into the containing block.
+ typedef std::pair<const MachineInstr *, unsigned> InstAndNum;
+ /// Map from debug instruction number to the MachineInstr labelled with that
+ /// number, and its location within the function. Used to transform
+ /// instruction numbers in DBG_INSTR_REFs into machine value numbers.
+ std::map<uint64_t, InstAndNum> DebugInstrNumToInstr;
+
// Map of overlapping variable fragments.
OverlapMap OverlapFragments;
VarToFragments SeenFragments;
@@ -1304,6 +1324,10 @@ private:
/// \returns true if MI was recognized and processed.
bool transferDebugValue(const MachineInstr &MI);
+ /// Examines whether \p MI is a DBG_INSTR_REF and notifies trackers.
+ /// \returns true if MI was recognized and processed.
+ bool transferDebugInstrRef(MachineInstr &MI);
+
/// Examines whether \p MI is copy instruction, and notifies trackers.
/// \returns true if MI was recognized and processed.
bool transferRegisterCopy(MachineInstr &MI);
@@ -1497,6 +1521,7 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) {
"Expected inlined-at fields to agree");
DebugVariable V(Var, Expr, InlinedAt);
+ DbgValueProperties Properties(MI);
// If there are no instructions in this lexical scope, do no location tracking
// at all, this variable shouldn't get a legitimate location range.
@@ -1519,9 +1544,9 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) {
// Feed defVar the new variable location, or if this is a
// DBG_VALUE $noreg, feed defVar None.
if (MO.getReg())
- VTracker->defVar(MI, MTracker->readReg(MO.getReg()));
+ VTracker->defVar(MI, Properties, MTracker->readReg(MO.getReg()));
else
- VTracker->defVar(MI, None);
+ VTracker->defVar(MI, Properties, None);
} else if (MI.getOperand(0).isImm() || MI.getOperand(0).isFPImm() ||
MI.getOperand(0).isCImm()) {
VTracker->defVar(MI, MI.getOperand(0));
@@ -1535,6 +1560,116 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) {
return true;
}
+bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI) {
+ if (!MI.isDebugRef())
+ return false;
+
+ // Only handle this instruction when we are building the variable value
+ // transfer function.
+ if (!VTracker)
+ return false;
+
+ unsigned InstNo = MI.getOperand(0).getImm();
+ unsigned OpNo = MI.getOperand(1).getImm();
+
+ const DILocalVariable *Var = MI.getDebugVariable();
+ const DIExpression *Expr = MI.getDebugExpression();
+ const DILocation *DebugLoc = MI.getDebugLoc();
+ const DILocation *InlinedAt = DebugLoc->getInlinedAt();
+ assert(Var->isValidLocationForIntrinsic(DebugLoc) &&
+ "Expected inlined-at fields to agree");
+
+ DebugVariable V(Var, Expr, InlinedAt);
+
+ auto *Scope = LS.findLexicalScope(MI.getDebugLoc().get());
+ if (Scope == nullptr)
+ return true; // Handled by doing nothing. This variable is never in scope.
+
+ const MachineFunction &MF = *MI.getParent()->getParent();
+
+ // Various optimizations may have happened to the value during codegen,
+ // recorded in the value substitution table. Apply any substitutions to
+ // the instruction / operand number in this DBG_INSTR_REF.
+ auto Sub = MF.DebugValueSubstitutions.find(std::make_pair(InstNo, OpNo));
+ while (Sub != MF.DebugValueSubstitutions.end()) {
+ InstNo = Sub->second.first;
+ OpNo = Sub->second.second;
+ Sub = MF.DebugValueSubstitutions.find(std::make_pair(InstNo, OpNo));
+ }
+
+ // Default machine value number is <None> -- if no instruction defines
+ // the corresponding value, it must have been optimized out.
+ Optional<ValueIDNum> NewID = None;
+
+ // Try to lookup the instruction number, and find the machine value number
+ // that it defines.
+ auto InstrIt = DebugInstrNumToInstr.find(InstNo);
+ if (InstrIt != DebugInstrNumToInstr.end()) {
+ const MachineInstr &TargetInstr = *InstrIt->second.first;
+ uint64_t BlockNo = TargetInstr.getParent()->getNumber();
+
+ // Pick out the designated operand.
+ assert(OpNo < TargetInstr.getNumOperands());
+ const MachineOperand &MO = TargetInstr.getOperand(OpNo);
+
+ // Today, this can only be a register.
+ assert(MO.isReg() && MO.isDef());
+
+ unsigned LocID = MTracker->getLocID(MO.getReg(), false);
+ LocIdx L = MTracker->LocIDToLocIdx[LocID];
+ NewID = ValueIDNum(BlockNo, InstrIt->second.second, L);
+ }
+
+ // We, we have a value number or None. Tell the variable value tracker about
+ // it. The rest of this LiveDebugValues implementation acts exactly the same
+ // for DBG_INSTR_REFs as DBG_VALUEs (just, the former can refer to values that
+ // aren't immediately available).
+ DbgValueProperties Properties(Expr, false);
+ VTracker->defVar(MI, Properties, NewID);
+
+ // If we're on the final pass through the function, decompose this INSTR_REF
+ // into a plain DBG_VALUE.
+ if (!TTracker)
+ return true;
+
+ // Pick a location for the machine value number, if such a location exists.
+ // (This information could be stored in TransferTracker to make it faster).
+ Optional<LocIdx> FoundLoc = None;
+ for (auto Location : MTracker->locations()) {
+ LocIdx CurL = Location.Idx;
+ ValueIDNum ID = MTracker->LocIdxToIDNum[CurL];
+ if (NewID && ID == NewID) {
+ // If this is the first location with that value, pick it. Otherwise,
+ // consider whether it's a "longer term" location.
+ if (!FoundLoc) {
+ FoundLoc = CurL;
+ continue;
+ }
+
+ if (MTracker->isSpill(CurL))
+ FoundLoc = CurL; // Spills are a longer term location.
+ else if (!MTracker->isSpill(*FoundLoc) &&
+ !MTracker->isSpill(CurL) &&
+ !isCalleeSaved(*FoundLoc) &&
+ isCalleeSaved(CurL))
+ FoundLoc = CurL; // Callee saved regs are longer term than normal.
+ }
+ }
+
+ // Tell transfer tracker that the variable value has changed.
+ TTracker->redefVar(MI, Properties, FoundLoc);
+
+ // Produce a DBG_VALUE representing what this DBG_INSTR_REF meant.
+ // This DBG_VALUE is potentially a $noreg / undefined location, if
+ // FoundLoc is None.
+ // (XXX -- could morph the DBG_INSTR_REF in the future).
+ MachineInstr *DbgMI = MTracker->emitLoc(FoundLoc, V, Properties);
+ TTracker->PendingDbgValues.push_back(DbgMI);
+ TTracker->flushDbgValues(MI.getIterator(), nullptr);
+
+ return true;
+}
+
void InstrRefBasedLDV::transferRegisterDef(MachineInstr &MI) {
// Meta Instructions do not affect the debug liveness of any register they
// define.
@@ -1916,6 +2051,8 @@ void InstrRefBasedLDV::process(MachineInstr &MI) {
// definitions.
if (transferDebugValue(MI))
return;
+ if (transferDebugInstrRef(MI))
+ return;
if (transferRegisterCopy(MI))
return;
if (transferSpillOrRestoreInst(MI))
@@ -1960,6 +2097,20 @@ void InstrRefBasedLDV::produceMLocTransferFunction(
// Also accumulate fragment map.
if (MI.isDebugValue())
accumulateFragmentMap(MI);
+
+ // Create a map from the instruction number (if present) to the
+ // MachineInstr and its position.
+ if (MI.peekDebugInstrNum()) {
+ uint64_t InstrNo = MI.peekDebugInstrNum();
+ auto InstrAndPos = std::make_pair(&MI, CurInst);
+ auto InsertResult =
+ DebugInstrNumToInstr.insert(std::make_pair(InstrNo, InstrAndPos));
+
+ // There should never be duplicate instruction numbers.
+ assert(InsertResult.second);
+ (void)InsertResult;
+ }
+
++CurInst;
}
@@ -3123,6 +3274,7 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
OrderToBB.clear();
BBToOrder.clear();
BBNumToRPO.clear();
+ DebugInstrNumToInstr.clear();
return Changed;
}