在某个库(FFTW:离散傅里叶变换计算)中,我遇到了一个头文件,其中包含以下注释,一些#定义如下。这则评论谈到了一些编程技巧。但我无法理解这个编程技巧到底是什么。谁能解释一下吗?
/* hackery to prevent the compiler from ``optimizing'' induction
variables in codelet loops. The problem is that for each K and for
each expression of the form P[I + STRIDE * K] in a loop, most
compilers will try to lift an induction variable PK := &P[I + STRIDE * K].
For large values of K this behavior overflows the
register set, which is likely worse than doing the index computation
in the first place.
If we guess that there are more than
ESTIMATED_AVAILABLE_INDEX_REGISTERS such pointers, we deliberately confuse
the compiler by setting STRIDE ^= ZERO, where ZERO is a value guaranteed to
be 0, but the compiler does not know this.
16 registers ought to be enough for anybody, or so the amd64 and ARM ISA's
seem to imply.
*/
#define ESTIMATED_AVAILABLE_INDEX_REGISTERS 16
#define MAKE_VOLATILE_STRIDE(nptr, x) \
(nptr <= ESTIMATED_AVAILABLE_INDEX_REGISTERS ? \
0 : \
((x) = (x) ^ X(an_INT_guaranteed_to_be_zero)))
#endif /* PRECOMPUTE_ARRAY_INDICES */发布于 2015-07-23 11:25:43
优化:一些编译器没有在循环中每次迭代时重新计算数组的索引,而是预测下一个地址并将它们放入寄存器中,因为索引表达式是可预测的。
问题是:一些索引表达式(如I + STRIDE * K)可能导致大量寄存器的使用,如果这个数目超过寄存器的总数,一些寄存器值将被推入堆栈内存,包括循环可能使用的其他变量。
诀窍:为了迫使编译器不使用这种优化,使用了一个外部整数。添加或异或将此零添加或存储在x中是一个“污染”步幅的无操作操作,因此也就是索引表达式,通过优化分析使其不可预测。即使我们知道它的行为非常零,它也无法推断这个变量的行为。从中派生的文件ifftw.h的相关摘录:
extern const INT X(an_INT_guaranteed_to_be_zero);
#ifdef PRECOMPUTE_ARRAY_INDICES
...
#define MAKE_VOLATILE_STRIDE(nptr, x) (x) = (x) + X(an_INT_guaranteed_to_be_zero)
#else
...
#define ESTIMATED_AVAILABLE_INDEX_REGISTERS 16
#define MAKE_VOLATILE_STRIDE(nptr, x) \
(nptr <= ESTIMATED_AVAILABLE_INDEX_REGISTERS ? \
0 : \
((x) = (x) ^ X(an_INT_guaranteed_to_be_zero)))
#endif /* PRECOMPUTE_ARRAY_INDICES */尝试完全避免这种优化,或者允许在索引能够适合猜测可用寄存器数量的条件下进行优化。它允许优化的方式是使用常数为零。
一些词源:宏MAKE_VOLATILE_STRIDE从易失性关键字派生其名称,该关键字指示一个值在不同的访问之间可能会发生变化,即使它似乎没有被修改。此关键字可防止优化编译器对后续的读或写进行优化,从而错误地重用陈旧的值或省略写入。(维基百科)
我不知道为什么可变关键字(而不是XOR‘’ing外部值)是不够的。
https://stackoverflow.com/questions/31536087
复制相似问题