введите vs нажмите ebp; mov ebp, esp; sub esp, imm и leave vs mov esp, ebp; поп-эбп

В чем разница между enter и

push ebp
mov  ebp, esp
sub  esp, imm

инструкции? Есть ли разница в производительности? Если да, то что быстрее и почему компиляторы всегда используют последнее?

Аналогично с leave и

mov  esp, ebp
pop  ebp

инструкции.


person 小太郎    schedule 11.05.2011    source источник


Ответы (4)


Есть разница в производительности, особенно для enter. На современных процессорах это декодирование составляет от 10 до 20 мкопс, в то время как последовательность из трех инструкций составляет от 4 до 6, в зависимости от архитектуры. Подробнее см. В таблицах инструкций Agner Fog.

Кроме того, инструкция enter обычно имеет довольно высокую задержку, например, 8 тактов на ядре 2, по сравнению с цепочкой зависимостей 3 тактов для последовательности из трех инструкций.

Кроме того, последовательность из трех инструкций может быть распределена компилятором для целей планирования, конечно, в зависимости от окружающего кода, чтобы обеспечить более параллельное выполнение инструкций.

person Gunther Piez    schedule 11.05.2011
comment
Могу я спросить, откуда у вас эта информация? А что насчет leave? - person 小太郎; 12.05.2011
comment
См. agner.org/optimize/microarchitecture.pdf для глобального обзора того, как процессор выполняет code и agner.org/optimize/instruction_tables.pdf для получения подробной информации о задержках выполнения инструкций. leave на некоторых архитектурах одинаковая по производительности, но AFAIK ни в коем случае не быстрее. Он потребляет меньше памяти в кеше инструкций, хотя - person Gunther Piez; 12.05.2011
comment
Если последовательность из 3 инструкций быстрее, чем enter, в чем ее смысл? - person 小太郎; 14.05.2011
comment
Совместимость. Он существует с 8086 года и, скорее всего, будет всегда. То же самое и с инструкцией loop: она намного медленнее, чем dec reg; jnz, но она все еще существует, потому что какое-то старое программное обеспечение может ее использовать. - person Gunther Piez; 14.05.2011
comment
Входов / выходов не было в 8086/8. Я считаю, что они были добавлены в 80186/8, поскольку эти (редко используемые) чипы имели все инструкции реального режима iapx286 (которые хорошо документированы, чтобы иметь вход / выход). - person Brian Knoblauch; 05.07.2013

При использовании любого из них нет реального преимущества в скорости, хотя длинный метод, вероятно, будет работать лучше из-за того, что в наши дни ЦП более `` оптимизированы '' для более коротких и простых инструкций, которые являются более общими в использовании (плюс он позволяет насыщать выполнение порты, если повезет).

Преимущество LEAVE (который все еще используется, просто посмотрите DLL-файлы Windows) в том, что он меньше, чем ручной разрыв фрейма стека, это очень помогает, когда ваше пространство ограничено.

Руководства по эксплуатации Intel (если быть точным, том 2A) будут содержать более подробные сведения об инструкциях, так же как и д-р Агнер Фогс Руководства по оптимизации

person Necrolis    schedule 11.05.2011

При разработке 80286 разработчики процессоров Intel решили добавить две инструкции для обслуживания дисплеев.

Вот микрокод внутри процессора:

; ENTER Locals, LexLevel

push    bp              ;Save dynamic link.
mov     tempreg, sp     ;Save for later.
cmp     LexLevel, 0     ;Done if this is lex level zero.
je      Lex0

lp:
dec     LexLevel
jz      Done            ;Quit if at last lex level.
sub     bp, 2           ;Index into display in prev act rec
push    [bp]            ; and push each element there.
jmp     lp              ;Repeat for each entry.

Done:
push    tempreg         ;Add entry for current lex level.

Lex0:
mov     bp, tempreg     ;Ptr to current act rec.
sub     sp, Locals      ;Allocate local storage

Альтернативой ENTER может быть:

; введите n, 0; 14 циклов на 486

push    bp              ;1 cycle on the 486
sub     sp, n           ;1 cycle on the 486

; введите n, 1; 17 циклов на 486

push    bp              ;1 cycle on the 486
push    [bp-2]          ;4 cycles on the 486
mov     bp, sp          ;1 cycle on the 486
add     bp, 2           ;1 cycle on the 486
sub     sp, n           ;1 cycle on the 486

; введите n, 3; 23 цикла на 486

push    bp              ;1 cycle on the 486
push    [bp-2]          ;4 cycles on the 486
push    [bp-4]          ;4 cycles on the 486
push    [bp-6]          ;4 cycles on the 486
mov     bp, sp          ;1 cycle on the 486
add     bp, 6           ;1 cycle on the 486
sub     sp, n           ;1 cycle on the 486

Экт. Длинный способ может увеличить размер вашего файла, но это намного быстрее.

в последней заметке, программист больше не использует display, так как это была очень медленная работа, что делало ENTER сейчас довольно бесполезным.

Источник: https://courses.engr.illinois.edu/ece390/books/artofasm/CH12/CH12-3.html

person Pr0c3ss0r    schedule 02.05.2014
comment
The; введите n, 0; 14 циклов в примере 486 отсутствует строка mov bp, sp. И enter, и leave появились на 186, а не на 286. - person ecm; 12.07.2020

enter работает необычно медленно на всех процессорах, никто не использует его, за исключением, возможно, оптимизации размера кода за счет скорости. (Если указатель кадра вообще необходим или желательно обеспечить более компактные режимы адресации для адресации пространства стека.)

leave достаточно быстр, чтобы его стоило использовать, а GCC действительно использует его (если ESP / RSP еще не указывает на сохраненный EBP / RBP; в противном случае используется просто pop ebp).

leave составляет всего 3 мупа на современных процессорах Intel (и 2 на некоторых AMD). (https://agner.org/optimize/, https://упс.info/).

mov / pop всего 2 мупа (на современной x86, где движок стека отслеживает обновления ESP / RSP). Так что leave - это всего лишь на один удар больше, чем делать что-то по отдельности. Я тестировал это на Skylake, сравнивая call / ret в цикле с функцией, устанавливающей традиционный указатель фрейма и разрывая его фрейм стека с помощью _6 _ / _ 7_ или leave. perf счетчики для uops_issued.any показывают на один интерфейсный uop больше, чем для mov / pop. (Я провел свой собственный тест на случай, если другие методы измерения подсчитывают синхронизацию стека в своих измерениях отпуска, но используют его в реальных элементах управления для этого.)

Возможные причины, по которым старые процессоры могли получить больше преимуществ при разделении mov / pop:

  • В большинстве процессоров без кэша uop (например, Intel до Sandybridge, AMD до Zen) инструкции с несколькими uop могут быть узким местом при декодировании. Они могут декодировать только в первом (сложном) декодере, что может означать, что цикл декодирования до этого производил меньше мопов, чем обычно.

  • Некоторые соглашения о вызовах Windows представляют собой аргументы стека вызываемых объектов с использованием ret n. (например, ret 8 для выполнения ESP / RSP + = 8 после появления адреса возврата). Это многопозиционная инструкция, в отличие от простой около ret на современных x86. Таким образом, указанная выше причина двоякая: оставьте и ret 12 не смогли декодировать в одном и том же цикле.

  • Эти причины также применимы к устаревшему декодированию для создания записей uop-cache.

  • P5 Pentium также предпочел RISC-подобную подмножество x86, будучи неспособным даже разбить сложные инструкции на отдельные uops вообще.

Для современных ЦП leave занимает 1 лишнюю моп в кэше мопов. И все 3 должны находиться в одной строке кэша uop, что может привести только к частичному заполнению предыдущей строки. Таким образом, больший размер кода x86 может фактически улучшить упаковку в кэш uop. Или нет, смотря как обстоят дела.

Сохранение 2 байтов (или 3 в 64-битном режиме) может стоить или не стоить 1 лишних моп на функцию.

GCC поддерживает leave, clang и MSVC поддерживает _17 _ / _ 18_ (даже с clang -Oz оптимизацией размера кода даже за счет скорости, например, выполнение таких вещей, как push 1 / pop rax (3 байта) вместо 5-байтового mov eax,1).

ICC отдает предпочтение mov / pop, но с -Os будет использовать leave. https://godbolt.org/z/95EnP3G1f

person Peter Cordes    schedule 06.05.2021