编译器是否优化了内联函数的局部变量

Does compiler optimize inline function's local variables

本文关键字:函数 局部变量 是否 优化 编译器      更新时间:2023-10-16

现在我正在阅读Inside The C++ Object Model这本书的第四部分,并有一些问题。

像这样的内联函数:

inline int max(int a, int b)
{
    return (a > b) ? a : b;
}

然后,一个如下的语句:a = max(x, y);

该语句将转换为a = (x > y) ? x : y;

但书中说,当向内联函数添加局部变量时,如下所示:

inline int max(int a, int b)
{
    int maxval = (a > b) ? a : b;
    return maxval;
}

它将转变为

int __max_lv_maxval;
a = (__max_lv_maxval = (x > y) ? x : y), __max_lv_maxval;

很明显,该功能的性能会下降。

我的问题是编译(如VC2010、gcc)是否优化了内联函数并删除了局部变量?

这本书似乎假设编译器在源代码级别内联,这当然完全取决于编译器。大多数都将在AST级别开始内联,在那里可以并且将发生转换和某些优化。这一切都假设编译器内联代码。

如果我们查看您的函数,任何像样的编译器都会将它们转换为相同的IR代码,因为它会在内联函数之前对其进行编译,因此无论何时(在IR级别)都需要临时的。当IR被实际内联时,临时将被折叠起来,取而代之的是调用max的分配目的地。

当我们编译到机器代码时,情况可能会发生更大的变化,不仅可以删除临时性,而且目标很可能是一个寄存器(在这种情况下),它可能也会用于任何源操作数。

底线:这完全取决于您的编译器、优化级别以及它如何进行变量活泼性分析、值传播和折叠。

我们可以对代码进行任何有趣的转换,编译器也可以。然后是一些!

当编译器可以看到

inline int max(int a, int b) 
{
     return (a > b) ? a : b; 
} 
a = max(x, y);

可以转换为

 a = (x > y) ? x : y;

它还可以很容易地看出,将值存储到以后再也不用的变量中是没有意义的。存储(和变量)可以在不更改程序结果的情况下删除。

小函数中的局部变量通常保存在CPU寄存器中,根本不会存储在内存中。

inline int max(int a, int b)
{
    return (a > b) ? a : b;
}

然后,一个语句如下:a = max(x, y);

该语句将转换为a = (x > y) ? x : y;

事情没那么简单。inline是一个提示,而不是一个要求。关键字确实会稍微更改规则,但不会强制内联。你还忘记了ab也是max函数的局部变量,而假设局部变量不能被优化掉的同一本书假设这些局部变量可以被优化掉。在安全的情况下,它们可能会被优化掉,也可能不会,这取决于编译器和编译器选项。对于在调试器中运行,保留它们可能更有意义。当这样做不安全时,例如当xyvolatile时,它们可能而不是被优化掉。在这种情况下,(x > y) ? x : y读取其中一个两次,这是一种潜在的可见行为变化,因此是无效的。

编译器就像您展示的那样。如果我们把这个内联称为有趣的

void example()
{
  int m = max(10, 11);
}

扩展将是

{
  int __max_lv_maxval;// mangled inline local variable  
 int m = (__max_lv_maxval = (x > y) ? x : y), __max_lv_maxval;
}

通常,内联函数中的每个局部变量都必须引入到调用的封闭块中作为唯一命名的变量。海湾合作委员会不会为你做更多的事情。