编译器可以优化多个相同的函数调用

时间:2016-06-17 08:35:59

标签: c++ function optimization

有关编译器优化的大量问题和好答案关于"冗余函数调用"在SO(我不会发布链接),然而,我在SO上找不到任何关于多个相同函数调用的内容。

说我有这样的代码片段:

void fairlyComplexFunction(const double &angle)
{
    //do stuff and call "sin(angle)" very often in here
}

调用sin(angle)相当昂贵的操作,因为anglefairlyComplexFunction范围内的常量,所以每次正弦调用都会以相同的结果,所以只调用一次将是一个更好的方法:

void fairlyComplexFunction(const double &angle)
{
    const double sineOfAngle = sin(angle);
    //do stuff and use sineOfAngle very often in here
}

编译器是否能够以任何方式检测这些内容并为我优化,或者第二个示例是更好的方法?

2 个答案:

答案 0 :(得分:3)

正如评论中已经说明的那样,如果编译器可以检测到被调用的函数是纯函数(没有副作用,没有i / o,.. )。

一个带有g ++的小例子(https://godbolt.org/g/2b3Vgg

#include <cmath>

extern double g (double);

template <double (*F) (double)>
double f1 (double angle) {
  double x = 3 * F(angle) + F(angle);
  double y = F(angle) + F(angle) * F(angle);
  return x + y * F(angle);
}

template double f1<sin> (double);
template double f1<g> (double);

f1中,您有多次调用F函数和两个实例:

  • 一个std::sin - 任何理智的编译器都应该将其视为纯函数。
  • 一个extern函数,不能被视为纯函数。

如果查看生成的程序集*:

double f1<&sin>(double):
        subq    $8, %rsp
        call    sin
        ...
        ret

double f1<&(g(double))>(double):
        subq    $40, %rsp
        movsd   %xmm0, (%rsp)
        call    g(double)
        movsd   %xmm0, 8(%rsp)
        movsd   (%rsp), %xmm0
        call    g(double)
        movsd   8(%rsp), %xmm1
        mulsd   .LC0(%rip), %xmm1
        ...
        call    g(double)
        movsd   %xmm0, 16(%rsp)
        movsd   (%rsp), %xmm0
        call    g(double)
        movsd   %xmm0, 24(%rsp)
        movsd   (%rsp), %xmm0
        call    g(double)
        mulsd   24(%rsp), %xmm0
        movsd   16(%rsp), %xmm2
        ...
        call    g(double)
        mulsd   16(%rsp), %xmm0
        addsd   8(%rsp), %xmm0
        ...

你看到在sin的实例化中,g ++只进行一次函数调用(call sin),而在g的实例化中,你有6次调用。

所以,编译器可能会对纯函数的多次调用做一些优化,但我不会依赖它**并使用显式的中间变量,就像你的第二个例子。

*我删除了大部分生成的指令,但显示了所有call指令。

** clang即使使用-O3也不会对此进行优化(但-ffast-math也是如此)。

答案 1 :(得分:1)

如果可以证明sin没有任何副作用,它可以优化它。

但是,即使它可以,你的第二个版本也向读者和你自己明确表示所有代码应该使用相同的值并且没有任何用途是一个bug;错误和不确定性的空间较小。