- Есть ли разница между использованием того или иного встроенного (с соответствующим приведением типов). Не будет ли каких-либо скрытых затрат, таких как более длительное исполнение в какой-то конкретной ситуации?
Да, могут быть причины выбора одного из вариантов по сравнению с другим.
1: Иногда возникает один или два дополнительных цикла задержки (задержка пересылки), если выход целочисленного исполнительного блока необходимо направить на вход исполнительного блока FP, или наоборот. Для перемещения 128 байт данных в любое из множества возможных мест назначения требуется МНОГО проводов, поэтому разработчикам ЦП приходится идти на компромиссы, например, иметь только прямой путь от каждого выхода FP к каждому входу FP, а не ко ВСЕМ возможным входам.
См. этот ответ или Документ по микроархитектуре Агнера Фога для обхода задержек. Найдите задержку обхода данных на Nehalem в документе Агнера; в нем есть несколько хороших практических примеров и обсуждение. У него есть соответствующий раздел для каждого проанализированного им микроархитектуры.
Однако задержки при передаче данных между разными доменами или разными типами регистров меньше на Sandy Bridge и Ivy Bridge, чем на Nehalem, и часто равны нулю. - Документ по микроархитектуре Агнера Фога
Помните, что задержка не имеет значения, если она не находится на критическом пути вашего кода (кроме случаев, когда в Haswell / Skylake он заражает более позднее использование созданного значения, спустя много времени после фактического обхода: /). Использование pshufd
вместо movaps + shufps
может быть преимуществом, если вашим узким местом является пропускная способность uop, а не задержка критического пути.
2: версия ...ps
занимает на 1 байт кода меньше, чем две другие для устаревшего кодирования SSE. (Не AVX). Это по-разному выровняет следующие инструкции, что может иметь значение для декодеров и / или строк кэша uop. Как правило, меньший размер лучше для лучшей плотности кода в I-кэше и извлечения кода из ОЗУ и его упаковки в кеш-память uop.
3: Последние процессоры Intel могут запускать только версии FP на порту 5.
Merom (Core2) и Penryn: orps
могут работать на p0 / p1 / p5, но только в целочисленном домене. Предположительно все 3 версии декодируются в один и тот же uop. Таким образом, происходит задержка переадресации между доменами. (Процессоры AMD также делают это: побитовые инструкции FP выполняются в домене ivec.)
Nehalem / Sandybridge / IvB / Haswell / Broadwell: por
может работать на p0 / p1 / p5, но orps
может работать только на порту 5. p5 также необходим для перемешивания, но блоки FMA, FP add и FP mul находятся на портах 0/1.
Skylake: por
и orps
оба имеют пропускную способность 3 на цикл. В руководстве Intel по оптимизации есть некоторая информация об обходе задержек пересылки: в / из инструкций FP это зависит от того, на каком порту работает uop. (Обычно все еще порт 5, потому что модули FP add / mul / fma находятся на портах 0 и 1.) См. Также Задержки Haswell AVX / FMA протестированы на 1 цикл медленнее, чем указано в руководстве Intel - задержка обхода может повлиять на каждое использование регистра, пока он не будет перезаписан .
Обратите внимание, что на SnB / IvB (AVX, но не AVX2) только p5 должен обрабатывать логические операции 256b, поскольку vpor ymm, ymm
требует AVX2. Вероятно, это не было причиной изменения, поскольку это сделала Нехалем.
Как выбрать с умом:
Имейте в виду, что компиляторы могут использовать por
вместо _mm_or_pd
, если они хотят, поэтому некоторые из них применимы в основном к рукописному asm. Но некоторые компиляторы в некоторой степени верны выбранным вами встроенным функциям.
Если пропускная способность логических операций на порту 5 может быть узким местом, тогда используйте целочисленные версии, даже для данных FP. Это особенно верно, если вы хотите использовать перемешивание целых чисел или другие инструкции по перемещению данных.
Процессоры AMD всегда используют целочисленный домен для логических операций, поэтому, если у вас есть несколько задач, связанных с целочисленным доменом, делайте их все одновременно, чтобы минимизировать круговые обходы между доменами. Более короткие задержки позволят быстрее очистить буфер переупорядочения, даже если цепочка деплоя не является узким местом для вашего кода.
Если вы просто хотите установить / очистить / перевернуть бит в векторах FP между инструкциями FP add и mul, используйте логические логики ...ps
даже для данных с двойной точностью, потому что одиночный и двойной FP являются одним и тем же доменом на каждом существующем процессоре, и версии ...ps
на один байт короче (без AVX).
Однако есть практические / человеческие причины для использования ...pd
версий с внутренними функциями. Важным фактором является удобочитаемость вашего кода для других людей: они будут удивляться, почему вы обрабатываете свои данные как одиночные, хотя на самом деле они удваиваются. Для встроенных функций C / C ++ забрасывать код приведениями между __m128
и __m128d
не стоит. (И, надеюсь, компилятор все равно будет использовать orps
вместо _mm_or_pd
, если он компилируется без AVX, где он фактически сохранит байт.)
Если настройка на уровне выравнивания insn имеет значение, пишите напрямую в asm, а не в intrinsics! (Если инструкция на один байт длиннее, это может лучше согласовать ситуацию с плотностью строк кэша uop и / или декодерами, но с префиксами и режимами адресации вы можете расширять инструкции в целом)
Для целочисленных данных используйте целочисленные версии. Сохранение одного байта инструкции не стоит задержки обхода между paddd
или чем-то еще, а целочисленный код часто сохраняет порт 5 полностью занятым перемешиванием. Для Haswell многие инструкции перемешивания / вставки / извлечения / упаковки / распаковки стали только p5, вместо p1 / p5 для SnB / IvB. (Ice Lake наконец-то добавила устройство тасования на другой порт для более распространенных тасовок.)
- Эти встроенные функции соответствуют трем различным инструкциям x86 (
por
, orps
, orpd
). Есть ли у кого-нибудь идеи, почему Intel тратит драгоценное пространство кода операции на несколько инструкций, которые делают то же самое?
Если вы посмотрите на историю этих наборов инструкций, вы увидите, как мы сюда попали.
por (MMX): 0F EB /r
orps (SSE): 0F 56 /r
orpd (SSE2): 66 0F 56 /r
por (SSE2): 66 0F EB /r
MMX существовал до SSE, поэтому похоже, что коды операций для инструкций SSE (...ps
) были выбраны из того же 0F xx
пространства. Затем для SSE2 версия ...pd
добавила префикс размера операнда 66
к коду операции ...ps
, а целочисленная версия добавила префикс 66
к версии MMX.
Они могли пропустить orpd
и / или por
, но они этого не сделали. Возможно, они думали, что будущие проекты ЦП могут иметь более длинные пути пересылки между разными доменами, и поэтому использование инструкции сопоставления для ваших данных будет более сложной задачей. Несмотря на то, что существуют отдельные коды операций, AMD и ранние Intel относились к ним одинаково, как к int-векторам.
Связанный / близкий к дубликату:
person
Peter Cordes
schedule
05.07.2015