[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