编译器会用一次调用替换循环中对 sqrt(2) 的调用吗?

问题描述 投票:0回答:2
double var = 0.;
for(int i = 0; i < 1000000 ; i++)
{
    var += sqrt(2.0);
}
std::cout << var << std::endl;

在MSVC2012下,是否有可能在开启优化的发布下,

sqrt(2.0)
会被调用的值替换,而不是调用106次?

这是汇编输出,尽管我不确定如何解释它:

; Line 7
    push    ebp
    mov ebp, esp
    and esp, -8                 ; fffffff8H
; Line 11
    movsd   xmm0, QWORD PTR __real@4000000000000000
    call    __libm_sse2_sqrt_precise
    movsd   xmm2, QWORD PTR ?var@@3NA
    mov eax, 1000000                ; 000f4240H
$LL3@main:
    movapd  xmm1, xmm0
    addsd   xmm2, xmm1
    dec eax
    jne SHORT $LL3@main
    movsd   QWORD PTR ?var@@3NA, xmm2
; Line 13
    mov esp, ebp
    pop ebp
    ret 0
c++ loops compiler-optimization loop-invariant
2个回答
5
投票

如果我正确读取该程序集转储,编译器会将

sqrt
留在调试构建的循环中,并将其移出优化构建。但它本可以更加激进。您显示的代码可以合理地优化为

std::cout << "1414213.56238\n" << std::flush;

“as-if”规则允许编译器做“任何事情”,但不会改变程序的“可观察行为”——并且执行时间不计为可观察行为。编译器还可以“知道”所有标准库函数的作用并在此基础上进行优化。

这显然是按预期被调用的:

1
投票
movsd QWORD PTR [esp], xmm0 call _sqrt

编辑: 我能想到的一种强制编译器不优化调用而不更改优化标志的方法是在命令行上传递传递给
sqrt()
的值或从

stdin

:
读取它
double var = 0.;
double x;
cin >> x;
for(int i = 0; i < 1000000 ; i++) {
    var += sqrt(x);
}

我相信这应该使得优化调用变得不可能,因为该值在编译时未知,循环可能仍会被优化,但您也可以传递计数器值。
    

© www.soinside.com 2019 - 2024. All rights reserved.