[llvm] 8496fc2 - [DebugInstrRef][1/3] Track PHI values through register allocation

Jeremy Morse via llvm-commits llvm-commits at lists.llvm.org
Wed May 26 12:24:30 PDT 2021


Author: Jeremy Morse
Date: 2021-05-26T20:24:00+01:00
New Revision: 8496fc2ec8046727e298629aa74943be0137267b

URL: https://github.com/llvm/llvm-project/commit/8496fc2ec8046727e298629aa74943be0137267b
DIFF: https://github.com/llvm/llvm-project/commit/8496fc2ec8046727e298629aa74943be0137267b.diff

LOG: [DebugInstrRef][1/3] Track PHI values through register allocation

This patch introduces "DBG_PHI" instructions, a marker of where a PHI
instruction used to be, before PHI elimination. Under the instruction
referencing model, we want to know where every value in the function is
defined -- and a PHI, even if implicit, is such a place.

Just like instruction numbers, we can use this to identify a value to be
used as a variable value, but we don't need to know what instruction
defines that value, for example:

bb1:
   DBG_PHI $rax, 1
   [... more insts ... ]
bb2:
   DBG_INSTR_REF 1, 0, !1234, !DIExpression()

This specifies that on entry to bb1, whatever value is in $rax is known
as value number one -- and the later DBG_INSTR_REF marks the position
where variable !1234 should take on value number one.

PHI locations are stored in MachineFunction for the duration of the
regalloc phase in the DebugPHIPositions map. The map is populated by
PHIElimination, and then flushed back into the instruction stream by
virtregrewriter. A small amount of maintenence is needed in
LiveDebugVariables to account for registers being split, but only for
individual positions, not for entire ranges of blocks.

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

Added: 
    llvm/test/DebugInfo/MIR/InstrRef/phi-regallocd-to-stack.mir
    llvm/test/DebugInfo/MIR/InstrRef/phi-through-regalloc.mir

Modified: 
    llvm/include/llvm/CodeGen/MachineFunction.h
    llvm/include/llvm/CodeGen/MachineInstr.h
    llvm/include/llvm/Support/TargetOpcodes.def
    llvm/include/llvm/Target/Target.td
    llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    llvm/lib/CodeGen/LiveDebugVariables.cpp
    llvm/lib/CodeGen/PHIElimination.cpp
    llvm/lib/CodeGen/PrologEpilogInserter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h
index e14b337098aff..639077e762efc 100644
--- a/llvm/include/llvm/CodeGen/MachineFunction.h
+++ b/llvm/include/llvm/CodeGen/MachineFunction.h
@@ -457,6 +457,24 @@ class MachineFunction {
   std::map<DebugInstrOperandPair, DebugInstrOperandPair>
       DebugValueSubstitutions;
 
+  /// Location of a PHI instruction that is also a debug-info variable value,
+  /// for the duration of register allocation. Loaded by the PHI-elimination
+  /// pass, and emitted as DBG_PHI instructions during VirtRegRewriter, with
+  /// maintenance applied by intermediate passes that edit registers (such as
+  /// coalescing and the allocator passes).
+  class DebugPHIRegallocPos {
+  public:
+    MachineBasicBlock *MBB; ///< Block where this PHI was originally located.
+    Register Reg;           ///< VReg where the control-flow-merge happens.
+    unsigned SubReg;        ///< Optional subreg qualifier within Reg.
+    DebugPHIRegallocPos(MachineBasicBlock *MBB, Register Reg, unsigned SubReg)
+        : MBB(MBB), Reg(Reg), SubReg(SubReg) {}
+  };
+
+  /// Map of debug instruction numbers to the position of their PHI instructions
+  /// during register allocation. See DebugPHIRegallocPos.
+  DenseMap<unsigned, DebugPHIRegallocPos> DebugPHIPositions;
+
   /// Create a substitution between one <instr,operand> value to a 
diff erent,
   /// new value.
   void makeDebugValueSubstitution(DebugInstrOperandPair, DebugInstrOperandPair);

diff  --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h
index 4760459d5a158..12da008a7bf44 100644
--- a/llvm/include/llvm/CodeGen/MachineInstr.h
+++ b/llvm/include/llvm/CodeGen/MachineInstr.h
@@ -1207,8 +1207,9 @@ class MachineInstr
   }
   bool isDebugLabel() const { return getOpcode() == TargetOpcode::DBG_LABEL; }
   bool isDebugRef() const { return getOpcode() == TargetOpcode::DBG_INSTR_REF; }
+  bool isDebugPHI() const { return getOpcode() == TargetOpcode::DBG_PHI; }
   bool isDebugInstr() const {
-    return isDebugValue() || isDebugLabel() || isDebugRef();
+    return isDebugValue() || isDebugLabel() || isDebugRef() || isDebugPHI();
   }
   bool isDebugOrPseudoInstr() const {
     return isDebugInstr() || isPseudoProbe();
@@ -1314,6 +1315,7 @@ class MachineInstr
     case TargetOpcode::DBG_VALUE:
     case TargetOpcode::DBG_VALUE_LIST:
     case TargetOpcode::DBG_INSTR_REF:
+    case TargetOpcode::DBG_PHI:
     case TargetOpcode::DBG_LABEL:
     case TargetOpcode::LIFETIME_START:
     case TargetOpcode::LIFETIME_END:

diff  --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index 09f182c46b374..a153eae965195 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -85,6 +85,10 @@ HANDLE_TARGET_OPCODE(DBG_VALUE_LIST)
 /// that defines the value, rather than a virtual register.
 HANDLE_TARGET_OPCODE(DBG_INSTR_REF)
 
+/// DBG_PHI - remainder of a PHI, identifies a program point where values
+/// merge under control flow.
+HANDLE_TARGET_OPCODE(DBG_PHI)
+
 /// DBG_LABEL - a mapping of the llvm.dbg.label intrinsic
 HANDLE_TARGET_OPCODE(DBG_LABEL)
 

diff  --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 46d265be6e288..71c74f3d5cdec 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -1125,6 +1125,12 @@ def DBG_INSTR_REF : StandardPseudoInstruction {
   let AsmString = "DBG_INSTR_REF";
   let hasSideEffects = false;
 }
+def DBG_PHI : StandardPseudoInstruction {
+  let OutOperandList = (outs);
+  let InOperandList = (ins variable_ops);
+  let AsmString = "DBG_PHI";
+  let hasSideEffects = 0;
+}
 def DBG_LABEL : StandardPseudoInstruction {
   let OutOperandList = (outs);
   let InOperandList = (ins unknown:$label);

diff  --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 27f6c17994473..05edf12234ef2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1313,6 +1313,10 @@ void AsmPrinter::emitFunctionBody() {
         // location, and a nearby DBG_VALUE created. We can safely ignore
         // the instruction reference.
         break;
+      case TargetOpcode::DBG_PHI:
+        // This instruction is only used to label a program point, it's purely
+        // meta information.
+        break;
       case TargetOpcode::DBG_LABEL:
         if (isVerbose()) {
           if (!emitDebugLabelComment(&MI, *this))

diff  --git a/llvm/lib/CodeGen/LiveDebugVariables.cpp b/llvm/lib/CodeGen/LiveDebugVariables.cpp
index 2761ee62f7ae3..e04e248a1978f 100644
--- a/llvm/lib/CodeGen/LiveDebugVariables.cpp
+++ b/llvm/lib/CodeGen/LiveDebugVariables.cpp
@@ -538,6 +538,21 @@ class LDVImpl {
   using StashedInstrRef =
       std::tuple<unsigned, unsigned, const DILocalVariable *,
                  const DIExpression *, DebugLoc>;
+
+  /// Position and VReg of a PHI instruction during register allocation.
+  struct PHIValPos {
+    SlotIndex SI;    /// Slot where this PHI occurs.
+    Register Reg;    /// VReg this PHI occurs in.
+    unsigned SubReg; /// Qualifiying subregister for Reg.
+  };
+
+  /// Map from debug instruction number to PHI position during allocation.
+  std::map<unsigned, PHIValPos> PHIValToPos;
+  /// Index of, for each VReg, which debug instruction numbers and corresponding
+  /// PHIs are sensitive to splitting. Each VReg may have multiple PHI defs,
+  /// at 
diff erent positions.
+  DenseMap<Register, std::vector<unsigned>> RegToPHIIdx;
+
   std::map<SlotIndex, std::vector<StashedInstrRef>> StashedInstrReferences;
 
   /// Whether emitDebugValues is called.
@@ -614,6 +629,8 @@ class LDVImpl {
   /// Release all memory.
   void clear() {
     MF = nullptr;
+    PHIValToPos.clear();
+    RegToPHIIdx.clear();
     StashedInstrReferences.clear();
     userValues.clear();
     userLabels.clear();
@@ -629,6 +646,10 @@ class LDVImpl {
   /// Map virtual register to an equivalence class.
   void mapVirtReg(Register VirtReg, UserValue *EC);
 
+  /// Replace any PHI referring to OldReg with its corresponding NewReg, if
+  /// present.
+  void splitPHIRegister(Register OldReg, ArrayRef<Register> NewRegs);
+
   /// Replace all references to OldReg with NewRegs.
   void splitRegister(Register OldReg, ArrayRef<Register> NewRegs);
 
@@ -1224,6 +1245,21 @@ bool LDVImpl::runOnMachineFunction(MachineFunction &mf) {
   bool Changed = collectDebugValues(mf);
   computeIntervals();
   LLVM_DEBUG(print(dbgs()));
+
+  // Collect the set of VReg / SlotIndexs where PHIs occur; index the sensitive
+  // VRegs too, for when we're notified of a range split.
+  SlotIndexes *Slots = LIS->getSlotIndexes();
+  for (const auto &PHIIt : MF->DebugPHIPositions) {
+    const MachineFunction::DebugPHIRegallocPos &Position = PHIIt.second;
+    MachineBasicBlock *MBB = Position.MBB;
+    Register Reg = Position.Reg;
+    unsigned SubReg = Position.SubReg;
+    SlotIndex SI = Slots->getMBBStartIdx(MBB);
+    PHIValPos VP = {SI, Reg, SubReg};
+    PHIValToPos.insert(std::make_pair(PHIIt.first, VP));
+    RegToPHIIdx[Reg].push_back(PHIIt.first);
+  }
+
   ModifiedMF = Changed;
   return Changed;
 }
@@ -1382,7 +1418,50 @@ UserValue::splitRegister(Register OldReg, ArrayRef<Register> NewRegs,
   return DidChange;
 }
 
+void LDVImpl::splitPHIRegister(Register OldReg, ArrayRef<Register> NewRegs) {
+  auto RegIt = RegToPHIIdx.find(OldReg);
+  if (RegIt == RegToPHIIdx.end())
+    return;
+
+  std::vector<std::pair<Register, unsigned>> NewRegIdxes;
+  // Iterate over all the debug instruction numbers affected by this split.
+  for (unsigned InstrID : RegIt->second) {
+    auto PHIIt = PHIValToPos.find(InstrID);
+    assert(PHIIt != PHIValToPos.end());
+    const SlotIndex &Slot = PHIIt->second.SI;
+    assert(OldReg == PHIIt->second.Reg);
+
+    // Find the new register that covers this position.
+    for (auto NewReg : NewRegs) {
+      const LiveInterval &LI = LIS->getInterval(NewReg);
+      auto LII = LI.find(Slot);
+      if (LII != LI.end() && LII->start <= Slot) {
+        // This new register covers this PHI position, record this for indexing.
+        NewRegIdxes.push_back(std::make_pair(NewReg, InstrID));
+        // Record that this value lives in a 
diff erent VReg now.
+        PHIIt->second.Reg = NewReg;
+        break;
+      }
+    }
+
+    // If we do not find a new register covering this PHI, then register
+    // allocation has dropped its location, for example because it's not live.
+    // The old VReg will not be mapped to a physreg, and the instruction
+    // number will have been optimized out.
+  }
+
+  // Re-create register index using the new register numbers.
+  RegToPHIIdx.erase(RegIt);
+  for (auto &RegAndInstr : NewRegIdxes)
+    RegToPHIIdx[RegAndInstr.first].push_back(RegAndInstr.second);
+}
+
 void LDVImpl::splitRegister(Register OldReg, ArrayRef<Register> NewRegs) {
+  // Consider whether this split range affects any PHI locations.
+  splitPHIRegister(OldReg, NewRegs);
+
+  // Check whether any intervals mapped by a DBG_VALUE were split and need
+  // updating.
   bool DidChange = false;
   for (UserValue *UV = lookupVirtReg(OldReg); UV; UV = UV->getNext())
     DidChange |= UV->splitRegister(OldReg, NewRegs, *LIS);
@@ -1722,11 +1801,53 @@ void LDVImpl::emitDebugValues(VirtRegMap *VRM) {
     userLabel->emitDebugLabel(*LIS, *TII, BBSkipInstsMap);
   }
 
+  LLVM_DEBUG(dbgs() << "********** EMITTING DEBUG PHIS **********\n");
+
+  auto Slots = LIS->getSlotIndexes();
+  for (auto &It : PHIValToPos) {
+    // For each ex-PHI, identify its physreg location or stack slot, and emit
+    // a DBG_PHI for it.
+    unsigned InstNum = It.first;
+    auto Slot = It.second.SI;
+    Register Reg = It.second.Reg;
+    unsigned SubReg = It.second.SubReg;
+
+    MachineBasicBlock *OrigMBB = Slots->getMBBFromIndex(Slot);
+    if (VRM->isAssignedReg(Reg) &&
+        Register::isPhysicalRegister(VRM->getPhys(Reg))) {
+      unsigned PhysReg = VRM->getPhys(Reg);
+      if (SubReg != 0)
+        PhysReg = TRI->getSubReg(PhysReg, SubReg);
+
+      auto Builder = BuildMI(*OrigMBB, OrigMBB->begin(), DebugLoc(),
+                             TII->get(TargetOpcode::DBG_PHI));
+      Builder.addReg(PhysReg);
+      Builder.addImm(InstNum);
+    } else if (VRM->getStackSlot(Reg) != VirtRegMap::NO_STACK_SLOT) {
+      const MachineRegisterInfo &MRI = MF->getRegInfo();
+      const TargetRegisterClass *TRC = MRI.getRegClass(Reg);
+      unsigned SpillSize, SpillOffset;
+
+      // Test whether this location is legal with the given subreg.
+      bool Success =
+          TII->getStackSlotRange(TRC, SubReg, SpillSize, SpillOffset, *MF);
+
+      if (Success) {
+        auto Builder = BuildMI(*OrigMBB, OrigMBB->begin(), DebugLoc(),
+                               TII->get(TargetOpcode::DBG_PHI));
+        Builder.addFrameIndex(VRM->getStackSlot(Reg));
+        Builder.addImm(InstNum);
+      }
+    }
+    // If there was no mapping for a value ID, it's optimized out. Create no
+    // DBG_PHI, and any variables using this value will become optimized out.
+  }
+  MF->DebugPHIPositions.clear();
+
   LLVM_DEBUG(dbgs() << "********** EMITTING INSTR REFERENCES **********\n");
 
   // Re-insert any DBG_INSTR_REFs back in the position they were. Ordering
   // is preserved by vector.
-  auto Slots = LIS->getSlotIndexes();
   const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_INSTR_REF);
   for (auto &P : StashedInstrReferences) {
     const SlotIndex &Idx = P.first;

diff  --git a/llvm/lib/CodeGen/PHIElimination.cpp b/llvm/lib/CodeGen/PHIElimination.cpp
index bd586efd18136..54805584dbc1c 100644
--- a/llvm/lib/CodeGen/PHIElimination.cpp
+++ b/llvm/lib/CodeGen/PHIElimination.cpp
@@ -316,6 +316,16 @@ void PHIElimination::LowerPHINode(MachineBasicBlock &MBB,
                                   IncomingReg, DestReg);
   }
 
+  if (MPhi->peekDebugInstrNum()) {
+    // If referred to by debug-info, store where this PHI was.
+    MachineFunction *MF = MBB.getParent();
+    unsigned ID = MPhi->peekDebugInstrNum();
+    auto P = MachineFunction::DebugPHIRegallocPos(&MBB, IncomingReg, 0);
+    auto Res = MF->DebugPHIPositions.insert({ID, P});
+    assert(Res.second);
+    (void)Res;
+  }
+
   // Update live variable information if there is any.
   if (LV) {
     if (IncomingReg) {

diff  --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index c12417a2cbf2c..ca57248d855b7 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -1269,6 +1269,9 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
         }
         MI.getDebugExpressionOp().setMetadata(DIExpr);
         continue;
+      } else if (MI.isDebugPHI()) {
+        // Allow stack ref to continue onwards.
+        continue;
       }
 
       // TODO: This code should be commoned with the code for

diff  --git a/llvm/test/DebugInfo/MIR/InstrRef/phi-regallocd-to-stack.mir b/llvm/test/DebugInfo/MIR/InstrRef/phi-regallocd-to-stack.mir
new file mode 100644
index 0000000000000..09593b1c9a91c
--- /dev/null
+++ b/llvm/test/DebugInfo/MIR/InstrRef/phi-regallocd-to-stack.mir
@@ -0,0 +1,153 @@
+# RUN: llc %s -o - -mtriple=x86_64-unknown-unknown \
+# RUN:    -experimental-debug-variable-locations \
+# RUN:    -run-pass=phi-node-elimination,livedebugvars,greedy,virtregrewriter \
+# RUN:    | FileCheck %s
+#
+# Like phi-through-regalloc.mir, pass a PHI node into register allocation, and
+# test that it correctly comes out, in a stack slot. Fifteen spurious PHIs have
+# been added to force the register allocator to spill one.
+
+--- |
+  ; ModuleID = 'promoted.ll'
+  source_filename = "test.c"
+  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"
+
+  define dso_local i32 @foo(i32 %bar, i32 %baz) !dbg !7 {
+  entry:
+    ret i32 0, !dbg !19
+  }
+
+  declare dso_local i32 @ext(i32)
+
+  ; Function Attrs: nounwind readnone speculatable willreturn
+  declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!3, !4, !5}
+  !llvm.ident = !{!6}
+
+  !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+  !1 = !DIFile(filename: "test.c", directory: ".")
+  !2 = !{}
+  !3 = !{i32 7, !"Dwarf Version", i32 4}
+  !4 = !{i32 2, !"Debug Info Version", i32 3}
+  !5 = !{i32 1, !"wchar_size", i32 4}
+  !6 = !{!"."}
+  !7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+  !8 = !DISubroutineType(types: !9)
+  !9 = !{!10, !10, !10}
+  !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+  !11 = !DILocalVariable(name: "bar", arg: 1, scope: !7, file: !1, line: 2, type: !10)
+  !12 = !DILocation(line: 0, scope: !7)
+  !13 = !DILocalVariable(name: "baz", arg: 2, scope: !7, file: !1, line: 2, type: !10)
+  !14 = !DILocalVariable(name: "either", scope: !7, file: !1, line: 3, type: !10)
+  !15 = !DILocation(line: 4, column: 7, scope: !16)
+  !16 = distinct !DILexicalBlock(scope: !7, file: !1, line: 4, column: 7)
+  !17 = !DILocation(line: 4, column: 7, scope: !7)
+  !18 = !DILocation(line: 0, scope: !16)
+  !19 = !DILocation(line: 9, column: 3, scope: !7)
+
+...
+---
+name:            foo
+alignment:       16
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gr32 }
+  - { id: 1, class: gr32 }
+  - { id: 2, class: gr32 }
+  - { id: 3, class: gr32 }
+  - { id: 4, class: gr32 }
+liveins:
+  - { reg: '$edi', virtual-reg: '%1' }
+  - { reg: '$esi', virtual-reg: '%2' }
+frameInfo:
+  maxAlignment:    1
+  hasCalls:        true
+machineFunctionInfo: {}
+body:             |
+  ; CHECK-LABEL: bb.0:
+  ; CHECK:       renamable $ebp = COPY $edi
+  ; CHECK:       MOV32mr %stack.1, 1, $noreg, 0, $noreg, killed renamable $ebp
+  bb.0:
+    successors: %bb.2(0x50000000), %bb.1(0x30000000)
+    liveins: $edi, $esi
+
+    DBG_VALUE $edi, $noreg, !11, !DIExpression(), debug-location !12
+    DBG_VALUE $esi, $noreg, !13, !DIExpression(), debug-location !12
+    %2:gr32 = COPY killed $esi
+    DBG_VALUE %2, $noreg, !13, !DIExpression(), debug-location !12
+    %1:gr32 = COPY killed $edi
+    DBG_VALUE %1, $noreg, !11, !DIExpression(), debug-location !12
+    DBG_VALUE 0, $noreg, !14, !DIExpression(), debug-location !12
+    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !15
+    %3:gr32 = MOV32r0 implicit-def dead $eflags
+    $edi = COPY killed %3, debug-location !15
+    CALL64pcrel32 @ext, csr_64, implicit $rsp, implicit $ssp, implicit killed $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !15
+    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !15
+    %4:gr32 = COPY killed $eax, debug-location !15
+    %10:gr32 = MOV32ri 0
+    %11:gr32 = MOV32ri 1
+    %12:gr32 = MOV32ri 2
+    %13:gr32 = MOV32ri 3
+    %14:gr32 = MOV32ri 4
+    %15:gr32 = MOV32ri 5
+    %16:gr32 = MOV32ri 6
+    %17:gr32 = MOV32ri 7
+    %18:gr32 = MOV32ri 8
+    %19:gr32 = MOV32ri 9
+    %20:gr32 = MOV32ri 10
+    %21:gr32 = MOV32ri 11
+    %22:gr32 = MOV32ri 12
+    %23:gr32 = MOV32ri 13
+    %24:gr32 = MOV32ri 14
+    TEST32rr killed %4, %4, implicit-def $eflags, debug-location !15
+    JCC_1 %bb.2, 5, implicit killed $eflags, debug-location !17
+    JMP_1 %bb.1, debug-location !17
+
+  bb.1:
+    DBG_VALUE %2, $noreg, !14, !DIExpression(), debug-location !12
+    %30:gr32 = MOV32ri 0
+    %31:gr32 = MOV32ri 1
+    %32:gr32 = MOV32ri 2
+    %33:gr32 = MOV32ri 3
+    %34:gr32 = MOV32ri 4
+    %35:gr32 = MOV32ri 5
+    %36:gr32 = MOV32ri 6
+    %37:gr32 = MOV32ri 7
+    %38:gr32 = MOV32ri 8
+    %39:gr32 = MOV32ri 9
+    %40:gr32 = MOV32ri 10
+    %41:gr32 = MOV32ri 11
+    %42:gr32 = MOV32ri 12
+    %43:gr32 = MOV32ri 13
+    %44:gr32 = MOV32ri 14
+
+    ; CHECK-LABEL: bb.2:
+  bb.2:
+    %0:gr32 = PHI %1, %bb.0, %2, %bb.1, debug-instr-number 1, debug-location !18
+    %50:gr32 = PHI %10, %bb.0, %30, %bb.1, debug-location !18
+    %51:gr32 = PHI %11, %bb.0, %31, %bb.1, debug-location !18
+    %52:gr32 = PHI %12, %bb.0, %32, %bb.1, debug-location !18
+    %53:gr32 = PHI %13, %bb.0, %33, %bb.1, debug-location !18
+    %54:gr32 = PHI %14, %bb.0, %34, %bb.1, debug-location !18
+    %55:gr32 = PHI %15, %bb.0, %35, %bb.1, debug-location !18
+    %56:gr32 = PHI %16, %bb.0, %36, %bb.1, debug-location !18
+    %57:gr32 = PHI %17, %bb.0, %37, %bb.1, debug-location !18
+    %58:gr32 = PHI %18, %bb.0, %38, %bb.1, debug-location !18
+    %59:gr32 = PHI %19, %bb.0, %39, %bb.1, debug-location !18
+    %60:gr32 = PHI %20, %bb.0, %40, %bb.1, debug-location !18
+    %61:gr32 = PHI %21, %bb.0, %41, %bb.1, debug-location !18
+    %62:gr32 = PHI %22, %bb.0, %42, %bb.1, debug-location !18
+    %63:gr32 = PHI %23, %bb.0, %43, %bb.1, debug-location !18
+    %64:gr32 = PHI %24, %bb.0, %44, %bb.1, debug-location !18
+
+    DBG_INSTR_REF 1, 0, !14, !DIExpression(), debug-location !12
+    ; CHECK:      DBG_PHI %stack.1, 1
+    ; CHECK:      renamable $eax = MOV32rm %stack.1,
+    ; CHECK:      DBG_INSTR_REF 1, 0
+    $eax = COPY killed %0, debug-location !19
+    RET 0, killed $eax, debug-location !19
+
+...

diff  --git a/llvm/test/DebugInfo/MIR/InstrRef/phi-through-regalloc.mir b/llvm/test/DebugInfo/MIR/InstrRef/phi-through-regalloc.mir
new file mode 100644
index 0000000000000..fbb5db605a7c1
--- /dev/null
+++ b/llvm/test/DebugInfo/MIR/InstrRef/phi-through-regalloc.mir
@@ -0,0 +1,134 @@
+# RUN: llc %s -o - -mtriple=x86_64-unknown-unknown \
+# RUN:    -experimental-debug-variable-locations \
+# RUN:    -run-pass=phi-node-elimination,livedebugvars,greedy,virtregrewriter \
+# RUN:    | FileCheck %s
+#
+# This test checks that for a very simple PHI, we produce a corresponding
+# DBG_PHI instruction, that a DBG_INSTR_REF refers to. Tests the path through
+# phi-node-elimination, live debug variables, and then placement after register
+# allocation.
+#
+# Original code, compiled with only -mem2reg, then fed to llc -stop-before...
+#
+#    int ext(int);
+#    int foo(int bar, int baz) {
+#      int either = 0;
+#      if (ext(0))
+#        either = bar;
+#      else
+#        either = baz;
+#
+#      return either;
+#    }
+#
+
+--- |
+  ; ModuleID = 'promoted.ll'
+  source_filename = "test.c"
+  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"
+
+  define dso_local i32 @foo(i32 %bar, i32 %baz) !dbg !7 {
+  entry:
+    call void @llvm.dbg.value(metadata i32 %bar, metadata !11, metadata !DIExpression()), !dbg !12
+    call void @llvm.dbg.value(metadata i32 %baz, metadata !13, metadata !DIExpression()), !dbg !12
+    call void @llvm.dbg.value(metadata i32 0, metadata !14, metadata !DIExpression()), !dbg !12
+    %call = call i32 @ext(i32 0), !dbg !15
+    %tobool = icmp ne i32 %call, 0, !dbg !15
+    br i1 %tobool, label %if.end, label %if.else, !dbg !17
+
+  if.else:                                          ; preds = %entry
+    call void @llvm.dbg.value(metadata i32 %baz, metadata !14, metadata !DIExpression()), !dbg !12
+    br label %if.end
+
+  if.end:                                           ; preds = %entry, %if.else
+    %either.0 = phi i32 [ %baz, %if.else ], [ %bar, %entry ], !dbg !18
+    call void @llvm.dbg.value(metadata i32 %either.0, metadata !14, metadata !DIExpression()), !dbg !12
+    ret i32 %either.0, !dbg !19
+  }
+
+  declare dso_local i32 @ext(i32)
+
+  ; Function Attrs: nounwind readnone speculatable willreturn
+  declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!3, !4, !5}
+  !llvm.ident = !{!6}
+
+  !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+  !1 = !DIFile(filename: "test.c", directory: ".")
+  !2 = !{}
+  !3 = !{i32 7, !"Dwarf Version", i32 4}
+  !4 = !{i32 2, !"Debug Info Version", i32 3}
+  !5 = !{i32 1, !"wchar_size", i32 4}
+  !6 = !{!"."}
+  !7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+  !8 = !DISubroutineType(types: !9)
+  !9 = !{!10, !10, !10}
+  !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+  !11 = !DILocalVariable(name: "bar", arg: 1, scope: !7, file: !1, line: 2, type: !10)
+  !12 = !DILocation(line: 0, scope: !7)
+  !13 = !DILocalVariable(name: "baz", arg: 2, scope: !7, file: !1, line: 2, type: !10)
+  !14 = !DILocalVariable(name: "either", scope: !7, file: !1, line: 3, type: !10)
+  !15 = !DILocation(line: 4, column: 7, scope: !16)
+  !16 = distinct !DILexicalBlock(scope: !7, file: !1, line: 4, column: 7)
+  !17 = !DILocation(line: 4, column: 7, scope: !7)
+  !18 = !DILocation(line: 0, scope: !16)
+  !19 = !DILocation(line: 9, column: 3, scope: !7)
+
+...
+---
+name:            foo
+alignment:       16
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: gr32 }
+  - { id: 1, class: gr32 }
+  - { id: 2, class: gr32 }
+  - { id: 3, class: gr32 }
+  - { id: 4, class: gr32 }
+liveins:
+  - { reg: '$edi', virtual-reg: '%1' }
+  - { reg: '$esi', virtual-reg: '%2' }
+frameInfo:
+  maxAlignment:    1
+  hasCalls:        true
+machineFunctionInfo: {}
+body:             |
+  bb.0.entry:
+    successors: %bb.2(0x50000000), %bb.1(0x30000000)
+    liveins: $edi, $esi
+
+    DBG_VALUE $edi, $noreg, !11, !DIExpression(), debug-location !12
+    DBG_VALUE $esi, $noreg, !13, !DIExpression(), debug-location !12
+    %2:gr32 = COPY killed $esi
+    DBG_VALUE %2, $noreg, !13, !DIExpression(), debug-location !12
+    %1:gr32 = COPY killed $edi
+    DBG_VALUE %1, $noreg, !11, !DIExpression(), debug-location !12
+    DBG_VALUE 0, $noreg, !14, !DIExpression(), debug-location !12
+    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !15
+    %3:gr32 = MOV32r0 implicit-def dead $eflags
+    $edi = COPY killed %3, debug-location !15
+    CALL64pcrel32 @ext, csr_64, implicit $rsp, implicit $ssp, implicit killed $edi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !15
+    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp, debug-location !15
+    %4:gr32 = COPY killed $eax, debug-location !15
+    TEST32rr killed %4, %4, implicit-def $eflags, debug-location !15
+    JCC_1 %bb.2, 5, implicit killed $eflags, debug-location !17
+    JMP_1 %bb.1, debug-location !17
+
+  bb.1.if.else:
+    DBG_VALUE %2, $noreg, !14, !DIExpression(), debug-location !12
+
+    ; CHECK-LABEL: bb.2.if.end:
+  bb.2.if.end:
+    %0:gr32 = PHI %1, %bb.0, %2, %bb.1, debug-instr-number 1, debug-location !18
+    DBG_INSTR_REF 1, 0, !14, !DIExpression(), debug-location !12
+    ; CHECK:      DBG_PHI $ebp, 1
+    ; CHECK:      DBG_INSTR_REF 1, 0
+    $eax = COPY killed %0, debug-location !19
+    ; Confirm that %0 is allocated in $ebp,
+    ; CHECK:      $eax = COPY killed renamable $ebp
+    RET 0, killed $eax, debug-location !19
+
+...


        


More information about the llvm-commits mailing list