【发布时间】:2016-09-04 05:00:34
【问题描述】:
我有一个简单的程序:
#include <cmath>
int main()
{
for (int i = 0; i < 50; ++i)
std::sqrt(i);
}
Clang 3.8 在-O3 优化它,但gcc 6.1 没有。它产生以下程序集:
## Annotations in comments added after the question was answered,
## for the benefit of future readers.
main:
pushq %rbx
xorl %ebx, %ebx
jmp .L2
.L4:
pxor %xmm0, %xmm0 # break cvtsi2sd's false dep on the old value of xmm0
pxor %xmm1, %xmm1 # xmm1 = 0.0
cvtsi2sd %ebx, %xmm0 # xmm0 = (double)i
ucomisd %xmm0, %xmm1 # scalar double comparison, setting flags
ja .L7 # if (0.0 > (double)i) sqrt(i); // The `a` = above. AT&T syntax reverses the order, but it's jump if xmm1 above xmm0
.L2:
addl $1, %ebx # i++
cmpl $50, %ebx
jne .L4 # i != 50
xorl %eax, %eax
popq %rbx
ret # return 0
.L7:
call sqrt # only executed on i < 0. Otherwise gcc knows std::sqrt has no side effects.
jmp .L2
如果我正确理解 as-if 规则,则允许编译器优化不会改变程序可观察行为的代码,包括 I/O 写入等。我丢弃std::sqrt 的结果并且不做任何I/O。此外,我的程序中没有#pragma STDC FENV_ACCESS。 std::sqrt 是否有可观察到的副作用,还是 GCC 没有优化调用的其他原因?
(这个问题的初始版本有一个上限10e50,使它成为一个无限循环。同样的事情发生在50,所以nvm关于这个问题。)
【问题讨论】:
-
@Michael
std::sqrt是实现的一部分,所以编译器可以知道它做了什么。 -
sqrt可能有一个高度优化的汇编器实现,这使得 gcc 很难证明它没有副作用。 -
它与 -ffast-math 一起使用。没有它,sqrt 可以设置 errno (编辑:等等,那只是 C 平方根吗?e2: ok std::sqrt 也是),所以它可能看不到(或没有尝试看到)它不会。
-
谁在乎?你不会写这段代码。
-
-fno-math-errno?
标签: c++ gcc optimization