[llvm] 68f4715 - [DebugInstrRef] Convert DBG_INSTR_REFs into variable locations
Jeremy Morse via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 23 06:50:30 PDT 2020
Author: Jeremy Morse
Date: 2020-10-23T14:50:02+01:00
New Revision: 68f47157164e0513fb5bf3a4639884c85b8a1308
URL: https://github.com/llvm/llvm-project/commit/68f47157164e0513fb5bf3a4639884c85b8a1308
DIFF: https://github.com/llvm/llvm-project/commit/68f47157164e0513fb5bf3a4639884c85b8a1308.diff
LOG: [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
Added:
llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir
Modified:
llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
index 0d10c7cde163..32cccc13fa8b 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
@@ -900,12 +900,11 @@ class VLocTracker {
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 @@ class VLocTracker {
}
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 @@ class TransferTracker {
}
}
- /// 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 @@ class InstrRefBasedLDV : public LDVImpl {
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 @@ class InstrRefBasedLDV : public LDVImpl {
/// \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;
}
diff --git a/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir b/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir
new file mode 100644
index 000000000000..5f9238cde927
--- /dev/null
+++ b/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir
@@ -0,0 +1,72 @@
+--- |
+ ; RUN: llc %s -march=x86-64 -run-pass=livedebugvalues -o - -experimental-debug-variable-locations | FileCheck %s -implicit-check-not=DBG_VALUE
+
+ define i32 @_Z8bb_to_bb() local_unnamed_addr !dbg !12 {
+ entry:
+ ret i32 0, !dbg !17
+ }
+
+ !llvm.dbg.cu = !{!0}
+ !llvm.module.flags = !{!7, !8, !9, !10}
+ !llvm.ident = !{!11}
+ !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, debugInfoForProfiling: true, nameTableKind: None)
+ !1 = !DIFile(filename: "main.cpp", directory: "F:\")
+ !2 = !{}
+ !3 = !{!4}
+ !4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+ !5 = distinct !DIGlobalVariable(name: "start", scope: !0, file: !1, line: 4, type: !6, isLocal: false, isDefinition: true)
+ !6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+ !7 = !{i32 2, !"Dwarf Version", i32 4}
+ !8 = !{i32 2, !"Debug Info Version", i32 3}
+ !9 = !{i32 1, !"wchar_size", i32 2}
+ !10 = !{i32 7, !"PIC Level", i32 2}
+ !11 = !{!"clang version 10.0.0"}
+ !12 = distinct !DISubprogram(name: "bb_to_bb", linkageName: "bb_to_bb", scope: !1, file: !1, line: 6, type: !13, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15)
+ !13 = !DISubroutineType(types: !14)
+ !14 = !{!6, !6}
+ !15 = !{!16}
+ !16 = !DILocalVariable(name: "myVar", scope: !12, file: !1, line: 7, type: !6)
+ !17 = !DILocation(line: 10, scope: !12)
+
+...
+---
+name: _Z8bb_to_bb
+debugValueSubstitutions:
+ - { srcinst: 4, srcop: 0, dstinst: 3, dstop: 0 }
+body: |
+ bb.0.entry:
+ $rax = MOV64ri 1, debug-instr-number 1, debug-location !17
+ ; This debug instruction should identify the value as being in $rax.
+ DBG_INSTR_REF 1, 0, !16, !DIExpression(), debug-location !17
+ ; CHECK: DBG_VALUE $rax, $noreg
+
+ $rbx = COPY killed $rax, debug-location !17
+ $rax = MOV64ri 1, debug-location !17
+ ; Presently, this COPY isn't followed. Dealing with that is future work.
+
+ DBG_INSTR_REF 2, 0, !16, !DIExpression(), debug-location !17
+ ; No instruction is labelled with the number "2". This should produce an
+ ; empty variable location.
+ ; CHECK: DBG_VALUE $noreg, $noreg
+
+ $rbx = MOV64ri 1, debug-instr-number 3, debug-location !17
+ JMP_1 %bb.1
+
+
+ ; CHECK-LABEL: bb.1:
+ bb.1:
+
+ DBG_INSTR_REF 3, 0, !16, !DIExpression(), debug-location !17
+ ; This refers to a value def'd in a parent block -- but it should be
+ ; tracked into this block.
+ ; CHECK: DBG_VALUE $rbx, $noreg
+ JMP_1 %bb.2
+
+ ; CHECK-LABEL: bb.2:
+ bb.2:
+ ; Just like any other variable location, live-ins should be created for
+ ; any successor blocks.
+ ; CHECK: DBG_VALUE $rbx, $noreg
+
+ RETQ $eax, debug-location !17
+...
More information about the llvm-commits
mailing list