Я знаю, что они могут правильно выполняться только после того, как инструкции перед ними в Re-Order Buffer зафиксированы. Я сомневаюсь, что современные процессоры удерживают их до тех пор, пока они не станут последними в ROB, или какие-либо счетчики/структуры прогнозирования используются даже для прогнозирования значений флага, таких как нулевой флаг или флаг переноса, а затем повторяют их, если они были неверно предсказаны
Как работает выполнение вне очереди с условными инструкциями, например: CMOVcc в Intel или ADDNE (добавить не равно) в ARM
Ответы (1)
Я знаю, что они могут правильно выполняться только после того, как инструкции перед ними в Re-Order Buffer зафиксированы.
Нет, им нужны только их собственные входные данные, чтобы быть готовыми: эти конкретные предыдущие инструкции выполнены, а не отменены/зафиксированы.
Инструкции с условным перемещением (и предикативное выполнение ARM) обрабатывают ввод флагов как зависимость данных, точно так же, как сложение с переносом, или точно так же, как целочисленный входной регистр. Условная инструкция не может быть отправлена исполнительному устройству, пока все 3 его входа не будут готовы1. (Или в ARM, флаги + столько входных данных, сколько обычно имеет предикатная инструкция.)
В отличие от управляющих зависимостей (ветвей), они не предсказывают и не предполагают, какими будут флаги, поэтому cmovcc
вместо jcc
может создать циклическую цепочку зависимостей и в конечном итоге оказаться хуже, чем предсказуемая ветвь. флаг оптимизации gcc -O3 делает код медленнее, чем -O2 тому пример.
Линус Торвальдс более подробно объясняет, почему cmov часто отстой: https://yarchive.net/comp/linux/cmov.html
(Предикативное выполнение ARM может обрабатываться немного по-другому. Он должен логически НЕ выполнять инструкцию, даже для загрузки или сохранения по недопустимому адресу. Это может быть обработано только подавлением ошибок для условной загрузки. ложный предикат по-прежнему стоит любой задержки в цепочке зависимостей для регистра назначения.)
Сноска 1: Вот почему cmovcc
и adc
— это 2 моп в Intel до Broadwell: один моп не может иметь 3 входных зависимостей. Haswell представила поддержку МОПов с 3 входами для FMA.
Инструкции cmov
, которые считывают CF и один из флагов SPAZO (т. е. cmova
и cmovbe
, которые считывают CF и ZF), на самом деле по-прежнему выполняются на Skylake за 2 моп. Подробнее см. в этих вопросах и ответах: кажется, что эти две отдельно переименованные группы флаги являются отдельными входными данными, что позволяет избежать слияния флагов. См. также https://uops.info/ для подсчета uop.
См. также http://agner.org/optimize/ и https://stackoverflow.com/tags/x86/info для получения дополнительной информации о микроархитектурах x86 и руководств по оптимизации.
CMOVcc r,r
состоит из 1 uop
на Broadwell+
, но 2 мкп на Haswell-
. Однако на моем KbL i7-8550U
счетчики производительности показывают, что он включает 2 мопов. Я полагаю, это была опечатка.
- person St.Antario; 05.04.2020
cmova
или cmovbe
? Это все еще 2 мопов, потому что они считывают и CF, и флаг из кластера SPAZO (в частности, ZF). Другие инструкции CMOV являются однократными. См. uops.info См. также Что является частичной задержкой флага? для получения подробной информации о SKL.
- person Peter Cordes; 05.04.2020