查询开源软件中使用的某种编程技巧
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 关键字而不是对外部值进行异或运算是不够的,我不知道。
某库中(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 关键字而不是对外部值进行异或运算是不够的,我不知道。