Работа с встроенными функциями Intel SSE SIMD

У меня вопрос относительно различных арифметических операций для встроенных функций Intel SSE. в чем разница между _mm_add_ps Vs. _mm_add_epi8 / 16/32? Я хочу быть уверенным, что мои данные всегда выровнены.

В образце кода, когда я это делаю:

 __m128 u1 = _mm_load_ps(&V[(i-1)]);

Я получаю ошибку сегментации. Но когда я это сделаю:

 __m128 u1 = _mm_loadu_ps(&V[(i-1)]);

Работает нормально.

Поскольку я хочу, чтобы мои данные были выровнены, я объявил массив следующим образом:

 posix_memalign((void**)&V, 16, dx*sizeof(float));

Может кто-нибудь помочь объяснить это.


person PGOnTheGo    schedule 15.06.2012    source источник
comment
Вы спрашиваете что-то о различных дополнениях и что-то о выравнивании, что вы на самом деле хотите знать? Разница между различными добавками заключается в том, к каким типам данных они относятся.   -  person harold    schedule 15.06.2012


Ответы (1)


_mm_add_ps складывает floats вместе, где _mm_add_epi8/16/32 добавляет целые числа, которые не являются числами с плавающей запятой.

_mm_loadu_ps не требует, чтобы ваши числа с плавающей запятой были выровнены по 16 байт (128 бит), тогда как _mm_load_ps требует выравнивания по 16 байт.

Так что, если вы получаете ошибку сегмента на первом, ваше выравнивание неверно.

На странице posix_memalign написано следующее:

Функция posix_memalign () завершится ошибкой, если:

[EINVAL] Значение параметра выравнивания не является степенью двойного кратного sizeof (void *).

Я не уверен, что sizeof(float) == sizeof(void*) ?? Согласно this, похоже, то же самое в C (в 32-битной системе). Хорошо, здесь небольшая хитрость, потому что размер указателя обычно равен размеру ширины регистра ЦП, 32 бит или 64 бит (8 байтов) в зависимости от используемой системы, тогда как float обычно будет 32 бит (4 байта)

Ваше выровненное распределение должно выглядеть примерно так:

posix_memalign((void**)&V, 16, dx*sizeof(void*)); //since it will the correct size for your platform.  You can always cast to `float` later on.
person Tony The Lion    schedule 15.06.2012
comment
Ваше последнее утверждение определенно не соответствует действительности. float составляет (обычно) 4 байта. void* - размер указателя. (обычно: 4 байта на 32-битном, 8 байтов на 64-битном) - person Mysticial; 15.06.2012
comment
@Mysticial да, я нашел это довольно странным, но почему он печатает same тогда на моем маленьком тесте. Возможно, случайно 32-битная система, в которой указатель составляет 4 байта, а float также 4 байта? - person Tony The Lion; 15.06.2012
comment
Этот случай определенно компилируется на 32-бит. Попробуйте 64-битную версию, и все будет по-другому. - person Mysticial; 15.06.2012
comment
@ Тони Лев: Спасибо, что указали на это. Как вы думаете, как лучше всего выделить 16-байтовые данные? Я тоже использовал эту технику: __declspec (align (16)) float V [dx * sizeof (float)]; .Но это статическое объявление, как я могу сделать это динамически. Когда я пытаюсь использовать _aligned_malloc в упомянутом здесь: songho.ca/misc/alignment/dataalign. html, мой компилятор (icc) не может его идентифицировать. - person PGOnTheGo; 15.06.2012
comment
Какой компилятор вы используете? _align_mallac предназначен для MSVC. Используйте набор функций memalign для GCC. - person Tony The Lion; 15.06.2012
comment
@ Тони Лев: могу ли я использовать memalign для компилятора Intel ICC? - person PGOnTheGo; 15.06.2012
comment
Я бы так предположил. Основная проблема с вашим кодом заключалась не в memmalign, а в том, что ваш sizeof параметр был неправильным. См. Последнее изменение, которое я внес в свой ответ - person Tony The Lion; 15.06.2012