【问题标题】:Does compilers move skip checks to outside the function call?编译器是否将跳过检查移到函数调用之外?
【发布时间】:2013-05-25 23:46:58
【问题描述】:

函数或方法如:

void DoSomething(...){

  if( ... ) return;

  ...
}

如果满足条件,则检查是否跳过整个函数。编译器是否将检查代码移到函数/方法之外以避免无用的函数调用?

【问题讨论】:

  • 可能不会,考虑到一个函数可以在一百个不同的位置调用。这些“跳过检查”必须插入到每个位置。函数调用的成本很大程度上取决于传递的参数。
  • 据我所知,if() 不会被移到外面。你能解释一下你为什么对这个感兴趣吗?
  • 如果if 总是评估为真(以某种编译时可确定的方式),那么函数的重置可以被优化掉,但如果是这种情况,你可能会看到一个编译器警告告诉你 if 总是正确的
  • 大多数编译器优化器会整体内联函数,而不仅仅是部分函数。

标签: c++ optimization compiler-construction


【解决方案1】:

这取决于编译器。使用 gcc on -O3 调用会被忽略。

为了尝试,我写道:

int g;                                       

int dosomething(int x) {                     
    if (x == 0) return g;                    

    int y = 0;                               
    for (int i = 0; i < x; i++)              
        y += i;                              
    return y;                                
}                                            

int docall() {                               
    return dosomething(0);                   
} 

(有一个全局变量可以确保最后一次调用不会被 优化)使用 -s 编译但没有 O 标志我在汇编程序中得到了这个:

_Z6docallv:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $0, %edi
    call    _Z11dosomethingi
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret

有一个以 0 作为参数的对 dosomething 的完整调用,而使用 -O3 我得到:

_Z6docallv:
.LFB1:
    .cfi_startproc
    movl    g(%rip), %eax
    ret

所以它返回dsomething的默认值而不调用它。

【讨论】:

  • 如果将参数更改为 0 以外的其他值,它仍然不会插入函数调用。所以它不会将 if 移到函数之外——它只是内联(然后是常量折叠和死代码删除)整个函数。
  • 是的,我认为这就是问题所在。但你是对的,这是关于在呼叫点移动支票。是的,没有那样的。
【解决方案2】:

如果满足if 条件,则将执行return 语句并跳过函数的其余部分。 如果不是,则执行函数体的其余部分(取决于函数体)。

【讨论】:

  • 你读过这个问题吗?你明白被问到什么了吗?因为你的回答根本没有解决问题。
猜你喜欢
  • 1970-01-01
  • 2021-08-06
  • 2015-05-04
  • 1970-01-01
  • 2022-01-12
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
相关资源
最近更新 更多