GCC 6.3.1 не выполняет авто-векторизацию без -ffinite-math-only
Я хотел бы понять, почему 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= неон