Различная семантика встроенных инструкций сравнения в avx512?

С операциями сравнения sse2 или avx возвращались битовые маски всех нулей или всех единиц (например, _mm_cmpge_pd возвращает __m128d.

Не могу найти аналог с avx512. Операции сравнения, похоже, возвращают только короткие битовые маски. Произошло ли фундаментальное изменение семантики или я что-то упустил?


person Fabio    schedule 04.01.2018    source источник


Ответы (1)


Да, в AVX512 семантика немного другая. Инструкции сравнения возвращают результаты в регистрах маски. У этого есть пара преимуществ:

  • Регистры маски (8) полностью отделены от набора регистров [xyz]mm, поэтому вы не тратите впустую векторный регистр для результата сравнения.
  • Существуют маскированные версии почти всего набора инструкций AVX512, что дает вам большую гибкость при использовании результатов сравнения.

Это требует немного другого кода по сравнению с устаревшей реализацией SSE/AVX, но это не так уж плохо.

Изменить. Если вы хотите подражать старому поведению, вы можете сделать что-то вроде этого:

// do comparison, store results in mask register
__mmask8 k = _mm512_cmp_pd_mask(...);
// broadcast a mask of all ones to a vector register, then use the mask
// register to zero out the elements that have a mask bit of zero (i.e.
// the corresponding comparison was false)
__m512d k_like_sse = _mm512_maskz_mov_pd(k, 
    (__m512d) _mm512_maskz_set1_epi64(0xFFFFFFFFFFFFFFFFLL));

Возможно, есть более оптимальный способ сделать это, но я относительно новичок в использовании AVX512. Маска всех единиц может быть предварительно рассчитана и использована повторно, поэтому вы, по сути, просто добавляете одну дополнительную инструкцию перемещения в маске, чтобы сгенерировать векторный результат, который вы ищете.

Редактировать 2: Как предложил Питер Кордес в комментарии ниже, вместо этого вы можете использовать _mm512_movm_epi64(), чтобы еще больше упростить вышеизложенное:

// do comparison, store results in mask register
__mmask8 k = _mm512_cmp_pd_mask(...);
// expand the mask to all-0/1 masks like SSE/AVX comparisons did
__m512d k_like_sse = (__m512d) _mm512_movm_epi64(k);
person Jason R    schedule 04.01.2018
comment
Если вам нужно сохранить промежуточные результаты, то то, что раньше было вектором из двойных чисел с забавными значениями, теперь представляет собой вектор из одиночных битов. Это кошмарный рефакторинг! Изменяются размеры векторных контейнеров. Изменение логики очистки цикла. Все случаи использования этих битовых масок для выполнения таких операций, как x и y, где x — это двойное число, а y — битовая маска, изменяются. В любом случае, спасибо, это правильный ответ. - person Fabio; 04.01.2018
comment
Да, я думал о чем-то подобном, хотя бы как о временном решении. Возможно, с blend_pd. Нужно поэкспериментировать, что эффективнее. - person Fabio; 04.01.2018
comment
Наверное это: _mm512_maskz_mov_pd - person Fabio; 04.01.2018
comment
Да, это то, что я бы использовал. Я исправил пару опечаток в своем примере. - person Jason R; 04.01.2018
comment
@Fabio Эти изменения являются досадными издержками такого низкого уровня программирования. Но как только он будет правильно написан, количество необработанных инструкций для кода, использующего подобные вещи, вероятно, значительно уменьшится. В основном из-за потери всех побитовых инструкций, которые сливаются во встроенную маскировку. Единственная проблема, с которой я когда-либо сталкивался в новой системе, — это нехватка регистров масок. - person Mysticial; 05.01.2018
comment
Существует инструкция AVX512DQ (или AVX512BW для узких элементов) для преобразования маски k в вектор 0/-1: __m512i _mm512_movm_epi64(__mmask16 ) / VPMOVM2Q zmm1, k1. Используйте это вместо maskz_mov_pd, чтобы вам вообще не нужна была константа "все единицы". Или лучше просто используйте маски так, как они предназначены для использования, когда это возможно. - person Peter Cordes; 05.01.2018
comment
@PeterCordes спасибо, что указали на это, я этого не видел. AVX512 настолько большой, что бывает трудно отделить зерна от плевел. - person Jason R; 05.01.2018
comment
@JasonR без шуток! Для обратного направления (знаковый бит -> маска типа pmovmskb) есть целочисленные инструкции вида vpmovq2m (опять же AVX512DQ/BW, так что не на KNL), а для FP есть только AVX512DQ VFPCLASSPS / PD (что не делает различий между -NaN и +NaN, но делает для всех остальных случаев, включая -0 и +0 , Конечно, вы можете использовать целочисленные инструкции для данных FP, но я не думаю, что FPCLASSPS медленнее на Skylake, и целочисленное может иметь обходную задержку.Или вы можете просто использовать целочисленное AVX512F VPCMPQ против нуля. - person Peter Cordes; 05.01.2018
comment
@PeterCordes Не измерив его, я не уверен, что FPCLASS обязательно является быстрой инструкцией, поскольку она, вероятно, попадает в блок FMA, что составляет 4 цикла по всем направлениям. Но я не могу сказать, глядя на InstLatx64, так как они не делают задержек между доменами регистрации, а пропускная способность ограничена маской порта. - person Mysticial; 05.01.2018