int f(int x, int y) {
return 20 * (x - 10) + 50 * (x + 5);
}
int f_expected(int x, int y) {
return 70 * x + 50;
}
The generated code is:
f(int, int):
lea eax, [rdi-50+rdi*4]
add edi, 5
imul edi, edi, 50
lea eax, [rdi+rax*4]
ret
f_expected(int, int):
imul eax, edi, 70
add eax, 50
ret
I expect f to be compiled to f_expected. I tried -O3 and -Ofast on GCC 7. Which flag am I looking for, exactly (if any)? clang and icc produce the expected code under -O3.
For reference, clang code:
f(int, int):
imul eax, edi, 70
add eax, 50
ret
f_expected(int, int):
imul eax, edi, 70
add eax, 50
ret
This happens because GCC is scared to introduce signed integer overflow which didn't exist in original version (and which will cause undefined behavior in program). You can force GCC to allow signed overflow by adding -fwrapv to CFLAGS but this would bring other issues (e.g. inability to optimize some loops).
$ gcc tmp.c -S -o- -O2
...
leal -50(%rdi,%rdi,4), %eax
movl $50, %edx
addl $5, %edi
imull %edx, %edi
leal (%rdi,%rax,4), %eax
ret
$ gcc tmp.c -S -o- -O2 -fwrapv
...
movl %edi, %eax
movl $70, %edx
imull %edx, %eax
addl $50, %eax
ret
Now Clang is able to somehow figure out that UB isn't present in original code so this may be a missing optimization in GCC (which I encourage you to report to their Bugzilla).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With