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

标签 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
}

编译器是否能够以任何方式检测此类事情并为我优化它,或者第二个示例是更好的方法?

最佳答案

如评论中所述,如果编译器能够检测到被调用函数是一个纯函数(没有副作用,没有 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)。

关于c++ - 编译器可以优化多个相同的函数调用吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37876815/

相关文章:

c++ - 以编程方式将 LAN 计算机名称解析为完全限定名称?

c++ - 您从经验中学到了哪些与 C++ 相关的习语、误解和陷阱?

c++ - 可以 std::map 键地址值的数量吗?

javascript - Angular 。如何不重复相同的功能

c++ - 什么是复制省略和返回值优化?

c - 一条 switch 语句占用多少代码空间?

C++ 映射 - 表达式必须是整型常量表达式

java - 如何将函数和方法合并到 Java 中的 if-else 条件中?

arrays - Perl:如何在不创建数组副本的情况下取消引用数组?

optimization - 为什么 Java API 使用 int 而不是 short 或 byte?