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).