Как переместить ST (0) в EAX?

Здравствуйте, я изучаю сборку x86 FPU, и у меня есть простой вопрос, на который я не могу найти ответа:

Как переместить значение из ST(0) (верх стека FPU) в EAX?

также:
правильный ли этот код:

; multiply (dot) two vectors of 3 floats passed by pointers as arg 1 arg 2
; passings are ok I think, but not sure if multiplies-adds are ok

    push    ebp                                     
    mov     ebp, esp                                
    mov     eax, dword [ebp+8H]                     
    mov     edx, dword [ebp+0CH]                    

    fld     qword [eax]                             
    fmul    qword [edx]                             
    fld     qword [eax+4H]                          
    fmul    qword [edx+4H]                          
    fld     qword [eax+8H]                          
    fmul    qword [edx+8H]                          
    faddp   st1, st(0)                              
    faddp   st1, st(0)                            
    fstp    qword [ebp+10H]     ; here I vould prefer 'mov eax, st0'

    pop     ebp                                   
    ret                                           

person grunge fightr    schedule 10.08.2012    source источник
comment
вы хотите битовое представление числа fp в EAX или целочисленное представление (преобразование)?   -  person Necrolis    schedule 10.08.2012
comment
Я думаю, что, возможно, я сделал какую-то ошибку, мне нужно написать c-подобную функцию, которая будет возвращать float - я ошибся, предположив, что значение ret - это eax, но это float, поэтому, возможно, мне просто нужно оставить его на st0 - (теперь я так понимаю), кроме того, мои вычисления с точками FPU (float *, float *) в порядке ??   -  person grunge fightr    schedule 10.08.2012
comment
Да, в обычных соглашениях о вызовах значения FP возвращаются в ST(0) или XMM0. Никогда в eax, потому что тогда вызывающему абоненту придется вернуть его обратно в ST(0) или XMM0, чтобы использовать его.   -  person Peter Cordes    schedule 11.11.2017


Ответы (2)


Нет реальной причины, по которой вам следует это делать. Помните, что EAX - это только 32-битный регистр, в то время как все регистры FPU имеют ширину 80 бит, потому что FPU по умолчанию выполняет вычисления с 80-битными числами с плавающей запятой. Следовательно, перемещение данных из регистра FPU в регистр общего назначения приведет к потере данных. Если вы действительно хотите сделать что-то подобное, попробуйте следующее (при условии, что у вас есть свободное место в стеке):

sub esp, 4           ; or use space you already reserved
fstp dword [esp]
mov eax, [esp]       ; or better,  pop eax
add esp, 4

Эта последовательность инструкций округлит число с плавающей запятой, которое в настоящее время находится на вершине стека FPU, до 32-битного, затем запишет его во временное место стека, загрузит битовый шаблон float (binary32) в EAX и очистит используемое пространство стека.


Это почти никогда не то, что вам нужно. Стандартные соглашения о вызовах возвращают значения float / double / long double в st(0), поэтому компилятор C ожидает, что функция double foo() оставит значение. (Или xmm0 с SSE / SSE2).

Вам это нужно только в том случае, если вы хотите выполнять целочисленные манипуляции / тесты на битовых шаблонах FP. (т.е. для реализации набора текста в C, например memcpy от float до uint32_t). например для известных, но теперь в основном устаревших, быстрых приближенных обратных-sqrtf магических- number hack, использованный в исходном коде Quake.

person Daniel Kamil Kozar    schedule 10.08.2012
comment
Хорошо, TNX в каком-то смысле. Не знал, что такой инструкции нет (возможно, немного грустно, что приходится использовать оперативную память в качестве промежуточного звена). Но в такой процедуре, которую я тестировал, я мог оставить результат на вершине стека - и это так. в порядке - person grunge fightr; 10.08.2012
comment
Последние 2 инструкции можно заменить на pop eax. Это было бы не менее эффективно на современных процессорах. Конечно, обычно вы просто резервируете некоторое пространство стека в начале функции и сохраняете / перезагружаете его / из него, вместо того, чтобы возиться с указателем стека внутри цикла. - person Peter Cordes; 11.11.2017

Инструкций x87 для перемещения значений с плавающей запятой между регистрами FPU и регистрами CPU нет.

Вы должны использовать память как промежуточное звено.

person Alexey Frunze    schedule 10.08.2012
comment
Хорошо, можете ли вы также указать, может ли моя процедура с точкой (float *, float *) быть в порядке? - person grunge fightr; 10.08.2012
comment
Что ж, если вы используете двойные (qword = quad word = 4 * 2 байта = 8 байтов), ваши смещения не могут быть 4. Вы сможете легко тестировать / отлаживать свой код. - person Alexey Frunze; 10.08.2012