查询开源软件中使用的某种编程技巧

Query about a certain programming trick used in an open source software

某库中(FFTW:discrete Fourier transform computation), 我遇到了一个头文件,其中包含以下注释和一些#defines。该评论谈到了一些编程技巧。 但我无法理解这个编程技巧到底是什么。 有人可以解释一下吗?

/* 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 */

优化:不是每次循环中的迭代都重新计算数组的索引,一些编译器会预测下一个地址并将它们放在寄存器中,因为索引表达式是可预测的。

问题:一些索引表达式(如I + STRIDE * K)可能会导致这样使用大量的寄存器,如果这个数量超过了寄存器的总数,一些寄存器值将被压入堆栈内存,包括循环可能使用的其他变量。

诀窍:为了强制编译器不使用此优化,使用了外部整数。添加或 XOR'ing 这个零并将其存储在 x 中是一个空操作 "taints" 步幅,因此是索引表达式,使其无法通过优化分析进行预测。它不能再推断这个变量的行为,即使我们知道它的行为非常像零。派生文件 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 的名称来源于 volatile 关键字,它表示一个值可能会在不同的访问之间发生变化,即使它看起来没有被修改。此关键字可防止优化编译器优化后续读取或写入,从而错误地重用陈旧值或省略写入。 (Wikipedia)

为什么 volatile 关键字而不是对外部值进行异或运算是不够的,我不知道。