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

            Bug ID: 105249
           Summary: schedule-insns2 makes a variable not available and
                    associates the code that assigns it to a different
                    function frame
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: debug
          Assignee: unassigned at gcc dot gnu.org
          Reporter: assaiante at diag dot uniroma1.it
  Target Milestone: ---

In this minimized C example, induction variable i is not available when
stepping on line 9. At -Os we note that the address of the instruction that
assigns to variable a is associated in DWARF with locations from c(), thus
leading to a wrong current function frame when debugging. At -Og/-O1 the
behavior is instead correct. Apparently, schedule-insns2 is responsible for
generating overlapping locations for function c and induction variable i.

At -Oz/-O2/-O3, if we place a breakpoint on line 9 the line is never stepped,
but instead the program breaks inside the body of function c. For this scenario
too, the issue disappears with -fno-schedule-insns2.

Please find below a detailed analysis for -Os on x64 and a quick assessment on
past gcc versions where the issue is sometimes not present.

$ cat a.c
volatile int a;
int b[2];
static void c(int d3) { printf("%d", d3); }
int main() {
  int i;
  b[0] = 0;
  i = 0;
  for (; i < 2; i++)
    a = b[i];
  c(0);
}

GCC and GDB version:
- gcc (GCC) 12.0.0 20211227 (experimental) - commit id: 500d3f0a302
- GNU gdb (GDB) 11.2

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

Breakpoint 1, c (d3=<optimized out>) at a.c:9
9           a = b[i];
(gdb) info loc
No locals.


ASM at -Os:
0000000000400410 <main>:
  400410:       50                      push   %rax
  400411:       8b 05 25 0c 20 00       mov    0x200c25(%rip),%eax        #
60103c <b+0x4>
  400417:       31 d2                   xor    %edx,%edx
  400419:       31 f6                   xor    %esi,%esi
  40041b:       89 15 1f 0c 20 00       mov    %edx,0x200c1f(%rip)        #
601040 <a>
  400421:       bf b4 05 40 00          mov    $0x4005b4,%edi
  400426:       89 05 14 0c 20 00       mov    %eax,0x200c14(%rip)        #
601040 <a>
  40042c:       31 c0                   xor    %eax,%eax
  40042e:       89 15 04 0c 20 00       mov    %edx,0x200c04(%rip)        #
601038 <b>
  400434:       e8 c7 ff ff ff          callq  400400 <printf@plt>
  400439:       31 c0                   xor    %eax,%eax
  40043b:       59                      pop    %rcx
  40043c:       c3                      retq

DWARF at -Os:
[ function c DIE ]
0x000000a7:     DW_TAG_inlined_subroutine
                  DW_AT_abstract_origin (0x000000f1 "c")
                  DW_AT_entry_pc        (0x000000000040042c)
                  DW_AT_unknown_2138    (0x03)
                  DW_AT_ranges  (0x0000000c
                     [0x0000000000400419, 0x000000000040041b)
                     [0x0000000000400421, 0x0000000000400426)
                     [0x000000000040042c, 0x000000000040042e)
                     [0x0000000000400434, 0x0000000000400439))
                  DW_AT_call_file       ("/tmp/a.c")
                  DW_AT_call_line       (10)
                  DW_AT_call_column     (0x03)

[ variable i DIE ]
0x00000095:     DW_TAG_variable
                  DW_AT_name    ("i")
                  DW_AT_decl_file       ("/tmp/a.c")
                  DW_AT_decl_line       (5)
                  DW_AT_decl_column     (0x07)
                  DW_AT_type    (0x0000003d "int")
                  DW_AT_location        (0x00000010: 
                     [0x0000000000400421, 0x000000000040042c): DW_OP_lit1,
DW_OP_stack_value
                     [0x000000000040042c, 0x000000000040043d): DW_OP_lit2,
DW_OP_stack_value)
                  DW_AT_GNU_locviews    (0x0000000c)


DEBUG line info at -Os:
Address            Line   Column File   ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x0000000000400421      9      5      1   0             0  is_stmt

In the DWARF info function c is defined in the range [0x0000000000400421,
0x0000000000400426) and from the line info we can see how the begin address of
the range is associated with line 9. This causes the variable i to not be
available when debugging even if its location is correctly defined.

Through some testing we found out that the optimization that makes the variable
not available and introduces the location overlapping is -fschedule-insns2. If
we add -fno-schedule-insns2 to the previous compilation command line, the issue
is not present anymore since the DWARF location and line number association are
correctly computed. The option would also solve the correctness problem pointed
out for -Oz/-O2/-O3.

ASM at -Os with -fno-schedule-insns2:
0000000000400410 <main>:
  400410:       50                      push   %rax
  400411:       31 d2                   xor    %edx,%edx
  400413:       89 15 1f 0c 20 00       mov    %edx,0x200c1f(%rip)        #
601038 <b>
  400419:       89 15 21 0c 20 00       mov    %edx,0x200c21(%rip)        #
601040 <a>
  40041f:       8b 05 17 0c 20 00       mov    0x200c17(%rip),%eax        #
60103c <b+0x4>
  400425:       89 05 15 0c 20 00       mov    %eax,0x200c15(%rip)        #
601040 <a>
  40042b:       31 f6                   xor    %esi,%esi
  40042d:       bf b4 05 40 00          mov    $0x4005b4,%edi
  400432:       31 c0                   xor    %eax,%eax
  400434:       e8 c7 ff ff ff          callq  400400 <printf@plt>
  400439:       31 c0                   xor    %eax,%eax
  40043b:       59                      pop    %rcx
  40043c:       c3                      retq 


DWARF info at -Os with -fno-schedule-insns2:
[ function c DIE ]
0x000000a7:     DW_TAG_inlined_subroutine
                  DW_AT_abstract_origin (0x000000f7 "c")
                  DW_AT_entry_pc        (0x000000000040042b)
                  DW_AT_unknown_2138    (0x03)
                  DW_AT_low_pc  (0x000000000040042b)
                  DW_AT_high_pc (0x0000000000400439)
                  DW_AT_call_file       ("/tmp/a.c")
                  DW_AT_call_line       (10)
                  DW_AT_call_column     (0x03)

[ variable i DIE ]
0x00000095:     DW_TAG_variable
                  DW_AT_name    ("i")
                  DW_AT_decl_file       ("/tmp/a.c")
                  DW_AT_decl_line       (5)
                  DW_AT_decl_column     (0x07)
                  DW_AT_type    (0x0000003d "int")
                  DW_AT_location        (0x00000010: 
                     [0x000000000040041f, 0x000000000040042b): DW_OP_lit1,
DW_OP_stack_value
                     [0x000000000040042b, 0x000000000040043d): DW_OP_lit2,
DW_OP_stack_value)
                  DW_AT_GNU_locviews    (0x0000000c)


DEBUG line info at -Os with -fno-schedule-insns2:
Address            Line   Column File   ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x000000000040041f      9      5      1   0             0  is_stmt

We have also tested older gcc versions (6.4, 7.5, 8.4, 9.3, 10.3, 11.1) and the
results are identical to the git version starting from gcc-9. Instead, on
previous versions the variable is correctly shown.
  • [Bug debug/105249] New: sch... assaiante at diag dot uniroma1.it via Gcc-bugs

Reply via email to