]> granicus.if.org Git - llvm/commitdiff
[DebugInfo] Terminate more location-list ranges at the end of blocks
authorJeremy Morse <jeremy.morse.llvm@gmail.com>
Mon, 29 Apr 2019 09:13:16 +0000 (09:13 +0000)
committerJeremy Morse <jeremy.morse.llvm@gmail.com>
Mon, 29 Apr 2019 09:13:16 +0000 (09:13 +0000)
This patch fixes PR40795, where constant-valued variable locations can
"leak" into blocks placed at higher addresses. The root of this is that
DbgEntityHistoryCalculator terminates all register variable locations at
the end of each block, but not constant-value variable locations.

Fixing this requires constant-valued DBG_VALUE instructions to be
broadcast into all blocks where the variable location remains valid, as
documented in the LiveDebugValues section of SourceLevelDebugging.rst,
and correct termination in DbgEntityHistoryCalculator.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@359426 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp
lib/CodeGen/LiveDebugValues.cpp
test/DebugInfo/COFF/pieces.ll
test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir
test/DebugInfo/X86/fission-ranges.ll
test/DebugInfo/X86/live-debug-values-constprop.mir [new file with mode: 0644]

index c006f3cc2efc346e595cca0503169177cf050516..5601678734a7f6ad7e3081f9b51a7c883cc18661 100644 (file)
@@ -352,17 +352,43 @@ void llvm::calculateDbgEntityHistory(const MachineFunction *MF,
       }
     }
 
-    // Make sure locations for register-described variables are valid only
-    // until the end of the basic block (unless it's the last basic block, in
-    // which case let their liveness run off to the end of the function).
+    // Make sure locations for all variables are valid only until the end of
+    // the basic block (unless it's the last basic block, in which case let
+    // their liveness run off to the end of the function).
     if (!MBB.empty() && &MBB != &MF->back()) {
-      for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) {
-        auto CurElem = I++; // CurElem can be erased below.
-        if (TRI->isVirtualRegister(CurElem->first) ||
-            ChangingRegs.test(CurElem->first))
-          clobberRegisterUses(RegVars, CurElem, DbgValues, LiveEntries,
-                              MBB.back());
+      // Iterate over all variables that have open debug values.
+      SmallSet<unsigned, 8> RegsToClobber;
+      for (auto &Pair : LiveEntries) {
+        // Iterate over history entries for all open fragments.
+        SmallVector<EntryIndex, 8> IdxesToRemove;
+        for (EntryIndex Idx : Pair.second) {
+          DbgValueHistoryMap::Entry &Ent = DbgValues.getEntry(Pair.first, Idx);
+          assert(Ent.isDbgValue() && !Ent.isClosed());
+          const MachineInstr *DbgValue = Ent.getInstr();
+
+          // If this is a register or indirect DBG_VALUE, apply some futher
+          // tests to see if we should clobber it. Perform the clobbering
+          // later though, to keep LiveEntries iteration stable.
+          if (DbgValue->getOperand(0).isReg()) {
+            unsigned RegNo = DbgValue->getOperand(0).getReg();
+            if (TRI->isVirtualRegister(RegNo) || ChangingRegs.test(RegNo))
+              RegsToClobber.insert(RegNo);
+          } else {
+            // This is a constant, terminate it at end of the block. Store
+            // eliminated EntryIdx and delete later, for iteration stability.
+            EntryIndex ClobIdx = DbgValues.startClobber(Pair.first, MBB.back());
+            DbgValues.getEntry(Pair.first, Idx).endEntry(ClobIdx);
+            IdxesToRemove.push_back(Idx);
+          }
+        }
+
+        for (EntryIndex Idx : IdxesToRemove)
+          Pair.second.erase(Idx);
       }
+
+      // Implement clobbering of registers at the end of BB.
+      for (unsigned Reg : RegsToClobber)
+        clobberRegisterUses(RegVars, Reg, DbgValues, LiveEntries, MBB.back());
     }
   }
 }
index 449f10c7ef721d30a1ff562d9872370a7484138d..e36694d2c5b3ade3d945a38c85b93ed9f0ec1565 100644 (file)
@@ -143,7 +143,8 @@ private:
     enum VarLocKind {
       InvalidKind = 0,
       RegisterKind,
-      SpillLocKind
+      SpillLocKind,
+      ImmediateKind
     } Kind = InvalidKind;
 
     /// The value location. Stored separately to avoid repeatedly
@@ -152,6 +153,9 @@ private:
       uint64_t RegNo;
       SpillLoc SpillLocation;
       uint64_t Hash;
+      int64_t Immediate;
+      const ConstantFP *FPImm;
+      const ConstantInt *CImm;
     } Loc;
 
     VarLoc(const MachineInstr &MI, LexicalScopes &LS)
@@ -164,6 +168,15 @@ private:
       if (int RegNo = isDbgValueDescribedByReg(MI)) {
         Kind = RegisterKind;
         Loc.RegNo = RegNo;
+      } else if (MI.getOperand(0).isImm()) {
+        Kind = ImmediateKind;
+        Loc.Immediate = MI.getOperand(0).getImm();
+      } else if (MI.getOperand(0).isFPImm()) {
+        Kind = ImmediateKind;
+        Loc.FPImm = MI.getOperand(0).getFPImm();
+      } else if (MI.getOperand(0).isCImm()) {
+        Kind = ImmediateKind;
+        Loc.CImm = MI.getOperand(0).getCImm();
       }
     }
 
@@ -178,6 +191,9 @@ private:
       Loc.SpillLocation = {SpillBase, SpillOffset};
     }
 
+    // Is the Loc field a constant or constant object?
+    bool isConstant() const { return Kind == ImmediateKind; }
+
     /// If this variable is described by a register, return it,
     /// otherwise return 0.
     unsigned isDescribedByReg() const {
@@ -195,7 +211,8 @@ private:
 #endif
 
     bool operator==(const VarLoc &Other) const {
-      return Var == Other.Var && Loc.Hash == Other.Loc.Hash;
+      return Kind == Other.Kind && Var == Other.Var &&
+             Loc.Hash == Other.Loc.Hash;
     }
 
     /// This operator guarantees that VarLocs are sorted by Variable first.
@@ -408,11 +425,23 @@ void LiveDebugValues::transferDebugValue(const MachineInstr &MI,
   OpenRanges.erase(V);
 
   // Add the VarLoc to OpenRanges from this DBG_VALUE.
-  // TODO: Currently handles DBG_VALUE which has only reg as location.
-  if (isDbgValueDescribedByReg(MI)) {
+  unsigned ID;
+  if (isDbgValueDescribedByReg(MI) || MI.getOperand(0).isImm() ||
+      MI.getOperand(0).isFPImm() || MI.getOperand(0).isCImm()) {
+    // Use normal VarLoc constructor for registers and immediates.
     VarLoc VL(MI, LS);
-    unsigned ID = VarLocIDs.insert(VL);
+    ID = VarLocIDs.insert(VL);
+    OpenRanges.insert(ID, VL.Var);
+  } else if (MI.hasOneMemOperand()) {
+    // It's a stack spill -- fetch spill base and offset.
+    VarLoc::SpillLoc SpillLocation = extractSpillBaseRegAndOffset(MI);
+    VarLoc VL(MI, SpillLocation.SpillBase, SpillLocation.SpillOffset, LS);
+    ID = VarLocIDs.insert(VL);
     OpenRanges.insert(ID, VL.Var);
+  } else {
+    // This must be an undefined location. We should leave OpenRanges closed.
+    assert(MI.getOperand(0).isReg() && MI.getOperand(0).getReg() == 0 &&
+           "Unexpected non-undef DBG_VALUE encountered");
   }
 }
 
@@ -806,12 +835,19 @@ bool LiveDebugValues::join(
     // a new DBG_VALUE. process() will end this range however appropriate.
     const VarLoc &DiffIt = VarLocIDs[ID];
     const MachineInstr *DMI = &DiffIt.MI;
-    MachineInstr *MI =
-        BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(),
-                DMI->isIndirectDebugValue(), DMI->getOperand(0).getReg(),
-                DMI->getDebugVariable(), DMI->getDebugExpression());
-    if (DMI->isIndirectDebugValue())
-      MI->getOperand(1).setImm(DMI->getOperand(1).getImm());
+    MachineInstr *MI = nullptr;
+    if (DiffIt.isConstant()) {
+      MachineOperand MO(DMI->getOperand(0));
+      MI = BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(),
+                   false, MO, DMI->getDebugVariable(),
+                   DMI->getDebugExpression());
+    } else {
+      MI = BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(),
+                   DMI->isIndirectDebugValue(), DMI->getOperand(0).getReg(),
+                   DMI->getDebugVariable(), DMI->getDebugExpression());
+      if (DMI->isIndirectDebugValue())
+        MI->getOperand(1).setImm(DMI->getOperand(1).getImm());
+    }
     LLVM_DEBUG(dbgs() << "Inserted: "; MI->dump(););
     ILS.set(ID);
     ++NumInserted;
index b218f076fde20e781ea1251f0a8f7ea8bfa46190..eebef3895d40bb9f0a23bc7c37c0db0f5dbf3af3 100644 (file)
 ; ASM: # %bb.2:                                 # %for.body.preheader
 ; ASM:         xorl    %edi, %edi
 ; ASM:         xorl    %esi, %esi
+; ASM: [[oy_ox_start:\.Ltmp[0-9]+]]:
 ; ASM:         .p2align        4, 0x90
 ; ASM: .LBB0_3:                                # %for.body
-; ASM: [[oy_ox_start:\.Ltmp[0-9]+]]:
+; ASM:        #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 0 32] 0
 ; ASM:        #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 0 32] $edi
 ; ASM:        #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 32 32] $esi
 ; ASM:        .cv_loc 0 1 13 11               # t.c:13:11
 ; ASM:         #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 32 32] $esi
 ; ASM:         cmpl    n(%rip), %eax
 ; ASM:         jl      .LBB0_3
+; ASM: [[loopskip_start:\.Ltmp[0-9]+]]:
+; ASM:         #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 0 32] 0
+; ASM:         xorl    %esi, %esi
+; ASM:         xorl    %edi, %edi
 ; ASM: [[oy_end:\.Ltmp[0-9]+]]:
 ; ASM:         addl    %edi, %esi
 ; ASM:         movl    %esi, %eax
 
+; XXX FIXME: the debug value line after loopskip_start should be repeated
+; because both fields of 'o' are zero flowing into this block. However, it
+; appears livedebugvalues doesn't account for fragments.
 
 ; ASM-LABEL: pad_right: # @pad_right
 ; ASM:         movq    %rcx, %rax
+; ASM: [[pad_right_tmp:\.Ltmp[0-9]+]]:
 ; ASM:         #DEBUG_VALUE: pad_right:o <- [DW_OP_LLVM_fragment 32 32] $eax
 ; ASM:         retq
 
@@ -73,6 +82,7 @@
 ; ASM-LABEL: pad_left: # @pad_left
 ; ASM:         .cv_loc 2 1 24 3                # t.c:24:3
 ; ASM:         movq    %rcx, %rax
+; ASM: [[pad_left_tmp:\.Ltmp[0-9]+]]:
 ; ASM:         #DEBUG_VALUE: pad_left:o <- [DW_OP_LLVM_fragment 0 32] $eax
 ; ASM:         retq
 
 ; ASM:        .asciz  "o"
 ; ASM:        .cv_def_range    [[oy_ox_start]] [[ox_start]], "C\021\030\000\000\000\000\000\000\000"
 ; ASM:        .cv_def_range    [[oy_ox_start]] [[oy_start]], "C\021\027\000\000\000\004\000\000\000"
-; ASM:        .cv_def_range    [[ox_start]] [[oy_end]], "C\021\030\000\000\000\000\000\000\000"
-; ASM:        .cv_def_range    [[oy_start]] [[oy_end]], "C\021\027\000\000\000\004\000\000\000"
+; ASM:        .cv_def_range    [[ox_start]] [[loopskip_start]], "C\021\030\000\000\000\000\000\000\000"
+; ASM:        .cv_def_range    [[oy_start]] [[loopskip_start]], "C\021\027\000\000\000\004\000\000\000"
 
 
 ; OBJ-LABEL: GlobalProcIdSym {
 ; ASM:        .asciz  "pad_right"             # Function name
 ; ASM:        .short  4414                    # Record kind: S_LOCAL
 ; ASM:        .asciz  "o"
-; ASM:        .cv_def_range    .Ltmp8 .Ltmp8, "C\021\021\000\000\000\004\000\000\000"
+; ASM:        .cv_def_range    [[pad_right_tmp]] [[pad_right_tmp]], "C\021\021\000\000\000\004\000\000\000"
 
 ; OBJ-LABEL: GlobalProcIdSym {
 ; OBJ:         Kind: S_GPROC32_ID (0x1147)
 ; ASM:        .asciz  "pad_left"              # Function name
 ; ASM:        .short  4414                    # Record kind: S_LOCAL
 ; ASM:        .asciz  "o"
-; ASM:        .cv_def_range    .Ltmp10 .Ltmp10, "C\021\021\000\000\000\000\000\000\000"
+; ASM:        .cv_def_range    [[pad_left_tmp]] [[pad_left_tmp]], "C\021\021\000\000\000\000\000\000\000"
 
 ; OBJ-LABEL: GlobalProcIdSym {
 ; OBJ:         Kind: S_GPROC32_ID (0x1147)
index 06db415068478f2eb52c5c3a22308fbd9baaf31f..d2a8d4cd322e72e5cb3e2603367f202b4ff1e221 100644 (file)
@@ -5,8 +5,10 @@
 #  encountering an IMPLICIT_DEF in its own lexical scope.
 
 # CHECK: .debug_info contents:
-# CHECK: DW_TAG_formal_parameter
-# CHECK:   DW_AT_const_value [DW_FORM_udata]   (0)
+# CHECK:       DW_TAG_formal_parameter
+# CHECK:       DW_AT_location [DW_FORM_sec_offset]
+# CHECK-NEXT:                 DW_OP_lit0, DW_OP_stack_value
+# CHECK-NEXT:  DW_AT_abstract_origin {{.*}} "name"
 --- |
   ; ModuleID = 't.ll'
   source_filename = "t.ll"
   !15 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "v", file: !5, line: 97, size: 64, elements: !2, identifier: "_ZTS1v")
   !16 = !DISubroutineType(types: !2)
   !17 = !DISubprogram(name: "bv", linkageName: "_ZN1v2bvEv", scope: !15, file: !5, line: 98, type: !16, isLocal: false, isDefinition: false, scopeLine: 98, flags: DIFlagPrototyped, isOptimized: true)
-  !18 = !DILocalVariable(arg: 2, scope: !19, file: !5, line: 22, type: !21)
+  !18 = !DILocalVariable(name: "name", arg: 2, scope: !19, file: !5, line: 22, type: !21)
   !19 = distinct !DISubprogram(name: "m", linkageName: "_ZN1jILi6EN1a1fEE1mEj", scope: !11, file: !5, line: 22, type: !16, isLocal: false, isDefinition: true, scopeLine: 22, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !20, retainedNodes: !2)
   !20 = !DISubprogram(name: "m", linkageName: "_ZN1jILi6EN1a1fEE1mEj", scope: !11, file: !5, line: 22, type: !16, isLocal: false, isDefinition: false, scopeLine: 22, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
   !21 = !DIDerivedType(tag: DW_TAG_typedef, name: "h", file: !5, line: 10, baseType: !22)
index 1a1dc22870adfc3fe6639dd18183e45497da8222..b9a1675d608ede3260c5086bdf4b9fe4ccce9385 100644 (file)
@@ -15,6 +15,7 @@
 ; CHECK-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset]                   (0x00000000)
 
 ; CHECK: .debug_info.dwo contents:
+; CHECK: DW_AT_location [DW_FORM_sec_offset]   ([[P:0x[0-9a-z]*]]
 ; CHECK: DW_AT_location [DW_FORM_sec_offset]   ([[A:0x[0-9a-z]*]]
 ; CHECK: DW_AT_location [DW_FORM_sec_offset]   ([[E:0x[0-9a-z]*]]
 ; CHECK: DW_AT_location [DW_FORM_sec_offset]   ([[B:0x[0-9a-z]*]]
 ; Don't assume these locations are entirely correct - feel free to update them
 ; if they've changed due to a bugfix, change in register allocation, etc.
 
+; CHECK:      [[P]]:
+; CHECK-NEXT:   Addr idx 1 (w/ length 204): DW_OP_consts +1, DW_OP_stack_value
 ; CHECK:      [[A]]:
 ; CHECK-NEXT:   Addr idx 2 (w/ length 169): DW_OP_consts +0, DW_OP_stack_value
-; CHECK-NEXT:   Addr idx 3 (w/ length 25): DW_OP_reg0 RAX
+; CHECK-NEXT:   Addr idx 3 (w/ length 15): DW_OP_reg0 RAX
+; CHECK-NEXT:   Addr idx 4 (w/ length 6): DW_OP_breg7 RSP-8
+; CHECK-NEXT:   Addr idx 5 (w/ length 4): DW_OP_reg0 RAX
 ; CHECK:      [[E]]:
-; CHECK-NEXT:   Addr idx 4 (w/ length 19): DW_OP_reg0 RAX
+; CHECK-NEXT:   Addr idx 6 (w/ length 9): DW_OP_reg0 RAX
+; CHECK-NEXT:   Addr idx 7 (w/ length 98): DW_OP_breg7 RSP-44
 ; CHECK:      [[B]]:
-; CHECK-NEXT:   Addr idx 5 (w/ length 17): DW_OP_reg0 RAX
+; CHECK-NEXT:   Addr idx 8 (w/ length 15): DW_OP_reg0 RAX
+; CHECK-NEXT:   Addr idx 9 (w/ length 66): DW_OP_breg7 RSP-32
 ; CHECK:      [[D]]:
-; CHECK-NEXT:   Addr idx 6 (w/ length 17): DW_OP_reg0 RAX
+; CHECK-NEXT:   Addr idx 10 (w/ length 15): DW_OP_reg0 RAX
+; CHECK-NEXT:   Addr idx 11 (w/ length 42): DW_OP_breg7 RSP-20
 
 ; Make sure we don't produce any relocations in any .dwo section (though in particular, debug_info.dwo)
 ; HDR-NOT: .rela.{{.*}}.dwo
 
 ; Make sure we have enough stuff in the debug_addr to cover the address indexes
-; (6 is the last index in debug_loc.dwo, making 7 entries of 8 bytes each, 7 * 8
-; == 56 base 10 == 38 base 16)
+; (11 is the last index in debug_loc.dwo, making 12 entries of 8 bytes each,
+; 12 * 8 == 96 base 10 == 60 base 16)
 
-; HDR: .debug_addr 00000038
+; HDR: .debug_addr 00000060
 ; HDR-NOT: .rela.{{.*}}.dwo
 
 ; Check for the existence of a DWARF v5-style range list table in the .debug_rnglists
diff --git a/test/DebugInfo/X86/live-debug-values-constprop.mir b/test/DebugInfo/X86/live-debug-values-constprop.mir
new file mode 100644 (file)
index 0000000..086f664
--- /dev/null
@@ -0,0 +1,347 @@
+# RUN: llc %s -o - -run-pass=livedebugvalues -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK
+# RUN: llc %s -o - -start-before=livedebugvalues -filetype=obj -mtriple=x86_64-unknown-unknown | llvm-dwarfdump - | FileCheck %s --check-prefix=RANGES
+# Check that livedebugvalues does the right thing when register and constant
+# DBG_VALUEs interact, and that their ranges are correctly terminated by the
+# debug printing backend.
+--- |
+  ; All these IR functions are duds, see the MIR below.
+  source_filename = "<stdin>"
+  target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+  
+  define i32 @foo(i32* %bees, i32* %output) !dbg !4 {
+  entry:
+    br i1 undef, label %bb1, label %bb1
+  bb1:
+    br label %bb3
+  bb2:
+    br label %bb3
+  bb3:
+    ret i32 0
+  }
+
+  define i32 @bar(i32* %bees, i32* %output) !dbg !40 {
+  entry:
+    br i1 undef, label %bb1, label %bb1
+  bb1:
+    br label %bb3
+  bb2:
+    br label %bb3
+  bb3:
+    ret i32 0
+  }
+
+  define i32 @baz(i32* %bees, i32* %output) !dbg !80 {
+  entry:
+    br i1 undef, label %bb1, label %bb1
+  bb1:
+    br label %bb3
+  bb2:
+    br label %bb3
+  bb3:
+    ret i32 0
+  }
+
+  define i32 @qux(i32* %bees, i32* %output) !dbg !120 {
+  entry:
+    br i1 undef, label %bb1, label %bb1
+  bb1:
+    br label %bb3
+  bb2:
+    br label %bb3
+  bb3:
+    ret i32 0
+  }
+
+  ; Function Attrs: nounwind readnone speculatable
+  declare void @llvm.dbg.value(metadata, metadata, metadata)
+  
+  ; Function Attrs: nounwind readnone speculatable
+  declare void @llvm.dbg.declare(metadata, metadata, metadata)
+  
+  ; Function Attrs: nounwind
+  declare void @llvm.stackprotector(i8*, i8**)
+  
+  !llvm.module.flags = !{!0, !100}
+  !llvm.dbg.cu = !{!1}
+  
+  !100 = !{i32 2, !"Dwarf Version", i32 4}
+  !0 = !{i32 2, !"Debug Info Version", i32 3}
+  !1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "beards", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+  !2 = !DIFile(filename: "bees.cpp", directory: ".")
+  !3 = !DILocalVariable(name: "flannel", scope: !4, file: !2, line: 1, type: !16)
+  !4 = distinct !DISubprogram(name: "nope", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true)
+  !5 = !DILocation(line: 0, scope: !4)
+  !6 = !DILocation(line: 1, scope: !4)
+  !7 = !DILocation(line: 2, scope: !4)
+  !8 = !DILocation(line: 4, scope: !4)
+  !9 = !DILocation(line: 5, scope: !4)
+  !10 = !DILocation(line: 6, scope: !4)
+  !11 = !DILocation(line: 7, scope: !4)
+  !12 = !DILocation(line: 8, scope: !4)
+  !13 = !{!3}
+  !14 = !DISubroutineType(types: !15)
+  !15 = !{!16}
+  !16 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+  !40 = distinct !DISubprogram(name: "bar", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true)
+  !41 = !DILocalVariable(name: "towel", scope: !40, file: !2, line: 1, type: !16)
+  !42 = !DILocation(line: 40, scope: !40)
+  !80 = distinct !DISubprogram(name: "baz", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true)
+  !81 = !DILocalVariable(name: "socks", scope: !80, file: !2, line: 1, type: !16)
+  !82 = !DILocation(line: 40, scope: !80)
+  !120 = distinct !DISubprogram(name: "qux", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true)
+  !121 = !DILocalVariable(name: "shoes", scope: !120, file: !2, line: 1, type: !16)
+  !122 = !DILocation(line: 40, scope: !120)
+
+...
+---
+name:            foo
+alignment:       4
+tracksRegLiveness: true
+registers:       []
+liveins:         
+  - { reg: '$rdi', virtual-reg: '' }
+body:             |
+
+  ; Two DBG_VALUEs for eax merge into bb3, check that livedebugvalues propagates
+  ; the location.
+  ; CHECK-LABEL: name: foo
+  ; CHECK-LABEL: bb.1.bb1
+  ; CHECK:       $eax = MOV32rr
+  ; CHECK-NEXT:  DBG_VALUE $eax
+  ; CHECK-NEXT:  JMP_1 %bb.3
+  ; CHECK-LABEL: bb.2.bb2
+  ; CHECK:       $eax = ADD32ri8
+  ; CHECK-NEXT:  DBG_VALUE $eax
+  ; CHECK-NEXT:  JMP_1 %bb.3
+  ; CHECK-LABEL: bb.3.bb3
+  ; CHECK:       DBG_VALUE $eax
+  ; Test for there being a location-list gap between bb1 and bb2, as the
+  ; variable does not have a location over the ADD32ri. The range should also
+  ; extend over the final bb.
+  ; RANGES-LABEL: DW_TAG_subprogram
+  ; RANGES:       DW_AT_high_pc (0x[[NOPEHIGHPC:[0-9a-f]+]])
+  ; RANGES-LABEL: DW_AT_name ("nope")
+  ; RANGES:       DW_AT_location (0x{{[0-9a-f]+}}
+  ; RANGES-NEXT:   [0x{{[0-9a-f]+}}, 0x[[NOPEADDR:[0-9a-f]+]]): DW_OP_reg0 RAX
+  ; RANGES-NEXT:   [
+  ; RANGES-NOT:    0x[[NOPEADDR]]
+  ; RANGES-SAME:   , 0x[[NOPEHIGHPC]]): DW_OP_reg0 RAX
+
+  bb.0.entry:
+    successors: %bb.1, %bb.2
+    liveins: $rdi
+  
+    $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags
+    JCC_1 %bb.1, 2, implicit killed $eflags
+    JMP_1 %bb.2
+  
+  bb.1.bb1 (align 4):
+    successors: %bb.3
+    liveins: $ecx, $rdi
+  
+    $eax = MOV32rr killed $ecx, implicit-def $rax
+    DBG_VALUE $eax, $noreg, !3, !DIExpression(), debug-location !8
+    JMP_1 %bb.3
+  
+  bb.2.bb2:
+    successors: %bb.3
+    liveins: $rax
+  
+    $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax
+    DBG_VALUE $eax, $noreg, !3, !DIExpression(), debug-location !8
+    JMP_1 %bb.3
+
+  bb.3.bb3:
+    liveins: $rax
+    RETQ $eax, debug-location !9
+
+...
+---
+name:            bar
+alignment:       4
+tracksRegLiveness: true
+registers:       []
+liveins:         
+  - { reg: '$rdi', virtual-reg: '' }
+body:             |
+  ; Two DBG_VALUEs, one for eax, the other for zero, merge into bb3. Check that
+  ; livedebugvalues does not propagate anything.
+  ; the location.
+  ; CHECK-LABEL: name: bar
+  ; CHECK-LABEL: bb.1.bb1
+  ; CHECK:       $eax = MOV32rr
+  ; CHECK-NEXT:  DBG_VALUE 0
+  ; CHECK-NEXT:  JMP_1 %bb.3
+  ; CHECK-LABEL: bb.2.bb2
+  ; CHECK:       $eax = ADD32ri8
+  ; CHECK-NEXT:  DBG_VALUE $eax
+  ; CHECK-NEXT:  JMP_1 %bb.3
+  ; CHECK-LABEL: bb.3.bb3
+  ; CHECK-NOT:   DBG_VALUE
+  ; Test for there being a location-list gap between bb1 and bb2, the variable
+  ; should not have a location over the ADD32ri. The range of the last entry
+  ; should not cover the last block.
+  ; RANGES-LABEL: DW_TAG_subprogram
+  ; RANGES:       DW_AT_high_pc (0x[[BARHIGHPC:[0-9a-f]+]])
+  ; RANGES-LABEL: DW_AT_name ("bar")
+  ; RANGES:       DW_AT_location (0x{{[0-9a-f]+}}
+  ; RANGES-NEXT:   [0x{{[0-9a-f]+}}, 0x[[BARADDR:[0-9a-f]+]]): DW_OP_consts +0, DW_OP_stack_value
+  ; RANGES-NEXT:   [
+  ; RANGES-NOT:    0x[[BARADDR]]
+  ; RANGES-NOT:    0x[[BARHIGHPC]]
+  ; RANGES-SAME:   ): DW_OP_reg0 RAX
+
+  bb.0.entry:
+    successors: %bb.1, %bb.2
+    liveins: $rdi
+  
+    $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags
+    JCC_1 %bb.1, 2, implicit killed $eflags
+    JMP_1 %bb.2
+  
+  bb.1.bb1 (align 4):
+    successors: %bb.3
+    liveins: $ecx, $rdi
+  
+    $eax = MOV32rr killed $ecx, implicit-def $rax
+    DBG_VALUE 0, $noreg, !41, !DIExpression(), debug-location !42
+    JMP_1 %bb.3
+  
+  bb.2.bb2:
+    successors: %bb.3
+    liveins: $rax
+  
+    $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax
+    DBG_VALUE $eax, $noreg, !41, !DIExpression(), debug-location !42
+    JMP_1 %bb.3
+
+  bb.3.bb3:
+    liveins: $rax
+    RETQ $eax, debug-location !42
+
+...
+---
+name:            baz
+alignment:       4
+tracksRegLiveness: true
+registers:       []
+liveins:         
+  - { reg: '$rdi', virtual-reg: '' }
+body:             |
+  ; Two DBG_VALUEs, one for zero, the other for eax, merge into bb3. Check that
+  ; livedebugvalues does not propagate anything.
+  ; the location.
+  ; CHECK-LABEL: name: baz
+  ; CHECK-LABEL: bb.1.bb1
+  ; CHECK:       $eax = MOV32rr
+  ; CHECK-NEXT:  DBG_VALUE $eax
+  ; CHECK-NEXT:  JMP_1 %bb.3
+  ; CHECK-LABEL: bb.2.bb2
+  ; CHECK:       $eax = ADD32ri8
+  ; CHECK-NEXT:  DBG_VALUE 0
+  ; CHECK-NEXT:  JMP_1 %bb.3
+  ; CHECK-LABEL: bb.3.bb3
+  ; CHECK-NOT:   DBG_VALUE
+  ; Test for there being a location-list gap between bb1 and bb2, the variable
+  ; should not have a location over the ADD32ri. The range of the last item
+  ; should not cover the last block.
+  ; RANGES-LABEL: DW_TAG_subprogram
+  ; RANGES:       DW_AT_high_pc (0x[[BAZHIGHPC:[0-9a-f]+]])
+  ; RANGES-LABEL: DW_AT_name ("baz")
+  ; RANGES:       DW_AT_location (0x{{[0-9a-f]+}}
+  ; RANGES-NEXT:   [0x{{[0-9a-f]+}}, 0x[[BAZADDR:[0-9a-f]+]]): DW_OP_reg0 RAX
+  ; RANGES-NEXT:   [
+  ; RANGES-NOT:    0x[[BAZADDR]]
+  ; RANGES-NOT:    0x[[BAZHIGHPC]]
+  ; RANGES-SAME:   ): DW_OP_consts +0, DW_OP_stack_value
+
+  bb.0.entry:
+    successors: %bb.1, %bb.2
+    liveins: $rdi
+  
+    $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags
+    JCC_1 %bb.1, 2, implicit killed $eflags
+    JMP_1 %bb.2
+  
+  bb.1.bb1 (align 4):
+    successors: %bb.3
+    liveins: $ecx, $rdi
+  
+    $eax = MOV32rr killed $ecx, implicit-def $rax
+    DBG_VALUE $eax, $noreg, !81, !DIExpression(), debug-location !82
+    JMP_1 %bb.3
+  
+  bb.2.bb2:
+    successors: %bb.3
+    liveins: $rax
+  
+    $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax
+    DBG_VALUE 0, $noreg, !81, !DIExpression(), debug-location !82
+    JMP_1 %bb.3
+
+  bb.3.bb3:
+    liveins: $rax
+    RETQ $eax, debug-location !82
+
+...
+---
+name:            qux
+alignment:       4
+tracksRegLiveness: true
+registers:       []
+liveins:         
+  - { reg: '$rdi', virtual-reg: '' }
+body:             |
+  ; Two DBG_VALUEs for zero merging into bb3, Check that livedebugvalues does
+  ; propagate the zero into the merging block.
+  ; CHECK-LABEL: name: qux
+  ; CHECK-LABEL: bb.1.bb1
+  ; CHECK:       $eax = MOV32rr
+  ; CHECK-NEXT:  DBG_VALUE 0
+  ; CHECK-NEXT:  JMP_1 %bb.3
+  ; CHECK-LABEL: bb.2.bb2
+  ; CHECK:       $eax = ADD32ri8
+  ; CHECK-NEXT:  DBG_VALUE 0
+  ; CHECK-NEXT:  JMP_1 %bb.3
+  ; CHECK-LABEL: bb.3.bb3
+  ; CHECK:       DBG_VALUE 0
+  ; Test for there being a location-list gap between bb1 and bb2, the variable
+  ; should not have a location over the ADD32ri. The final entry should cover
+  ; the final block.
+  ; RANGES-LABEL: DW_TAG_subprogram
+  ; RANGES:       DW_AT_high_pc (0x[[QUXHIGHPC:[0-9a-f]+]])
+  ; RANGES-LABEL: DW_AT_name ("qux")
+  ; RANGES:       DW_AT_location (0x{{[0-9a-f]+}}
+  ; RANGES-NEXT:   [0x{{[0-9a-f]+}}, 0x[[QUXADDR:[0-9a-f]+]]): DW_OP_consts +0, DW_OP_stack_value
+  ; RANGES-NOT:    0x[[QUXADDR]]
+  ; RANGES-NEXT:   [0x{{[0-9a-f]+}}, 0x[[QUXHIGHPC]]): DW_OP_consts +0, DW_OP_stack_value
+
+  bb.0.entry:
+    successors: %bb.1, %bb.2
+    liveins: $rdi
+  
+    $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags
+    JCC_1 %bb.1, 2, implicit killed $eflags
+    JMP_1 %bb.2
+  
+  bb.1.bb1 (align 4):
+    successors: %bb.3
+    liveins: $ecx, $rdi
+  
+    $eax = MOV32rr killed $ecx, implicit-def $rax
+    DBG_VALUE 0, $noreg, !121, !DIExpression(), debug-location !122
+    JMP_1 %bb.3
+  
+  bb.2.bb2:
+    successors: %bb.3
+    liveins: $rax
+  
+    $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax
+    DBG_VALUE 0, $noreg, !121, !DIExpression(), debug-location !122
+    JMP_1 %bb.3
+
+  bb.3.bb3:
+    liveins: $rax
+    RETQ $eax, debug-location !122
+
+...