Проверьте, равен ли регистр нулю с помощью CMP reg, 0 против OR reg, reg?

Есть ли разница в скорости выполнения, используя следующий код:

cmp al, 0 je done 

и следующее:

 or al, al jz done 

Я знаю, что инструкции JE и JZ одинаковы, а также то, что использование OR дает улучшение размера одного байта. Тем не менее, я также обеспокоен скоростью кода. Похоже, что логические операторы будут быстрее SUB или CMP, но я просто хотел убедиться. Это может быть компромисс между размером и скоростью или беспроигрышный (конечно, код будет более непрозрачным).

Это зависит от точной последовательности кода, конкретного процессора и других факторов.

Основная проблема с or al, al, заключается в том or al, al, что она «изменяет» EAX , а это означает, что последующая инструкция, использующая EAX каким-либо образом, может остановиться до завершения этой инструкции. Обратите внимание, что условная ветвь ( jz ) также зависит от инструкции, но производители процессоров выполняют большую работу (предсказание ветвей и спекулятивное выполнение), чтобы смягчить это. Также обратите внимание, что теоретически возможно, что разработчик ЦП для проектирования ЦП, который распознает EAX , в этом конкретном случае не изменяется, но есть сотни этих особых случаев, и преимущества распознавания большинства из них слишком малы.

Основная проблема с cmp al,0 заключается в том, что она немного больше, что может означать медленное извлечение команды / избыточное давление в кеше, и (если это цикл) может означать, что код больше не подходит для «циклического буфера» процессора.

Как отметил Шутт в комментариях; test al,al избегает обеих проблем – он меньше, чем cmp al,0 и не изменяет EAX .

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

Да , есть разница в производительности.

Лучшим выбором для сравнения регистра с нолем на современном x86 является test reg, reg (если ZF уже не установлен надлежащим образом инструкцией, устанавливающей reg ). Это как AND reg,reg но без записи адресата.

or reg,reg не может использовать макро-предохранитель, добавляет латентность для всего, что читает его позже, и для получения результата нужен новый физический регистр. (Таким образом, он использует ресурсы для переименования реестров, где test не будет, ограничивая окно инструкции не по заказу процессора ). (Переписывание dst может стать победой в семействе Intel P6, хотя, см. Ниже.)


Результаты флага test reg,reg / and reg,reg / or reg,reg идентичны cmp reg, 0 во всех случаях (кроме AF):

  • CF = OF = 0 потому что test / and всегда это делает, и для cmp потому что вычитание нуля не может переполняться или переноситься.
  • ZF , SF , PF устанавливаются в соответствии с результатом (т.е. reg ): reg&reg для теста или reg - 0 для cmp. Таким образом, вы можете протестировать отрицательные целые числа или без знака с высоким битом, установленным при просмотре SF.

    Или с jl , поскольку OF = 0, поэтому условие l ( SF!=OF ) эквивалентно SF . Каждый процессор, который может использовать MEST TEST / JL, может также использовать MEST-TEST / JS, даже Core2. Но после CMP byte [mem],0 , всегда используйте JL, а не JS, чтобы разветвить бит знака.

( AF не определена после test , но задана в соответствии с результатом для cmp . Я игнорирую это, потому что это действительно неясно: единственными потребителями для AF являются ASCII-настраиваемые команды BCD, такие как AAS , и lahf / pushf .)


test короче для кодирования, чем cmp с немедленным 0, во всех случаях, кроме случая cmp al, imm8 который по-прежнему остается двумя байтами. Даже в этом случае test предпочтительнее по причинам макро-фьюжн (с jle и аналогичным по Core2), и потому что отсутствие немедленного вообще может помочь повысить плотность кеш-памяти, оставив слот, который может использовать другая команда, если ему нужно больше места (SnB -семейством).


Декодеры процессоров Intel и AMD могут выполнять внутренний test с cmp предохранителем и cmp с некоторыми условными инструкциями ветвления в единую операцию сравнения и ветвления. Это дает максимальную пропускную способность 5 инструкций за цикл, когда происходит макро-слияние, против 4 без макро-слияния. (Для процессоров Intel с Core2.)

Недавние процессоры Intel могут с макросплавкой выполнять некоторые инструкции (например, and или add / sub ), а также test и cmp , но or не являются одним из них. Процессоры AMD могут объединять test и cmp с JCC. См. X86_64 – Условия сборки и порядок работы или просто обратитесь непосредственно к документам микроархива Agner Fog для деталей о том, какой CPU может скомпенсировать. test может быть макро-предохранителем в некоторых случаях, когда cmp не может, например, с js .

Почти все простые операторы ALU (побитовые логические, add / sub и т. Д.) Запускаются за один цикл. Все они имеют одинаковую «стоимость» при отслеживании их по конвейеру исполнения вне очереди. Intel и AMD тратят транзисторы на то, чтобы сделать быстрые исполнительные блоки для добавления / суб / всего за один цикл. Да, побитовое OR или OR проще и, вероятно, потребляет меньше энергии, но все равно не может работать быстрее, чем один такт.


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

Тем не менее, на процессорах семейства P6 (PPro / PII до Nehalem) запись адресата может фактически быть преимуществом . Существует ограниченное количество портов чтения регистра для этапа выпуска / переименования для чтения из файла постоянного регистра, но недавно написанные значения доступны непосредственно из ROB. Неправильное переписывание регистра может привести к тому, что он снова будет работать в сети переадресации, чтобы избежать сбоев при чтении регистра. (См . Микроархит Agner Fog pdf .

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

К сожалению, компиляторы-писатели в то время не знали будущего, потому что and eax,eax выполняет в точности эквивалентно or eax,eax на семействе Intel P6, но хуже на других ургах, потому что and может использовать макро-предохранитель на Sandybridge- семьи.

Для Core2 / Nehalem (последние 2 урфий семейства P6) test может быть макро-предохранителем, но and не может, поэтому (в отличие от Pentium II / III / M) это компромисс между макро-слиянием и, возможно, читать киоски. Уклонение от регистрации в режиме ожидания-чтения остается по-прежнему за счет дополнительной задержки, если значение считывается после тестирования, поэтому test может быть лучшим выбором, чем and в некоторых случаях даже до cmov или setcc , а не jcc или на процессорах без макро-слияния.

Если вы настроите что-то быстро на несколько uarches, используйте test если профилирование не показывает, что стойки для чтения в регистре являются большой проблемой в конкретном случае на Core2 / Nehalem и используют and фактически исправляют его.

IDK, где произошла or reg,reg идиома, за исключением, может быть, ее короче набирать. Или, возможно, это было специально предназначено для процессоров P6, чтобы переписать регистр преднамеренно, прежде чем использовать его еще немного. Кодеры в то время не могли предсказать, что это окажется менее эффективным, чем and для этой цели. Но, очевидно, мы никогда не должны использовать его в test или в новом коде. (Есть только разница, когда это происходит непосредственно перед jcc на семействе Sandybridge, но проще просто забыть о or reg,reg .)


Чтобы проверить значение в памяти , это прекрасно для cmp dword [mem], 0 , но процессоры Intel не могут устанавливать команды установки флага cmp dword [mem], 0 макросов, которые имеют как непосредственный, так и операнд памяти. Если вы собираетесь использовать значение после сравнения в одной из ветвей ветки, вы должны, вероятно, использовать mov eax, [mem] / test eax,eax или что-то еще. Если нет (например, тестирование логического), cmp с операндом памяти в порядке.

Хотя обратите внимание, что некоторые режимы адресации не будут микшироваться либо в семействе SnB : RIP-relative + немедленный не будет микро-предохранителем в декодерах, или режимы с индексированной адресацией не будут ламинировать. В любом случае, это приводит к 3- cmp dword [rsi + rcx*4], 0 доменами для cmp dword [rsi + rcx*4], 0 / jne или [rel some_static_location] .

Вы также можете проверить значение в памяти с помощью test dword [mem], -1 , но не делать этого. Так как test r/m16/32/64, sign-extended-imm8 недоступен, это хуже размер кода, чем cmp для чего-либо большего, чем байты. (Я думаю, что идея дизайна заключалась в том, что если вы хотите протестировать только небольшой бит регистра, просто test cl, 1 вместо test ecx, 1 , и примеры использования, такие как test ecx, 0xfffffff0 , достаточно редки, чтобы не было стоит потратить опкод. Тем более, что это решение было принято для 8086 с 16-битным кодом, где это была только разница между imm8 и imm16, а не imm32.)

Я написал -1, а не 0xFFFFFFFF, так что это будет то же самое с byte или qword . ~0 это еще один способ написать его.

  • Как вы прокручиваете загруженные в настоящее время сборки?
  • x86_64 - Условия сборки и выход из строя
  • Как я могу перечислить все загруженные сборки?
  • Безопасно ли читать конец конца буфера на одной странице на x86 и x64?
  • Возможно ли одноуровневое многоязычное развертывание Windows Forms (ILMerge и спутниковые сборки / локализация)?
  • Как объединить несколько сборок в один?
  • Как определить, была ли assembly .NET построена для x86 или x64?
  • Есть ли альтернатива Maven или порт для мира .NET?
  • Visual Studio 2010 не создает перед запуском при изменении кода
  • Как загрузить сборку .NET для операций отражения и впоследствии выгрузить ее?
  • Как точно работает инструкция x86 LOOP?
  • Interesting Posts

    Составьте список селекторов с МЕНЬШЕ

    Как установить цвет текста TextView в коде?

    EF5 Получение этого сообщения об ошибке: Совместимость модели не может быть проверена, поскольку firebase database не содержит метаданных модели

    .NET HttpClient. Как значение строки POST?

    Как использовать различное масштабирование для каждого монитора?

    Автозагрузка файлов lib в Rails 4

    gfortran для макетов: что делает mcmodel = medium?

    Как улавливать исключения / недостающие страницы в Laravel 5?

    «Все параметры загрузки проверяются» после обновления BIOS

    Использование свойств javafx.beans в classах моделей

    angular2 resolveAndCreate HTTP – отсутствует HTTP_PROVIDERS в RC7

    Ошибка в файле styles_base.xml – приложение для Android – Ресурс не найден, который соответствует указанному имени ‘android: Widget.Material.ActionButton’

    Создать простой HTTP-сервер с Java?

    Функция jQuery.active

    Как я могу скрыть экран моего компьютера за пределы минимума?

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