Как вы можете заставить gcc полностью векторизовать этот цикл sqrt?

#c #gcc #x86 #icc #auto-vectorization

#c #gcc #x86 #icc #автоматическая векторизация

Вопрос:

Если я возьму этот код

 #include <cmath>

void compute_sqrt(const double* x, double* y, int n) {
  int i;
#pragma omp simd linear(i)
  for (i=0; i<n;   i) {
    y[i] = std::sqrt(x[i]);
  }
}
  

и скомпилировать с помощью g -S -c -O3 -fopenmp-simd -march=cascadelake , затем я получаю подобные инструкции в цикле (компилятор-проводник)

 ...
  vsqrtsd %xmm0, %xmm0, %xmm0
...
  

XMM — это 128-битные регистры, но cascadelake поддерживает avx-512. Есть ли способ заставить gcc использовать 256 (YMM) или 512-битные (ZMM) регистры?

Для сравнения, ICC по умолчанию использует 256 регистров для cascadelake: компиляция с icc -c -S -O3 -march=cascadelake -qopenmp-simd результатами (compiler-explorer)

 ...
  vsqrtpd 32(%rdi,%r9,8), %ymm1 #7.12
...
  

и вы можете добавить опцию -qopt-zmm-usage=high для использования 512-разрядных регистров (компилятор-проводник)

 ...
  vrsqrt14pd %zmm4, %zmm1 #7.12
...
  

Комментарии:

1. Обратите внимание, что vrsqrt14pd это быстрое приблизительное обратное, часть приближения к sqrt, которое выполняется быстрее, если это все, что вы делаете в цикле (например, ваш код). В реальной жизни выполняйте sqrt как часть какого-либо другого вычисления, чтобы оно могло перекрываться с другими активными ALU.

Ответ №1:

XMM — это 128-битные регистры

Это еще хуже, vsqrtsd это даже не векторная операция, как указано sd в конце (скалярная, двойная точность). Регистры XMM также используются подобными скалярными операциями с плавающей запятой, но только младшие 64 или 32 бита регистра содержат полезные данные, остальные обнуляются.

Отсутствующими параметрами являются -fno-math-errno (этот флаг также подразумевается -ffast-math , что имеет дополнительные эффекты) и (необязательно) -mprefer-vector-width=512 .

-fno-math-errno отключает настройку errno для математических операций, в частности для квадратных корней, это означает отрицательный результат ввода в NaN без установки errno на EDOM . ICC, по-видимому, по умолчанию это не волнует.

-mprefer-vector-width=512 при автоматической векторизации предпочтение отдается 512-битным операциям, когда они имеют смысл. По умолчанию предпочтительны 256-битные операции, по крайней мере, для cascadelake and skylake-avx512 и других текущих процессоров, вероятно, так не останется для всех будущих процессоров.

Комментарии:

1. ICC по умолчанию имеет значение -fp-model fast=1 , что-то вроде gcc / clang -ffast-math , включая, я думаю, обработку FP math как ассоциативной. Так что да, ICC наплевать на настройку errno по умолчанию! производительность icc main.cpp == g -ffast-math main.cpp . Вот почему OP видит это с помощью vrsqrt14pd , быстрой приблизительной обратной связи.

Ответ №2:

Если вы добавите -ffast-math флаг, gcc будет использовать регистры YMM, например:

 vsqrtpd (%rdi,%rax), %ymm0
vmovupd %ymm0, (%rcx,%rax)
  

ДЕМОНСТРАЦИЯ