基于常量函数参数的编译时优化

3

我有两个函数void f(int x){...}void g(int x){f(x);}。我知道99%的情况下g()接收到的参数是3或5。在f()中,x从不改变并监督很多循环和条件分支。以下代码是否比我的原始代码更快?

void g(int x)
{
  if(x == 3) f(3);
  else if(x == 5) f(5);
  else f(x);
}

编译器(g++ -Ofast)会将f(3)f(5)分别编译,类似于编译两个模板参数吗?我还需要做什么才能让编译器更容易地认识到优化机会?声明void f(const int &x){...}有帮助或必要吗?


1
如果在f()和/或g()中,x的值没有变化,最好将其作为const传递。不确定是否能够提高性能,但肯定可以告诉编译器x是不可变的状态。 - CinCout
检查汇编代码,有可能会编译成完全相同的东西。如果需要提示,请参考类似于“__bulitin_expect”的内容。 - Passer By
2个回答

1
这类问题的答案最终都是误导性的,因为它们不仅取决于您使用的确切环境,还取决于您的项目将与之链接的其他代码(如果使用链接时间优化)。此外,编译器可以生成多个版本 - 其中一些更“优化”,然后“优化程度”取决于谁调用g()。如果g()是constexpr-那么就是这样,编译器可以利用这个事实来指导优化。
无论如何:您需要查看编译器的输出;以编译成您的项目的代码形式。只有这样你才能知道。作为前奏,您应该前往https://godbolt.org上的Compiler Explorer,在一个隔离的环境中亲自查看。

1
如果这是一个性能关键的函数,99%的时间会调用f(3)或f(5),而你正在尝试优化,那么你应该测量这些调用的差异。如果f()是一个内联函数,优化器可能比变量更好地处理您的常量,以使其某些功能在编译时评估(如常量折叠、强度降低等)。可以使用Godbolt.org查看汇编并查看是否存在任何明显的改进。即使它没有被内联,LTO也可能有所帮助,尽管不同的人报告了不同程度的成功。
如果您没有看到太多改进,但认为事先了解x可能会有一些改进,您还可以考虑编写不同的专门版本的f(),例如f3()和f5(),这些版本针对这些情况进行了优化(尽管您可能还会遇到更大的指令和icache问题)。最重要的是要测量。为了优化而使代码复杂并没有乐趣(或更糟糕的是,在优化的名义下减慢它的速度)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接