[llvm-bugs] [Bug 41992] New: [DebugInfo at O2] LiveDebugVariables can drop DBG_VALUEs through misinterpreting fragments

via llvm-bugs llvm-bugs at lists.llvm.org
Thu May 23 03:55:53 PDT 2019


https://bugs.llvm.org/show_bug.cgi?id=41992

            Bug ID: 41992
           Summary: [DebugInfo at O2] LiveDebugVariables can drop DBG_VALUEs
                    through misinterpreting fragments
           Product: libraries
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Keywords: wrong-debug
          Severity: normal
          Priority: P
         Component: Common Code Generator Code
          Assignee: unassignedbugs at nondot.org
          Reporter: jeremy.morse.llvm at gmail.com
                CC: aprantl at apple.com, chackz0x12 at gmail.com,
                    david.stenberg at ericsson.com, greg.bedwell at sony.com,
                    llvm-bugs at lists.llvm.org, orlando.hyams at sony.com,
                    paul.robinson at am.sony.com, stephen.tozer at sony.com

With LLVM/clang 361045, it seems LiveDebugVariables can drop DBG_VALUE
instructions in the presence of complex expressions, as demonstrated in the
code below, when fed into "llc -stop-after=virtregrewriter -o -". The code is
adapted from the dbg-addr-dse.ll test, and after virtregrewriter the third
DBG_VALUE instruction is not re-inserted, which makes an assignment disappear.

The cause seems to be this check [0] in LiveDebugVariables: it intends to
ensure that fragments are recorded as different "UserValue"s. However the fact
it's only comparing Expression pointers means that any complex expression at
all will be considered a different fragment of the variable. Thus the
DW_OP_deref's in the code below effectively make the dbg.value's refer to
different fragments, according to LiveDebugVariables.

In the example code, after calling collectDebugValues,
LiveDebugVariables::print represents the program state thus:

  !"x,3"   [32r;32d):0 [128r;128d):0 Loc0=%stack.0
  !"x,3"   [112r;112d):0 Loc0=1

Here the first and last DBG_VALUE insts are recorded in the first line as being
in location 0 (%stack.0) at slot indexes 32 and 128. The second line represents
the middle DBG_VALUE, as a different fragment, having location const-1 at slot
index 112. (The DIExpressions aren't printed).

After calling computeIntervals the LiveDebugVariables state becomes:

  !"x,3"   [48B;240B):0 Loc0=%stack.0
  !"x,3"   [112r;240B):0 Loc0=1

The first line coalesces its locations to the end of the block (240B) because
that "fragment" always appears to be in %stack.0. Then when virtregrewriter
re-inserts DBG_VALUEs, it doesn't see any reason to replace what was the third
DBG_VALUE in the original code: as far as it sees it, there are two different
fragments that get their locations defined once each, and that's it. Thus, the
third DBG_VALUE goes missing.

I anticipate LiveDebugVariables could be convinced to insert fresh DBG_VALUEs
where it shouldn't in a similar way. UserValue::extendDef can be convinced to
extend the lifetime of a fragment to a copy of a register location, if the
original register is killed. That would then lead to it inserting a fresh
DBG_VALUE, possibly terminating an earlier DBG_VALUE for the same (but
unrecognised) fragment.

(I was going to just submit a patch for this, but I think some non-trivial
datastructure changes are required, and it's not something I'm immediately
working on).

[0]
https://github.com/llvm/llvm-project/blob/e85bbf564de9adfe09d6b24b9861b28e2b78e9ad/llvm/lib/CodeGen/LiveDebugVariables.cpp#L207

--------8<--------
target triple = "x86_64-unknown-linux"

declare void @llvm.dbg.addr(metadata, metadata, metadata)
declare void @llvm.dbg.value(metadata, metadata, metadata)
declare void @escape(i32*)

@global = external global i32, align 4

define void @f(i32 %x) !dbg !8 {
entry:
  %x.addr = alloca i32, align 4
  store i32 %x, i32* %x.addr, align 4
  call void @llvm.dbg.value(metadata i32* %x.addr, metadata !13, metadata
!DIExpression(DW_OP_deref)), !dbg !18
  call void @escape(i32* %x.addr), !dbg !18
  call void @llvm.dbg.value(metadata i32 1, metadata !13, metadata
!DIExpression()), !dbg !18
  store i32 1, i32* @global, align 4, !dbg !18
  call void @llvm.dbg.value(metadata i32* %x.addr, metadata !13, metadata
!DIExpression(DW_OP_deref)), !dbg !18
  store i32 2, i32* %x.addr, align 4, !dbg !18
  call void @escape(i32* %x.addr), !dbg !18
  ret void, !dbg !18
}

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4}
!llvm.ident = !{!7}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang
version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug,
enums: !2)
!1 = !DIFile(filename: "dse.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!7 = !{!"clang version 6.0.0 "}
!8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !9,
isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped,
isOptimized: true, unit: !0, retainedNodes: !12)
!9 = !DISubroutineType(types: !10)
!10 = !{null, !11}
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!12 = !{!13}
!13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 3, type:
!11)
!18 = !DILocation(line: 3, column: 12, scope: !8)
-------->8--------

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20190523/4c443cce/attachment.html>


More information about the llvm-bugs mailing list