Установка и очистка нулевого флага в x86 - PullRequest
0 голосов
/ 03 февраля 2019

Какой самый эффективный способ установить, а также очистить флаг нуля (ZF) в x86-64?

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

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

ZF = 0

Это сложнее.cmp между любыми двумя регами, которые, как известно, не равны.Или cmp reg,imm с любым значением, которое не может иметь какой-либо регистр.test r32,imm8 не существует (только такая же ширина, как у reg), так что это больше.Но если есть известный бит, который всегда установлен выше нижнего 8, это означает, что само значение reg гарантировано ненулевое, так что вы можете test reg,reg.

В общем случае test reg,reg хорошо с любымзначение регистра с ненулевым значением, например указатель .

или cmp reg,1 с любым регистром с известным нулем.

Я не вижу способа создать ZF = 0в одной инструкции без ложной зависимости от некоторого ввода рег.xor eax,eax / neg eax выполнит трюк за 2 мопа, если вы не против уничтожить регистр, нарушив ложные зависимости.

or eax, -1 не требует каких-либо предварительных условий длязначение регистра. (Ложная зависимость, но не истинная зависимость, поэтому вы можете выбрать любой регистр, даже если он может быть нулевым.) Это не обязательно должно быть -1, это ничего не даст вам, так что если вы можете сделатьэто что-то полезное, тем лучше.

or eax,-1 Результаты FLAG: ZF = 0 PF = 1 SF = 1 CF = 0 OF = 0 (AF = не определено).

Если вам нужно сделать это в цикле, вы, очевидно, можете настроить его на вне цикла, если вы можете назначить регистр ненулевым для использования с test.


ZF = 1

xor-zeroing (например, xor eax,eax с использованием любого свободного регистра), безусловно, самый эффективный способ для семейства SnB (то же самое)стоимость в виде 2-байтового nop или 3-байтового, если ваш свободный регистр равен r8d..r15 и требует префикса REX): 1 входной моп, нулевой внутренний и результат FLAGSготов в том же цикле, что и выдает.(Уместно только в том случае, если внешний интерфейс был остановлен, или если моп в зависимости от него выдает цикл, и в RS нет более старых мопов.)

Результаты пометок: ZF = 1 PF= 1 SF = 0 CF = 0 OF = 0 (AF = undefined).

xor-zero также очень дешев на всех других uarches, конечно: нет входных зависимостей и ненужно любое ранее существующее значение регистра.(И, таким образом, не способствует киоскам чтения регистров семейства P6).Так что в худшем случае это будет связано с чем-то еще, что вы можете сделать на любом другом уарче (где для этого требуется исполнительный блок).

(В раннем семействе P6, до Pentium M, xor -задание делает не разрывает зависимости, он только запускает специальное состояние al = eax, которое позволяет избежать частичной регистрации. Но ни один из этих процессоров не x86-64, все 32-битные.)

Этодовольно часто в любом случае требуется обнулять регистр для чего-либо, например, как sub назначение для 0 - x для копирования и отрицания, поэтому воспользуйтесь этим, поместив обнуление xor там, где это необходимо, чтобы также создать полезный FLAGусловие.


Как и предположил @prl, cmp same,same с любым регистром будет работать без изменения значения .Я подозреваю, что это , а не в специальном случае, поскольку зависимость нарушает способ sub same,same на некоторых процессорах, поэтому выбирает «холодный» регистр .Снова 2 или 3 байта, 1 моп.Он может слиться с JCC, но это будет глупо (если JCC также не является целью ветвления из какого-то другого условия?)

Результаты флага: то же, что xor-zeroing.

Недостатки:

  • (возможно) ложная зависимость
  • на семействе P6 может привести к срыву чтения с регистра, поэтому выберите холодный регистр, который вы уже читаете в ближайших инструкциях.
  • требуется внутреннее исполнительное устройство в семействе SnB

Просто для удовольствия, другие дешевые альтернативы включают test al, 0.2 байта для AL, 3 или 4 байта для любого другого 8-битного регистра.(REX) + код операции + modrm + imm8.Исходное значение регистра не имеет значения, потому что imm8 с нулем гарантирует, что reg & 0 = 0.


Если в регистре вы можете уничтожить 1 или -1, который вы можете уничтожить, 32-битный режим inc или dec установит ZF только в 1 байт.Но в x86-64 это как минимум 2 байта.Ничто не приходит на ум, если в 64-битном режиме работает 1-байтовая инструкция, которая действительно эффективна и устанавливает флаги.


ZF = CF

sbb same,same может установить ZF = CF (оставляяCF немодифицировано), и установите reg на 0 (CF = 0) или -1 (CF = 1).В семействе Bulldozer это не зависит от регистра GP, только CF, но на других uarches это не специальный случай, и есть ложное депо в регистре.


ZF = bool (целочисленный регистр)

Чтобы установить ZF = integer_reg, очевидно, что нормальная test reg,reg является вашей лучшей ставкой .(Лучше, чем and reg,reg или or reg,reg, если только вы намеренно не переписываете регистр, чтобы избежать задержек при чтении из регистра P6.)


Другие условия FLAGS:

CF имеет clc / stc / cmc инструкции.(clc столь же эффективен, как обнуление xor на семействе SnB.)

0 голосов
/ 03 февраля 2019

Если вам не нужно сохранять значения других флагов,

cmp eax, eax
...