При оптимизации для процессоров Intel всегда помещайте инструкцию установки флага прямо перед инструкцией условного перехода (если она одна из простых, перечисленных в таблице ниже), чтобы они могли объединиться в один муп в декодерах.
Это не намного хуже для старых процессоров, которые не поддерживают макрослияние. Установка флага раньше может сократить штраф за неверное предсказание ветвления на единицу для таких процессоров, но выполнение вне очереди означает, что перемещение dec
на пару инструкций раньше не будет иметь реального значения. См. Также Избегайте остановки конвейера, вычисляя условное раннее. Чтобы действительно иметь значение, вы делаете такие вещи, как разворачивание цикла и / или ветвление на чем-то, что может быть вычислено более просто, в идеале без зависимости от медленного ввода, поэтому OoO exec может иметь ветвь, уже разрешенную во время работы над более старыми итерациями тело цикла. то есть счетчик циклов dep-chain может работать раньше основной работы.
У меня нет тестов, но я не думаю, что небольшой недостаток все более редких процессоров оправдывает упущение преимущества пропускной способности внешнего интерфейса (декодирование и выпуск) для процессоров, которые выполняют слияние. Общая пропускная способность uop часто может быть узким местом.
AMD Bulldozer / Piledriver / Steamroller может объединять test/cmp
с любыми jcc
, но только с test/cmp
, а не с любыми другими инструкциями ALU. Так что однозначно ставлю сравнения с ветками. Для процессоров Intel по-прежнему полезно размещать другие вещи с ветвями, если они могут макросовкладывать семейство Sandybridge.
Из руководства по микроархитекту Агнера Фога, таблица 9.2 (для Sandybridge / Ivybridge):
First | can pair with these | cannot pair with
instruction | (and the inverse) |
---------------------------------------------
cmp |jz, jc, jb, ja, jl, jg| js, jp, jo
add, sub |jz, jc, jb, ja, jl, jg| js, jp, jo
adc, sbb |none |
inc, dec |jz, jl, jg | jc, jb, ja, js, jp, jo
test | all |
and | all |
or, xor, not, neg | none |
shift, rotate | none |
Table 9.2. Instruction fusion
Таким образом, inc/dec
может объединяться с jcc
макросами, если условие зависит только от битов, измененных inc/dec
.
(В противном случае они не сливаются с макросами, и вы получаете дополнительный uop, вставленный для слияния флагов (например, когда вы читаете eax
после записи al
). Или на более ранних процессорах, остановка частичных флагов.)
Core2 / Nehalem был более ограничен в возможностях макро-слияния (только для CMP / TEST с более ограниченными комбинациями JCC), а Core2 вообще не мог макрос-слияние в 64-битном режиме.
Прочтите также руководства Agner Fog по оптимизации asm и C, если вы еще этого не сделали. Они полны важных знаний.
person
Peter Cordes
schedule
03.08.2015
dec
не рекомендуется, потому что это вызывает частичную остановку обновления флагов. - person Jester   schedule 02.08.2015dec
иadd
? В таком случае нельзя использоватьjcxz
? (Вы не можете сделать условный переход независимо от инструкции, которая создает условие). - person davmac   schedule 02.08.2015lea 4(%esi),%esi
для добавления, это не влияет на флаги, поэтому вы можете вставитьsubl $1, %ecx
выше. Как говорит @davmac, вы не можете избавиться от зависимости, если не используете инструкциюloop
, что снова не рекомендуется. - person Jester   schedule 02.08.2015jcxz
, если только это не позволит вам избежать инструкцийtest
илиcmp
. В процессорах Intel это двухкомпонентная инструкция. (Меньше проблем, когда код находится в кэше uop, иначе это может замедлить декодирование, потому что с ним может справиться только сложный декодер.) - person Peter Cordes   schedule 03.08.2015dec
в порядке, если он макрос-сливается со следующей ветвью (на процессорах Intel). Процессоры AMD также избегают срывов с частичным флагом, рассматривая отдельные биты флагов как независимые. (Тем не менее, я не тестировал AMD или корпус Intel, не связанный с макросами.) - person Peter Cordes   schedule 03.08.2015