Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC won't optimize integer arithmetic expression

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
like image 445
Gabriel Garcia Avatar asked May 30 '26 11:05

Gabriel Garcia


1 Answers

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

like image 188
yugr Avatar answered Jun 02 '26 00:06

yugr