$ gcc --version gcc (GCC) 13.0.0 20221107 (experimental) Copyright (C) 2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gdb --version GNU gdb (GDB) 14.0.50.20230417-git Copyright (C) 2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. $ gdb -q a.out Reading symbols from a.out... (gdb) b main Breakpoint 1 at 0x401040: file small.c, line 29. (gdb) r Starting program: /root/devil/a.out Breakpoint 1, main () at small.c:29 29 __builtin_prefetch (glob_int_arr, 0, 0); (gdb) si 0x0000000000401044 in simple_global () at small.c:30 30 __builtin_prefetch (glob_ptr_int, 0, 0); (gdb) si 0x000000000040104b in main () at small.c:151 151 exit (0); (gdb) ================================================= When using the 'stepi' command in GDB, an abnormal jump in the execution occurs when reaching line 30. The execution unexpectedly jumps to line 151. Additional Information: Source-level stepping (e.g., 'next' or 'step') works fine without any abnormal jumps. I was wondering that this might be a bug in gdb. This is the test program in gcc test suite (gcc-12.1.0/gcc/testsuite/gcc.c-torture/execute/builtin-prefetch-2.c). $ cat small.c /* Test that __builtin_prefetch does no harm. Prefetch data using a variety of storage classes and address expressions. */ int glob_int_arr[100]; int *glob_ptr_int = glob_int_arr; int glob_int = 4; static stat_int_arr[100]; static int *stat_ptr_int = stat_int_arr; static int stat_int; struct S { int a; short b, c; char d[8]; struct S *next; }; struct S str; struct S *ptr_str = &str; /* Prefetch global variables using the address of the variable. */ void simple_global () { __builtin_prefetch (glob_int_arr, 0, 0); __builtin_prefetch (glob_ptr_int, 0, 0); __builtin_prefetch (&glob_int, 0, 0); } /* Prefetch file-level static variables using the address of the variable. */ void simple_file () { __builtin_prefetch (stat_int_arr, 0, 0); __builtin_prefetch (stat_ptr_int, 0, 0); __builtin_prefetch (&stat_int, 0, 0); } /* Prefetch local static variables using the address of the variable. */ void simple_static_local () { static int gx[100]; static int *hx = gx; static int ix; __builtin_prefetch (gx, 0, 0); __builtin_prefetch (hx, 0, 0); __builtin_prefetch (&ix, 0, 0); } /* Prefetch local stack variables using the address of the variable. */ void simple_local () { int gx[100]; int *hx = gx; int ix; __builtin_prefetch (gx, 0, 0); __builtin_prefetch (hx, 0, 0); __builtin_prefetch (&ix, 0, 0); } /* Prefetch arguments using the address of the variable. */ void simple_arg (int g[100], int *h, int i) { __builtin_prefetch (g, 0, 0); __builtin_prefetch (h, 0, 0); __builtin_prefetch (&i, 0, 0); } /* Prefetch using address expressions involving global variables. */ void expr_global (void) { __builtin_prefetch (&str, 0, 0); __builtin_prefetch (ptr_str, 0, 0); __builtin_prefetch (&str.b, 0, 0); __builtin_prefetch (&ptr_str->b, 0, 0); __builtin_prefetch (&str.d, 0, 0); __builtin_prefetch (&ptr_str->d, 0, 0); __builtin_prefetch (str.next, 0, 0); __builtin_prefetch (ptr_str->next, 0, 0); __builtin_prefetch (str.next->d, 0, 0); __builtin_prefetch (ptr_str->next->d, 0, 0); __builtin_prefetch (&glob_int_arr, 0, 0); __builtin_prefetch (glob_ptr_int, 0, 0); __builtin_prefetch (&glob_int_arr[2], 0, 0); __builtin_prefetch (&glob_ptr_int[3], 0, 0); __builtin_prefetch (glob_int_arr+3, 0, 0); __builtin_prefetch (glob_int_arr+glob_int, 0, 0); __builtin_prefetch (glob_ptr_int+5, 0, 0); __builtin_prefetch (glob_ptr_int+glob_int, 0, 0); } /* Prefetch using address expressions involving local variables. */ void expr_local (void) { int b[10]; int *pb = b; struct S t; struct S *pt = &t; int j = 4; __builtin_prefetch (&t, 0, 0); __builtin_prefetch (pt, 0, 0); __builtin_prefetch (&t.b, 0, 0); __builtin_prefetch (&pt->b, 0, 0); __builtin_prefetch (&t.d, 0, 0); __builtin_prefetch (&pt->d, 0, 0); __builtin_prefetch (t.next, 0, 0); __builtin_prefetch (pt->next, 0, 0); __builtin_prefetch (t.next->d, 0, 0); __builtin_prefetch (pt->next->d, 0, 0); __builtin_prefetch (&b, 0, 0); __builtin_prefetch (pb, 0, 0); __builtin_prefetch (&b[2], 0, 0); __builtin_prefetch (&pb[3], 0, 0); __builtin_prefetch (b+3, 0, 0); __builtin_prefetch (b+j, 0, 0); __builtin_prefetch (pb+5, 0, 0); __builtin_prefetch (pb+j, 0, 0); } int main () { simple_global (); simple_file (); simple_static_local (); simple_local (); simple_arg (glob_int_arr, glob_ptr_int, glob_int); str.next = &str; expr_global (); expr_local (); exit (0); }
The command used for the compilation is: $ gcc -O2 -g small.c
Here is the reduced version of the code that triggers the bug: $ cat small.c int glob_int_arr[100]; int *glob_ptr_int = glob_int_arr; void simple_global () { __builtin_prefetch (glob_int_arr, 0, 0); __builtin_prefetch (glob_ptr_int, 0, 0); } int main() { simple_global (); exit (0); } $ gcc -w -O2 -g small.c; gdb -q a.out Reading symbols from a.out... (gdb) b main Breakpoint 1 at 0x401040: file small.c, line 6. (gdb) r Starting program: /root/devil/a.out Breakpoint 1, main () at small.c:6 6 __builtin_prefetch (glob_int_arr, 0, 0); (gdb) si 0x0000000000401044 in simple_global () at small.c:7 7 __builtin_prefetch (glob_ptr_int, 0, 0); (gdb) si 0x000000000040104b in main () at small.c:13 13 exit (0); (gdb) si 0x000000000040104d in simple_global () at small.c:6 6 __builtin_prefetch (glob_int_arr, 0, 0); (gdb)
I have verified that the latest trunk versions of GCC and GDB still exhibit the same problem. $ gcc --version gcc (GCC) 14.0.0 20231116 (experimental) Copyright (C) 2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gdb --version GNU gdb (GDB) 15.0.50.20231116-git Copyright (C) 2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
I can reproduce this: ... Temporary breakpoint 1, main () at small.c:10 10 __builtin_prefetch (glob_int_arr, 0, 0); (gdb) si 0x0000000000401044 in simple_global () at small.c:11 11 __builtin_prefetch (glob_ptr_int, 0, 0); (gdb) si 0x000000000040104b in main () at small.c:19 19 exit (0); (gdb) si 0x000000000040104d in simple_global () at small.c:10 10 __builtin_prefetch (glob_int_arr, 0, 0); (gdb) si 11 __builtin_prefetch (glob_ptr_int, 0, 0); ... When decoding the line numbers I see: ... small.c 11 0x401044 small.c 19 0x40104b small.c 10 0x40104d small.c 11 0x401054 ... which perfectly matches the progression we see. So gdb doesn't do anything wrong, it accurately show the line info as generated by gcc. So why does the insn at 0x40104b have line number 19? The disassembly is: ... 0000000000401040 <main>: 401040: 48 83 ec 08 sub $0x8,%rsp 401044: 48 8b 05 cd 2f 00 00 mov 0x2fcd(%rip),%rax # 404018 <glob_ptr_int> 40104b: 31 ff xor %edi,%edi 40104d: 0f 18 05 ec 2f 00 00 prefetchnta 0x2fec(%rip) # 404040 <glob_int_arr> 401054: 0f 18 00 prefetchnta (%rax) 401057: e8 d4 ff ff ff call 401030 <exit@plt> 40105c: 0f 1f 40 00 nopl 0x0(%rax) ... and the call to exit is represented by these two insns: ... 40104b: 31 ff xor %edi,%edi 401057: e8 d4 ff ff ff call 401030 <exit@plt> ... Optimization separated the two insns and that causes the "jumping" through the lines. AFAICT, this falls in the range of expected behaviour when debugging optimized code.
(In reply to Tom de Vries from comment #4) > I can reproduce this: > ... > Temporary breakpoint 1, main () at small.c:10 > 10 __builtin_prefetch (glob_int_arr, 0, 0); > (gdb) si > 0x0000000000401044 in simple_global () at small.c:11 > 11 __builtin_prefetch (glob_ptr_int, 0, 0); > (gdb) si > 0x000000000040104b in main () at small.c:19 > 19 exit (0); > (gdb) si > 0x000000000040104d in simple_global () at small.c:10 > 10 __builtin_prefetch (glob_int_arr, 0, 0); > (gdb) si > 11 __builtin_prefetch (glob_ptr_int, 0, 0); > ... > > When decoding the line numbers I see: > ... > small.c 11 0x401044 > small.c 19 0x40104b > small.c 10 0x40104d > small.c 11 0x401054 > ... > which perfectly matches the progression we see. > > So gdb doesn't do anything wrong, it accurately show the line info as > generated by gcc. > > So why does the insn at 0x40104b have line number 19? > > The disassembly is: > ... > 0000000000401040 <main>: > 401040: 48 83 ec 08 sub $0x8,%rsp > 401044: 48 8b 05 cd 2f 00 00 mov 0x2fcd(%rip),%rax # 404018 > <glob_ptr_int> > 40104b: 31 ff xor %edi,%edi > 40104d: 0f 18 05 ec 2f 00 00 prefetchnta 0x2fec(%rip) # 404040 > <glob_int_arr> > 401054: 0f 18 00 prefetchnta (%rax) > 401057: e8 d4 ff ff ff call 401030 <exit@plt> > 40105c: 0f 1f 40 00 nopl 0x0(%rax) > ... > and the call to exit is represented by these two insns: > ... > 40104b: 31 ff xor %edi,%edi > 401057: e8 d4 ff ff ff call 401030 <exit@plt> > ... > > Optimization separated the two insns and that causes the "jumping" through > the lines. > > AFAICT, this falls in the range of expected behaviour when debugging > optimized code. Thank you for your feedback. Following your advice, I have officially reported this issue to the GCC Bugzilla for further investigation. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112565
(In reply to Anonymous from comment #5) > Thank you for your feedback. Following your advice, That was not my advice. > I have officially > reported this issue to the GCC Bugzilla for further investigation. > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112565
(In reply to Tom de Vries from comment #6) > (In reply to Anonymous from comment #5) > > Thank you for your feedback. Following your advice, > > That was not my advice. > > > I have officially > > reported this issue to the GCC Bugzilla for further investigation. > > > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112565 I apologize for the misunderstanding. I didn't notice that you mentioned this behavior was expected.