Why most compilers can't do modulus calculation combination optimization?

Viewed 102
unsigned long f1(unsigned long num) {
    if (num % 5L == 0 && num % 3L == 0) { return 1000; }
    return 0;
}

unsigned long f2(unsigned long num) {
    if (num % 15L == 0) { return 1000; }
    return 0;
}

Compiler result:

f1(unsigned long):
        movabs  rdx, -3689348814741910323
        mov     rax, rdi
        mov     rcx, rdi
        mul     rdx
        mov     rax, rdx
        and     rdx, -4
        shr     rax, 2
        add     rdx, rax
        mov     rax, rdi
        sub     rcx, rdx
        movabs  rdx, -6148914691236517205
        mul     rdx
        mov     rax, rdx
        and     rdx, -2
        shr     rax
        add     rdx, rax
        sub     rdi, rdx
        or      rdi, rcx
        cmp     rdi, 1
        sbb     rax, rax
        and     eax, 1000
        ret
f2(unsigned long):
        movabs  rax, -1229782938247303441
        imul    rdi, rax
        movabs  rax, 1229782938247303441
        cmp     rax, rdi
        sbb     rax, rax
        not     rax
        and     eax, 1000
        ret

tried GCC, msvc, clang, Java C2, C# JIT
I think num % 5 == 0 && num % 3 == 0 can be optimized into num % 15 == 0, but most compilers won't do it.
Is there any situations that will make these compare different or just no one just think about it?

by icebp: godbolt link

1 Answers

This is surely not a comprehensive answer, but keep in mind that boolean operators in C use short-circuit evaluation. This means that for if (A && B), if A is false then B is never evaluated because the whole condition can never be true. Similarly for if (A || B), if A is true then B is never evaluated because the whole condition can never be false.

In your specific case, this means that if num % 5 == 0 is false, then it never has to evaluate num % 3 == 0 because the whole condition can never be true.

Related