Bug 105158 - ftree-ccp (CFG cleanup) drops DWARF const value attribute at -Og/-O1/-O2/-O3
Summary: ftree-ccp (CFG cleanup) drops DWARF const value attribute at -Og/-O1/-O2/-O3
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: 12.0
: P3 enhancement
Target Milestone: 13.0
Assignee: Richard Biener
URL:
Keywords: patch
: 105194 (view as bug list)
Depends on:
Blocks:
 
Reported: 2022-04-05 10:20 UTC by Daniele Cono D'Elia
Modified: 2022-11-15 06:13 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-04-05 00:00:00


Attachments
patch (1.22 KB, patch)
2022-04-05 13:27 UTC, Richard Biener
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Daniele Cono D'Elia 2022-04-05 10:20:19 UTC
In this code, variable l_171 is displayed optimized out at every stepped line when debugging, including line 10 where it is used as a call argument to an externally defined function. We tested with -Og/O1/O2/O3 and the issue is present at all these levels.

Apparently, -ftree-ccp drops the const value attribute in the DWARF DIE for l_171 while the final compiled code stays the same. By turning it off, the debugger can display the value of the variable.

We found this issue on gcc commit 500d3f0a302 using gdb 11.2 and the behavior seems consistent with prior gcc versions (e.g., 6.4, 7.5, 8.4, 9.3, 10.3, 11.1).


$ cat a.c
int a;
void b()
{
    int l_169, l_174 = 0, l_188 = 0, l_191 = 0, l_240 = 1;
    short l_171 ;
    l_171 = (l_169 = 0) && a;
    for (; l_169 <= 9; l_169 = l_169 + 3)
    {
        int l_187 = 0,  l_189 = 0,  l_190 = 8;
        test(l_169, l_171, l_174, l_188, l_191, l_240, l_187, l_189, l_190);
    }
}
int main ()
{
    b();
}

$ cat lib.c
#include <stdio.h>

void test(int l_169, int l_171, int l_174, int l_188, int l_191, int l_240, int l_187, int l_189, int l_190) {
    printf("%d %d %d %d %d %d %d %d %d", l_169, l_171, l_174, l_188, l_191, l_240, l_187, l_189, l_190);
}

GDB trace:
$ gcc -O1 -g a.c lib.c -o opt
$ gdb -q opt
Reading symbols from opt...
(gdb) b 10
Breakpoint 1 at 0x4004fc: file a.c, line 10.
(gdb) r
Starting program: /tmp/opt 

Breakpoint 1, b () at a.c:10
10              test(l_169, l_171, l_174, l_188, l_191, l_240, l_187, l_189, l_190);
(gdb) info locals
l_187 = 0
l_189 = 0
l_190 = 8
l_169 = 0
l_174 = 0
l_188 = 0
l_191 = 0
l_240 = 1
l_171 = <optimized out>

Code at -O1:
00000000004004f6 <b>:
 4004f6:       53                      push   %rbx
 4004f7:       bb 00 00 00 00          mov    $0x0,%ebx
 4004fc:       48 83 ec 08             sub    $0x8,%rsp
 400500:       6a 08                   pushq  $0x8
 400502:       6a 00                   pushq  $0x0
 400504:       6a 00                   pushq  $0x0
 400506:       41 b9 01 00 00 00       mov    $0x1,%r9d
 40050c:       41 b8 00 00 00 00       mov    $0x0,%r8d
 400512:       b9 00 00 00 00          mov    $0x0,%ecx
 400517:       ba 00 00 00 00          mov    $0x0,%edx
 40051c:       be 00 00 00 00          mov    $0x0,%esi
 400521:       89 df                   mov    %ebx,%edi
 400523:       b8 00 00 00 00          mov    $0x0,%eax
 400528:       e8 26 00 00 00          callq  400553 <test>
 40052d:       83 c3 03                add    $0x3,%ebx
 400530:       48 83 c4 20             add    $0x20,%rsp
 400534:       83 fb 0c                cmp    $0xc,%ebx
 400537:       75 c3                   jne    4004fc <b+0x6>
 400539:       5b                      pop    %rbx
 40053a:       c3                      retq 

The code at higher optimization levels is very similar, besides where strength reduction, we suppose, kicks in (e.g. mov $0, %edi => xor %edi, %edi).

DWARF at -O1:
0x000000e8:     DW_TAG_variable
                  DW_AT_name    ("l_171")
                  DW_AT_decl_file       ("/tmp/a.c")
                  DW_AT_decl_line       (5)
                  DW_AT_decl_column     (0x0b)
                  DW_AT_type    (0x00000167 "short int")

If we add -fno-tree-ccp to the compilation command line used above, the code of function b remains unchanged but the DWARF const value information is preserved for the variable, meaning its value 0 is visible when debugging throughout its whole lifetime.

DWARF at -O1 with -fno-tree-ccp:
0x000000e8:     DW_TAG_variable
                  DW_AT_name    ("l_171")
                  DW_AT_decl_file       ("/tmp/a.c")
                  DW_AT_decl_line       (5)
                  DW_AT_decl_column     (0x0b)
                  DW_AT_type    (0x00000167 "short int")
Comment 1 Richard Biener 2022-04-05 12:48:14 UTC
The issue is that the definition we put the debug stmt into is in

<bb 2> :
[t.c:4:5] # DEBUG BEGIN_STMT
[t.c:4:16] # DEBUG l_174 => 0
[t.c:4:27] # DEBUG l_188 => 0
[t.c:4:38] # DEBUG l_191 => 0
[t.c:4:49] # DEBUG l_240 => 1
[t.c:5:5] # DEBUG BEGIN_STMT
[t.c:6:5] # DEBUG BEGIN_STMT
[t.c:6:20] # DEBUG l_169 => 0
[t.c:6:25] if (0 != 0)
  goto <bb 3>; [INV]
else
  goto <bb 5>; [INV]

<bb 5> :

<bb 6> :
[t.c:6:11] # DEBUG l_171 => 0
[t.c:7:5] # DEBUG BEGIN_STMT
[t.c:7:5] goto <bb 8>; [INV]

<bb 8> :
# l_169_3 = PHI <[t.c:6:20] 0(6), [t.c:7:30] l_169_19(7)>
# DEBUG l_169 => l_169_3
[t.c:7:18] # DEBUG BEGIN_STMT
[t.c:7:18] if (l_169_3 <= 9)
  goto <bb 7>; [INV]
else
  goto <bb 9>; [INV]

and when CFG cleanup merges all the forwarders it finds no location to
put the debug stmt to - it tries to move the debug stmts to the
successor but that doesn't have a single predecessor so that's not a
valid thing to do.  Moving to the predecessor would be valid if that
has a single successor though but that's not implemented.  In this
case the predecessor is block 2 at the point in question and it has
a single successor plus the last stmt in it doesn't end the BB.
Comment 2 Richard Biener 2022-04-05 13:27:10 UTC
I have a patch.
Comment 3 Richard Biener 2022-04-05 13:27:24 UTC
Created attachment 52748 [details]
patch
Comment 4 Richard Biener 2022-04-07 12:47:55 UTC
*** Bug 105194 has been marked as a duplicate of this bug. ***
Comment 5 GCC Commits 2022-05-04 07:52:15 UTC
The master branch has been updated by Richard Biener <rguenth@gcc.gnu.org>:

https://gcc.gnu.org/g:1ba68f78c9d2510eb095f7d8a90c87cd5fd4183d

commit r13-99-g1ba68f78c9d2510eb095f7d8a90c87cd5fd4183d
Author: Richard Biener <rguenther@suse.de>
Date:   Tue Apr 5 15:23:54 2022 +0200

    debug/105158 - improve debug stmt retaining for forwarder removal
    
    Currently when we cannot move debug stmt from a forwarder to the
    destination block we drop/reset them.  But in some cases as for
    the testcase we can move them to the predecessor when that has
    a single successor and we can insert after the last stmt of the
    block.  That allows us to preserve debug info here.
    
    2022-04-05  Richard Biener  <rguenther@suse.de>
    
            PR debug/105158
            * tree-cfgcleanup.cc (move_debug_stmts_from_forwarder):
            Move debug stmts to the predecessor if moving to the
            destination is not possible.
            (remove_forwarder_block): Adjust.
            (remove_forwarder_block_with_phi): Likewise.
Comment 6 Richard Biener 2022-05-04 07:53:08 UTC
Fixed.