While writing an answer regarding how compilers must treat volatile
, I believe I may have stumbled upon a gcc bug and would like someone to verify before I report it.
I wrote up a simple function such as this:
int foo (int a, int b, int c)
{
b = a + 1;
c = b + 1;
a = c + 1;
return a;
}
Without optimizations this results in a lot of pointless moving of data back and forth. With optimizations the compiler just grabs the register where a
was stored, then adds 3 and returns that result. To speak x86 lea eax, [rdi+3]
and ret
. This is expected, so far so good.
To demonstrate sequencing and volatile access, I changed the example to this:
int foo (int a, int b, int c)
{
b = a + 1;
c = *(volatile int*)&b + 1;
a = c + 1;
return a;
}
Here there's a lvalue access of the contents of b
that is volatile qualified and as far as I can tell, the compiler is absolutely not allowed to optimize away that access1). From gcc 4.1.2 (and probably earlier) to gcc 10.3 I get conforming behavior (same in clang). The x86 machine code looks like this even with -O3
:
foo:
add edi, 1
mov DWORD PTR [rsp-4], edi
mov eax, DWORD PTR [rsp-4]
add eax, 2
ret
Then I try the same on gcc 11.1 and beyond, now I get:
foo:
lea eax, [rdi+3]
ret
https://godbolt.org/z/e5x74z3Kb
ARM gcc 11.1 does something similar.
Is this a compiler bug?
1) References: ISO/IEC 9899:2018 5.1.2.3, particularly §2, §4 and §6.
uintptr_t x = (uintptr_t)&b; c = *(volatile int*)x + 1;
but it gets optimized away too. – Maguirevolatile int
. What you're describing would be*(int *volatile)&b
and indeed lets the access optimize away even with older GCC like 9.4 that don't have the bug(?) described in this question. godbolt.org/z/bs31xveYK (the volatile-qualified pointer object result of the cast is never materialized anywhere, which is fine since it's only an rvalue) – Lipetskvolatile int*
is a pointer to volatile data. – Claustrophobia-std=c2x
and eventually it will get fixed since C23 changes the behavior of volatile lvalue access. Or you can rollback to gcc 10 or earlier. Bug fixes are never a priority in open source projects, alas. gcc has a long tradition of focusing all efforts on optimization and implementing non-standard features that nobody asked for... – Maguire