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.