[Bug debug/105179] New: -fcprop-registers shrinks a DWARF location range making a variable optimized out at -Og

dc.delia at protonmail dot com gcc-bugzilla@gcc.gnu.org
Wed Apr 6 13:57:03 GMT 2022


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105179

            Bug ID: 105179
           Summary: -fcprop-registers shrinks a DWARF location range
                    making a variable optimized out at -Og
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: debug
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dc.delia at protonmail dot com
  Target Milestone: ---

In this code, the value of variable l_36 from function e is available when
debugging on line 23, which uses it as (dead) call argument for a function in
the same module, but is optimized out at the very next line 24, which uses it
as call argument for a function from an external module.

This seems to affect only -Og, as at -O1/O2/O3 the value is available.

Apparently, with -fcprop-registers the range in the DWARF location definition
of l_36 does not include the call to the external function, while it does if
disabled and the compiled code is unchanged. At -Og the location of the
variable is defined using DW_OP_reg, while other levels see a DW_OP_addr.

We found this issue on x64 using gdb 11.2 with gcc commit 500d3f0a302; as for
gcc releases, the issue is found in gcc-10 (we tested 10.3) and 11 (11.1),
while the variable value was available in, e.g., 6.4, 7.5, 8.4, and 9.3.

$ cat a.c  
short a;
int c;

short b()
{
 return a;
}
short d(unsigned short f)
{
 return 0;
}
void e(char f)
{
   short g;
   char l_36;
   int l_51, l_57 = 0 ;
   for (; c <= 0; c++)
   {
       int l_30 = 0, l_80 = 2;
       char l_81 = f;
       g = b();
       l_36 = g;
       l_51 = d(l_36);
       test(l_36, l_51, l_57, l_30, l_80, l_81);
   }
}
int main ()
{
   e(8);
}
$ cat lib.c  
#include <stdio.h>

void test(int l_36, int l_51, int l_57, int l_30, int l_80, int l_81) {
   printf("%d %d %d %d %d %d %d", l_36, l_51, l_57, l_30, l_80, l_81);
}

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

Breakpoint 1, e (f=f@entry=8 '\b') at a.c:24
24              test(l_36, l_51, l_57, l_30, l_80, l_81);
(gdb) info loc
l_30 = 0
l_80 = 2
l_81 = 8 '\b'
g = 0
l_36 = <optimized out>
l_51 = 0
l_57 = 0

Code at -Og:
0000000000400504 <e>:
 400504:       55                      push   %rbp
 400505:       53                      push   %rbx
 400506:       48 83 ec 08             sub    $0x8,%rsp
 40050a:       89 fd                   mov    %edi,%ebp
 40050c:       eb 43                   jmp    400551 <e+0x4d>
 40050e:       b8 00 00 00 00          mov    $0x0,%eax
 400513:       e8 de ff ff ff          callq  4004f6 <b>
 400518:       89 c3                   mov    %eax,%ebx
 40051a:       66 0f be f8             movsbw %al,%di
 40051e:       0f b7 ff                movzwl %di,%edi
 400521:       e8 d8 ff ff ff          callq  4004fe <d>
 400526:       0f bf f0                movswl %ax,%esi
 400529:       0f be fb                movsbl %bl,%edi
 40052c:       44 0f be cd             movsbl %bpl,%r9d
 400530:       41 b8 02 00 00 00       mov    $0x2,%r8d
 400536:       b9 00 00 00 00          mov    $0x0,%ecx
 40053b:       ba 00 00 00 00          mov    $0x0,%edx
 400540:       b8 00 00 00 00          mov    $0x0,%eax
 400545:       e8 2f 00 00 00          callq  400579 <test>
 40054a:       83 05 e3 0a 20 00 01    addl   $0x1,0x200ae3(%rip)        #
601034 <c>
 400551:       83 3d dc 0a 20 00 00    cmpl   $0x0,0x200adc(%rip)        #
601034 <c>
 400558:       7e b4                   jle    40050e <e+0xa>
 40055a:       48 83 c4 08             add    $0x8,%rsp
 40055e:       5b                      pop    %rbx
 40055f:       5d                      pop    %rbp
 400560:       c3                      retq 

DWARF at -Og:
0x000000e7:     DW_TAG_variable
                  DW_AT_name    ("l_36")
                  DW_AT_decl_line       (15)
                  DW_AT_decl_column     (0x0a)
                  DW_AT_type    (0x000001c4 "char")
                  DW_AT_location        (0x00000036: 
                     [0x000000000040051a, 0x0000000000400525): DW_OP_reg0 RAX)
                  DW_AT_GNU_locviews    (0x00000034)

In the DWARF location info from -Og, the range does not include the call to the
test function at address 400545.

Through some testing we found out that the transformation behind the issue is
likely -fcprop-registers. With -fno-cprop-registers, variable l_36 appears with
its value when stepping at line 24 and the DWARF location info seems correctly
defined for the whole lifetime of the variable.

DWARF at -Og with -fno-cprop-registers:
0x000000e7:     DW_TAG_variable
                  DW_AT_name    ("l_36")
                  DW_AT_decl_line       (15)
                  DW_AT_decl_column     (0x0a)
                  DW_AT_type    (0x000001d9 "char")
                  DW_AT_location        (0x00000036: 
                     [0x000000000040051a, 0x0000000000400551): DW_OP_reg3 RBX)
                  DW_AT_GNU_locviews            (0x00000034)

The range is now larger than it was at -Og, capturing the call at 400545.

If helpful, please find below what happens at other optimization levels:

Code at -O1:
0000000000400504 <e>:
  400504:       83 3d 29 0b 20 00 00    cmpl   $0x0,0x200b29(%rip)        #
601034 <c>
  40050b:       7f 43                   jg     400550 <e+0x4c>
  40050d:       53                      push   %rbx
  40050e:       40 0f be df             movsbl %dil,%ebx
  400512:       0f be 3d 1f 0b 20 00    movsbl 0x200b1f(%rip),%edi        #
601038 <a>
  400519:       41 89 d9                mov    %ebx,%r9d
  40051c:       41 b8 02 00 00 00       mov    $0x2,%r8d
  400522:       b9 00 00 00 00          mov    $0x0,%ecx
  400527:       ba 00 00 00 00          mov    $0x0,%edx
  40052c:       be 00 00 00 00          mov    $0x0,%esi
  400531:       b8 00 00 00 00          mov    $0x0,%eax
  400536:       e8 2e 00 00 00          callq  400569 <test>
  40053b:       8b 05 f3 0a 20 00       mov    0x200af3(%rip),%eax        #
601034 <c>
  400541:       83 c0 01                add    $0x1,%eax
  400544:       89 05 ea 0a 20 00       mov    %eax,0x200aea(%rip)        #
601034 <c>
  40054a:       85 c0                   test   %eax,%eax
  40054c:       7e c4                   jle    400512 <e+0xe>
  40054e:       5b                      pop    %rbx
  40054f:       c3                      retq   
  400550:       c3                      retq


DWARF at -O1 (same for -O2/-O3):
0x000000e7:     DW_TAG_variable
                  DW_AT_name    ("l_36")
                  DW_AT_decl_line       (15)
                  DW_AT_decl_column     (0x0a)
                  DW_AT_type    (0x000001b7 "char")
                  DW_AT_location        (0x0000003e: 
                     [0x0000000000400512, 0x000000000040053a): DW_OP_addr
0x601038)
                  DW_AT_GNU_locviews    (0x0000003c)


More information about the Gcc-bugs mailing list