编译器是否会将常量参数转换为唯一指令来简化简单函数?

Tho*_*mas 4 c c++ optimization gcc compiler-optimization

这是我一直认为是真实的,但从未进行任何验证.考虑一个非常简单的功能:

int subtractFive(int num) {
    return num -5;
}
Run Code Online (Sandbox Code Playgroud)

如果对此函数的调用使用编译时常量,例如

  getElement(5);
Run Code Online (Sandbox Code Playgroud)

打开优化的编译器很可能会内联这个.然而,我不清楚的是,如果在运行时或编译时评估num-5.表达式简化是否会以这种方式通过内联函数递归递增?或者它没有超越功能?

Bau*_*gen 13

我们可以简单地查看生成的程序集以找出答案.这段代码:

int subtractFive(int num) {
    return num -5;
}

int main(int argc, char *argv[]) {
  return subtractFive(argc);
}
Run Code Online (Sandbox Code Playgroud)

g++ -O2收益率编制

leal    -5(%rdi), %eax
ret
Run Code Online (Sandbox Code Playgroud)

所以函数调用确实简化为单个指令.这种优化技术称为内联.

当然可以使用相同的技术来查看编译器将使用多远,例如稍微复杂一点

int subtractFive(int num) {
    return num -5;
}

int foo(int i) {
    return subtractFive(i) * 5;
}

int main(int argc, char *argv[]) {
  return foo(argc);
}
Run Code Online (Sandbox Code Playgroud)

仍然被编译到

leal    -25(%rdi,%rdi,4), %eax
ret
Run Code Online (Sandbox Code Playgroud)

所以这里的两个函数都在编译时被删除了.如果输入to foo在编译时是已知的,则函数调用(在这种情况下)将简单地在编译时(生存)由结果常量替换.

编译器还可以将此内联与常量折叠组合在一起,如果所有参数都是编译时常量,则将函数调用替换为完全评估的结果.例如,

int subtractFive(int num) {
    return num -5;
}

int foo(int i) {
    return subtractFive(i) * 5;
}

int main() {
  return foo(7);
}
Run Code Online (Sandbox Code Playgroud)

编译成

mov     eax, 10
ret
Run Code Online (Sandbox Code Playgroud)

这相当于

int main () {
    return 10;
}
Run Code Online (Sandbox Code Playgroud)

编译器将始终在认为这是一个好主意的情况下执行此操作,并且(通常)在优化此级别上的代码方面(通常)更好.