На Intel ваш код был бы оптимальным. Лучшее, что вы получите - это одна инструкция на 1 муп. (За исключением того, что вы можете захотеть использовать vpermps
, чтобы избежать любого риска задержки обхода int / FP, если ваш вектор ввода был создан инструкцией pd
, а не загрузкой или чем-то еще. Использование результата перемешивания FP в качестве ввода для целочисленных инструкций является Обычно это нормально для Intel, но я менее уверен в том, что результат инструкции FP передается целочисленному перемешиванию.)
Хотя, если вы настраиваетесь на Intel, вы можете попробовать изменить окружающий код, чтобы вы могли перетасовать нижние 64 бита каждой полосы 128b, чтобы избежать использования перемешивания с пересечением полос. (Тогда вы можете просто использовать vshufps ymm
, или, если вы настраиваете KNL, vpermilps
, поскольку 2 входа vshufps
медленнее.)
В AVX512 есть _ 6_ (vpmovqd
), который упаковывает элементы по полосам с усечением.
На Ryzen перестановка при пересечении полос идет медленно. Agner Fog не имеет номеров для vpermd
, но он перечисляет vpermps
(который, вероятно, использует то же оборудование для внутренних целей) при 3 мупа, задержке 5 с, по одному на пропускную способность 4 с.
vextractf128 xmm, ymm, 1
очень эффективен на Ryzen (задержка 1c, пропускная способность 0,33c), что неудивительно, поскольку он уже отслеживает регистры 256b как две половины 128b. shufps
также эффективен (задержка 1 с, пропускная способность 0,5 с) и позволит вам перетасовать два регистра 128b для получения желаемого результата.
Это также экономит вам 2 регистра для 2 vpermps
масок перемешивания, которые вам больше не нужны.
Поэтому я бы посоветовал:
__m256d x = /* computed here */;
// Tuned for Ryzen. Sub-optimal on Intel
__m128 hi = _mm_castpd_ps(_mm256_extractf128_pd(x, 1));
__m128 lo = _mm_castpd_ps(_mm256_castpd256_pd128(x));
__m128 odd = _mm_shuffle_ps(lo, hi, _MM_SHUFFLE(3,1,3,1));
__m128 even = _mm_shuffle_ps(lo, hi, _MM_SHUFFLE(2,0,2,0));
На Intel использование 3 перетасовок вместо 2 дает 2/3 оптимальной пропускной способности с дополнительной задержкой 1 с для первого результата.
person
Peter Cordes
schedule
24.08.2017
_mm256_cvtepi64_epi32
(vpmovqd
)? Я не думаю, что вы собираетесь превзойти 1 инструкцию перемешивания с задержкой в 3 цикла, потому что перемешивание при пересечении полосы движения всегда имеет задержку 3c на процессорах Intel. Вашеvpermd
решение имеет пропускную способность за один цикл. - person Peter Cordes   schedule 24.08.2017shufps
(за исключением того, что это не пересечение полосы движения, поэтому это не решает вашу проблему, и нет инструкцииvpackqd
, и инструкции упаковки также не пересекают полосу). - person Peter Cordes   schedule 24.08.2017__m128i
, или вы можете использовать перетасовку внутренней полосы, чтобы поместить нижнюю и верхнюю половины в нижние 2 элемента каждой дорожки__m256i
? Если вы настраиваетесь на Ryzen, вероятно, имеет смысл снизить его до 128b. Но, возможно,vextractf128
, а затем использовать перемешивание с двумя источниками (например,shufps
) будет лучше на Ryzen, где перемешивание при пересечении полосы движения происходит очень медленно. - person Peter Cordes   schedule 24.08.2017