C 为什么大多数编译器可以';做模数计算组合优化?
编译器结果:C 为什么大多数编译器可以';做模数计算组合优化?,c,gcc,compiler-construction,compiler-optimization,C,Gcc,Compiler Construction,Compiler Optimization,编译器结果: 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; } 尝试过GCC、msvc、clang、Java C2、C
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;
}
尝试过GCC、msvc、clang、Java C2、C#JIT我认为
num%5==0&&num%3==0
可以优化为num%15==0
,但大多数编译器不会这样做。是否有任何情况会使这些比较不同,或者只是没有人去想它
这肯定不是一个全面的答案,但请记住,C语言中的布尔运算符使用。这意味着对于
如果(A和&B)
,如果A
为false,则永远不会计算B
,因为整个条件永远不会为true。类似地,对于如果(A | | B)
,如果A
为真,则永远不会计算B
,因为整个条件永远不会为假
在您的特定情况下,这意味着如果
num%5==0
为false,则它永远不必计算num%3==0
,因为整个条件永远不可能为true。不要发布代码图像。以文本形式发布。您可以发布一个指向godbolt的链接:可能这只是一个非常不常见的模式,因此编译器无法将其识别为可优化模式。如果我们将除数更改为4L
和8L
,则。这证明优化不存在语义障碍,也不存在排序、可观察或未定义行为的问题。因此,正如Eugene Sh.所说,原因很可能只是该模式不常见,因此希望将其添加到编译器中,而不是出现这种情况。@EricPostphil抱歉,重读我的评论,它看起来很粗鲁,这不是我的目标。关键是,我们每天都有问题问编译器为什么不执行优化,答案几乎总是他们不执行,因为没有人实现它。如果人们关心这个优化,并且不能自己实现它,他们可以提交一个bug/增强报告。如果他们真的想要它,他们可以花钱让人来实现它。如果我将&&to&,godbolt会显示相同的编译结果:这根本不是原因。在这种情况下,所谓的短路规则并不是优化的障碍,因为代码具有相同的语义,无论正确的操作数是被计算并丢弃还是从未计算过。啊,好吧,是的,我不确定这是否相关。但我认为这是值得指出的。也许作为一个评论会更好,但我在这方面还没有足够的声誉。如果%3
和%5
比%15
便宜,这将是一个原因。但看起来他们不是
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