编译器是否自动优化对数学函数的重复调用

Do compilers automatically optimise repeated calls to mathematical functions?

本文关键字:函数 调用 是否 优化 编译器      更新时间:2023-10-16

假设我有这段代码:

#include <cmath>
// ...
float f = rand();
std::cout << sin(f) << " " << sin(f);

由于sin(f)是一个定义明确的函数,因此可以轻松优化:

float f = rand();
float sin_f = sin(f);
std::cout << sin_f << " " << sin_f;

这是否是一种优化,期望现代C++编译器自行完成是合理的?还是编译器无法确定sin(f)应始终为相等的 f 值返回相同的值?

使用使用默认优化标志构建的 g++:

float f = rand();
40117e: e8 75 01 00 00          call   4012f8 <_rand>
401183: 89 44 24 1c             mov    %eax,0x1c(%esp)
401187: db 44 24 1c             fildl  0x1c(%esp)
40118b: d9 5c 24 2c             fstps  0x2c(%esp)
std::cout << sin(f) << " " << sin(f);
40118f: d9 44 24 2c             flds   0x2c(%esp)
401193: dd 1c 24                fstpl  (%esp)
401196: e8 65 01 00 00          call   401300 <_sin>  <----- 1st call
40119b: dd 5c 24 10             fstpl  0x10(%esp)
40119f: d9 44 24 2c             flds   0x2c(%esp)
4011a3: dd 1c 24                fstpl  (%esp)
4011a6: e8 55 01 00 00          call   401300 <_sin>  <----- 2nd call
4011ab: dd 5c 24 04             fstpl  0x4(%esp)
4011af: c7 04 24 e8 60 40 00    movl   $0x4060e8,(%esp)

内置-O2

float f = rand();
4011af: e8 24 01 00 00          call   4012d8 <_rand>
4011b4: 89 44 24 1c             mov    %eax,0x1c(%esp)
4011b8: db 44 24 1c             fildl  0x1c(%esp)
std::cout << sin(f) << " " << sin(f);
4011bc: dd 1c 24                fstpl  (%esp)
4011bf: e8 1c 01 00 00          call   4012e0 <_sin>  <----- 1 call

由此我们可以看到,在没有优化的情况下,编译器使用 2 个调用,只有 1 个优化,根据经验,我想,我们可以说编译器确实优化了调用。

我相当确定GCC用非标准的纯属性标记sin,即__attribute__ ((pure));

这具有以下效果:

许多函数除了返回值之外没有任何影响,它们的返回值仅取决于参数和/或全局变量。这样的函数可以像算术运算符一样进行公共子表达式消除和循环优化。

http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

因此,这种纯调用很有可能通过公共子表达式消除进行优化。

(更新:实际上CMAhA正在使用ConstexPR,这意味着相同的优化)