У меня есть регистр __m256i, и я хочу извлечь 4 младших 32 бит из каждой 64-битной группы, упаковать их и хранить их непрерывно в памяти. Т.е. если регистр __m256i содержит 8 32-битных слов: {a0, a1, a2, a3, a4, a5, a6, a7}, я хочу, чтобы сохранить в памяти по четыре слова {a0, a2, a4, a6}Извлеките и сохраните альтернативные нижние 32 бита из регистра AVX
я придумал следующий код:
void mystore(uint32 *dst, const __m256i& src)
{
__m256 ps256 = _mm256_castsi256_ps(src);
__m128 lo128 = _mm256_extractf128_ps(ps256, 0);
__m128 hi128 = _mm256_extractf128_ps(ps256, 1);
__m128 pack128 = _mm_shuffle_ps(lo128, hi128, 0 + (2<<2) + (0<<4) + (2<<6));
__m128i r = _mm_castps_si128(pack);
_mm256_storeu_si256(reinterpret_cast<__m128i*>(dst), r)
}
Если я правильно, операции литей существует только для удовлетворения компилятора проверки типов, но они по существу эквивалентно не-оп, так общая стоимость задержки составляет 3 для инструкции в случайном порядке и 2 команды извлечения, а также стоимость неглавного хранилища.
Есть ли более быстрый способ сделать это?
Благодаря
'_mm256_extractf128_ps (ps256, 0);' также просто слепок. Низкая половина каждого регистра YMM доступна как соответствующий регистр XMM, и, к счастью, компиляторы знают об этом и не наказывают нас за запись extract (v, 0), а не за то, что правильный '_mm_cast' intrinsic более прямо выражает оптимальный asm. (Аналогичным образом, компиляторы используют MOVD, когда вы пишете '_mm_extract_epi32 (v, 0)' вместо фактического PEXTRD). –
Интересно, я этого не знал. – Fabio