Как взять верхнюю часть __m256 - PullRequest
1 голос
/ 23 марта 2020

У меня есть __m256 или __m256i, я хочу взять более высокую часть.

Учитывая __m256 variable, я знаю, что могу сделать это с _mm256_extractf128_ps(variable, 1)

, но для нижней части: _mm256_extractf128_ps(tr3, 0) лучше сделать это *((__m128*)&variable)

Я не знаю, как взять верхнюю часть, используя некоторые указатели так же, как я использовал ранее для нижней части?

Можно ли добавить число или увеличить указатель? *((__m128*)&variable+128)

1 Ответ

1 голос
/ 24 марта 2020

_mm256_extractf128_ps(v, 1) - лучший способ . Если ваш компилятор не компилирует это эффективно, используйте лучший компилятор (например, clang имеет очень хороший оптимизатор перемешивания).

Для младшей половины все компиляторы оптимизируют _mm256_extractf128_ps(v, 0), чтобы фактически не использовать vextractf128 инструкция, но самый явный способ сказать, что вы просто хотите низко 128, это _mm256_castps256_ps128 и аналогичные приведенные значения для __m256i (_mm256_castsi256_si128) или __m256d.

Обычно они компилируются только с использованием младшей половины XMM любого регистра YMM, в котором компилятор содержал векторную переменную, хотя некоторые компиляторы пропустили ошибки оптимизации и иногда выдают бесполезную инструкцию vmovaps xmm, xmm вместо того, чтобы более поздние инструкции читали либо младший xmm, либо полный ymm любого регистра.

Использование математического указателя побуждает компилятор сохранять и перезагружать, что вам обычно не нужно. Но на практике большинство компиляторов большую часть времени оптимизируют его обратно до случайных операций ALU, даже если вы пытались избежать узкого места в случайном порядке и фактически сохраняете / перезагружаете.


I не рекомендуем использовать указатель . Тем не менее, *((__m128*)&variable) и ((__m128*)&variable)[1] являются допустимыми, потому что встроенные c векторные типы, такие как __m128, похожи на char - им разрешено псевдоним любого другого типа, не нарушая строгое псевдоним и не вызывая неопределенное поведение.

C указатель математика перемещает указатель на 1 единицу размера указанного типа. например, +1 на __m128* перемещается на 16 байтов, что составляет один __m128. Вот почему ++ всегда работает, чтобы перебрать указатель на массив. Arinter Arithmeti c

Так как вы хотите 2-й __m128, вы должны добавить 1 к вашему __m128*. например, *(1 + (__m128*)&variable). C [] синтаксис определен в терминах добавления указателя + разыменования, поэтому мы можем записать его таким образом, применяя [] к результату приведения. Оба этих порядка написания дают понять, что +1 применяется к __m128* после каста, а не к __m256 с &var до каста. Хотя IIR C, приведение имеет более высокий приоритет, чем +1 к *((__m128)&var + 1), также будет безопасным. Но если вы пишете по-другому, вам не нужно помнить об этом при чтении кода позже.


В GNU C типы intrinsi c определены с __attribute__((may_alias)). В MSV C алиасинг всегда разрешен. Является ли `reinterpret_cast`ing между указателем вектора аппаратного SIMD и соответствующим типом неопределенным поведением? Это то, что делает приведение указателя безопасным для этого типа наказания.

Любой прочее * Тип 1061 *, такой как ((float*)&vec)[0], будет нарушать строгое псевдонимы и будет UB.

Как я уже сказал, поскольку вы обычно хотите, чтобы компилятор использовал инструкции случайного порядка, для работы с указателями требуется, чтобы компилятор оптимизировал все указатели. , Используйте встроенные функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...