如何不优化 - 愚蠢功能的机制

How not to optimize away - mechanics of a folly function

我正在寻找一种编程技术,以确保用于基准测试的变量(没有可观察到的副作用)不会被编译器优化掉

This gives some info, but I ended up using folly 和下面的函数

/**
 * Call doNotOptimizeAway(var) against variables that you use for
 * benchmarking but otherwise are useless. The compiler tends to do a
 * good job at eliminating unused variables, and this function fools
 * it into thinking var is in fact needed.
 */
#ifdef _MSC_VER

#pragma optimize("", off)

template <class T>
void doNotOptimizeAway(T&& datum) {
  datum = datum;
}

#pragma optimize("", on)

#else
template <class T>
void doNotOptimizeAway(T&& datum) {
  asm volatile("" : "+r" (datum));
}
#endif

我想使用上面的,但我对其工作原理了解甚少。我最感兴趣的是非 VC++ 部分和 why/how 行

asm volatile("" : "+r" (datum));

创建一个不可优化的上下文或为什么人们会选择实现这样的东西。这两种方法之间的比较也很有趣(我不知道 pragma optimize 是如何工作的,但它看起来像是一个更干净的解决方案 - 虽然不可移植)

没有禁用优化的标准方法,因此如果您需要禁用优化,您只能使用您的实施恰好提供的任何内容。比较这两种方法没有意义,除非您找到同时支持这两种方法的编译器。

无论如何,在 GCC 中,

asm volatile("" : "+r" (datum));

表示用户提供的未经验证的汇编代码被嵌入到GCC生成的程序集中。第一个字符串文字 ("") 包含要注入的汇编代码。它是空的,所以实际上根本没有发出任何代码。

:之后的部分通知GCC汇编代码的作用。 "+r" (datum) 意味着 GCC 应该假定汇编代码读取并修改 datum。即使它没有。这样做的原因是,任何早期的计算最终都会将值存储在 datum 中,因此不能因为不必要而被丢弃。同时,由于对 datum 的潜在修改,汇编代码本身不能因为不必要而被丢弃。 volatile 还将汇编代码标记为不得优化掉的代码,as documented here:

GCC's optimizers sometimes discard asm statements if they determine there is no need for the output variables. Also, the optimizers may move code out of loops if they believe that the code will always return the same result (i.e. none of its input values change between calls). Using the volatile qualifier disables these optimizations. [...]

使用两种不同的方法来防止汇编代码被删除似乎有点过分,真的,但我想最好确定一下。

r 约束意味着代码并不关心 GCC 提供给汇编代码使用的寄存器,is documented here:

‘r’
    A register operand is allowed provided that it is in a general register.

+ 修饰符表示代码可以读取和写入 datum,并且 is documented here:

‘+’
    Means that this operand is both read and written by the instruction. [...]