[llvm] b1b2c6a - [DebugInstrRef] Handle DBG_INSTR_REFs use-before-defs in LiveDebugValues
Jeremy Morse via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 23 08:38:28 PDT 2020
Author: Jeremy Morse
Date: 2020-10-23T16:33:23+01:00
New Revision: b1b2c6ab667d50e68a6f945f6b64ce0351c2739c
URL: https://github.com/llvm/llvm-project/commit/b1b2c6ab667d50e68a6f945f6b64ce0351c2739c
DIFF: https://github.com/llvm/llvm-project/commit/b1b2c6ab667d50e68a6f945f6b64ce0351c2739c.diff
LOG: [DebugInstrRef] Handle DBG_INSTR_REFs use-before-defs in LiveDebugValues
Deciding where to place debugging instructions when normal instructions
sink between blocks is difficult -- see PR44117. Dealing with this with
instruction-referencing variable locations is simple: we just tolerate
DBG_INSTR_REFs referring to values that haven't been computed yet. This
patch adds support into InstrRefBasedLDV to record when a variable value
appears in the middle of a block, and should have a DBG_VALUE added when it
appears (a debug use before def).
While described simply, this relies heavily on the value-propagation
algorithm in InstrRefBasedLDV. The implementation doesn't attempt to verify
the location of a value unless something non-trivial occurs to merge
variable values in vlocJoin. This means that a variable with a value that
has no location can retain it across all control flow (including loops).
It's only when another debug instruction specifies a different variable
value that we have to check, and find there's no location.
This property means that if a machine value is defined in a block dominated
by a DBG_INSTR_REF that refers to it, all the successor blocks can
automatically find a location for that value (if it's not clobbered). Thus
in a sense, InstrRefBasedLDV is already supporting and implementing
use-before-defs. This patch allows us to specify a variable location in the
block where it's defined.
When loading live-in variable locations, TransferTracker currently discards
those where it can't find a location for the variable value. However, we
can tell from the machine value number whether the value is defined in this
block. If it is, add it to a set of use-before-def records. Then, once the
relevant instruction has been processed, emit a DBG_VALUE immediately after
it.
Differential Revision: https://reviews.llvm.org/D85775
Added:
Modified:
llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
index 32cccc13fa8b5..926163fa521ea 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
@@ -992,6 +992,27 @@ class TransferTracker {
/// Temporary cache of DBG_VALUEs to be entered into the Transfers collection.
SmallVector<MachineInstr *, 4> PendingDbgValues;
+ /// Record of a use-before-def: created when a value that's live-in to the
+ /// current block isn't available in any machine location, but it will be
+ /// defined in this block.
+ struct UseBeforeDef {
+ /// Value of this variable, def'd in block.
+ ValueIDNum ID;
+ /// Identity of this variable.
+ DebugVariable Var;
+ /// Additional variable properties.
+ DbgValueProperties Properties;
+ };
+
+ /// Map from instruction index (within the block) to the set of UseBeforeDefs
+ /// that become defined at that instruction.
+ DenseMap<unsigned, SmallVector<UseBeforeDef, 1>> UseBeforeDefs;
+
+ /// The set of variables that are in UseBeforeDefs and can become a location
+ /// once the relevant value is defined. An element being erased from this
+ /// collection prevents the use-before-def materializing.
+ DenseSet<DebugVariable> UseBeforeDefVariables;
+
const TargetRegisterInfo &TRI;
const BitVector &CalleeSavedRegs;
@@ -1014,6 +1035,8 @@ class TransferTracker {
ActiveVLocs.clear();
VarLocs.clear();
VarLocs.reserve(NumLocs);
+ UseBeforeDefs.clear();
+ UseBeforeDefVariables.clear();
auto isCalleeSaved = [&](LocIdx L) {
unsigned Reg = MTracker->LocIdxToLocID[L];
@@ -1058,9 +1081,15 @@ class TransferTracker {
}
// If the value has no location, we can't make a variable location.
- auto ValuesPreferredLoc = ValueToLoc.find(Var.second.ID);
- if (ValuesPreferredLoc == ValueToLoc.end())
+ const ValueIDNum &Num = Var.second.ID;
+ auto ValuesPreferredLoc = ValueToLoc.find(Num);
+ if (ValuesPreferredLoc == ValueToLoc.end()) {
+ // If it's a def that occurs in this block, register it as a
+ // use-before-def to be resolved as we step through the block.
+ if (Num.getBlock() == (unsigned)MBB.getNumber() && !Num.isPHI())
+ addUseBeforeDef(Var.first, Var.second.Properties, Num);
continue;
+ }
LocIdx M = ValuesPreferredLoc->second;
auto NewValue = LocAndProperties{M, Var.second.Properties};
@@ -1074,6 +1103,44 @@ class TransferTracker {
flushDbgValues(MBB.begin(), &MBB);
}
+ /// Record that \p Var has value \p ID, a value that becomes available
+ /// later in the function.
+ void addUseBeforeDef(const DebugVariable &Var,
+ const DbgValueProperties &Properties, ValueIDNum ID) {
+ UseBeforeDef UBD = {ID, Var, Properties};
+ UseBeforeDefs[ID.getInst()].push_back(UBD);
+ UseBeforeDefVariables.insert(Var);
+ }
+
+ /// After the instruction at index \p Inst and position \p pos has been
+ /// processed, check whether it defines a variable value in a use-before-def.
+ /// If so, and the variable value hasn't changed since the start of the
+ /// block, create a DBG_VALUE.
+ void checkInstForNewValues(unsigned Inst, MachineBasicBlock::iterator pos) {
+ auto MIt = UseBeforeDefs.find(Inst);
+ if (MIt == UseBeforeDefs.end())
+ return;
+
+ for (auto &Use : MIt->second) {
+ LocIdx L = Use.ID.getLoc();
+
+ // If something goes very wrong, we might end up labelling a COPY
+ // instruction or similar with an instruction number, where it doesn't
+ // actually define a new value, instead it moves a value. In case this
+ // happens, discard.
+ if (MTracker->LocIdxToIDNum[L] != Use.ID)
+ continue;
+
+ // If a
diff erent debug instruction defined the variable value / location
+ // since the start of the block, don't materialize this use-before-def.
+ if (!UseBeforeDefVariables.count(Use.Var))
+ continue;
+
+ PendingDbgValues.push_back(MTracker->emitLoc(L, Use.Var, Use.Properties));
+ }
+ flushDbgValues(pos, nullptr);
+ }
+
/// Helper to move created DBG_VALUEs into Transfers collection.
void flushDbgValues(MachineBasicBlock::iterator Pos, MachineBasicBlock *MBB) {
if (PendingDbgValues.size() > 0) {
@@ -1097,6 +1164,8 @@ class TransferTracker {
ActiveMLocs[It->second.Loc].erase(Var);
ActiveVLocs.erase(It);
}
+ // Any use-before-defs no longer apply.
+ UseBeforeDefVariables.erase(Var);
return;
}
@@ -1112,6 +1181,8 @@ class TransferTracker {
Optional<LocIdx> OptNewLoc) {
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
MI.getDebugLoc()->getInlinedAt());
+ // Any use-before-defs no longer apply.
+ UseBeforeDefVariables.erase(Var);
// Erase any previous location,
auto It = ActiveVLocs.find(Var);
@@ -1659,6 +1730,12 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI) {
// Tell transfer tracker that the variable value has changed.
TTracker->redefVar(MI, Properties, FoundLoc);
+ // If there was a value with no location; but the value is defined in a
+ // later instruction in this block, this is a block-local use-before-def.
+ if (!FoundLoc && NewID && NewID->getBlock() == CurBB &&
+ NewID->getInst() > CurInst)
+ TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false}, *NewID);
+
// Produce a DBG_VALUE representing what this DBG_INSTR_REF meant.
// This DBG_VALUE is potentially a $noreg / undefined location, if
// FoundLoc is None.
@@ -3069,6 +3146,7 @@ void InstrRefBasedLDV::emitLocations(
CurInst = 1;
for (auto &MI : MBB) {
process(MI);
+ TTracker->checkInstForNewValues(CurInst, MI.getIterator());
++CurInst;
}
}
diff --git a/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir b/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir
index 5f9238cde9271..9f77add7bc137 100644
--- a/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir
+++ b/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir
@@ -68,5 +68,91 @@ body: |
; any successor blocks.
; CHECK: DBG_VALUE $rbx, $noreg
+ DBG_INSTR_REF 5, 0, !16, !DIExpression(), debug-location !17
+ ; This is a debug use-before-def: the value appears a few instructions
+ ; later. Any earlier value should be terminated here, _and_ we should
+ ; emit a DBG_VALUE when the value becomes available.
+ ; CHECK: DBG_VALUE $noreg, $noreg
+
+ $rax = MOV64ri 1, debug-location !17
+ $rax = MOV64ri 1, debug-location !17
+ $rcx = MOV64ri 1, debug-instr-number 5, debug-location !17
+ ; CHECK: DBG_VALUE $rcx, $noreg
+ $rax = MOV64ri 1, debug-location !17
+
+ DBG_INSTR_REF 6, 0, !16, !DIExpression(), debug-location !17
+ ; Another debug use-before-def, but across block boundaries.
+ ; CHECK: DBG_VALUE $noreg, $noreg
+ JMP_1 %bb.3
+
+ ; CHECK-LABEL: bb.3:
+ bb.3:
+ $rax = MOV64ri 1, debug-location !17
+ $rdx = MOV64ri 1, debug-instr-number 6, debug-location !17
+ ; CHECK: DBG_VALUE $rdx, $noreg
+
+ ; Terminate variable location for next few blocks,
+ DBG_VALUE $noreg, $noreg, !16, !DIExpression(), debug-location !17
+ ; CHECK: DBG_VALUE $noreg, $noreg
+ JMP_1 %bb.4
+
+ bb.4:
+ ; The next three blocks form a debug use-before-def modelling a scenario
+ ; where an instruction is sunk (debug inst in bb5, value in bb6). However,
+ ; because a
diff erent path joins bb.6, we should _not_ add any DBG_VALUE.
+ ; A
diff erent variable value may enter the block via the other path.
+ $rdx = MOV64ri 1, implicit-def $eflags, debug-location !17
+ JCC_1 %bb.6, 4, implicit $eflags, debug-location !17
+ bb.5:
+ DBG_INSTR_REF 7, 0, !16, !DIExpression(), debug-location !17
+ ; CHECK: DBG_VALUE $noreg, $noreg
+ JMP_1 %bb.6, debug-location !17
+ bb.6:
+ $rsi = MOV64ri 1, debug-instr-number 7, debug-location !17
+ JMP_1 %bb.7, debug-location !17
+
+ ; A use-before-def shouldn't pass another definition of the variable location
+ ; or value.
+ bb.7:
+ DBG_INSTR_REF 8, 0, !16, !DIExpression(), debug-location !17
+ ; CHECK: DBG_VALUE $noreg, $noreg
+ DBG_VALUE $rax, $noreg, !16, !DIExpression(), debug-location !17
+ ; CHECK: DBG_VALUE $rax, $noreg,
+ $rdi = MOV64ri 1, debug-instr-number 8, debug-location !17
+
+ ; Loops: use-before-defs should be live-through loops, assuming that nothing
+ ; in that loop modifies the variable location.
+ bb.8:
+ DBG_INSTR_REF 9, 0, !16, !DIExpression(), debug-location !17
+ ; CHECK: DBG_VALUE $noreg, $noreg
+ JCC_1 %bb.8, 4, implicit $eflags
+ bb.9:
+ $rax = MOV64ri 11, debug-instr-number 9, debug-location !17
+ ; CHECK: DBG_VALUE $rax, $noreg,
+
+ ; Likewise, use-before-defs where anything changes the variable location
+ ; or value in the loop, should be discarded.
+ bb.10:
+ ; live-in,
+ ; CHECK: DBG_VALUE $rax, $noreg,
+ DBG_INSTR_REF 10, 0, !16, !DIExpression(), debug-location !17
+ ; CHECK: DBG_VALUE $noreg, $noreg
+
+ bb.11:
+ $rbx = MOV64ri 1, debug-location !17
+
+ bb.12:
+ DBG_INSTR_REF 9, 0, !16, !DIExpression(), debug-location !17
+ ; This still has a value in $rax,
+ ; CHECK: DBG_VALUE $rax, $noreg
+ JCC_1 %bb.11, 4, implicit $eflags
+
+ bb.13:
+ ; Live in,
+ ; CHECK: DBG_VALUE $rax, $noreg
+ $rbx = MOV64ri 11, debug-instr-number 10, debug-location !17
+ ; This is instruction 10 referred to in bb.10. However, as the variable
+ ; location/value has been modified in the meantime, no DBG_VALUE should be
+ ; generated here.
RETQ $eax, debug-location !17
...
More information about the llvm-commits
mailing list