Подтвердить что ты не робот

Можно ли прикладывать поплавки непосредственно к __m128, если они выровнены по 16 байт?

Безопасно ли/целесообразно ли применять float непосредственно к __m128, если они выровнены по 16 байт?

Я заметил, что с помощью _mm_load_ps и _mm_store_ps для "обертки" необработанный массив добавляет значительные накладные расходы.

Каковы потенциальные ошибки, о которых я должен знать?

EDIT:

На самом деле нет накладных расходов при использовании инструкций по загрузке и хранению, я немного смешал некоторые цифры, и поэтому я получил лучшую производительность. Даже я смог сделать некоторые HORRENDOUS mangling с необработанными адресами памяти в экземпляре __m128, когда я запустил тест, ему потребовалось сделать TWICE AS LONG без инструкции _mm_load_ps, возможно, вернувшись к некоторому пути с безопасным кодом.

4b9b3361

Ответ 1

Что заставляет вас думать, что _mm_load_ps и _mm_store_ps "добавить значительные накладные расходы"? Это нормальный способ загрузки/хранения данных с плавающей запятой в/из регистров SSE, предполагая, что источник/назначение - это память (и любой другой метод в конечном итоге сводится к этому).

Ответ 2

Существует несколько способов добавить значения float в регистры SSE; можно использовать следующие возможности:

__m128 sseval;
float a, b, c, d;

sseval = _mm_set_ps(a, b, c, d);  // make vector from [ a, b, c, d ]
sseval = _mm_setr_ps(a, b, c, d); // make vector from [ d, c, b, a ]
sseval = _mm_load_ps(&a);         // ill-specified here - "a" not float[] ...
                                  // same as _mm_set_ps(a[0], a[1], a[2], a[3])
                                  // if you have an actual array

sseval = _mm_set1_ps(a);          // make vector from [ a, a, a, a ]
sseval = _mm_load1_ps(&a);        // load from &a, replicate - same as previous

sseval = _mm_set_ss(a);           // make vector from [ a, 0, 0, 0 ]
sseval = _mm_load_ss(&a);         // load from &a, zero others - same as prev

Компилятор часто создает те же инструкции, независимо от того, укажите ли вы _mm_set_ss(val) или _mm_load_ss(&val) - попробуйте и разобьете свой код.

В некоторых случаях может быть полезно написать _mm_set_ss(*valptr) вместо _mm_load_ss(valptr)... зависит от структуры вашего кода.

Ответ 3

Переход на http://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx, это возможно, но не безопасно и не рекомендуется.

Нельзя напрямую обращаться к полям __ m128.


И вот почему:

http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/766c8ddc-2e83-46f0-b5a1-31acbb6ac2c5/

  • Литье поплавка * на __m128 не будет работать. Компилятор С++ преобразует присвоение типа __m128 в инструкцию SSE, загружая 4 числа с плавающей запятой в регистр SSE. Предполагая, что это кастинг компилируется, он не создает рабочий код, потому что инструкция загрузки SEE не генерируется.

__ m128 переменная не является фактически переменной или массивом. Это место для регистра SSE, замененное компилятором С++ на инструкцию SSE Assembly. Чтобы понять это лучше, прочитайте Справочник по программированию Intel.

Ответ 4

Очевидная проблема, которую я вижу, заключается в том, что вы - не псевдоним (ссылаясь на расположение памяти более чем на один тип указателя), что может смутить оптимизатора. Типичными проблемами с псевдонимом является то, что, поскольку оптимизатор не замечает, что вы изменяете местоположение памяти через исходный указатель, он считает, что он не изменился.

Поскольку вы явно не используете оптимизатора в полной мере (или вы готовы полагаться на него, чтобы исправить правильные инструкции SSE), вы, вероятно, будете в порядке.

Проблема с самим внутренним интерфейсом заключается в том, что они предназначены для работы с SSE-регистрами и не могут использовать варианты команд, которые загружаются из памяти и обрабатывают ее в одной команде.

Ответ 5

Несколько лет прошло с тех пор, как был задан вопрос. Чтобы ответить на вопрос, мой опыт показывает:

Да

reinterpret_cast -канирование a float* в __m128* и наоборот хорошо, если этот float* пример с 16-байтовым выравниванием (в MSVC 2012):

__declspec( align( 16 ) ) float f[4];
return _mm_mul_ps( _mm_set_ps1( 1.f ), *reinterpret_cast<__m128*>( f ) );