#gcc #intrinsics #avx
#c #sse #simd #avx
Вопрос:
Итак, в AVX есть функция от immintrin.h
, которая должна позволять сохранять объединение двух __m128i
значений в одно __m256i
значение. Функция является
__m256i _mm256_set_m128i (__m128i hi, __m128i lo)
Однако, когда я использую его, вот так:
__m256i as[2]; __m128i s[4]; as[0] = _mm256_setr_m128i(s[0], s[1]);
Я получаю ошибку компиляции:
error: incompatible types when assigning to type ‘__m256i’ from type ‘int’
Я действительно не понимаю, почему это происходит. Любая помощь приветствуется!
Комментарии:
1. Вы уверены, что эта функция находится в этом заголовке? Когда я пытаюсь использовать функцию, как у вас после
#include <immintrin.h>
, я получаю предупреждающее сообщение «неявное объявление_mm256_set_m128i
«. В C неявное объявление означает, что компилятор предполагает, что функция вернетint
, что также объясняет ошибку компилятора.
Ответ №1:
Похоже, что не все компиляторы _mm256_setr_m128i
или даже _mm256_set_m128i
не определены в immintrin.h
. Поэтому я обычно просто определяю макросы по мере необходимости, заключая в квадратные скобки подходящие #ifdef
s, которые проверяют компилятор и версию:
#define _mm256_set_m128i(v0, v1) _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1)
#define _mm256_setr_m128i(v0, v1) _mm256_set_m128i((v1), (v0))
-
В Intel ICC 11.1 и более поздних версиях есть оба
_mm256_set_m128i
и_mm256_setr_m128i
. -
MSVC 2012 и более поздние версии имеют только
_mm256_set_m128i
. -
похоже, что у gcc / clang тоже нет, хотя я не проверял последние версии, чтобы узнать, было ли это исправлено.
Комментарии:
1. GCC, похоже, не хватает многих встроенных функций «composite». Недавно я обнаружил, что
_mm256_loadu2_m128
и family — лучший способ выполнить транспонирование из памяти, поскольку (в ICC) он компилируется в две инструкции, которые не используют порт векторной перетасовки. В GCC встроенная сборка — единственный способ получить тот же эффект. Для AVX512 в GCC отсутствуют все встроенные функции сокращения.2. @Mysticial: хм, хорошо, я понимаю проблему, о которой ты говоришь. Вы должны убедиться, что все ваши ссылки на память проходят через
loadu
, иначе компилятор может выполнить их с помощьюmovaps
at-O0
. Решение: используйте gcc 4.9.2 или новее, тогдаloadu
произойдет свертка в vinsertf128. Или для gcc 4.8: всегда используйте по крайней мере-Og
: «оптимизировать для отладки» и сохраняйте свой код, который будет давать сбой при компиляции в-O0
. goo.gl/eBPD5a . Обратите внимание, что clang имеет обе рассматриваемые встроенные функции,_mm256_set_m128i
и_mm256_loadu2_m128
.3. @PeterCordes О, это здорово! Я действительно тестировал с GCC 4.8. Спасибо!
4.Я только что столкнулся с этим. Я хотел
vbroadcastf128
ввести константу pshufb в обе строки регистра ymm. Но gcc6.3.1 ужасен во всем, что я пробовал. Ваш макрос — лучшее из плохой ситуации, он компилируется вvmovdqa
vinserti128
. (clang компилируется в вектор 256b). Другие попытки с gcc:const __m128 tmp = _mm_castsi128_ps(shufmask128);
_mm256_castps_si256(_mm256_broadcast_ps(amp;tmp))
выполняется компиляция с загрузкой константы FP 128b, сохранения FP 128b в стек, а затемvinsertf128
из только что сохраненной копии. Приведение указателя было еще хуже, если вы можете в это поверить.5. Боль, боль, еще раз боль. Это в gcc 8.1. Этого нет в gcc 7.3. Смотрите исходный код на github.com/gcc-mirror/gcc/blob/master/gcc/config/i386 /… . _mm256_set_m128i находится там.
Ответ №2:
У нас была такая же проблема, и мы использовали макрос, чтобы обойти ее.
#ifdef __GNUC__
#if __GNUC__ < 8
#define _mm256_set_m128i(xmm1, xmm2) _mm256_permute2f128_si256(_mm256_castsi128_si256(xmm1), _mm256_castsi128_si256(xmm2), 2)
#define _mm256_set_m128f(xmm1, xmm2) _mm256_permute2f128_ps(_mm256_castps128_ps256(xmm1), _mm256_castps128_ps256(xmm2), 2)
#endif
#endif
Комментарии:
1.
_mm256_insertf128_si256
всегда по крайней мере так же дешево, как_mm256_permute2f128_ps
, или, по крайней мере, соответствующие инструкции asm. Я не проверял, как это компилируется для констант по сравнению с переменными времени выполнения.