[llvm] r361820 - Stop undef fragments from closing non-overlapping fragments

David Stenberg via llvm-commits llvm-commits at lists.llvm.org
Tue May 28 06:23:25 PDT 2019


Author: dstenb
Date: Tue May 28 06:23:25 2019
New Revision: 361820

URL: http://llvm.org/viewvc/llvm-project?rev=361820&view=rev
Log:
Stop undef fragments from closing non-overlapping fragments

Summary:
When DwarfDebug::buildLocationList() encountered an undef debug value,
it would truncate all open values, regardless if they were overlapping or
not. This patch fixes so that it only does that for overlapping fragments.

This change unearthed a bug that I had introduced in D57511,
which I have fixed in this patch. The code in DebugHandlerBase that
changes labels for parameter debug values could break DwarfDebug's
assumption that the labels for the entries in the debug value history
are monotonically increasing. Before this patch, that bug could result
in location list entries whose ending address was lower than the
beginning address, and with the changes for undef debug values that this
patch introduces it could trigger an assertion, due to attempting to
emit location list entries with empty ranges. A reproducer for the bug
is added in param-reg-const-mix.mir.

Reviewers: aprantl, jmorse, probinson

Reviewed By: aprantl

Subscribers: javed.absar, llvm-commits

Tags: #debug-info, #llvm

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

Added:
    llvm/trunk/test/DebugInfo/MIR/ARM/param-reg-const-mix.mir
    llvm/trunk/test/DebugInfo/X86/undef-fragment.ll
Modified:
    llvm/trunk/include/llvm/CodeGen/MachineInstr.h
    llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Modified: llvm/trunk/include/llvm/CodeGen/MachineInstr.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineInstr.h?rev=361820&r1=361819&r2=361820&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/MachineInstr.h (original)
+++ llvm/trunk/include/llvm/CodeGen/MachineInstr.h Tue May 28 06:23:25 2019
@@ -1005,6 +1005,12 @@ public:
       && getOperand(1).isImm();
   }
 
+  /// Return true if the instruction is a debug value which describes a part of
+  /// a variable as unavailable.
+  bool isUndefDebugValue() const {
+    return isDebugValue() && getOperand(0).isReg() && !getOperand(0).getReg();
+  }
+
   bool isPHI() const {
     return getOpcode() == TargetOpcode::PHI ||
            getOpcode() == TargetOpcode::G_PHI;

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp?rev=361820&r1=361819&r2=361820&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp Tue May 28 06:23:25 2019
@@ -246,8 +246,13 @@ void DebugHandlerBase::beginFunction(con
                                        Pred.getInstr()->getDebugExpression());
                           }))
             break;
-          if (!IsDescribedByReg(I->getInstr()))
-            LabelsBeforeInsn[I->getInstr()] = Asm->getFunctionBegin();
+          // The code that generates location lists for DWARF assumes that the
+          // entries' start labels are monotonically increasing, and since we
+          // don't change the label for fragments that are described by
+          // registers, we must bail out when encountering such a fragment.
+          if (IsDescribedByReg(I->getInstr()))
+            break;
+          LabelsBeforeInsn[I->getInstr()] = Asm->getFunctionBegin();
         }
       }
     }

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=361820&r1=361819&r2=361820&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Tue May 28 06:23:25 2019
@@ -1139,16 +1139,6 @@ void DwarfDebug::buildLocationList(Small
   for (auto EB = Entries.begin(), EI = EB, EE = Entries.end(); EI != EE; ++EI) {
     const MachineInstr *Instr = EI->getInstr();
 
-    if (EI->isDbgValue()) {
-      // Check if a variable is inaccessible in this range.
-      // TODO: This should only truncate open ranges that are overlapping.
-      if (Instr->getNumOperands() > 1 &&
-          Instr->getOperand(0).isReg() && !Instr->getOperand(0).getReg()) {
-        OpenRanges.clear();
-        continue;
-      }
-    }
-
     // Remove all values that are no longer live.
     size_t Index = std::distance(EB, EI);
     auto Last =
@@ -1177,8 +1167,16 @@ void DwarfDebug::buildLocationList(Small
     // If this history map entry has a debug value, add that to the list of
     // open ranges.
     if (EI->isDbgValue()) {
-      auto Value = getDebugLocValue(Instr);
-      OpenRanges.emplace_back(EI->getEndIndex(), Value);
+      // Do not add undef debug values, as they are redundant information in
+      // the location list entries. An undef debug results in an empty location
+      // description. If there are any non-undef fragments then padding pieces
+      // with empty location descriptions will automatically be inserted, and if
+      // all fragments are undef then the whole location list entry is
+      // redundant.
+      if (!Instr->isUndefDebugValue()) {
+        auto Value = getDebugLocValue(Instr);
+        OpenRanges.emplace_back(EI->getEndIndex(), Value);
+      }
     }
 
     // Location list entries with empty location descriptions are redundant

Added: llvm/trunk/test/DebugInfo/MIR/ARM/param-reg-const-mix.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/MIR/ARM/param-reg-const-mix.mir?rev=361820&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/MIR/ARM/param-reg-const-mix.mir (added)
+++ llvm/trunk/test/DebugInfo/MIR/ARM/param-reg-const-mix.mir Tue May 28 06:23:25 2019
@@ -0,0 +1,96 @@
+# RUN: llc -mtriple=armv4t-unknown-unknown -start-after=livedebugvalues -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
+
+# This reproducer is based on the following C code:
+#
+# struct S0 { int f1; int f2; int f3; };
+#
+# int a;
+#
+# void fn1(struct S0 p1) {
+#   a = p1.f1 >= fn2(p1.f2);
+# }
+#
+# and was generated using the following commands:
+# $ clang -O1 -g --target=armv4t -S -emit-llvm
+# $ llc -O1 -stop-after=livedebugvalues
+
+--- |
+  target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
+  target triple = "armv4t-unknown-unknown"
+
+  ; Function Attrs: nounwind
+  define arm_aapcscc i32 @fn1([3 x i32] %p1.coerce) !dbg !7 {
+  entry:
+    %p1.coerce.fca.0.extract = extractvalue [3 x i32] %p1.coerce, 0
+    call void @llvm.dbg.value(metadata i32 %p1.coerce.fca.0.extract, metadata !17, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !18
+    %p1.coerce.fca.1.extract = extractvalue [3 x i32] %p1.coerce, 1
+    call void @llvm.dbg.value(metadata i32 %p1.coerce.fca.1.extract, metadata !17, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !18
+    call void @llvm.dbg.value(metadata i32 undef, metadata !17, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32)), !dbg !18
+    %call = tail call arm_aapcscc i32 bitcast (i32 (...)* @fn2 to i32 (i32)*)(i32 %p1.coerce.fca.1.extract), !dbg !19
+    %cmp = icmp sge i32 %p1.coerce.fca.0.extract, %call, !dbg !19
+    %conv = zext i1 %cmp to i32, !dbg !19
+    ret i32 %conv, !dbg !19
+  }
+
+  declare arm_aapcscc i32 @fn2(...)
+
+  ; Function Attrs: nounwind readnone speculatable
+  declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+
+  attributes #0 = { nounwind readnone speculatable }
+
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!3, !4, !5}
+  !llvm.ident = !{!6}
+
+  !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+  !1 = !DIFile(filename: "test.c", directory: "/")
+  !2 = !{}
+  !3 = !{i32 2, !"Dwarf Version", i32 4}
+  !4 = !{i32 2, !"Debug Info Version", i32 3}
+  !5 = !{i32 1, !"min_enum_size", i32 4}
+  !6 = !{!"clang version 9.0.0"}
+  !7 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16)
+  !8 = !DISubroutineType(types: !9)
+  !9 = !{!10, !11}
+  !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+  !11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S0", file: !1, line: 1, size: 96, elements: !12)
+  !12 = !{!13, !14, !15}
+  !13 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !11, file: !1, line: 1, baseType: !10, size: 32)
+  !14 = !DIDerivedType(tag: DW_TAG_member, name: "f2", scope: !11, file: !1, line: 1, baseType: !10, size: 32, offset: 32)
+  !15 = !DIDerivedType(tag: DW_TAG_member, name: "f3", scope: !11, file: !1, line: 1, baseType: !10, size: 32, offset: 64)
+  !16 = !{!17}
+  !17 = !DILocalVariable(name: "p1", arg: 1, scope: !7, file: !1, line: 3, type: !11)
+  !18 = !DILocation(line: 3, scope: !7)
+  !19 = !DILocation(line: 4, scope: !7)
+
+...
+---
+name:            fn1
+tracksRegLiveness: false
+body:             |
+  bb.0.entry:
+    $sp = frame-setup STMDB_UPD $sp, 14, $noreg, killed $r4, killed $lr
+    $r4 = MOVr $r0, 14, $noreg, $noreg
+    DBG_VALUE $r1, $noreg, !17, !DIExpression(DW_OP_LLVM_fragment, 32, 32), debug-location !18
+    DBG_VALUE $noreg, $noreg, !17, !DIExpression(DW_OP_LLVM_fragment, 64, 32), debug-location !18
+    DBG_VALUE $r4, $noreg, !17, !DIExpression(DW_OP_LLVM_fragment, 0, 32), debug-location !18
+    $r0 = MOVr killed $r1, 14, $noreg, $noreg, debug-location !19
+    BL @fn2, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit-def $sp, implicit-def $r0, debug-location !19
+    renamable $r1 = MOVi 0, 14, $noreg, $noreg
+    CMPrr killed renamable $r4, killed renamable $r0, 14, $noreg, implicit-def $cpsr, debug-location !19
+    $r1 = MOVi 1, 10, killed $cpsr, $noreg, implicit killed renamable $r1, debug-location !19
+    $r0 = MOVr killed $r1, 14, $noreg, $noreg, debug-location !19
+    $sp = LDMIA_UPD $sp, 14, $noreg, def $r4, def $lr, debug-location !19
+    BX_RET 14, $noreg, implicit $r0, debug-location !19
+
+...
+
+# Verify that the addresses in the location list for the parameter are
+# monotonically increasing, and that the undef debug value fragment does not
+# terminate the non-overlapping fragment that is described by $r1.
+
+# CHECK: DW_AT_location (0x00000000
+# CHECK-NEXT: [0x00000008, 0x00000010): DW_OP_reg4 R4, DW_OP_piece 0x4, DW_OP_reg1 R1, DW_OP_piece 0x4
+# CHECK-NEXT: [0x00000010, 0x00000024): DW_OP_reg4 R4, DW_OP_piece 0x4)
+# CHECK-NEXT: DW_AT_name ("p1")

Added: llvm/trunk/test/DebugInfo/X86/undef-fragment.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/X86/undef-fragment.ll?rev=361820&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/X86/undef-fragment.ll (added)
+++ llvm/trunk/test/DebugInfo/X86/undef-fragment.ll Tue May 28 06:23:25 2019
@@ -0,0 +1,78 @@
+; RUN: llc -mtriple=x86_64-pc-linux-gnu -O2 -filetype=obj < %s | llvm-dwarfdump - | FileCheck %s
+
+; This reproducer is based on the following C code:
+;
+; typedef struct { int a; int b; } S;
+;
+; extern int ext(int);
+;
+; int foo() {
+;   S s = {123, 456};
+;   ext(1);
+;   s.a = ext(2);
+;   ext(3);
+;   s.a = 789;
+;   return s.b;
+; }
+;
+; and was generated using -O2 -g -fno-inline.
+;
+; As a small note, the third dbg.value's value has been changed from %call1 to
+; undef (it would have become undef either way, but this was done to make the
+; intention of the test a bit more clear).
+
+; Verify that a location list entry describing s.b is started at the
+; non-overlapping undef debug value.
+
+; CHECK: DW_AT_location (0x00000000
+; CHECK-NEXT: {{0x[0-9a-f]+}}, [[ADDR1:0x[0-9a-f]+]]): DW_OP_constu 0x7b, DW_OP_stack_value, DW_OP_piece 0x4, DW_OP_constu 0x1c8, DW_OP_stack_value, DW_OP_piece 0x4
+; CHECK-NEXT: [[ADDR1]], [[ADDR2:0x[0-9a-f]+]]): DW_OP_piece 0x4, DW_OP_constu 0x1c8, DW_OP_stack_value, DW_OP_piece 0x4
+; CHECK-NEXT: [[ADDR2]], {{0x[0-9a-f]+}}): DW_OP_constu 0x315, DW_OP_stack_value, DW_OP_piece 0x4, DW_OP_constu 0x1c8, DW_OP_stack_value, DW_OP_piece 0x4)
+; CHECK-NEXT: DW_AT_name    ("s")
+
+; Function Attrs: noinline nounwind uwtable
+define i32 @main() !dbg !7 {
+entry:
+  call void @llvm.dbg.value(metadata i32 123, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !18
+  call void @llvm.dbg.value(metadata i32 456, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !18
+  %call = tail call i32 @ext(i32 1), !dbg !19
+  %call1 = tail call i32 @ext(i32 2), !dbg !20
+  call void @llvm.dbg.value(metadata i32 undef, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !18
+  %call2 = tail call i32 @ext(i32 3), !dbg !21
+  call void @llvm.dbg.value(metadata i32 789, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !18
+  ret i32 456, !dbg !22
+}
+
+declare i32 @ext(i32)
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+
+attributes #0 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "undef.c", directory: "/")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!6 = !{!"clang version 9.0.0"}
+!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+!12 = !DILocalVariable(name: "s", scope: !7, file: !1, line: 6, type: !13)
+!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "S", file: !1, line: 1, baseType: !14)
+!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 1, size: 64, elements: !15)
+!15 = !{!16, !17}
+!16 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !14, file: !1, line: 1, baseType: !10, size: 32)
+!17 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 1, baseType: !10, size: 32, offset: 32)
+!18 = !DILocation(line: 6, scope: !7)
+!19 = !DILocation(line: 7, scope: !7)
+!20 = !DILocation(line: 8, scope: !7)
+!21 = !DILocation(line: 9, scope: !7)
+!22 = !DILocation(line: 11, scope: !7)




More information about the llvm-commits mailing list