Нередко сравнение двух значений произодится, чтобы в зависимости от результатов сравнения загрузить в регистр некоторое значение или, наоборот, не загружать это значение, если проверка или сравнение не пройдены. Для упрощения подобных действий процессоры x86-64 поддерживают набор инструкций условного копирования. Инструкции перемещения с проверкой флагов:
cmovc / cmovb / cmovnae: перемещает, если флаг переноса CF = 1
cmovnc / cmovnb / cmovae: перемещает, если флаг переноса CF = 0
cmovz / cmove: перемещает, если флаг нуля ZF = 1
cmovnz / cmovne: перемещает, если флаг нуля ZF = 0
cmovs: перемещает, если флаг знака SF = 1
cmovns: перемещает, если флаг знака SF = 0
cmovo: перемещает, если флаг переполнения OF = 1
cmovno: перемещает, если флаг переполнения OF = 0
Отдельная группа инструкций предназначена для сравнения с копированием. Здесь есть инструкции для сравнения беззнаковых чисел:
cmova: перемещает, если первый операнд больше второго (CF=0, ZF=0
)
cmovnbe: перемещает, если первый операнд не меньше и не равен второму (CF=0, ZF=0
)
cmovae / cmovnc / cmovnb: перемещает, если первый операнд больше или равен второму (CF=0
)
cmovnae / cmovc / cmovb: перемещает, если первый операнд меньше второго (CF=1
)
cmovbe: перемещает, если первый операнд меньше или равен второму (CF=1
или ZF=1
)
cmovna: перемещает, если первый операнд не больше второго (CF=1
или ZF=1
)
И инструкции для сравнения чисел со знаком:
cmovg: перемещает, если первый операнд больше второго (SF=OF
или ZF=0
)
cmovnle: перемещает, если первый операнд больше второго (SF=OF
или ZF=0
)
cmovge: перемещает, если первый операнд больше или равен второму (SF=OF
)
cmovnl: перемещает, если первый операнд больше или равен второму (SF=OF
)
cmovl: перемещает, если первый операнд меньше второго (SF != OF
)
cmovnge: перемещает, если первый операнд меньше второго (SF != OF
)
cmovle: перемещает, если первый операнд меньше или равен второму (SF != OF
или ZF=1
)
cmovng: перемещает, если первый операнд меньше или равен второму (SF != OF
или ZF=1
)
И две общие инструкции как для чисел со знаком, так и для беззнаковых чисел:
cmove: перемещает, если первый операнд равен второму (ZF=1
). Аналогичен инструкции cmovz
cmovne: перемещает, если первый операнд не равен второму (ZF=0
). Аналогичен инструкции cmovnz
Первый параметр этих инструкций представляет регистр общего назначения (16, 32 или 64-битный). Второй параметр - либо регистр, либо переменная (также 16, 32 или 64-битные)
Например, возьмем следующую программу:
.data n1 dword 0FFFFFFFFh n2 dword 1h res0 dword 0 res1 dword 1 .code main proc mov eax, n1 add eax, n2 jc carry_set mov eax, res0 ret carry_set: mov eax, res1 ret main endp end
Здесь складываем 2 числа. И если при сложении устанавливается флаг переноса, то осуществляется переход к метке carry_set, где в регистр EAX помещается 1. С помощью инструкций условного перемещения эту программу можно сократить так:
.data n1 dword 0FFFFFFFFh n2 dword 1h res0 dword 0 res1 dword 1 .code main proc mov eax, n1 add eax, n2 cmovnc eax, res0 ; Если CF = 0 cmovc eax, res1 ; Если CF = 1 ret main endp end
Другой пример - поместим в регистр EAX определенное значение в зависимости от результата сравнения:
.data n1 dword 22 n2 dword 22 res0 dword 0 res1 dword 1 .code main proc mov eax, n1 cmp eax, n2 cmovne eax, res0 ; Если ZF = 0 cmove eax, res1 ; Если ZF = 1 ret main endp end
В данном случае если числа n1 и n2 равны, в регистр EAX помещается число 1, иначе помещается число 0.