2

我想了解为什么 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

4

0 回答 0