强制编译器不优化无副作用的语句

GMa*_*ckG 11 c++ optimization

我正在阅读一些旧的游戏编程书籍,正如你们中的一些人可能知道的那样,在那一天,做一些黑客攻击通常比以标准方式做事更快.(转换floatint,屏蔽符号位,转换回绝对值,而不是仅调用fabs(),例如)

现在,使用标准库数学函数几乎总是更好,因为这些微小的东西无论如何都不是大多数瓶颈的原因.

但为了好奇,我仍然想做一个比较.所以我想确保在我描述时,我没有得到偏差的结果.因此,我想确保编译器不会优化没有副作用的语句,例如:

void float_to_int(float f)
{
    int i = static_cast<int>(f); // has no side-effects
}
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点?据我所知,做类似的事情i += 10仍然没有副作用,因此无法解决问题.

我唯一能想到的是拥有一个全局变量int dummy;,并且在执行类似的操作之后dummy += i,所以使用了值i.但我觉得这个虚拟操作会妨碍我想要的结果.

我正在使用Visual Studio 2008/G ++(3.4.4).

编辑

为了澄清,我希望最大限度地优化所有优化,以获得良好的个人资料结果.问题在于,由此可以优化出没有副作用的陈述,因此情况就是如此.

再次编辑

为了再次澄清,请阅读:我不是试图在某种生产代码中对其进行微观优化.

我们都知道旧的技巧不再有用了,我只是好奇他们是多么有用.只是好奇心.当然,如果不知道这些旧的黑客对现代CPU的表现如何,生活可以继续下去,但要知道它永远不会伤害.

所以告诉我"这些技巧不再有用了,不要试图微观优化等等"是一个完全忽略这一点的答案.我知道它们没用,我不使用它们.

过早引用Knuth是所有烦恼的根源.

fin*_*nnw 9

volatile变量shold的赋值永远不会被优化掉,所以这可能会给你想要的结果:

static volatile int i = 0;

void float_to_int(float f)
{
    i = static_cast<int>(f); // has no side-effects
}
Run Code Online (Sandbox Code Playgroud)


Sam*_*ell 7

所以我想确保在我描述时,我没有得到偏差的结果.因此,我想确保编译器不优化out语句

根据定义,你倾向于结果.

以下是如何修复尝试分析您编写的"虚拟"代码以进行测试的问题:对于分析,将结果保存到全局/静态数组,并将数组的一个成员打印到程序末尾的输出.编译器将无法优化任何放入数组的值计算的,但你还是会得到任何其他的优化它可以把以使代码快.


Geo*_*ips 6

在这种情况下,我建议你让函数返回整数值:

int float_to_int(float f)
{
   return static_cast<int>(f);
}
Run Code Online (Sandbox Code Playgroud)

然后,您的调用代码可以使用printf来执行它,以确保它不会优化它.还要确保float_to_int位于单独的编译单元中,因此编译器无法播放任何技巧.

extern int float_to_int(float f)
int sum = 0;
// start timing here
for (int i = 0; i < 1000000; i++)
{
   sum += float_to_int(1.0f);
}
// end timing here
printf("sum=%d\n", sum);
Run Code Online (Sandbox Code Playgroud)

现在将它与一个空函数进行比较,如:

int take_float_return_int(float /* f */)
{
   return 1;
}
Run Code Online (Sandbox Code Playgroud)

哪个也应该是外部的.

时间的差异应该让您了解您要测量的费用.


pet*_*hen 5

到目前为止我使用的所有编译器总是有效的:

extern volatile int writeMe = 0;

void float_to_int(float f)
{    
  writeMe = static_cast<int>(f); 
}
Run Code Online (Sandbox Code Playgroud)

请注意,这会影响结果,boith 方法应该写入writeMe.

volatile告诉编译器“可能会在您不通知的情况下访问该值”,因此编译器不能省略计算并删除结果。要阻止输入常量的传播,您可能还需要通过 extern volatile 运行它们:

extern volatile float readMe = 0;
extern volatile int writeMe = 0;

void float_to_int(float f)
{    
  writeMe = static_cast<int>(f); 
}

int main()
{
  readMe = 17;
  float_to_int(readMe);
}
Run Code Online (Sandbox Code Playgroud)

尽管如此,读取和写入之间的所有优化都可以“全力”应用。在检查生成的程序集时,对全局变量的读取和写入通常是很好的“栅栏”。

如果没有extern编译器,编译器可能会注意到永远不会引用对变量的引用,从而确定它不能是 volatile。从技术上讲,使用链接时间代码生成,这可能还不够,但我还没有找到一个具有攻击性的编译器。(对于确实删除访问权限的编译器,需要将引用传递给运行时加载的 DLL 中的函数)


小智 4

不幸的是,如果代码的行为就像没有发生优化一样,即使没有任何显式开关,编译器也可以根据需要进行尽可能多的优化。但是,如果您表明稍后可能会使用该值,您通常可以欺骗他们不这样做,所以我会将您的代码更改为:

int float_to_int(float f)
{
    return static_cast<int>(f); // has no side-effects
}
Run Code Online (Sandbox Code Playgroud)

正如其他人所建议的,您需要检查汇编器输出以检查此方法是否确实有效。