Целочисленное сравнение AVX2 для меньшего равного

Каков наиболее эффективный способ сравнить два 4x 64-битных целочисленных вектора AVX для <=.

Из Руководства Intel Intrinsics у нас есть

  • _mm256_cmpgt_epi64(__m256i a, __m256i b) = a > 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) = a | b
  • _mm256_xor_si256(__m256i a, __m256i b) = a ^ 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))


person user2399267......seems good    schedule 25.05.2016    source источник
comment
Я не уверен, что есть более умный (более эффективный) способ сделать это, так как ненужные 0xF..F меня беспокоят   -  person user2399267......seems good    schedule 26.05.2016
comment
Вы проверили, что для этого сделает хороший компилятор? gcc генерирует маску всех единиц для, а не путем сравнения временного регистра на равенство с самим собой (всегда сравнивает true), поэтому вам не нужно сохранять это как константу, и, согласно анализу Агнера Фога, инструкция распознается как независимая от предыдущего значения регистра, поэтому вы можете быстро сгенерировать маску и не нужно хранить ее, тратя впустую регистр.   -  person EOF    schedule 26.05.2016


Ответы (1)


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

Инструкции вектор-НЕ нет, поэтому вам нужен вектор из всех единиц, а также дополнительная инструкция для инвертирования вектора. (Или вектор из всех нулей и _mm256_cmpeq_epi8, но он не может работать на таком количестве портов исполнения, как _mm256_xor_si256 с вектором из всех единиц.) См. x86 пометить вики для информации о производительности, особенно. Гид Агнера Фога.

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


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

например если это вход в 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 (из-за использования ~ в результате маски перемещения) дешевле, чем выполнение ее для вектора.


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

person Peter Cordes    schedule 26.05.2016
comment
@PaulR: Очевидно, мой сонный мозг знал, что правильный ответ включает в себя какое-то обращение операндов, но выдыхался, прежде чем заметил, что я совершенно ошибся. ›.‹ - person Peter Cordes; 26.05.2016
comment
вы правы насчет внутренних свойств blendv, но на самом деле после этого мне понадобится ИЛИ, а для него нет ИЛИ, но все равно спасибо - person user2399267......seems good; 26.05.2016
comment
@ user2399267......кажется хорошо: NOR будет ~(a|b). Нужная вам операция (~a | b) будет называться ORN, например ANDN. IIRC, векторные целочисленные сравнения AVX512 принимают аргумент предиката (закодированный в непосредственном байте), поэтому AVX512, наконец, предоставит нам широкий выбор операторов сравнения, как это делает cmpps в настоящее время. - person Peter Cordes; 26.05.2016
comment
@PeterCordes: ну, я думаю, что впервые заметил ошибку в одном из ваших постов, так что ваш средний результат намного лучше моего. ;-) Я удалю свой комментарий, чтобы уменьшить шум, теперь, когда вы обновили ответ... - person Paul R; 26.05.2016