Как работает выполнение вне очереди с условными инструкциями, например: CMOVcc в Intel или ADDNE (добавить не равно) в ARM

Я знаю, что они могут правильно выполняться только после того, как инструкции перед ними в Re-Order Buffer зафиксированы. Я сомневаюсь, что современные процессоры удерживают их до тех пор, пока они не станут последними в ROB, или какие-либо счетчики/структуры прогнозирования используются даже для прогнозирования значений флага, таких как нулевой флаг или флаг переноса, а затем повторяют их, если они были неверно предсказаны


person Tiwari    schedule 21.06.2018    source источник


Ответы (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 и руководств по оптимизации.

person Peter Cordes    schedule 21.06.2018
comment
Агнер Фог в своей таблице инструкций упоминает, что CMOVcc r,r состоит из 1 uop на Broadwell+, но 2 мкп на Haswell-. Однако на моем KbL i7-8550U счетчики производительности показывают, что он включает 2 мопов. Я полагаю, это была опечатка. - person St.Antario; 05.04.2020
comment
@St.Antario: Вы использовали cmova или cmovbe? Это все еще 2 мопов, потому что они считывают и CF, и флаг из кластера SPAZO (в частности, ZF). Другие инструкции CMOV являются однократными. См. uops.info См. также Что является частичной задержкой флага? для получения подробной информации о SKL. - person Peter Cordes; 05.04.2020