Что такое слияние команд в современных процессорах x86? - PullRequest
1 голос
/ 02 июня 2019

Я понимаю, что существует два типа сочетаний команд:

  1. Микрооперация Fusion
  2. Слияние макросов

Микрооперации - это те операции, которые могут быть выполнены за 1 такт. Если несколько микроопераций слиты, мы получаем «инструкцию».

Если объединены несколько инструкций, мы получаем макрооперацию.

Если слиты несколько макроопераций, мы получим слияние макроопераций.

Я прав?

1 Ответ

5 голосов
/ 02 июня 2019

Нет, слияние полностью отделено от того, как одна сложная инструкция (например, cpuid или lock add [mem], eax) может декодироваться в несколько мопов.

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


Macro-Fusion декодирует cmp / jcc или test / jcc в один uop сравнения-и-ветвления. (процессоры Intel и AMD). Остальная часть конвейера рассматривает его исключительно как один uop 1 (за исключением того, что счетчики производительности все еще считают его как 2 инструкции). Это экономит место в кэше UOP и пропускную способность повсюду, включая декодирование. В некотором коде сравнение и ветвление составляют значительную долю всего набора команд, например, может быть 25%, поэтому выбор поиска этого слияния, а не других возможных слияний, таких как mov dst,src1 / or dst,src2, имеет смысл.

Семейство Sandybridge также может макросить некоторые другие инструкции ALU с условными ветвями, например add / sub или inc / dec + JCC с некоторыми условиями. ( x86_64 - Сборка - условия цикла и выход из строя )


Micro-fusion хранит 2 мопа из одной и той же инструкции вместе, поэтому они занимают только 1 "слот" в частях конвейера слитых доменов . Но они все равно должны отправлять отдельно для отдельных исполнительных подразделений. А в семействе Intel Sandybridge RS (Reservation Station, он же планировщик) находится в незанятом домене, поэтому они даже хранятся отдельно в планировщике. (См. Сноску 2 в моем ответе о Понимание влияния lfence на цикл с двумя длинными цепочками зависимостей для увеличения длины .)

Семейство P6 имело как RS с плавкой областью, так и ROB, поэтому микрослияние помогло увеличить эффективный размер окна с нарушением порядка. Но, как сообщается, семейство SnB упростило формат uop, сделав его более компактным, что позволило использовать большие размеры RS, которые всегда полезны, а не только для микросинхронных инструкций.

И семейство Sandybridge будет «не ламинировать» индексированные режимы адресации при некоторых условиях, разделяя их на 2 отдельных мопа в своих собственных слотах перед выпуском / переименованием в ROB в некондиционном бэкэнде, так что вы потеряете преимущество интерфейса / выпуска / переименования пропускной способности micro-fusion. См. Режимы микросинтеза и адресации


И то и другое может произойти одновременно

    cmp   [rdi], eax
    jnz   .target

Компакт-диск cmp / jcc может слиться в один цикл ALU cmp-and-branch, а нагрузка из [rdi] может микроплавко сойти с этим шагом.

Отказ микроплавкого предохранителя cmp не предотвращает макросинтез.

Здесь существуют следующие ограничения: RIP-относительный + немедленный никогда не может содержать микроплавкий предохранитель, поэтому cmp dword [static_data], 1 / jnz может выполнять макроплавкий предохранитель, но не микроплавкий.

A cmp / jcc в семействе SnB (например, cmp [rdi+rax], edx / jnz) приведет к макро- и микроплавлению в декодерах, но микросинтез не будет ламинировать до стадии выпуска. (Таким образом, это всего 2 мопа как в fused-domain, так и в unsused-domain: загрузка с индексированным режимом адресации и ALU cmp/jnz). Вы можете проверить это с помощью счетчиков перфектов, поместив mov ecx, 1 между CMP и JCC против after, и обратите внимание, что uops_issued.any:u и uops_executed.thread оба увеличиваются на 1 за каждую итерацию цикла, потому что мы победили макрослияние. И микросинтез вел себя так же.

На Skylake cmp dword [rdi], 0 / jnz не может слиться с макрокомандой . (Только микро-предохранитель). Я тестировал с циклом, который содержал несколько фиктивных mov ecx,1 инструкций. Переупорядочив, чтобы одна из этих mov инструкций разделила cmp/jcc, не изменились счетчики перфорации для мопов с плавкой или неиспользуемой областью.

Но cmp [rdi],eax / jnz делает макро- и микро-предохранитель . Переупорядочение таким образом, что инструкция mov ecx,1 отделяет CMP от JNZ , меняет ли счетчики перфорации (проверка макрослияния), и значение uops_executed больше, чем значение uops_issued на 1 за итерацию (проверка микросинтеза).

cmp [rdi+rax], eax / jne только макро-предохранители;не микро.(Ну, на самом деле микроплавкие в декодировании, но не ламинируют перед выпуском из-за режима индексированной адресации, и это не место назначения RMW-регистра, такое как sub eax, [rdi+rax], которое может сохранять индексированные режимы адресации в микросинхронизированном виде. Это sub с индексированнымирежим адресации делает макро- и микро-предохранитель на SKL и, предположительно, Haswell).

(cmp dword [rdi],0 делает микро -фьюза, хотя: uops_issued.any:uна 1 меньше, чем uops_executed.thread, и цикл не содержит nop или других «исключенных» инструкций или любых других инструкций памяти, которые могут привести к микропереключению).

Некоторые компиляторы (включая GCC IIRC) предпочитаютиспользуйте отдельную инструкцию загрузки, а затем сравните + ветвь в регистре.TODO: проверьте, являются ли варианты gcc и clang оптимальными с немедленным и регистром.


Микрооперации - это те операции, которые могут быть выполнены за 1 такт.

Не совсем так.Они занимают 1 «слот» в конвейере или в ROB и RS, которые отслеживают их в неработающем бэк-энде.

И да, отправка UOP на порт исполнения происходит за 1 тактцикл и простые мопы (например, сложение целых чисел) могут завершить выполнение в одном и том же цикле.Это может происходить до 8 мопов одновременно с Haswell, но увеличено до 10 в Санни Коув.Фактическое выполнение может занять более 1 такта (занимая исполнительный модуль дольше, например, деление FP).

Делитель - это, я думаю, единственный исполнительный модуль в современном основном Intel, который не полностью конвейеризован, но Knight's Landingимеет некоторые не полностью конвейеризованные тасования SIMD, которые являются однопроцессорными, но (взаимная) пропускная способность которых составляет 2 цикла.).


Сноска 1:

Если cmp [rdi], eax / jneошибки операнда памяти, т.е. исключение #PF, оно берется с адресом возврата исключения, указывающим перед cmp.Поэтому я думаю, что даже обработка исключений все еще может обрабатывать это как одну вещь.

Или, если целевой адрес ветвления является поддельным, исключение #PF произойдет после того, как ветвь уже выполнена, извыборка кода с обновленным RIP.Опять же, я не думаю, что есть способ успешно выполнить cmp и ошибка jcc, требуя исключения, когда RIP указывает на JCC.

Но даже в этом случаеесть вероятность, что процессор должен быть спроектирован для обработки, сортировка может быть отложена до фактического обнаружения исключения.Может быть, с помощью микрокода или с каким-то особым оборудованием.

Что касается того, как ump cmp / jcc проходит по конвейеру в обычном случае, он работает точно так же, как одна длинная команда с одним мопом, которую устанавливают обаФлаги и условно разветвляются.

Удивительно, но инструкция loop (например, dec rcx/jnz, но без установки флагов) - это , а не единичная операция на процессорах Intel. Почему инструкция цикла слишком медленная?Разве Intel не смогла реализовать это эффективно? .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...