Как взять верхнюю часть __m256

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

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

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

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

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

Всего 1 ответ


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

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

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

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


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

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

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


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

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

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


Есть идеи?

10000