[llvm] 2b2ffb7 - [DebugInfo][InstrRef][3/4] Produce DBG_INSTR_REFs for all variable locations

Jeremy Morse via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 6 10:41:43 PDT 2021


Author: Jeremy Morse
Date: 2021-07-06T18:31:38+01:00
New Revision: 2b2ffb7bdc21bce33372fdd02571b94c2a5e774a

URL: https://github.com/llvm/llvm-project/commit/2b2ffb7bdc21bce33372fdd02571b94c2a5e774a
DIFF: https://github.com/llvm/llvm-project/commit/2b2ffb7bdc21bce33372fdd02571b94c2a5e774a.diff

LOG: [DebugInfo][InstrRef][3/4] Produce DBG_INSTR_REFs for all variable locations

This patch emits DBG_INSTR_REFs for two remaining flavours of variable
locations that weren't supported: copies, and inter-block VRegs. There are
still some locations that must be represented by DBG_VALUE such as
constants, but they're mostly independent of optimisations.

For variable locations that refer to values defined in different blocks,
vregs are allocated before isel begins, but the defining instruction
might not exist until late in isel. To get around this, emit
DBG_INSTR_REFs in a "half done" state, where the first operand refers to a
VReg. Then at the end of isel, patch these back up to refer to
instructions, using the finalizeDebugInstrRefs method.

Copies are something that I complained about the original RFC, and I
really don't want to have to put instruction numbers on copies. They don't
define a value: they move them. To address this isel, salvageCopySSA
interprets:
 * COPYs,
 * SUBREG_TO_REG,
 * Anything that isCopyInstr thinks is a copy.
And follows chains of copies back to the defining instruction that they
read from. This relies on any physical registers that COPYs read being
defined in the same block, or being entry-block arguments. For the former
we can put an instruction number on the defining instruction; for the
latter we can drop a DBG_PHI that reads the incoming value.

Differential Revision: https://reviews.llvm.org/D88896

Added: 
    

Modified: 
    llvm/include/llvm/CodeGen/MachineFunction.h
    llvm/lib/CodeGen/MachineFunction.cpp
    llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
    llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
    llvm/test/DebugInfo/X86/arg-dbg-value-list.ll
    llvm/test/DebugInfo/X86/dbg-val-list-undef.ll
    llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll
    llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h
index 1d0a2a7deb761..f7e94214ca53c 100644
--- a/llvm/include/llvm/CodeGen/MachineFunction.h
+++ b/llvm/include/llvm/CodeGen/MachineFunction.h
@@ -504,6 +504,25 @@ class MachineFunction {
   void substituteDebugValuesForInst(const MachineInstr &Old, MachineInstr &New,
                                     unsigned MaxOperand = UINT_MAX);
 
+  /// Find the underlying  defining instruction / operand for a COPY instruction
+  /// while in SSA form. Copies do not actually define values -- they move them
+  /// between registers. Labelling a COPY-like instruction with an instruction
+  /// number is to be avoided as it makes value numbers non-unique later in
+  /// compilation. This method follows the definition chain for any sequence of
+  /// COPY-like instructions to find whatever non-COPY-like instruction defines
+  /// the copied value; or for parameters, creates a DBG_PHI on entry.
+  /// May insert instructions into the entry block!
+  /// \p MI The copy-like instruction to salvage.
+  /// \returns An instruction/operand pair identifying the defining value.
+  DebugInstrOperandPair salvageCopySSA(MachineInstr &MI);
+
+  /// Finalise any partially emitted debug instructions. These are DBG_INSTR_REF
+  /// instructions where we only knew the vreg of the value they use, not the
+  /// instruction that defines that vreg. Once isel finishes, we should have
+  /// enough information for every DBG_INSTR_REF to point at an instruction
+  /// (or DBG_PHI).
+  void finalizeDebugInstrRefs();
+
   MachineFunction(Function &F, const LLVMTargetMachine &Target,
                   const TargetSubtargetInfo &STI, unsigned FunctionNum,
                   MachineModuleInfo &MMI);

diff  --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp
index 8b1d05d252de9..7cb7d0893f5d9 100644
--- a/llvm/lib/CodeGen/MachineFunction.cpp
+++ b/llvm/lib/CodeGen/MachineFunction.cpp
@@ -1007,6 +1007,205 @@ void MachineFunction::substituteDebugValuesForInst(const MachineInstr &Old,
   }
 }
 
+auto MachineFunction::salvageCopySSA(MachineInstr &MI)
+    -> DebugInstrOperandPair {
+  MachineRegisterInfo &MRI = getRegInfo();
+  const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
+  const TargetInstrInfo &TII = *getSubtarget().getInstrInfo();
+
+  // Chase the value read by a copy-like instruction back to the instruction
+  // that ultimately _defines_ that value. This may pass:
+  //  * Through multiple intermediate copies, including subregister moves /
+  //    copies,
+  //  * Copies from physical registers that must then be traced back to the
+  //    defining instruction,
+  //  * Or, physical registers may be live-in to (only) the entry block, which
+  //    requires a DBG_PHI to be created.
+  // We can pursue this problem in that order: trace back through copies,
+  // optionally through a physical register, to a defining instruction. We
+  // should never move from physreg to vreg. As we're still in SSA form, no need
+  // to worry about partial definitions of registers.
+
+  // Helper lambda to interpret a copy-like instruction. Takes instruction,
+  // returns the register read and any subregister identifying which part is
+  // read.
+  auto GetRegAndSubreg =
+      [&](const MachineInstr &Cpy) -> std::pair<Register, unsigned> {
+    Register NewReg, OldReg;
+    unsigned SubReg;
+    if (Cpy.isCopy()) {
+      OldReg = Cpy.getOperand(0).getReg();
+      NewReg = Cpy.getOperand(1).getReg();
+      SubReg = Cpy.getOperand(1).getSubReg();
+    } else if (Cpy.isSubregToReg()) {
+      OldReg = Cpy.getOperand(0).getReg();
+      NewReg = Cpy.getOperand(2).getReg();
+      SubReg = Cpy.getOperand(3).getImm();
+    } else {
+      auto CopyDetails = *TII.isCopyInstr(Cpy);
+      const MachineOperand &Src = *CopyDetails.Source;
+      const MachineOperand &Dest = *CopyDetails.Destination;
+      OldReg = Dest.getReg();
+      NewReg = Src.getReg();
+      SubReg = Src.getSubReg();
+    }
+
+    return {NewReg, SubReg};
+  };
+
+  // First seek either the defining instruction, or a copy from a physreg.
+  // During search, the current state is the current copy instruction, and which
+  // register we've read. Accumulate qualifying subregisters into SubregsSeen;
+  // deal with those later.
+  auto State = GetRegAndSubreg(MI);
+  auto CurInst = MI.getIterator();
+  SmallVector<unsigned, 4> SubregsSeen;
+  while (true) {
+    // If we've found a copy from a physreg, first portion of search is over.
+    if (!State.first.isVirtual())
+      break;
+
+    // Record any subregister qualifier.
+    if (State.second)
+      SubregsSeen.push_back(State.second);
+
+    assert(MRI.hasOneDef(State.first));
+    MachineInstr &Inst = *MRI.def_begin(State.first)->getParent();
+    CurInst = Inst.getIterator();
+
+    // Any non-copy instruction is the defining instruction we're seeking.
+    if (!Inst.isCopyLike() && !TII.isCopyInstr(Inst))
+      break;
+    State = GetRegAndSubreg(Inst);
+  };
+
+  // Helper lambda to apply additional subregister substitutions to a known
+  // instruction/operand pair. Adds new (fake) substitutions so that we can
+  // record the subregister. FIXME: this isn't very space efficient if multiple
+  // values are tracked back through the same copies; cache something later.
+  auto ApplySubregisters =
+      [&](DebugInstrOperandPair P) -> DebugInstrOperandPair {
+    for (unsigned Subreg : reverse(SubregsSeen)) {
+      // Fetch a new instruction number, not attached to an actual instruction.
+      unsigned NewInstrNumber = getNewDebugInstrNum();
+      // Add a substitution from the "new" number to the known one, with a
+      // qualifying subreg.
+      makeDebugValueSubstitution({NewInstrNumber, 0}, P, Subreg);
+      // Return the new number; to find the underlying value, consumers need to
+      // deal with the qualifying subreg.
+      P = {NewInstrNumber, 0};
+    }
+    return P;
+  };
+
+  // If we managed to find the defining instruction after COPYs, return an
+  // instruction / operand pair after adding subregister qualifiers.
+  if (State.first.isVirtual()) {
+    // Virtual register def -- we can just look up where this happens.
+    MachineInstr *Inst = MRI.def_begin(State.first)->getParent();
+    for (auto &MO : Inst->operands()) {
+      if (!MO.isReg() || !MO.isDef() || MO.getReg() != State.first)
+        continue;
+      return ApplySubregisters(
+          {Inst->getDebugInstrNum(), Inst->getOperandNo(&MO)});
+    }
+
+    llvm_unreachable("Vreg def with no corresponding operand?");
+  }
+
+  // Our search ended in a copy from a physreg: walk back up the function
+  // looking for whatever defines the physreg.
+  assert(CurInst->isCopyLike() || TII.isCopyInstr(*CurInst));
+  State = GetRegAndSubreg(*CurInst);
+  Register RegToSeek = State.first;
+
+  auto RMII = CurInst->getReverseIterator();
+  auto PrevInstrs = make_range(RMII, CurInst->getParent()->instr_rend());
+  for (auto &ToExamine : PrevInstrs) {
+    for (auto &MO : ToExamine.operands()) {
+      // Test for operand that defines something aliasing RegToSeek.
+      if (!MO.isReg() || !MO.isDef() ||
+          !TRI.regsOverlap(RegToSeek, MO.getReg()))
+        continue;
+
+      return ApplySubregisters(
+          {ToExamine.getDebugInstrNum(), ToExamine.getOperandNo(&MO)});
+    }
+  }
+
+  // We reached the start of the block before finding a defining instruction.
+  // It must be an argument: assert that this is the entry block, and produce
+  // a DBG_PHI.
+  assert(!State.first.isVirtual());
+  MachineBasicBlock &TargetBB = *CurInst->getParent();
+  assert(&*TargetBB.getParent()->begin() == &TargetBB);
+
+  // Create DBG_PHI for specified physreg.
+  auto Builder = BuildMI(TargetBB, TargetBB.getFirstNonPHI(), DebugLoc(),
+                         TII.get(TargetOpcode::DBG_PHI));
+  Builder.addReg(State.first, RegState::Debug);
+  unsigned NewNum = getNewDebugInstrNum();
+  Builder.addImm(NewNum);
+  return ApplySubregisters({NewNum, 0u});
+}
+
+void MachineFunction::finalizeDebugInstrRefs() {
+  auto *TII = getSubtarget().getInstrInfo();
+
+  auto MakeDbgValue = [&](MachineInstr &MI) {
+    const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_VALUE);
+    MI.setDesc(RefII);
+    MI.getOperand(1).ChangeToRegister(0, false);
+    MI.getOperand(0).setIsDebug();
+  };
+
+  if (!getTarget().Options.ValueTrackingVariableLocations)
+    return;
+
+  for (auto &MBB : *this) {
+    for (auto &MI : MBB) {
+      if (!MI.isDebugRef() || !MI.getOperand(0).isReg())
+        continue;
+
+      Register Reg = MI.getOperand(0).getReg();
+
+      // Some vregs can be deleted as redundant in the meantime. Mark those
+      // as DBG_VALUE $noreg.
+      if (Reg == 0) {
+        MakeDbgValue(MI);
+        continue;
+      }
+
+      assert(Reg.isVirtual());
+      MachineInstr &DefMI = *RegInfo->def_instr_begin(Reg);
+      assert(RegInfo->hasOneDef(Reg));
+
+      // If we've found a copy-like instruction, follow it back to the
+      // instruction that defines the source value, see salvageCopySSA docs
+      // for why this is important.
+      if (DefMI.isCopyLike() || TII->isCopyInstr(DefMI)) {
+        auto Result = salvageCopySSA(DefMI);
+        MI.getOperand(0).ChangeToImmediate(Result.first);
+        MI.getOperand(1).setImm(Result.second);
+      } else {
+        // Otherwise, identify the operand number that the VReg refers to.
+        unsigned OperandIdx = 0;
+        for (const auto &MO : DefMI.operands()) {
+          if (MO.isReg() && MO.isDef() && MO.getReg() == Reg)
+            break;
+          ++OperandIdx;
+        }
+        assert(OperandIdx < DefMI.getNumOperands());
+
+        // Morph this instr ref to point at the given instruction and operand.
+        unsigned ID = DefMI.getDebugInstrNum();
+        MI.getOperand(0).ChangeToImmediate(ID);
+        MI.getOperand(1).setImm(OperandIdx);
+      }
+    }
+  }
+}
+
 /// \}
 
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
index 017231c1ab582..348fad6daf8f0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
@@ -686,6 +686,9 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
   ArrayRef<SDDbgOperand> LocationOps = SD->getLocationOps();
   assert(!LocationOps.empty() && "dbg_value with no location operands?");
 
+  if (SD->isInvalidated())
+    return EmitDbgNoLocation(SD);
+
   // Emit variadic dbg_value nodes as DBG_VALUE_LIST.
   if (SD->isVariadic()) {
     // DBG_VALUE_LIST := "DBG_VALUE_LIST" var, expression, loc (, loc)*
@@ -694,26 +697,7 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
     auto MIB = BuildMI(*MF, DL, DbgValDesc);
     MIB.addMetadata(Var);
     MIB.addMetadata(Expr);
-    if (SD->isInvalidated()) {
-      // At least one node is no longer computed so we are unable to emit the
-      // location. Simply mark all of the operands as undef.
-      for (size_t i = 0; i < LocationOps.size(); ++i)
-        MIB.addReg(0U, RegState::Debug);
-    } else {
-      AddDbgValueLocationOps(MIB, DbgValDesc, LocationOps, VRBaseMap);
-    }
-    return &*MIB;
-  }
-
-  if (SD->isInvalidated()) {
-    // An invalidated SDNode must generate an undef DBG_VALUE: although the
-    // original value is no longer computed, earlier DBG_VALUEs live ranges
-    // must not leak into later code.
-    auto MIB = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE));
-    MIB.addReg(0U);
-    MIB.addReg(0U, RegState::Debug);
-    MIB.addMetadata(Var);
-    MIB.addMetadata(Expr);
+    AddDbgValueLocationOps(MIB, DbgValDesc, LocationOps, VRBaseMap);
     return &*MIB;
   }
 
@@ -725,23 +709,7 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
     if (auto *InstrRef = EmitDbgInstrRef(SD, VRBaseMap))
       return InstrRef;
 
-  // Emit non-variadic dbg_value nodes as DBG_VALUE.
-  // DBG_VALUE := "DBG_VALUE" loc, isIndirect, var, expr
-  const MCInstrDesc &DbgValDesc = TII->get(TargetOpcode::DBG_VALUE);
-  // Build the DBG_VALUE instruction base.
-  auto MIB = BuildMI(*MF, DL, DbgValDesc);
-  // Add the single location componenet 'loc'.
-  assert(LocationOps.size() == 1 &&
-         "Non variadic dbg_value should have only one location op");
-  AddDbgValueLocationOps(MIB, DbgValDesc, LocationOps, VRBaseMap);
-  // Add 'isIndirect'.
-  if (SD->isIndirect())
-    MIB.addImm(0U);
-  else
-    MIB.addReg(0U, RegState::Debug);
-  MIB.addMetadata(Var);
-  MIB.addMetadata(Expr);
-  return &*MIB;
+  return EmitDbgValueFromSingleOp(SD, VRBaseMap);
 }
 
 void InstrEmitter::AddDbgValueLocationOps(
@@ -794,62 +762,134 @@ void InstrEmitter::AddDbgValueLocationOps(
 MachineInstr *
 InstrEmitter::EmitDbgInstrRef(SDDbgValue *SD,
                               DenseMap<SDValue, Register> &VRBaseMap) {
-  // No support for instruction references for variadic values yet.
-  if (SD->isVariadic())
-    return nullptr;
+  assert(!SD->isVariadic());
   SDDbgOperand DbgOperand = SD->getLocationOps()[0];
-  // Instruction referencing is still in a prototype state: for now we're only
-  // going to support SDNodes within a block. Copies are not supported, they
-  // don't actually define a value.
-  if (DbgOperand.getKind() != SDDbgOperand::SDNODE)
-    return nullptr;
-
-  SDNode *Node = DbgOperand.getSDNode();
-  SDValue Op = SDValue(Node, DbgOperand.getResNo());
-  DenseMap<SDValue, Register>::iterator I = VRBaseMap.find(Op);
-  if (I==VRBaseMap.end())
-    return nullptr; // undef value: let EmitDbgValue produce a DBG_VALUE $noreg.
-
   MDNode *Var = SD->getVariable();
   MDNode *Expr = SD->getExpression();
   DebugLoc DL = SD->getDebugLoc();
+  const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_INSTR_REF);
 
-  // Try to pick out a defining instruction at this point.
-  unsigned VReg = getVR(Op, VRBaseMap);
-  MachineInstr *ResultInstr = nullptr;
+  // Handle variable locations that don't actually depend on the instructions
+  // in the program: constants and stack locations.
+  if (DbgOperand.getKind() == SDDbgOperand::FRAMEIX ||
+      DbgOperand.getKind() == SDDbgOperand::CONST)
+    return EmitDbgValueFromSingleOp(SD, VRBaseMap);
 
-  // No definition corresponds to scenarios where a vreg is live-in to a block,
-  // and doesn't have a defining instruction (yet). This can be patched up
-  // later; at this early stage of implementation, fall back to using DBG_VALUE.
-  if (!MRI->hasOneDef(VReg))
-    return nullptr;
+  // It may not be immediately possible to identify the MachineInstr that
+  // defines a VReg, it can depend for example on the order blocks are
+  // emitted in. When this happens, or when further analysis is needed later,
+  // produce an instruction like this:
+  //
+  //    DBG_INSTR_REF %0:gr64, 0, !123, !456
+  //
+  // i.e., point the instruction at the vreg, and patch it up later in
+  // MachineFunction::finalizeDebugInstrRefs.
+  auto EmitHalfDoneInstrRef = [&](unsigned VReg) -> MachineInstr * {
+    auto MIB = BuildMI(*MF, DL, RefII);
+    MIB.addReg(VReg);
+    MIB.addImm(0);
+    MIB.addMetadata(Var);
+    MIB.addMetadata(Expr);
+    return MIB;
+  };
 
-  MachineInstr &DefMI = *MRI->def_instr_begin(VReg);
-  // Some target specific opcodes can become copies. As stated above, we're
-  // ignoring those for now.
-  if (DefMI.isCopy() || DefMI.getOpcode() == TargetOpcode::SUBREG_TO_REG)
-    return nullptr;
+  // Try to find both the defined register and the instruction defining it.
+  MachineInstr *DefMI = nullptr;
+  unsigned VReg;
+
+  if (DbgOperand.getKind() == SDDbgOperand::VREG) {
+    VReg = DbgOperand.getVReg();
+
+    // No definition means that block hasn't been emitted yet. Leave a vreg
+    // reference to be fixed later.
+    if (!MRI->hasOneDef(VReg))
+      return EmitHalfDoneInstrRef(VReg);
+
+    DefMI = &*MRI->def_instr_begin(VReg);
+  } else {
+    assert(DbgOperand.getKind() == SDDbgOperand::SDNODE);
+    // Look up the corresponding VReg for the given SDNode, if any.
+    SDNode *Node = DbgOperand.getSDNode();
+    SDValue Op = SDValue(Node, DbgOperand.getResNo());
+    DenseMap<SDValue, Register>::iterator I = VRBaseMap.find(Op);
+    // No VReg -> produce a DBG_VALUE $noreg instead.
+    if (I==VRBaseMap.end())
+      return EmitDbgNoLocation(SD);
+
+    // Try to pick out a defining instruction at this point.
+    VReg = getVR(Op, VRBaseMap);
+
+    // Again, if there's no instruction defining the VReg right now, fix it up
+    // later.
+    if (!MRI->hasOneDef(VReg))
+      return EmitHalfDoneInstrRef(VReg);
+
+    DefMI = &*MRI->def_instr_begin(VReg);
+  }
+
+  // Avoid copy like instructions: they don't define values, only move them.
+  // Leave a virtual-register reference until it can be fixed up later, to find
+  // the underlying value definition.
+  if (DefMI->isCopyLike() || TII->isCopyInstr(*DefMI))
+    return EmitHalfDoneInstrRef(VReg);
 
-  const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_INSTR_REF);
   auto MIB = BuildMI(*MF, DL, RefII);
 
-  // Find the operand which defines the specified VReg.
+  // Find the operand number which defines the specified VReg.
   unsigned OperandIdx = 0;
-  for (const auto &MO : DefMI.operands()) {
+  for (const auto &MO : DefMI->operands()) {
     if (MO.isReg() && MO.isDef() && MO.getReg() == VReg)
       break;
     ++OperandIdx;
   }
-  assert(OperandIdx < DefMI.getNumOperands());
+  assert(OperandIdx < DefMI->getNumOperands());
 
   // Make the DBG_INSTR_REF refer to that instruction, and that operand.
-  unsigned InstrNum = DefMI.getDebugInstrNum();
+  unsigned InstrNum = DefMI->getDebugInstrNum();
   MIB.addImm(InstrNum);
   MIB.addImm(OperandIdx);
   MIB.addMetadata(Var);
   MIB.addMetadata(Expr);
-  ResultInstr = &*MIB;
-  return ResultInstr;
+  return &*MIB;
+}
+
+MachineInstr *InstrEmitter::EmitDbgNoLocation(SDDbgValue *SD) {
+  // An invalidated SDNode must generate an undef DBG_VALUE: although the
+  // original value is no longer computed, earlier DBG_VALUEs live ranges
+  // must not leak into later code.
+  MDNode *Var = SD->getVariable();
+  MDNode *Expr = SD->getExpression();
+  DebugLoc DL = SD->getDebugLoc();
+  auto MIB = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE));
+  MIB.addReg(0U);
+  MIB.addReg(0U, RegState::Debug);
+  MIB.addMetadata(Var);
+  MIB.addMetadata(Expr);
+  return &*MIB;
+}
+
+MachineInstr *
+InstrEmitter::EmitDbgValueFromSingleOp(SDDbgValue *SD,
+                                       DenseMap<SDValue, Register> &VRBaseMap) {
+  MDNode *Var = SD->getVariable();
+  MDNode *Expr = SD->getExpression();
+  DebugLoc DL = SD->getDebugLoc();
+  const MCInstrDesc &II = TII->get(TargetOpcode::DBG_VALUE);
+
+  assert(SD->getLocationOps().size() == 1 &&
+         "Non variadic dbg_value should have only one location op");
+
+  // Emit non-variadic dbg_value nodes as DBG_VALUE.
+  // DBG_VALUE := "DBG_VALUE" loc, isIndirect, var, expr
+  auto MIB = BuildMI(*MF, DL, II);
+  AddDbgValueLocationOps(MIB, II, SD->getLocationOps(), VRBaseMap);
+
+  if (SD->isIndirect())
+    MIB.addImm(0U);
+  else
+    MIB.addReg(0U, RegState::Debug);
+
+  return MIB.addMetadata(Var).addMetadata(Expr);
 }
 
 MachineInstr *

diff  --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
index 7bf0e0c4fb19a..ac8a70156522a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
+++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
@@ -119,11 +119,19 @@ class LLVM_LIBRARY_VISIBILITY InstrEmitter {
   MachineInstr *EmitDbgValue(SDDbgValue *SD,
                              DenseMap<SDValue, Register> &VRBaseMap);
 
-  /// Attempt to emit a dbg_value as a DBG_INSTR_REF. May fail and return
-  /// nullptr, in which case we fall back to plain EmitDbgValue.
+  /// Emit a dbg_value as a DBG_INSTR_REF. May produce DBG_VALUE $noreg instead
+  /// if there is no variable location; alternately a half-formed DBG_INSTR_REF
+  /// that refers to a virtual register and is corrected later in isel.
   MachineInstr *EmitDbgInstrRef(SDDbgValue *SD,
                                 DenseMap<SDValue, Register> &VRBaseMap);
 
+  /// Emit a DBG_VALUE $noreg, indicating a variable has no location.
+  MachineInstr *EmitDbgNoLocation(SDDbgValue *SD);
+
+  /// Emit a DBG_VALUE from the operands to SDDbgValue.
+  MachineInstr *EmitDbgValueFromSingleOp(SDDbgValue *SD,
+                                    DenseMap<SDValue, Register> &VRBaseMap);
+
   /// Generate machine instruction for a dbg_label node.
   MachineInstr *EmitDbgLabel(SDDbgLabel *SD);
 

diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index e3ff00131dbed..1415cce3b1dff 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -575,6 +575,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
         LiveInMap.insert(LI);
 
   // Insert DBG_VALUE instructions for function arguments to the entry block.
+  bool InstrRef = TM.Options.ValueTrackingVariableLocations;
   for (unsigned i = 0, e = FuncInfo->ArgDbgValues.size(); i != e; ++i) {
     MachineInstr *MI = FuncInfo->ArgDbgValues[e - i - 1];
     assert(MI->getOpcode() != TargetOpcode::DBG_VALUE_LIST &&
@@ -595,6 +596,10 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
                           << Register::virtReg2Index(Reg) << "\n");
     }
 
+    // Don't try and extend through copies in instruction referencing mode.
+    if (InstrRef)
+      continue;
+
     // If Reg is live-in then update debug info to track its copy in a vreg.
     DenseMap<unsigned, unsigned>::iterator LDI = LiveInMap.find(Reg);
     if (LDI != LiveInMap.end()) {
@@ -646,6 +651,10 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
     }
   }
 
+  // For debug-info, in instruction referencing mode, we need to perform some
+  // post-isel maintenence.
+  MF->finalizeDebugInstrRefs();
+
   // Determine if there are any calls in this machine function.
   MachineFrameInfo &MFI = MF->getFrameInfo();
   for (const auto &MBB : *MF) {

diff  --git a/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll b/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll
index 3886a545e1d6c..a817f9aef8c66 100644
--- a/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll
+++ b/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll
@@ -13,7 +13,7 @@
 
 ; CHECK: DBG_VALUE $ecx, $noreg, ![[A]], !DIExpression(), debug-location
 ; CHECK: DBG_VALUE $edx, $noreg, ![[B]], !DIExpression(), debug-location
-; CHECK: DBG_VALUE_LIST ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), $noreg, $noreg, debug-location
+; CHECK: DBG_VALUE $noreg, $noreg, ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), debug-location
 
 target triple = "x86_64-pc-windows-msvc19.16.27034"
 define dso_local i32 @"?foo@@YAHHH at Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 {

diff  --git a/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll b/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll
index c5c3522762528..8aa641d0c0fc8 100644
--- a/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll
+++ b/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll
@@ -4,7 +4,7 @@
 ;; variadic dbg_value using %y becomes undef.
 
 ; CHECK: ![[C:[0-9]+]] = !DILocalVariable(name: "c",
-; CHECK: DBG_VALUE_LIST ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), $noreg, $noreg, debug-location
+; CHECK: DBG_VALUE $noreg, $noreg, ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value),  debug-location
 
 target triple = "x86_64-pc-windows-msvc19.16.27034"
 define dso_local i32 @"?foo@@YAHHH at Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 {

diff  --git a/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll b/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll
index 62ff23a73881d..303e706e12700 100644
--- a/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll
+++ b/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll
@@ -10,6 +10,8 @@
 ; Test that SelectionDAG produces DBG_VALUEs normally, but DBG_INSTR_REFs when
 ; asked.
 
+; NORMAL-LABEL: name: foo
+
 ; NORMAL:      %[[REG0:[0-9]+]]:gr32 = ADD32rr
 ; NORMAL-NEXT: DBG_VALUE %[[REG0]]
 ; NORMAL-NEXT: %[[REG1:[0-9]+]]:gr32 = ADD32rr
@@ -19,6 +21,8 @@
 ; capture and check for the instruction numbers, we'd rely on machine verifier
 ; ensuring there were no duplicates.
 
+; INSTRREF-LABEL: name: foo
+
 ; INSTRREF:      ADD32rr
 ; INSTRREF-SAME: debug-instr-number 1
 ; INSTRREF-NEXT: DBG_INSTR_REF 1, 0
@@ -26,6 +30,10 @@
 ; INSTRREF-SAME: debug-instr-number 2
 ; INSTRREF-NEXT: DBG_INSTR_REF 2, 0
 
+ at glob32 = global i32 0
+ at glob16 = global i16 0
+ at glob8 = global i8 0
+
 declare void @llvm.dbg.value(metadata, metadata, metadata)
 
 define i32 @foo(i32 %bar, i32 %baz, i32 %qux) !dbg !7 {
@@ -37,6 +45,105 @@ entry:
   ret i32 %1, !dbg !14
 }
 
+; In the code below, isel produces a large number of copies between subregisters
+; to represent the gradually decreasing width of the argument. This gets
+; optimized away into three stores, but it's an objective of the instruction
+; referencing design that COPYs are not numbered: they move values, not define
+; them. Test that nothing is numbered, and instead that appropriate
+; substitutions with subregister details are recorded.
+
+; NORMAL-LABEL: name: bar
+
+; NORMAL:      DBG_VALUE $rdi
+; NORMAL-NEXT: %0:gr64_with_sub_8bit = COPY $rdi
+; NORMAL-NEXT: DBG_VALUE %0,
+; NORMAL-NEXT: %1:gr32 = COPY %0.sub_32bit,
+; NORMAL-NEXT: DBG_VALUE %1
+; NORMAL:      %3:gr16 = COPY %0.sub_16bit,
+; NORMAL-NEXT: DBG_VALUE %3
+; NORMAL:      %5:gr8 = COPY %0.sub_8bit,
+; NORMAL-NEXT: DBG_VALUE %5
+
+; INSTRREF-LABEL: name: bar
+
+;; 
+; INSTRREF:      debugValueSubstitutions:
+; INSTRREF-NEXT: - { srcinst: 2, srcop: 0, dstinst: 1, dstop: 0, subreg: 6 }
+; INSTRREF-NEXT: - { srcinst: 4, srcop: 0, dstinst: 3, dstop: 0, subreg: 4 }
+; INSTRREF-NEXT: - { srcinst: 6, srcop: 0, dstinst: 5, dstop: 0, subreg: 1 }
+
+;; As a slight inefficiency today, multiple DBG_PHIs are created.
+
+; INSTRREF:      DBG_PHI $rdi, 5
+; INSTRREF-NEXT: DBG_PHI $rdi, 3
+; INSTRREF-NEXT: DBG_PHI $rdi, 1
+;; Allow arguments to be specified by physreg DBG_VALUEs.
+; INSTRREF-NEXT: DBG_VALUE $rdi
+
+;; Don't test the location of these instr-refs, only that the three non-argument
+;; dbg.values become DBG_INSTR_REFs. We previously checked that these numbers
+;; get substituted, with appropriate subregister qualifiers.
+; INSTRREF:      DBG_INSTR_REF 2, 0
+; INSTRREF:      DBG_INSTR_REF 4, 0
+; INSTRREF:      DBG_INSTR_REF 6, 0
+
+define i32 @bar(i64 %bar) !dbg !20 {
+entry:
+  call void @llvm.dbg.value(metadata i64 %bar, metadata !21, metadata !DIExpression()), !dbg !22
+  %0 = trunc i64 %bar to i32, !dbg !22
+  call void @llvm.dbg.value(metadata i32 %0, metadata !21, metadata !DIExpression()), !dbg !22
+  store i32 %0, i32 *@glob32, !dbg !22
+  %1 = trunc i32 %0 to i16, !dbg !22
+  call void @llvm.dbg.value(metadata i16 %1, metadata !21, metadata !DIExpression()), !dbg !22
+  store i16 %1, i16 *@glob16, !dbg !22
+  %2 = trunc i16 %1 to i8, !dbg !22
+  call void @llvm.dbg.value(metadata i8 %2, metadata !21, metadata !DIExpression()), !dbg !22
+  store i8 %2, i8 *@glob8, !dbg !22
+  ret i32 0, !dbg !22
+}
+
+; Ensure that we can track copies back to physreg defs, and throw in a subreg
+; substitution for fun. The call to @xyzzy defines $rax, which gets copied to
+; a VReg, and then truncated by a subreg copy. We should be able to track
+; through the copies and walk back to the physreg def, labelling the CALL
+; instruction. We should also be able to do this even when the block layout is
+; crazily ordered.
+
+; NORMAL-LABEL: name: baz
+
+; NORMAL:      CALL64pcrel32 target-flags(x86-plt) @xyzzy
+; NORMAL:      %2:gr64 = COPY $rax,
+; NORMAL:      %0:gr64 = COPY %2,
+; NORMAL-LABEL: bb.1.slippers:
+; NORMAL:      DBG_VALUE %1
+; NORMAL-LABEL: bb.2.shoes:
+; NORMAL:      %1:gr16 = COPY %0.sub_16bit
+
+; INSTRREF-LABEL: name: baz
+
+; INSTRREF:      debugValueSubstitutions:
+; INSTRREF-NEXT:  - { srcinst: 2, srcop: 0, dstinst: 1, dstop: 6, subreg: 4 }
+
+; INSTRREF:      CALL64pcrel32 target-flags(x86-plt) @xyzzy, {{.*}} debug-instr-number 1
+; INSTRREF:      DBG_INSTR_REF 2, 0
+
+declare i64 @xyzzy()
+
+define i32 @baz() !dbg !30 {
+entry:
+  %foo = call i64 @xyzzy(), !dbg !32
+  br label %shoes
+
+slippers:
+  call void @llvm.dbg.value(metadata i16 %moo, metadata !31, metadata !DIExpression()), !dbg !32
+  store i16 %moo, i16 *@glob16, !dbg !32
+  ret i32 0, !dbg !32
+
+shoes:
+  %moo = trunc i64 %foo to i16
+  br label %slippers
+}
+
 !llvm.dbg.cu = !{!0}
 !llvm.module.flags = !{!3, !4}
 
@@ -52,3 +159,9 @@ entry:
 !11 = !{!13}
 !13 = !DILocalVariable(name: "baz", scope: !7, file: !1, line: 6, type: !10)
 !14 = !DILocation(line: 1, scope: !7)
+!20 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!21 = !DILocalVariable(name: "xyzzy", scope: !20, file: !1, line: 6, type: !10)
+!22 = !DILocation(line: 1, scope: !20)
+!30 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!31 = !DILocalVariable(name: "xyzzy", scope: !30, file: !1, line: 6, type: !10)
+!32 = !DILocation(line: 1, scope: !30)

diff  --git a/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll b/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll
index 1c20bd616ff76..b637f999289ec 100644
--- a/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll
+++ b/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll
@@ -5,9 +5,7 @@
 
 ; CHECK-LABEL: body:
 
-; CHECK: DBG_VALUE_LIST ![[VAR:[0-9]+]]
-; CHECK-SAME: $noreg, $noreg
-
+; CHECK: DBG_VALUE $noreg, $noreg, ![[VAR:[0-9]+]]
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"


        


More information about the llvm-commits mailing list