В x86 какая разница между "test eax, eax" и "cmp eax, 0"

Является ли test eax, eax более эффективным, чем cmp eax, 0? Есть ли случай, когда test eax, eax необходим, когда cmp eax, 0 не отвечает требованиям?

Ответ 1

Как уже сказал Zang MingJie в комментарии, test eax,eax почти идентичен cmp eax,0, за исключением того, что он короче cmp, потому что с cmp вам нужно поставить 0 в качестве аргумента. Обратите внимание, что сбережения не очень велики, потому что второй операнд получает расширенный знак, чтобы соответствовать размеру первого операнда, поэтому он не обязательно принимает целых 4 байта для представления этого нуля.

Теперь вы спрашиваете, есть ли другая разница. Это разумный вопрос, потому что cmp является арифметической операцией (он выполняет вычитание и отбрасывает результат), тогда как test является логической операцией (он выполняет побитовое И и отбрасывает результат), поэтому можно было бы разумно заподозрить что они могут изменять регистр Flags разному.

Как оказалось, обе инструкции изменяют регистр Flags почти одинаковым образом. Обе команды изменяют биты OF SF ZF AF PF и CF в регистре флагов. test команда всегда очищает OF и CF, но также и то, что делает cmp против нуля. Единственное другое отличие состоит в том, что команда cmp правильно установит неясный флаг AF, в то время как test инструкция оставляет содержимое этого флага неопределенным. Но в случае cmp eax,0 AF всегда будет очищаться независимо от значения eax, поэтому нет ничего, что вы можете узнать из cmp eax,0 что вы не узнаете из test eax,eax.

Поэтому я бы пришел к выводу, что нет ситуации, когда test eax,eax даст вам что-то, что cmp eax,0 не будет, и не наоборот. Две инструкции кажутся полностью взаимозаменяемыми для любой практической или даже не столь практичной цели, за исключением сохранения байта или двух кода команды.

Используя test eax,eax вместо cmp eax,0 показывает, что вы знаете свою сборку. Это также показывает, что вы предпочитаете слегка загадочную и слегка улучшающую инструкцию по простой, понятной инструкции. Это та вещь, которая имеет тенденцию зарабатывать бонусные очки от других вундеркиндов, но в последние пару десятилетий она не имела практической пользы в реальном мире.

Ответ 2

Разница (Теоретическое)

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

Потому что они разные, если используются с разными операндами. Тот факт, что test same,same работает как сравнение с нулем, является лишь удобным следствием того, как 2 дополняют и FLAGS работают, что делает его полезной оптимизацией глазка.

Инструкция TEST использует логику AND для пар битов из arg0 и arg1 и может проверить, установлен конкретный бит или нет, тогда FLAGS устанавливается соответствующим образом. (С целочисленным результатом отбрасывается). Точно так же, как cmp устанавливает флаги из вычитания, отбрасывая целочисленный результат.

Операция (ТЕСТ)

HTML, кроме из руководства Intel vol.2 PDF

TEMP ← SRC1 **AND** SRC2;
SF ← MSB(TEMP);
IF TEMP=0
    THEN ZF ← 1;
    ELSE ZF ← 0;
FI:

PF ← BitwiseXNOR(TEMP[0:7]);
CF ← 0;
OF ← 0;
(* AF is undefined *)

Flags Affected

Флаги OF и CF установлены в 0. Флаги SF, ZF и PF установлены в соответствии с результатом (см. раздел "Эксплуатация" выше). состояние флага AF не определено.

(Операция TEST устанавливает флаги CF и OF на ноль. SF устанавливается на старший значащий бит результата AND. Если результат равен 0, ZF устанавливается на 1, в противном случае устанавливается на 0.)


В то время как инструкция CMP использует инструкцию SUB и вычитает arg1 из arg0 и устанавливает CF (флаг переноса) и ZF (нулевой флаг) на основе заданных аргументов в инструкцию CMP,, если оба равны (arg1 == arg0), то очевидно, что результатом будет ноль, и ZF будет установлен в 1, и если arg0> arg1, тогда никакой флаг не будет установлен (остается 0 для ZF и CF), и если arg0 & lt; arg1, тогда ZF останется 0, поскольку они не равны, но CF будет установлен.

Операция (CMP)

temp ← SRC1 − SignExtend(SRC2); 
ModifyStatusFlags; 
   (* Modify status flags in  the same manner as the SUB instruction*)

Flags Affected

The CF, OF, SF, ZF, AF, и PF flags are set according to the result.

Ссылка от: assembly_language_for_x86_processors.pdf