Для сравнения чисел с плавающей точкой расширения SSE предоставляют набор инструкций сравнения для конкретных условий, которые сохраняют значение true (все биты 1) или false (все биты 0) в первом операнде:
cmpss xmmn, xmmm/mem32, imm8 cmpsd xmmn, xmmm/mem64, imm8 cmpeqss xmmn, xmmm/mem32 ; операнды равны cmpltss xmmn, xmmm/mem32 ; первый операнд меньше второго cmpless xmmn, xmmm/mem32 ; первый операнд меньше или равен второму cmpunordss xmmn, xmmm/mem32 ; неупорядоченное сравнение (один из операндов или оба равны NaN) cmpneqss xmmn, xmmm/mem32 ; операнды не равны cmpnltss xmmn, xmmm/mem32 ; первый операнд НЕ меньше второго cmpnless xmmn, xmmm/mem32 ; первый операнд НЕ меньше или равен второму cmpordss xmmn, xmmm/mem32 ; упорядоченное сравнение cmpeqsd xmmn, xmmm/mem64 ; операнды равны cmpltsd xmmn, xmmm/mem64 ; первый операнд меньше второго cmplesd xmmn, xmmm/mem64 ; первый операнд меньше или равен второму cmpunordsd xmmn, xmmm/mem64 ; неупорядоченное сравнение (один из операндов или оба равны NaN) cmpneqsd xmmn, xmmm/mem64 ; операнды не равны cmpnltsd xmmn, xmmm/mem64 ; первый операнд НЕ меньше второго cmpnlesd xmmn, xmmm/mem64 ; первый операнд НЕ меньше или равен второму cmpordsd xmmn, xmmm/mem64 ; упорядоченное сравнение
Первые две инструкции могут в качестве третьего операнда (imm8) принимать значение от 0 до 7, которое указывает на принцип сравнения:
0: Первый операнд == второй операнд
1: Первый операнд < второй операнд
2: Первый операнд <= второй операнд
3: Неупорядоченное сравнение
4: Первый операнд ≠ второй операнд
5: Первый операнд не меньше второго операнда (>=)
6: Первый операнд не меньше или равен второму операнду (>)
7: Упорядоченное сравнение
Эти инструкции устанавливают в 0 (неверно, ложь) или 1 (верно, истина) все биты в первом операнде. После сравнения значение из регистра XMM можно поместит в регистр общего назначения и проверить этот регистр на наличие нуля/не нуля. Для этого можно использовать инструкции movq или movd:
.data double1 real8 1.2 double2 real8 1.2 .code main proc movsd xmm0, double1 movsd xmm1, double2 cmpeqsd xmm0, xmm1 ; равны ли операнды movd eax, xmm0 ret main endp end
Здесь помещаем в XMM0 и XMM1 два числа real8 и инструкцией cmpeqsd
сравниваем их на равенство. Если они равны, то в xmm0 все биты будут равны 1, если нет - то 0. Для
проверки значения помещаем его в регистр EAX. Поскольку при равестве все биты будут установлены в 1, то фактически в десятичной системе это будет число -1.
Получив результат проверки в регистр EAX, мы можем использовать уже стандартные инструкции перехода, чтобы определить условные конструкции:
.data double1 real8 1.2 double2 real8 1.2 .code main proc movsd xmm0, double1 movsd xmm1, double2 cmpeqsd xmm0, xmm1 ; равны и=ли операнды movd eax, xmm0 and eax, eax ; проверяем на равенство jnz equal ; если xmm0 == xmm1 mov eax, 0 jmp proc_end equal: mov eax, 1 proc_end: ret main endp end
Здесь по сравнению с предыдущим примером добавили проверку на 0 с помощью инструкции and - если результат этой инструкии равен 0, то будет установлен флаг нуля ZF,
который мы можем проверить с помощью инструкции jnz
- если флаг не установлен (то есть по сути если xmm0 и xmm1 были равны),
то далее выполняем переход на метку equal.