Ответ 1
TL: DR: используйте условия выше/ниже (например, для целого числа без знака), чтобы проверить результат сравнений.
По различным историческим причинам (отображение из слова состояния FP в FLAGS через fstsw
/sahf
который fcomi
fcomi), FP сравнивает набор CF, а не OF или SF. Смотрите также http://www.ray.masmcode.com/tutorial/fpuchap7.htm
Это все из тома 2 Руководств разработчика программного обеспечения для архитектуры Intel 64 и IA-32.
FCOMI
устанавливает только некоторые флаги, которые делает CMP
. Ваш код имеет %st(0) == 9
и %st(1) == 10
. (Так как это стек, в который они загружены), обращаясь к таблице на странице 3-348 в Томе 2А, вы можете видеть, что это случай "ST0 <ST (i)", поэтому он очистит ZF и PF и установит CF. Тем временем на стр. 3-544 том. 2А вы можете прочитать, что JG
означает "Прыгай коротко, если больше (ZF = 0 и SF = OF)". Другими словами, он проверяет флаги знака, переполнения и нуля, но FCOMI
не устанавливает знак или переполнение!
В зависимости от того, в каких условиях вы хотите прыгнуть, вы должны посмотреть на возможные результаты сравнения и решить, когда вы хотите прыгнуть.
+--------------------+---+---+---+ | Comparison results | Z | P | C | +--------------------+---+---+---+ | ST0 > ST(i) | 0 | 0 | 0 | | ST0 < ST(i) | 0 | 0 | 1 | | ST0 = ST(i) | 1 | 0 | 0 | | unordered | 1 | 1 | 1 | one or both operands were NaN. +--------------------+---+---+---+
Я сделал эту маленькую таблицу, чтобы было легче разобраться:
+--------------+---+---+-----+------------------------------------+ | Test | Z | C | Jcc | Notes | +--------------+---+---+-----+------------------------------------+ | ST0 < ST(i) | X | 1 | JB | ZF will never be set when CF = 1 | | ST0 <= ST(i) | 1 | 1 | JBE | Either ZF or CF is ok | | ST0 == ST(i) | 1 | X | JE | CF will never be set in this case | | ST0 != ST(i) | 0 | X | JNE | | | ST0 >= ST(i) | X | 0 | JAE | As long as CF is clear we are good | | ST0 > ST(i) | 0 | 0 | JA | Both CF and ZF must be clear | +--------------+---+---+-----+------------------------------------+ Legend: X: don't care, 0: clear, 1: set
Другими словами, коды условий соответствуют кодам для использования беззнаковых сравнений. То же самое происходит, если вы используете FMOVcc
.
Если один или оба операнда для fcomi
равен NaN, он устанавливает ZF=1 PF=1 CF=1
. (Сравнение FP имеет 4 возможных результата: >
, <
, ==
или неупорядоченный). Если вас волнует, что ваш код делает с NaN, вам может понадобиться дополнительный jp
или jnp
. Но не всегда: например, ja
имеет значение true, только если CF = 0 и ZF = 0, поэтому он не будет принят в неупорядоченном случае. Если вы хотите, чтобы неупорядоченный случай использовал тот же путь выполнения, что и ниже или равный, тогда ja
- это все, что вам нужно.
Здесь вы должны использовать JA
если хотите, чтобы он печатал (т.е. if (!(f2 > f1)) { puts("hello"); }
) и JBE
если вы этого не делаете (соответствует if (!(f2 <= f1)) { puts("hello"); }
). (Обратите внимание, что это может немного сбить с толку из-за того, что мы печатаем, только если не прыгаем).
Что касается вашего второго вопроса: по умолчанию fcomi
ничего не fcomi
. Вы хотите его близкого кузена fcomip
который выдает %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