Я читал о математическом сопроцессоре (Paul Carters PC Assembly Book) и его инструкциях для расчета с плавающей запятой (на ASM i386). Тогда я побежал в следующий код, который должен вернуть большой двойник двух заданных двойных значений (C Вызов Конвенции):Сборка (i386): Math Сопроцессорный стек
1 %define d1 ebp+8
2 %define d2 ebp+16
3 global dmax
4
5 segment .text
6 dmax:
7 enter 0,0
8
9 fld qword [d2]
10 fld qword [d1] ;Now ST0 = d1 and ST1 = d2
11 fcomip st1 ;Compares ST0 with ST1 and pops ST0 out
12 jna short d2_bigger ;If not above (ST0<ST1)
13 fcomp st0 ;Get rid of ST0, which is actually d2 now (line 11)
14 fld qword [d1]
15 jmp short exit
16 d2_bigger:
17 exit:
18 leave
19 ret
Существовало две вещей, я думал об изменении этого кода. Во-первых, я бы использовал FCOMI
вместо FCOMIP
для сравнения (строка 11), чтобы избежать 1 ненужного всплывающего регистра сопроцессора. Сделав это, если ST0 = ST1 вообще не будет всплывать (поскольку он уже находится в верхней части стека). Единственная причина, по которой я не могу этого сделать, это то, что оставил бы непустую стек регистров сопроцессора. Однако, я думаю, единственное релевантное значение для C - ST0, которое будет возвратным значением двойной функции. Если другая функция переместила более 8 значений float/double в стек сопроцессора, не будут ли отброшены значения, хранящиеся в младших членах стека сопроцессора (ST7)? Итак, действительно ли проблема оставить функцию без очистки стека сопроцессора? => (READ EDIT)
Второе, что я имел в виду изменения, я бы, вероятно, не использовать инструкцию FCOMP
на линии 13. Я понимаю причина, это есть поп ST0 из стека, чтобы ST1 достигла вершины. Тем не менее, я думаю, что это немного накладные расходы, чтобы провести полное сравнение и установить флаги сопроцессора, чтобы вывести значение. Я искал инструкцию только для ввода ST0 и, видимо, ее нет. Я думал, что будет быстрее, хотя использовать FADDP ST0, ST0
(добавляет ST0 в ST0 и выталкивает ST0) или FSTP ST0
(сохраняет значение ST0 до ST0 и выдает ST0 вне). Они просто выглядят в моей голове, как меньше работы для сопроцессора.
Я попытался проверить скорость 3-х опций (один на код выше, FSTP ST0
и FADDP ST0, ST0
), и после нескольких быстрых тестов все они работали с очень близкими скоростями. Вид неточно сделать вывод из ценностей. По-видимому,FADDP ST0,ST0
был немного быстрее, затем FSTP ST0
и, наконец, FCOMP ST0
. Есть ли рекомендация по использованию? Или я слишком много беспокоюсь о чем-то, что будет иметь такой незначительный эффект на общую скорость?
Я просто расспросил себя, потому что, поскольку Ассамблея собирается делать все возможное, возможно, выбор между одним из этих подходов может принести пользу.
EDIT:
Я читал Intel 64 и IA-32 Набор команд и, по-видимому сопроцессор бросает исключение, если переполнение стека или недорасход (Exception #IS). Таким образом, используя стек и не опорожняя его (в этом случае, оставляя только ST0, чтобы C выдавал его возвращаемое значение), по-видимому, это не вариант.
Мир быстро иссякает машины, где этот вид код все еще имеет смысл. Особенно, когда вы используете сборку. Вместо этого используйте код SSE2. Используйте недавний компилятор C, если вы не знаете, как это выглядит. –
@ HansPassant IIRC NASA некоторое время держал на своих компьютерах 386-486 процессоров. С их большими транзисторами они менее уязвимы для космических лучей, изменяющих некоторую битовую ценность. Но это несколько лет назад, я понятия не имею, что такое текущее состояние. :) В другом месте это, вероятно, так, как вы его написали, SSE2 и более доступны. – Ped7g
@ Ped7g: используется FCOMI, который доступен только на p6. –