[llvm] r359426 - [DebugInfo] Terminate more location-list ranges at the end of blocks

Jeremy Morse via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 29 02:13:16 PDT 2019


Author: jmorse
Date: Mon Apr 29 02:13:16 2019
New Revision: 359426

URL: http://llvm.org/viewvc/llvm-project?rev=359426&view=rev
Log:
[DebugInfo] Terminate more location-list ranges at the end of blocks

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

Added:
    llvm/trunk/test/DebugInfo/X86/live-debug-values-constprop.mir
Modified:
    llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp
    llvm/trunk/lib/CodeGen/LiveDebugValues.cpp
    llvm/trunk/test/DebugInfo/COFF/pieces.ll
    llvm/trunk/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir
    llvm/trunk/test/DebugInfo/X86/fission-ranges.ll

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp?rev=359426&r1=359425&r2=359426&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp Mon Apr 29 02:13:16 2019
@@ -352,17 +352,43 @@ void llvm::calculateDbgEntityHistory(con
       }
     }
 
-    // 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());
     }
   }
 }

Modified: llvm/trunk/lib/CodeGen/LiveDebugValues.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveDebugValues.cpp?rev=359426&r1=359425&r2=359426&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/LiveDebugValues.cpp (original)
+++ llvm/trunk/lib/CodeGen/LiveDebugValues.cpp Mon Apr 29 02:13:16 2019
@@ -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
   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;

Modified: llvm/trunk/test/DebugInfo/COFF/pieces.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/pieces.ll?rev=359426&r1=359425&r2=359426&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/pieces.ll (original)
+++ llvm/trunk/test/DebugInfo/COFF/pieces.ll Mon Apr 29 02:13:16 2019
@@ -40,9 +40,10 @@
 ; 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
@@ -59,13 +60,21 @@
 ; 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
 
@@ -104,8 +114,8 @@
 ; 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 {
@@ -136,7 +146,7 @@
 ; 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)
@@ -159,7 +169,7 @@
 ; 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)

Modified: llvm/trunk/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir?rev=359426&r1=359425&r2=359426&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir (original)
+++ llvm/trunk/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir Mon Apr 29 02:13:16 2019
@@ -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"
@@ -103,7 +105,7 @@
   !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)

Modified: llvm/trunk/test/DebugInfo/X86/fission-ranges.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/fission-ranges.ll?rev=359426&r1=359425&r2=359426&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/fission-ranges.ll (original)
+++ llvm/trunk/test/DebugInfo/X86/fission-ranges.ll Mon Apr 29 02:13:16 2019
@@ -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]*]]
@@ -27,24 +28,31 @@
 ; 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

Added: llvm/trunk/test/DebugInfo/X86/live-debug-values-constprop.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/live-debug-values-constprop.mir?rev=359426&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/live-debug-values-constprop.mir (added)
+++ llvm/trunk/test/DebugInfo/X86/live-debug-values-constprop.mir Mon Apr 29 02:13:16 2019
@@ -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
+
+...




More information about the llvm-commits mailing list