2016-05-25 4 views
1

Что представляет собой самый эффективный способ сравнения двух векторов 4x 64bit-Integer AVX для <=.Сравнение целых чисел AVX2 для меньших равных

В руководстве по Intel Intrinsics мы

  • _mm256_cmpgt_epi64(__m256i a, __m256i b) = а> Ь
  • _mm256_cmpeq_epi64(__m256i a, __m256i b) = A == B

для сравнения

и

  • _mm256_and_si256(__m256i a, __m256i b) = а & б
  • _mm256_andnot_si256(__m256i a, __m256i b) = ~ а & б
  • _mm256_or_si256(__m256i a, __m256i b) = а | б
  • _mm256_xor_si256(__m256i a, __m256i b) = а^Ь

для логических операций.

Мой подход был:

// check = (a <= b) = ~(a > b) & 0xF..F
__m256i a = ...
__m256i b = ...
__m256i tmp = _mm256_cmpgt_epi64(a, b)
__m256i check = _mm256_andnot_si256(tmp, _mm256_set1_epi64x(-1))

+1

Я не уверен, если есть умнее (более эффективный) способ делать это, поскольку ненужный «0xF..F» беспокоит меня –

+2

Вы проверили, какой хороший компилятор сделает для этого? gcc генерирует маску all-ones для «а не», сравнивая временный регистр для равенства с (всегда сравнивает значение true), поэтому вам не нужно сохранять это как константу, и, согласно анализу Агнера Фога, инструкция распознается как независимая от предыдущего значения регистра, поэтому вы можете быстро сгенерировать маску и не нужно держать его вокруг, теряя регистрацию. – EOF

ответ

3

Вы правы, что нет никакого прямого способа получить маску вы действительно хотите, только перевернутая маска : A gt B = A nle B.

Нет инструкции vector-NOT, поэтому вам нужен вектор all-ones, а также дополнительная инструкция для инвертирования вектора. (Или вектор all-zero и _mm256_cmpeq_epi8, но который не может работать на таком количестве портов выполнения, как _mm256_xor_si256 с вектором all-ones.) См. Wiki темы для информации о производительности, особенно. Руководство Agner Fog.

Другая побитовая логическая опция, _mm256_andn_si256 так же хороша, как и xor. Это не коммутативно, а немного сложнее мысленно проверить, что вы поняли это правильно. xor-with-all-ones - хорошая идиома для flip-all-the-bits.


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

например. если это входной сигнал в blendv, то измените порядок операндов на смесь. Вместо
_mm256_blendv_epi8(a, b, A_le_B_mask), используйте
_mm256_blendv_epi8(b, a, A_nle_B_mask)

Если вы собираетесь что-то _mm_and с маской, используйте _mm_andn вместо этого.

Если вы собираетесь на _mm_movemask и протестировать все ноль, вы можете вместо этого проверить все-единицы.Он будет скомпилирован с инструкцией cmp eax, -1 вместо test eax,eax, что так же эффективно. Если вы собираетесь бить бит для первого 1, вам придется инвертировать его. Целая команда not (от использования ~ по результату movemask) дешевле, чем делать это на векторе.


У вас есть только проблема, если вы собираетесь OR или XOR, потому что те инструкции не приходят в ароматах, опровергающих один из своих входов. (ИКА, если Intel просто не хочет, чтобы добавить PORN мнемоническими, но, вероятно, PAND и PANDN получить больше пользы, особенно перед теми инструкциями переменной бленды.

+1

@PaulR: По-видимому, мой сонный мозг знал, что правильный ответ связан с некоторыми родственниками d реверсирования операндов, но испугался, прежде чем заметить, что я совершенно не прав. >. < –

+0

вы правы в отношении 'blendv' intrinsics, но мне на самом деле понадобится OR после этого, и для него нет NOR, но спасибо в любом случае –

+0

@ user2399267 ...... кажется good:' NOR' будет be '~ (a | b)'. Операция, в которой вы нуждаетесь, '(~ a | b)' будет называться 'ORN', например' ANDN'. Целочисленные сравнения IIRC, AVX512 принимают предикатный аргумент (закодированный в непосредственном байте), поэтому AVX512, наконец, даст нам широкий выбор операторов сравнения, как это делает 'cmpps'. –

Смежные вопросы