Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Incorrect location list entries are emitted when merging fragmented DBG_VALUEs with different ranges #39255

Closed Quuxplusone closed 5 years ago

Quuxplusone commented 5 years ago
Bugzilla Link PR40283
Status RESOLVED FIXED
Importance P normal
Reported by David Stenberg (david.stenberg@ericsson.com)
Reported on 2019-01-10 06:25:24 -0800
Last modified on 2019-04-11 00:18:22 -0700
Version trunk
Hardware PC Linux
CC david.stenberg@ericsson.com, jdevlieghere@apple.com, keith.walker@arm.com, llvm-bugs@lists.llvm.org, paul_robinson@playstation.sony.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
Tested on r350697.

When compiling the following C program:

    typedef struct { int a; int b; } S;

    int global;
    __attribute__((noinline))
    void baz(int p) {
      global = p; // Side effect to keep the call.
    }

    __attribute__((noinline))
    void bar(int p) {
      baz(p + 10000);
    }

    int var1 = 123;
    int var2 = 456;

    int main() {
      S s = {var1, var2};
      bar(s.a);
      return s.b;
    }

using:

  clang -O1 -g -gdwarf-4 -S foo.c

the following assembly output is emitted for main:

    main:                                   # @main
    .Lfunc_begin2:
            .loc    1 17 0 is_stmt 1        # foo.c:17:0
            .cfi_startproc
    # %bb.0:                                # %entry
            pushq   %rbx
            .cfi_def_cfa_offset 16
            .cfi_offset %rbx, -16
            .loc    1 18 10 prologue_end    # foo.c:18:10
            movl    var1(%rip), %edi
    .Ltmp3:
            #DEBUG_VALUE: main:s <- [DW_OP_LLVM_fragment 0 32] $edi
            .loc    1 18 16 is_stmt 0       # foo.c:18:16
            movl    var2(%rip), %ebx
    .Ltmp4:
            #DEBUG_VALUE: main:s <- [DW_OP_LLVM_fragment 32 32] $ebx
            .loc    1 19 3 is_stmt 1        # foo.c:19:3
            callq   bar
            .loc    1 20 3                  # foo.c:20:3
            movl    %ebx, %eax
            popq    %rbx
    .Ltmp5:
            .cfi_def_cfa_offset 8
            retq

As seen, a DBG_VALUE for s.a, which is described by the call-clobbered register
$edi, and a DBG_VALUE for s.b, which is described by the protected register
$ebx, is emitted. This looks fine to me. What we should expect here is for s.a
to be marked as unavailable (i.e. an empty piece) after the call to bar, and
s.b being located in $ebx. However, the location list does not look like that:

    .Ldebug_loc1:
            .quad   .Ltmp3-.Lfunc_begin0
            .quad   .Ltmp4-.Lfunc_begin0
            .short  3                       # Loc expr size
            .byte   85                      # super-register DW_OP_reg5
            .byte   147                     # DW_OP_piece
            .byte   4                       # 4
            .quad   .Ltmp4-.Lfunc_begin0
            .quad   .Ltmp5-.Lfunc_begin0
            .short  6                       # Loc expr size
            .byte   85                      # super-register DW_OP_reg5
            .byte   147                     # DW_OP_piece
            .byte   4                       # 4
            .byte   83                      # super-register DW_OP_reg3
            .byte   147                     # DW_OP_piece
            .byte   4                       # 4
            .quad   0
            .quad   0

As seen, we say that s.a is still in $edi after the call, resulting in an
incorrect value being printed there.
Quuxplusone commented 5 years ago
This seems to be due to the entry merging in DwarfDebug::buildLocationList()
not taking the preceding DBG_VALUE's range into account.

In fact, the DBG_VALUE for s.a does not have the end of its range calculated in
the history map, which can be seen by adding -debug:

    DbgValueHistoryMap:
     - s at <unknown location> --
       Begin: DBG_VALUE $edi, $noreg, !"s", !DIExpression(DW_OP_LLVM_fragment, 0, 32), debug-location !45; foo.c:18:5 line no:18

       Begin: DBG_VALUE $ebx, $noreg, !"s", !DIExpression(DW_OP_LLVM_fragment, 32, 32), debug-location !45; foo.c:18:5 line no:18
       End  : $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !48; foo.c:20:3

This seems to be due to the calculator only dealing with one register per
inlined entity at a time, so it is not able to end the first range, since it
switches the register-of-interest from $edi to $ebx when encountering the
second DBG_VALUE. I guess that the calulator should be made fragment-aware and
be made to support multiple registers at a time?
Quuxplusone commented 5 years ago

Proposed patch: https://reviews.llvm.org/D59942

Quuxplusone commented 5 years ago
(In reply to David Stenberg from comment #2)
> Proposed patch: https://reviews.llvm.org/D59942

That has been merged as r358073 now. Closing this issue.