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:
- Как читать и записывать регистры флагов x86 напрямую?
- Одна инструкция для очистки PF (Parity Flag) - получить нечетное количество битов в регистре результатов (невозможно)без уже существующих значений регистров для
test
или cmp
). - Как установить или снять флаг переполнения в сборке x86? (например, для начала цепочки ADOX.)
pushf
/ pop rax
не страшно, но запись флагов с popf
очень медленная (например, пропускная способность 1 / 20c в SKL).Он микрокодирован, потому что флаги, такие как IF, также живут в EFLAGS, и не существует версии только для кодов условий или специального быстрого пути для пользовательского пространства.(Или, может быть, 20c - это быстрый путь.) lahf
(FLAGS-> AH) / sahf
(AH-> FLAGS) могут быть полезны, но пропустите OF.
CF имеет clc
/ stc
/ cmc
инструкции.(clc
столь же эффективен, как обнуление xor на семействе SnB.)