double var = 0.;
for(int i = 0; i < 1000000 ; i++)
{
var += sqrt(2.0);
}
std::cout << var << std::endl;
在MSVC2012下,是否有可能在优化开启的情况下,sqrt(2.0)将被调用的值替换,而不是称之为1 * 10 ^ 6次?
Asm看起来像这样,不确定它的解释:
; Line 6
push ebp
mov ebp, esp
sub esp, 84 ; 00000054H
push ebx
push esi
push edi
; Line 8
movsd xmm0, QWORD PTR __real@0000000000000000
movsd QWORD PTR _var$[ebp], xmm0
; Line 9
mov DWORD PTR _i$1[ebp], 0
jmp SHORT $LN3@main
$LN2@main:
mov eax, DWORD PTR _i$1[ebp]
add eax, 1
mov DWORD PTR _i$1[ebp], eax
$LN3@main:
cmp DWORD PTR _i$1[ebp], 1000000 ; 000f4240H
jge SHORT $LN1@main
; Line 11
sub esp, 8
movsd xmm0, QWORD PTR __real@4000000000000000
movsd QWORD PTR [esp], xmm0
call _sqrt
add esp, 8
fstp QWORD PTR tv85[ebp]
movsd xmm0, QWORD PTR tv85[ebp]
addsd xmm0, QWORD PTR _var$[ebp]
movsd QWORD PTR _var$[ebp], xmm0
; Line 12
jmp SHORT $LN2@main
编辑:
抱歉,上面是调试版....; 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
答案 0 :(得分:5)
如果我正确读取汇编转储,编译器会在调试版本的循环中保留sqrt
,并在优化版本中将其移出。但它可能更具攻击性;您显示的代码可以合法地优化到
std::cout << "1414213.56238\n" << std::flush;
as-if rule允许编译器执行任何不会改变程序“可观察行为”的 - 并且执行时间不算作可观察行为。编译器还允许“知道”所有标准库函数在此基础上执行和优化的内容。
答案 1 :(得分: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);
}
我认为应该无法优化调用,因为在编译时不知道该值,循环可能仍然是优化的,但您也可以传递计数器值。