PR36417-DebugInfo-discard-invalid-DBG_VALUE-instructions.patch 11.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
From 783006ec19853403b8fe799e4c1b9496cb03504a Mon Sep 17 00:00:00 2001
From: Bjorn Pettersson <bjorn.a.pettersson@ericsson.com>
Date: Tue, 6 Mar 2018 08:47:07 +0000
Subject: [PATCH] [DebugInfo] Discard invalid DBG_VALUE instructions in
 LiveDebugVariables

Summary:
This is a workaround for pr36417
https://bugs.llvm.org/show_bug.cgi?id=36417

LiveDebugVariables will now verify that the DBG_VALUE instructions
are sane (prior to register allocation) by asking LIS if a virtual
register used in the DBG_VALUE is live (or dead def) in the slot
index before the DBG_VALUE. If it isn't sane the DBG_VALUE is
discarded.

One pass that was identified as introducing non-sane DBG_VALUE
instructtons, when analysing pr36417, was the DAG->DAG Instruction
Selection. It sometimes inserts DBG_VALUE instructions referring to
a virtual register that is defined later in the same basic block.
So it is a use before def kind of problem. The DBG_VALUE is
typically inserted in the beginning of a basic block when this
happens. The problem can be seen in the test case
test/DebugInfo/X86/dbg-value-inlined-parameter.ll

Reviewers: aprantl, rnk, probinson

Reviewed By: aprantl

Subscribers: vsk, davide, alexcrichton, Ka-Ka, eraman, llvm-commits, JDevlieghere

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@326769 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/LiveDebugVariables.cpp                 |  38 +++++-
 test/DebugInfo/X86/dbg-value-inlined-parameter.ll  |   6 +-
 .../X86/live-debug-vars-discard-invalid.mir        | 141 +++++++++++++++++++++
 3 files changed, 181 insertions(+), 4 deletions(-)
 create mode 100644 test/DebugInfo/X86/live-debug-vars-discard-invalid.mir

diff --git a/lib/CodeGen/LiveDebugVariables.cpp b/lib/CodeGen/LiveDebugVariables.cpp
index 09168b6b9309..f3fcd004defd 100644
--- a/lib/CodeGen/LiveDebugVariables.cpp
+++ b/lib/CodeGen/LiveDebugVariables.cpp
@@ -514,6 +514,39 @@ bool LDVImpl::handleDebugValue(MachineInstr &MI, SlotIndex Idx) {
     return false;
   }
 
+  // Detect invalid DBG_VALUE instructions, with a debug-use of a virtual
+  // register that hasn't been defined yet. If we do not remove those here, then
+  // the re-insertion of the DBG_VALUE instruction after register allocation
+  // will be incorrect.
+  // TODO: If earlier passes are corrected to generate sane debug information
+  // (and if the machine verifier is improved to catch this), then these checks
+  // could be removed or replaced by asserts.
+  bool Discard = false;
+  if (MI.getOperand(0).isReg() &&
+      TargetRegisterInfo::isVirtualRegister(MI.getOperand(0).getReg())) {
+    const unsigned Reg = MI.getOperand(0).getReg();
+    if (!LIS->hasInterval(Reg)) {
+      // The DBG_VALUE is described by a virtual register that does not have a
+      // live interval. Discard the DBG_VALUE.
+      Discard = true;
+      DEBUG(dbgs() << "Discarding debug info (no LIS interval): "
+            << Idx << " " << MI);
+    } else {
+      // The DBG_VALUE is only valid if either Reg is live out from Idx, or Reg
+      // is defined dead at Idx (where Idx is the slot index for the instruction
+      // preceeding the DBG_VALUE).
+      const LiveInterval &LI = LIS->getInterval(Reg);
+      LiveQueryResult LRQ = LI.Query(Idx);
+      if (!LRQ.valueOutOrDead()) {
+        // We have found a DBG_VALUE with the value in a virtual register that
+        // is not live. Discard the DBG_VALUE.
+        Discard = true;
+        DEBUG(dbgs() << "Discarding debug info (reg not live): "
+              << Idx << " " << MI);
+      }
+    }
+  }
+
   // Get or create the UserValue for (variable,offset) here.
   bool IsIndirect = MI.getOperand(1).isImm();
   if (IsIndirect)
@@ -522,7 +555,10 @@ bool LDVImpl::handleDebugValue(MachineInstr &MI, SlotIndex Idx) {
   const DIExpression *Expr = MI.getDebugExpression();
   UserValue *UV =
       getUserValue(Var, Expr, MI.getDebugLoc());
-  UV->addDef(Idx, MI.getOperand(0), IsIndirect);
+  if (!Discard)
+    UV->addDef(Idx, MI.getOperand(0), IsIndirect);
+  else
+    UV->addDef(Idx, MachineOperand::CreateReg(0U, RegState::Debug), false);
   return true;
 }
 
diff --git a/test/DebugInfo/X86/dbg-value-inlined-parameter.ll b/test/DebugInfo/X86/dbg-value-inlined-parameter.ll
index 9954039654bb..e83cf0aa7ffd 100644
--- a/test/DebugInfo/X86/dbg-value-inlined-parameter.ll
+++ b/test/DebugInfo/X86/dbg-value-inlined-parameter.ll
@@ -32,10 +32,10 @@
 ;CHECK-NEXT: DW_AT_call_line
 
 ;CHECK: DW_TAG_formal_parameter
-;FIXME: Linux shouldn't drop this parameter either...
 ;CHECK-NOT: DW_TAG
-;DARWIN:   DW_AT_abstract_origin {{.*}} "sp"
-;DARWIN: DW_TAG_formal_parameter
+;FIXME: Shouldn't drop this parameter...
+;XCHECK:   DW_AT_abstract_origin {{.*}} "sp"
+;XCHECK: DW_TAG_formal_parameter
 ;CHECK: DW_AT_abstract_origin {{.*}} "nums"
 ;CHECK-NOT: DW_TAG_formal_parameter
 
diff --git a/test/DebugInfo/X86/live-debug-vars-discard-invalid.mir b/test/DebugInfo/X86/live-debug-vars-discard-invalid.mir
new file mode 100644
index 000000000000..abc21bc6ac90
--- /dev/null
+++ b/test/DebugInfo/X86/live-debug-vars-discard-invalid.mir
@@ -0,0 +1,141 @@
+# RUN: llc -mtriple=x86_64-linux-gnu -start-before greedy -stop-after virtregrewriter -o - %s | FileCheck %s
+
+--- |
+  ; ModuleID = '<stdin>'
+  source_filename = "test/DebugInfo/X86/dbg-value-inlined-parameter.ll"
+  target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+  target triple = "x86_64-apple-darwin"
+
+  %struct.S1 = type { float*, i32 }
+
+  @p = common global %struct.S1 zeroinitializer, align 8, !dbg !0
+
+  ; Function Attrs: nounwind optsize ssp
+  define void @foobar() !dbg !15 {
+  entry:
+    tail call void @llvm.dbg.value(metadata %struct.S1* @p, metadata !18, metadata !DIExpression()) , !dbg !25
+    ret void, !dbg !32
+  }
+
+  ; Function Attrs: nounwind readnone speculatable
+  declare void @llvm.dbg.value(metadata, metadata, metadata) #2
+
+  !llvm.dbg.cu = !{!2}
+  !llvm.module.flags = !{!14}
+
+  !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+  !1 = !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 14, type: !6, isLocal: false, isDefinition: true)
+  !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 2.9 (trunk 125693)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !4, globals: !5, imports: !4)
+  !3 = !DIFile(filename: "nm2.c", directory: "/private/tmp")
+  !4 = !{}
+  !5 = !{!0}
+  !6 = !DIDerivedType(tag: DW_TAG_typedef, name: "S1", scope: !2, file: !3, line: 4, baseType: !7)
+  !7 = !DICompositeType(tag: DW_TAG_structure_type, name: "S1", scope: !2, file: !3, line: 1, size: 128, align: 64, elements: !8)
+  !8 = !{!9, !12}
+  !9 = !DIDerivedType(tag: DW_TAG_member, name: "m", scope: !3, file: !3, line: 2, baseType: !10, size: 64, align: 64)
+  !10 = !DIDerivedType(tag: DW_TAG_pointer_type, scope: !2, baseType: !11, size: 64, align: 64)
+  !11 = !DIBasicType(name: "float", size: 32, align: 32, encoding: DW_ATE_float)
+  !12 = !DIDerivedType(tag: DW_TAG_member, name: "nums", scope: !3, file: !3, line: 3, baseType: !13, size: 32, align: 32, offset: 64)
+  !13 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+  !14 = !{i32 1, !"Debug Info Version", i32 3}
+  !15 = distinct !DISubprogram(name: "foobar", scope: !3, file: !3, line: 15, type: !16, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: true, unit: !2)
+  !16 = !DISubroutineType(types: !17)
+  !17 = !{null}
+  !18 = !DILocalVariable(name: "sp", arg: 1, scope: !19, file: !3, line: 7, type: !24)
+  !19 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 8, type: !20, isLocal: false, isDefinition: true, scopeLine: 8, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !2, variables: !22)
+  !20 = !DISubroutineType(types: !21)
+  !21 = !{!13}
+  !22 = !{!18, !23}
+  !23 = !DILocalVariable(name: "nums", arg: 2, scope: !19, file: !3, line: 7, type: !13)
+  !24 = !DIDerivedType(tag: DW_TAG_pointer_type, scope: !2, baseType: !6, size: 64, align: 64)
+  !25 = !DILocation(line: 7, column: 13, scope: !19, inlinedAt: !26)
+  !26 = !DILocation(line: 16, column: 3, scope: !27)
+  !27 = distinct !DILexicalBlock(scope: !15, file: !3, line: 15, column: 15)
+  !32 = !DILocation(line: 17, column: 1, scope: !27)
+
+...
+---
+name:            foobar
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    %1:gr64 = IMPLICIT_DEF
+    %2:gr64 = IMPLICIT_DEF
+
+  bb.1:
+    ; This DBG_VALUE will be discarded (use before def of %0).
+    DBG_VALUE debug-use %0, debug-use %noreg, !18, !DIExpression(), debug-location !25
+    %0:gr64 = IMPLICIT_DEF
+    %0:gr64 = IMPLICIT_DEF
+    %0:gr64 = IMPLICIT_DEF
+    %0:gr64 = IMPLICIT_DEF
+
+  bb.2:
+    ; This DBG_VALUE will be discarded (%1 is defined earlier, but it is not live in, so we do not know where %1 is stored).
+    DBG_VALUE debug-use %1, debug-use %noreg, !18, !DIExpression(), debug-location !25
+    %1:gr64 = IMPLICIT_DEF
+    %1:gr64 = IMPLICIT_DEF
+    %1:gr64 = IMPLICIT_DEF
+    %1:gr64 = IMPLICIT_DEF
+    ; This DBG_VALUE is kept, even if %1 is dead, it was defined in the prev instruction,
+    ; so the value should be available for as long as the register allocated to %1 is live.
+    DBG_VALUE debug-use %1, debug-use %noreg, !18, !DIExpression(), debug-location !25
+
+  bb.3:
+    %1:gr64 = IMPLICIT_DEF
+    DBG_VALUE 0, debug-use %noreg, !23, !DIExpression(), debug-location !25
+    ; This DBG_VALUE is kept, even if %1 is dead, it was defined in the prev non-dbg instruction,
+    ; so the value should be available for as long as the register allocated to %1 is live.
+    DBG_VALUE debug-use %1, debug-use %noreg, !18, !DIExpression(), debug-location !25
+
+  bb.4:
+    ; All DBG_VALUEs here should survive. %2 is livein as it was defined in bb.0, and it has use/def in the BTS64rr instruction.
+    DBG_VALUE debug-use %2, debug-use %noreg, !18, !DIExpression(), debug-location !25
+    %2:gr64 = BTS64rr %2, 0, implicit-def %eflags
+    DBG_VALUE 0, debug-use %noreg, !23, !DIExpression(), debug-location !25
+    DBG_VALUE debug-use %2, debug-use %noreg, !18, !DIExpression(), debug-location !25
+    %2:gr64 = BTS64rr %2, 0, implicit-def %eflags
+    DBG_VALUE debug-use %2, debug-use %noreg, !18, !DIExpression(), debug-location !25
+    %2:gr64 = BTS64rr %2, 0, implicit-def %eflags
+    DBG_VALUE debug-use %2, debug-use %noreg, !18, !DIExpression(), debug-location !25
+
+  bb.5:
+    RET 0, debug-location !32
+...
+
+# CHECK-LABEL: name: foobar
+
+# CHECK-LABEL: bb.1:
+## After solving https://bugs.llvm.org/show_bug.cgi?id=36579 we expect to get a
+##   DBG_VALUE debug-use %noreg
+## here.
+# CHECK-NOT:    DBG_VALUE
+
+# CHECK-LABEL: bb.2:
+## After solving https://bugs.llvm.org/show_bug.cgi?id=36579 we expect to get a
+##   DBG_VALUE debug-use %noreg
+## here.
+# CHECK-NOT:    DBG_VALUE
+# CHECK:        dead renamable %rcx = IMPLICIT_DEF
+# CHECK-NEXT:   dead renamable %rcx = IMPLICIT_DEF
+# CHECK-NEXT:   dead renamable %rcx = IMPLICIT_DEF
+# CHECK-NEXT:   dead renamable %rcx = IMPLICIT_DEF
+# CHECK-NEXT:   DBG_VALUE debug-use %rcx, debug-use %noreg, !18, !DIExpression()
+
+# CHECK-LABEL: bb.3:
+# CHECK:        dead renamable %rcx = IMPLICIT_DEF
+# CHECK-NEXT:   DBG_VALUE 0, debug-use %noreg, !23, !DIExpression()
+# CHECK-NEXT:   DBG_VALUE debug-use %rcx, debug-use %noreg, !18, !DIExpression()
+
+# CHECK-LABEL: bb.4:
+# CHECK:        liveins: %rax
+# CHECK:        DBG_VALUE debug-use %rax, debug-use %noreg, !18, !DIExpression()
+# CHECK-NEXT:   renamable %rax = BTS64rr killed renamable %rax, 0, implicit-def %eflags
+# CHECK-NEXT:   DBG_VALUE 0, debug-use %noreg, !23, !DIExpression()
+# CHECK-NEXT:   DBG_VALUE debug-use %rax, debug-use %noreg, !18, !DIExpression()
+# CHECK-NEXT:   renamable %rax = BTS64rr killed renamable %rax, 0, implicit-def %eflags
+# CHECK-NEXT:   DBG_VALUE debug-use %rax, debug-use %noreg, !18, !DIExpression()
+# CHECK-NEXT:   dead renamable %rax = BTS64rr killed renamable %rax, 0, implicit-def %eflags
+
+# CHECK-LABEL: bb.5:
+# CHECK-NEXT:   RET 0