【问题标题】:c++ loop compiler optimizationc++循环编译器优化
【发布时间】:2012-12-11 02:14:36
【问题描述】:
double var = 0.;
for(int i = 0; i < 1000000 ; i++)
{
    var += sqrt(2.0);
}
std::cout << var << std::endl;

在MSVC2012下,是否有可能在开启优化的release下,sqrt(2.0)会被call的值代替,而不是调用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

【问题讨论】:

  • 可能吗?是的,当然!为什么不呢?
  • “有可能吗?” - 是的。 “会吗?” - 我不知道。看看组装吧。
  • 看起来它并没有优化那个特定的东西,不,但是你在编译优化吗?
  • 好问题。我猜编译器不知道 sqrt 将始终使用相同的参数获得相同的值。我不知道如何解决它
  • 如果 OP 开启了激进的浮点优化,结果可能会有所不同——我不知道 MSVC 怎么称呼那个特定的切换,但它肯定有一些相当于 GCC 的 -ffast-math

标签: c++ optimization loops


【解决方案1】:

如果我正确读取了该程序集转储,编译器会将sqrt 留在调试构建的循环中,并在优化构建中将其移出。但它本可以更具侵略性。您显示的代码可能会合法地优化为

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

as-if rule 允许编译器执行任何不改变程序“可观察行为”的事情——并且执行时间不计为可观察行为。编译器还可以“了解”所有标准库函数的功能并在此基础上进行优化。

【讨论】:

    【解决方案2】:

    显然是按预期调用的:

    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);
    }
    

    我认为应该无法优化调用,因为在编译时该值是未知的,循环可能仍被优化但您也可以传递计数器值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-21
      • 1970-01-01
      • 2015-09-30
      相关资源
      最近更新 更多