Consider some dead-simple code (or a more complicated one, see below1) that uses an uninitialized stack variable, e.g.:
int main() { int x; return 17 / x; }
Here's what GCC emits (-O3
):
mov eax, 17
xor ecx, ecx
cdq
idiv ecx
ret
Here's what MSVC emits (-O2
):
mov eax, 17
cdq
idiv DWORD PTR [rsp]
ret 0
For reference, here's what Clang emits (-O3
):
ret
The thing is, all three compilers detect that this is an uninitialized variable just fine (-Wall
), but only one of them actually performs any optimizations based on it.
This is kind of stumping me... I thought all the decades of fighting over undefined behavior was to allow compiler optimizations, and yet I'm seeing only one compiler cares to optimize even the most basic cases of UB.
Why is this? What do I do if I want compilers other than Clang to optimize such cases of UB? Is there any way for me to actually get the benefits of UB instead of just the downsides with either compiler?
Footnotes
1 Apparently this was too much of an SSCCE for some folks to appreciate the actual issue. If you want a more complicated example of this problem that isn't undefined on every execution of the program, just massage it a bit. e.g.:
int main(int argc, char *[])
{
int x;
if (argc) { x = 100 + (argc * argc + x); }
return x;
}
On GCC you get:
main:
xor eax, eax
test edi, edi
je .L1
imul edi, edi
lea eax, [rdi+100]
.L1:
ret
On Clang you get:
main:
ret
Same issue, just more complicated.