Какой смысл _mm_cmpgt_sd и других подобных методов? - PullRequest
3 голосов
/ 16 апреля 2019

Я искал опцию SIMD для ускорения сравнений и нашел функцию __m128d _mm_cmpgt_sd (__m128d a, __m128d b)

Очевидно, он сравнивает нижний дубль и копирует верхний дубль из a в вывод. То, что он делает, имеет смысл, но какой в ​​этом смысл? Какую проблему это пытается решить?

Ответы [ 2 ]

4 голосов
/ 16 апреля 2019

Возможно, дело в том, что на очень старом оборудовании, таком как, например, Intel Pentium II и III, _mm_cmpgt_sd() быстрее, чем _mm_cmpgt_pd(). См. инструкции Agner Fog * . Эти процессоры (PII и PIII) имеют только 64-битный модуль с плавающей запятой. Команды SSE шириной 128 бит выполняются в виде двух 64-битных микроопераций на этих процессорах. На более новых процессорах (таких как, например, Intel Core 2 (Merom) и новее) версии _pd и _ps работают так же быстро, как версии _sd и _ss. Таким образом, вы можете предпочесть версии _sd и _ss, если вам нужно только сравнить один элемент и не заботиться о старших 64 битах результата.

Более того, _mm_cmpgt_pd() может вызвать ложное исключение с плавающей запятой или ухудшить производительность, если верхние биты мусора случайно содержат NaN или ненормальное число, см. ответ Питера Кордеса . Хотя на практике должно быть легко избежать таких старших битов мусора при программировании с помощью встроенных функций.

Если вы хотите векторизовать свой код и вам требуется двойное сравнение в пакете, тогда используйте _mm_cmpgt_pd() вместо _mm_cmpgt_sd().

3 голосов
/ 17 апреля 2019

cmpsd - это инструкция, которая существует в asm и работает с регистрами XMM, поэтому было бы непоследовательным , а не , чтобы выставить ее с помощью встроенных функций.

(Почти все инструкции упакованных FP (кроме shuffles / blends) имеют скалярную версию, поэтому снова есть аргумент согласованности для дизайна ISA, это просто дополнительный префикс к тому же коду операции, и может потребоваться больше транзисторов для специального случая, чем коду операции не поддержка скалярной версии.)

Могли бы вы или люди, разрабатывающие встроенный API, придумать разумный вариант использования, совсем не в этом дело. Было бы глупо оставлять вещи на этой основе;когда кто-то придумывает сценарий использования, ему придется использовать встроенный asm или написать C, который компилирует больше инструкций.

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

Или учтите, что все единицы - этобитовый шаблон для NaN, а все ноль - это битовый шаблон для +0.0.


IIRC, cmppd замедляется, если какой-либо из элементов является ненормальным (если у вас нетбит DAZ, установленный в MXCSR).По крайней мере, на некоторых старых процессорах, которые существовали во время разработки ISA.Таким образом, для сравнения FP наличие скалярных версий является (или было) необходимым для избежания ложных вспомогательных операций FP для элементов, которые вам не нужны.

Также для избежания ложных исключений FP (или установка исключенияфлагы, если они замаскированы), например, если есть NaN в верхнем элементе любого вектора.

@ wim также хорошо показывает, что процессоры Intel до того, как Core2 декодировал 128-битные инструкции SIMD в 2 мопа, одиндля каждой 64-битной половины.Поэтому использование cmppd, когда вам не нужен высокий половинный результат, всегда будет медленнее, даже если оно не может быть ошибочным.Множество многопользовательских инструкций могут легко стать узким местом для декодеров переднего плана на процессорах без кэш-памяти uop, потому что только один из декодеров может их обрабатывать.


Обычно вы не используете встроенные функции для FPскалярные инструкции типа cmpsd или addsd, но они существуют в том случае, если вы хотите их (например, как последний шаг в горизонтальной сумме).Чаще всего вы просто предоставляете компилятору использовать скалярные версии инструкций при компиляции скалярного кода без автоматической векторизации.

И часто для скалярных сравнений компиляторы будут нуждаться в результате в EFLAGS, поэтому вместо них будут использовать ucomisdсоздания маски сравнения, но для кода без ответвлений маска часто полезна, например, для a < b ? c : 0.0 с cmpsd и andpd.(Или действительно andps, потому что он короче и делает то же самое, что и бессмысленный andpd.)

...