https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88000
Bug ID: 88000 Summary: Different local vars regs order may produce different and so wrong code Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: dominik.b.czarnota+bugzilla at gmail dot com Target Milestone: --- Depending on the order of two register local variables definition, when compiled with optimizations (-O1 / -O2 / -O3 or -Og), GCC may emit code that will not use the value assigned to the variable at all. This bug seems to be introduced in GCC 7.2 (tested with godbolt.org) and have been tested only on x86-64 targets. You can see a minimal working example below: ``` #include <stdio.h> void bar(int x) { printf("x = %d\n", x); } int main() { // if we change the order of those two lines // gcc will emit a proper `mov edi, 11` // otherwise, it fails to do so since gcc 7.2 // when compiled with -O1/2/3/g register int b asm("r11") = 11; register int a asm("r12") = 22; // also, if `b` is any of the registers that are // supposed to be preserved by the called function, // gcc will also emit proper code // (so any of: rbp, rbx, r12-r15) // the `a` register seem to not matter bar(a); bar(b); } ``` Tested locally on a GCC 7.3. The `main.c` is the program shown above, `main_rev.c` is the one with `b` and `a` variables definitions swapped: ``` $ gcc main.c -O1 && ./a.out x = 22 x = 582 $ gcc main_rev.c -O1 && ./a.out x = 22 x = 11 ``` The difference can be seen in the disassembly: ``` $ gcc -O1 main.c && gdb -batch -ex 'file ./a.out' -ex 'set disassembly-flavor intel' -ex 'disassemble main' Dump of assembler code for function main: 0x000000000000068b <+0>: sub rsp,0x8 0x000000000000068f <+4>: mov edi,0x16 0x0000000000000694 <+9>: call 0x66a <bar> 0x0000000000000699 <+14>: mov edi,r11d 0x000000000000069c <+17>: call 0x66a <bar> 0x00000000000006a1 <+22>: mov eax,0x0 0x00000000000006a6 <+27>: add rsp,0x8 0x00000000000006aa <+31>: ret End of assembler dump. $ gcc -O1 main_rev.c && gdb -batch -ex 'file ./a.out' -ex 'set disassembly-flavor intel' -ex 'disassemble main' Dump of assembler code for function main: 0x000000000000068b <+0>: push r12 0x000000000000068d <+2>: mov edi,0x16 0x0000000000000692 <+7>: call 0x66a <bar> 0x0000000000000697 <+12>: mov edi,0xb 0x000000000000069c <+17>: call 0x66a <bar> 0x00000000000006a1 <+22>: mov eax,0x0 0x00000000000006a6 <+27>: pop r12 0x00000000000006a8 <+29>: ret End of assembler dump. ``` As written in the comment, it seems that this change happens only if the `b` is assigned to a register that can be clobbered (and so different than rbp, rbx, r12-r15).