Нет, слияние полностью отделено от того, как одна сложная инструкция (например, 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 не смогла реализовать это эффективно? .