我想了解为什么 GCC 不自动矢量化以下循环,除非我通过 -ffinite-math-only。至于我的理解和 GCC 手册,优化需要-funsafe-math-optimizations
如果选定的浮点硬件包括 NEON 扩展(例如 -mfpu=neon),请注意浮点运算不是由 GCC 的自动矢量化过程生成的,除非还指定了 -funsafe-math-optimizations。这是因为 NEON 硬件没有完全实现浮点运算的 IEEE 754 标准(特别是非正规值被视为零),因此使用 NEON 指令可能会导致精度损失。
特别是,该标志使编译器能够假设关联数学,以便它可以首先累加 4 个部分和。代码看起来很简单
template<typename SumType = double>
class UipLineResult {
public:
SumType sqsum;
SumType dcsum;
float pkp;
float pkn;
public:
UipLineResult() {
clear();
}
void clear() {
sqsum = 0;
dcsum = 0;
pkp = -std::numeric_limits<float>::max();
pkn = +std::numeric_limits<float>::max();
}
};
未矢量化的循环
static void addSamplesLine(const float* ss, UipLineResult<>* line) {
UipLineResult<float> intermediate;
for(int idx = 0; idx < 120; idx++) {
float s = ss[idx];
intermediate.sqsum += s * s;
intermediate.dcsum += s;
intermediate.pkp = intermediate.pkp < s ? s : intermediate.pkp;
intermediate.pkn = intermediate.pkn > s ? s : intermediate.pkn;
}
line->addIntermediate(&intermediate);
}
例如,平方加法看起来像
intermediate.sqsum += s * s;
107da: ee47 6aa7 vmla.f32 s13, s15, s15
-ffinite-math-only
这样就变成了
intermediate.sqsum += s * s;
1054c: ef40 6df0 vmla.f32 q11, q8, q8
编译器标志
-funsafe-math-optimizations -ffinite-math-only -mcpu=cortex-a9 -mfpu=neon