Подразумевает передачу сигналов SIMD (SSE/AVX) с помощью GCC

Мне удалось преобразовать большую часть моего SIMD-кода в векторные расширения GCC. Однако я не нашел хорошего решения для трансляции следующим образом

__m256 areg0 = _mm256_broadcast_ss(&a[i]);

Я хочу сделать

__m256 argeg0 = a[i];

Если вы видите мой ответ в Mutiplying vector константой, используя SSE Мне удалось получить трансляции, работающие с другим регистром SIMD. Следующие работы:

__m256 x,y;
y = x + 3.14159f; // broadcast x + 3.14159
y = 3.14159f*x;  // broadcast 3.14159*x

но это не сработает:

 __m256 x;
 x = 3.14159f;  //should broadcast 3.14159 but does not work

Как я могу сделать это с помощью GCC?

Ответ 1

Я думаю, что в настоящее время нет прямого пути, и вы должны обойти его с помощью синтаксиса, который вы уже заметили:

__m256 zero={};
__m256 x=zero+3.14159f;

Это может измениться в будущем, если мы сможем согласовать хороший синтаксис, см. PR 55726.

Обратите внимание: если вы хотите создать вектор { s, s, ... s } с непостоянным float s, вышеприведенная техника работает только с целыми числами или с поплавками и -fno-signed-zeros. Вы можете настроить его на __m256 x=s-zero;, и он будет работать, если вы не используете -frounding-math. Последняя версия, предложенная Z бозоном, - это __m256 x=(zero+1.f)*s;, которая должна работать в большинстве случаев (за исключением, возможно, параноидального компилятора о sNaN).

Ответ 2

Оказывается, что с точной моделью с плавающей запятой (например, с -O3) GCC не может упростить x+0 до x из-за подписанного нуля. Таким образом, x = zero+3.14159f создает неэффективный код. Однако GCC может упростить 1.0*x до просто x, поэтому эффективное решение в этом случае есть.

__m256 x = ((__m256){} + 1)*3.14159f;

https://godbolt.org/g/5QAQkC

Подробнее см. этот ответ.


Более простое решение - это просто x = 3.14159f - (__m256){}, потому что x - 0 = x независимо от подписанного нуля.