Относительная производительность команды x86 inc vs. add
Быстрый вопрос, предполагая заранее
mov eax, 0
который более эффективен?
inc eax
inc eax
или
add eax, 2
Кроме того, в случае, если два inc
работают быстрее, обычно ли компиляторы (скажем, GCC) (т.е. без агрессивных флагов оптимизации) оптимизируют var += 2
?
Спасибо за ваше время!
PS: Не утруждайте себя ответом с изменением "не досрочно оптимизируйте", это просто академический интерес.
Ответы
Ответ 1
Две инструкции inc
в том же регистре (или, вообще говоря, две инструкции чтения-изменения-записи) всегда имеют цепочку зависимостей, состоящую не менее чем из двух циклов. Это предполагает одну задержку в часах для inc, что имеет место с 486. Это означает, что если окружающие инструкции не могут чередоваться с двумя командами inc, чтобы скрыть эти задержки, код будет выполняться медленнее.
Но никакой компилятор не будет генерировать последовательность команд, которую вы предлагаете в любом случае (mov eax,0
будет заменен на xor eax,eax
, см. В чем цель XORing реестра с самим собой?)
mov eax,0
inc eax
inc eax
он будет оптимизирован для
mov eax,2
Ответ 2
Если вы когда-либо захотите узнать сырую статистику производительности инструкций x86, см. Dr Agner Fogs листинга (объем 4, если быть точным). Что касается части о компиляторах, которая зависит от генератора кода компилятора, а не о том, на что вы должны полагаться слишком много.
на стороне примечания: мне смешно/иронично, что в вопросе о производительности вы использовали MOV EAX,0
для нулевого регистра вместо XOR EAX,EAX
: P (и если MOV EAX,0
было сделано заранее, самый быстрый вариант было бы удалить inc и добавить и просто MOV EAX,2
).
Ответ 3
Для всех целей это, вероятно, не имеет значения. Но учтите, что inc использует меньше байтов.
Рассмотрим следующий код:
int x = 0;
x += 2;
Без использования каких-либо флагов оптимизации GCC компилирует этот код в:
80483ed: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
80483f4: 00
80483f5: 83 44 24 1c 02 addl $0x2,0x1c(%esp)
Используя -O1
и -O2
, он становится:
c7 44 24 08 02 00 00 movl $0x2,0x8(%esp)
Смешно, не так ли?
Ответ 4
В руководстве Intel, которое вы можете найти здесь, похоже, что инструкции ADD/SUB в два раза дешевле одной конкретной архитектуры. Но помните, что Intel использует для него (недавние) процессоры модель исполнения вне очереди. Это в первую очередь означает, что узкие места производительности обнаруживаются там, где процессору приходится ждать ввода данных (например, в процессе получения данных L1/L2/L3/RAM не хватало вещей). Поэтому, если вы профилировщик говорит вам, что проблема с INC может быть проблемой; посмотрите на это, чтобы сформировать точку доступа к данным, вместо того, чтобы смотреть на количество необработанных циклов.
Instruction Latency1 Throughput Execution Unit
2
CPUID 0F_3H 0F_2H 0F_3H 0F_2H 0F_2H
ADD/SUB 1 0.5 0.5 0.5 ALU
[...]
DEC/INC 1 1 0.5 0.5 ALU