Ассемблер x86: сравнение с плавающей запятой
В рамках проекта компилятора я должен написать код ассемблера GNU для x86 для сравнения значений с плавающей запятой. Я попытался найти ресурсы о том, как сделать это в Интернете, и из того, что, как я понимаю, работает следующим образом:
Предполагая, что значения, которые я хочу сравнить, являются единственными значениями в стеке с плавающей запятой, тогда команда fcomi
будет сравнивать значения и устанавливать ЦП-флаги, чтобы можно было использовать команды je, jne, jl,
….
Я спрашиваю, потому что это работает только иногда. Например:
- Как бы вы сравнили два XML-документа?
- NSArray содержит метод Object
- Как сравнить один образ с другим, чтобы увидеть, похожи ли они на определенный процент, на iPhone?
- Инструмент для сравнения большого количества файлов PDF?
- Условие запроса MongoDb при сравнении двух полей
.section .data msg: .ascii "Hallo\n\0" f1: .float 10.0 f2: .float 9.0 .globl main .type main, @function main: flds f1 flds f2 fcomi jg leb pushl $msg call printf addl $4, %esp leb: pushl $0 call exit
не будет печатать «Hallo», хотя я думаю, что это нужно, и если вы переключите f1 и f2, это все равно не будет логичным противоречием. je
и jne
похоже, работают нормально.
Что я делаю не так?
PS: делает ли fcomip только одно значение или он всплывает?
Все это происходит из тома 2 руководств разработчика программного обеспечения Intel 64 и IA-32 .
FCOMI
устанавливает только некоторые из флагов, которые выполняет CMP
. Ваш код имеет %st(0) == 9
и %st(1) == 10
. (Так как это стек, на который они загружены), ссылаясь на таблицу на стр. 3-348 в томе 2А, вы можете видеть, что это так «ST0 FCOMI
, переполнения и нулевые флаги, но FCOMI
не устанавливает знак или переполнение!
В зависимости от условий, которые вы хотите прыгать, вы должны посмотреть возможные результаты сравнения и решить, когда вы хотите прыгать.
+ -------------------- + --- + --- + --- + | Результаты сравнения | Z | P | C | + -------------------- + --- + --- + --- + | ST0> ST (i) | 0 | 0 | 0 | | ST0Я сделал этот маленький стол, чтобы было легче понять:
+ -------------- + --- + --- + ----- + -------------------- ---------------- + | Тест | Z | C | Jcc | Примечания | + -------------- + --- + --- + ----- + -------------------- ---------------- + | ST0= ST (i) | X | 0 | JAE | Пока CF ясно, мы хорошие | | ST0> ST (i) | 0 | 0 | JA | Оба CF и ZF должны быть четкими | + -------------- + --- + --- + ----- + -------------------- ---------------- + Обозначения: X: все равно, 0: clear, 1: set Другими словами, коды условий соответствуют тем, которые используются для сравнения без знака. То же самое происходит, если вы используете
FMOVcc
.Если операнд (или оба) для
fcomi
равен NaN, он устанавливаетZF=1 PF=1 CF=1
. (Сравнение FP имеет 4 возможных результата:>
,<
,==
или неупорядоченный). Если вам небезразличен ваш код с помощью NaN, вам может понадобиться дополнительныйjp
илиjnp
. Но не всегда: например,ja
истинно, только если CF = 0 и ZF = 0, поэтому он не будет принят в неупорядоченном случае. Если вы хотите, чтобы неупорядоченный случай выполнял тот же путь выполнения, что и ниже или равный, тогдаja
- это все, что вам нужно.
Здесь вы должны использовать
JA
если вы хотите его распечатать (т.JBE
Ifif (!(f2 > f1)) { puts("hello"); }
) иJBE
если вы этого не сделаете (соответствуетif (!(f2 <= f1)) { puts("hello"); }
). (Обратите внимание, что это может быть немного запутанным из-за того, что мы печатаем только, если мы не прыгаем).
Что касается вашего второго вопроса: по умолчанию
fcomi
ничего неfcomi
. Вы хотите, чтобы его близкий родственникfcomip
который pops%st0
. Вы всегда должны очищать стек реестра fpu после использования, поэтому вся ваша программа заканчивается так, будто вы хотите напечатать сообщение:.section .rodata msg: .ascii "Hallo\n\0" f1: .float 10.0 f2: .float 9.0 .globl main .type main, @function main: flds f1 flds f2 fcomip fstp %st(0) # to clear stack ja leb # won't jump, jbe will pushl $msg call printf addl $4, %esp leb: pushl $0 call exit