неявные передачи SIMD (SSE/AVX) с GCC

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

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

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

__m256 argeg0 = a[i];

Если вы видите мой ответ на Умножение вектора на константу с использованием 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?


person Z boson    schedule 12.02.2014    source источник
comment
Кажется, это отлично работает в Clang с использованием векторных расширений OpenCL typedef float float4 __attribute__((ext_vector_type(8)));. Однако Clang не разрешает широковещательные передачи с регистром, использующим векторные расширения GCC, поэтому я не уверен, что он полностью совместим с GCC.   -  person Z boson    schedule 12.02.2014
comment
gcc.gnu.org/bugzilla/show_bug.cgi?id=55726   -  person Marc Glisse    schedule 12.02.2014
comment
@MarcGlisse, я протестировал ваше решение в GCC Explorer и могу подтвердить, что оно преобразуется в vbroadcastss. Если вы хотите написать ответ, я приму его. Я понимаю двусмысленность двойного и плавающего. Думаю, с целыми числами дело обстоит еще хуже, поскольку они могут быть 8-битными, 16-битными, 32-битными или 64-битными.   -  person Z boson    schedule 12.02.2014


Ответы (2)


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

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

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

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

person Marc Glisse    schedule 12.02.2014
comment
Это необходимо исправить. GCC не может сделать это эффективно из-за нуля со знаком. Насколько сложно принять участие в разработке GCC, чтобы исправить что-то подобное? Я хотел бы помочь, но я не знаю, будет ли это практично для меня. - person Z boson; 08.05.2017
comment
На самом деле, я только что нашел эффективное решение. v4sf one = {1,1,1,1}; x= one*3.14159f; Это связано с тем, что x*1 можно упростить до x для операций с плавающей запятой. См. конец моего ответа. - person Z boson; 08.05.2017
comment
Так что я мог просто сделать x = 3.14159f - (__m256){}. Очевидно, что знаковый ноль не имеет значения для x-0. - person Z boson; 10.05.2017
comment
@Zboson, как я писал выше, версия x-0 не оптимизируется с помощью -frounding-math, поэтому все еще есть случаи, когда x * 1 предпочтительнее. - person Marc Glisse; 10.05.2017

Оказывается, с точной моделью с плавающей запятой (например, с -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 независимо от нуля со знаком.

person Z boson    schedule 08.05.2017