LEA или ADD?

Когда я создаю почерк, я обычно выбираю форму

lea eax, [eax+4] 

По форме ..

 add eax, 4 

Я слышал, что lea – это «0-часовая» инструкция (например, NOP), а «add» – нет. Однако, когда я смотрю на сборщик, выпущенный сборкой, я часто вижу последнюю форму, используемую вместо первой. Я достаточно умен, чтобы доверять компилятору, так может ли кто-нибудь пролить свет, на котором лучше? Какой из них быстрее? Почему компилятор выбирает последнюю форму над первой?

Одно существенное различие между LEA и ADD на процессорах x86 – это исполнительный блок, который фактически выполняет инструкцию. Современные процессоры x86 являются суперскалярными и имеют несколько исполнительных блоков, которые работают параллельно, причем конвейер подает их несколько как круглые (барные стойки). Дело в том, что LEA обрабатывается (одним из) единицей (адресами), касающейся адресации (что происходит на ранней стадии в конвейере), тогда как ADD переходит к ALU (арифметическим / логическим единицам) и в конце трубопровод. Это означает, что суперскалярный процессор x86 может одновременно выполнять LEA и арифметическую / логическую инструкцию.

Тот факт, что LEA проходит логику генерации адресов вместо арифметических единиц, также является причиной, по которой ее называли «нулевые часы»; это не требует времени для выполнения, потому что генерация адресов уже произошла к моменту его выполнения /.

Это не бесплатно , поскольку генерация адресов является шагом в конвейере выполнения, но на него не наложен накладные расходы. И он не занимает слот в трубопроводах ALU.

Изменить: Чтобы уточнить, LEA не является бесплатным . Даже на процессорах, которые не реализуют его через арифметический блок, требуется время для выполнения из-за команд декодирования / отправки / выхода на пенсию и / или других этапов конвейера, которые проходят все инструкции. Время, затраченное на выполнение LEA просто происходит на другом этапе конвейера для процессоров, которые реализуют его посредством генерации адресов.

Я достаточно умен, чтобы доверять компилятору, так может ли кто-нибудь пролить свет, на котором лучше?

Да, немного. Во-первых, я беру это из следующего сообщения: https://groups.google.com/group/bsdnt-devel/msg/23a48bb18571b9a6

В этом сообщении разработчик оптимизирует некоторые сборки, которые я написал очень плохо, чтобы работать безумно быстро в процессорах Intel Core 2. В качестве фона для этого проекта, это библиотека bsd bignum, в которую я и несколько других разработчиков были вовлечены.

В этом случае все, что оптимизируется, это добавление двух массивов, которые выглядят так: uint64_t* x, uint64_t* y . Каждая «конечность» или член массива представляет собой часть бигума; основной процесс состоит в том, чтобы перебирать его, начиная с наименее значимой конечности, добавлять пару вверх и продолжать вверх, каждый раз перенося перенос (любое переполнение). adc делает это для вас на процессоре (невозможно получить доступ к флагом переноса из CI, не думайте).

В этом fragmentе кода используется комбинация lea something, [something+1] и jrcxz , которые, по-видимому, более эффективны, чем jnz / add something, size пары, которую мы ранее могли использовать. Однако я не уверен, что это было обнаружено в результате простого тестирования разных инструкций. Вы должны спросить.

Однако в более позднем сообщении он измеряется на чипе AMD и не работает так хорошо.

Мне также дано понять, что разные операции выполняются по-разному на разных процессорах. Я знаю, например, что проект GMP обнаруживает процессоры, использующие cpuid и проходит в разных сборочных процедурах на основе разных архитектур, например core2 , nehalem .

Вопрос, который вы задаете себе, заключается в том, что ваш компилятор производит оптимизированный вывод для вашей архитектуры процессора? Известно, что компилятор Intel, как известно, делает это, поэтому, возможно, стоит измерить производительность и посмотреть, какой результат он производит.

LEA не быстрее, чем команда ADD, скорость выполнения одинакова.

Но LEA иногда предлагает больше, чем ADD . Если нам нужно простое и быстрое добавление / умножение в сочетании со вторым регистром, то LEA может ускорить выполнение программы. С другой стороны LEA не влияет на флаг CPU, поэтому нет возможности обнаружения переполнения.

Вы можете выполнить инструкцию lea в том же такте, что и операция добавления, но если вы используете lea и добавляете вместе, вы можете выполнить добавление трех операндов всего за один цикл! Если вы будете использовать две операции добавления, которые могут выполняться только в 2 тактовых циклах:

 mov eax, [esp+4] ; get a from stack mov edx, [esp+8] ; get b from stack mov ecx, [esp+12] ; get c from stack lea eax, [eax+edx] ; add a and b in the adress decoding/fetch stage of the pipeline add eax, ecx ; Add c + eax in the execution stage of the pipeline ret 12 
  • Доступ к x86 COM с x64 .NET
  • об ассемблере CF (Carry) и OF (Overflow)
  • Самый быстрый способ вычисления 128-битного целого по модулю 64-разрядного целого числа
  • Как выполнить инверсию _mm256_movemask_epi8 (VPMOVMSKB)?
  • Загружает и сохраняет только инструкции, которые переупорядочиваются?
  • Потерянные циклы на Intel? Несоответствие между rdtsc и CPU_CLK_UNHALTED.REF_TSC
  • Оптимизация для быстрого умножения, но медленное добавление: FMA и doubleedouble
  • Как отключить компьютер из автономной среды?
  • Печать шестнадцатеричных цифр со сборкой
  • Что такое рамка стека в сборке?
  • x86 Расчет AX с учетом AH и AL?
  • Interesting Posts

    Программная клавиатура изменяет размер фонового изображения на Android

    Как подавить Java-предупреждения для определенных каталогов или файлов, таких как сгенерированный код

    Java BufferedReader вернется к началу текстового файла?

    Excel interop: рабочий стол или рабочий лист?

    Можно ли объявить dispatch_once_t предикат как переменную-член вместо статического?

    Связывание статических библиотек, совместно использующих статическую библиотеку

    Как работает ноутбук с HDD, когда он движется?

    Variable Sized Struct C ++

    nodejs требуется внутри файла TypeScript

    Могу ли я, и как мне удалить старые версии ядра в Ubuntu?

    Как сопоставить строку с строковыми литералами в Rust?

    Что делает размещение @ перед именем переменной C #?

    Объединение строк / строк конкатенации

    Автоматическое удаление старых файлов из корзины при сохранении новых?

    Laravel 5 – глобальная переменная вида Blade, доступная во всех шаблонах

    Давайте будем гением компьютера.