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;
}
编译器结果:
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
尝试了GCC、MSVC、clang、Java C2和C# JIT。
我认为num % 5 == 0 && num % 3 == 0
可以优化成num % 15 == 0
,但大多数编译器都不会这么做。
有没有情况会导致这些比较不同或只是没有人考虑过?
作者:icebp,godbolt链接在此
4L
和8L
,那么 GCC 会合并测试。这证明了进行这种优化没有语义障碍——不涉及顺序、可观察或未定义行为的问题。因此,正如 Eugene Sh. 提出的那样,原因很可能只是该模式不常见,因此没有将其添加到编译器中的需求出现。 - Eric Postpischil