我在x64位中的FLD指令有点问题... 想要将double值加载到st0寄存器中的堆栈指针FPU,但似乎是不可能的。 在Delphi x32中,我可以使用以下代码:
function DoSomething(X:Double):Double;
asm
FLD X
// Do Something ..
FST Result
end;
不幸的是,在x64中,相同的代码不起作用。
答案 0 :(得分:5)
Delphi继承Microsoft x64 Calling Convention。 因此,如果函数/过程的参数是float / double,则它们将在XMM0L,XMM1L,XMM2L和XMM3L寄存器中传递。
但您可以在参数之前使用var
作为解决方法,如:
function DoSomething(var X:Double):Double;
asm
FLD qword ptr [X]
// Do Something ..
FST Result
end;
答案 1 :(得分:4)
在x64模式下,浮点参数在xmm寄存器中传递。因此,当Delphi尝试编译FLD X时,它变为FLD xmm0,但是没有这样的指令。首先需要将其移动到内存中。
结果相同,它应该在xmm0中传回。
试试这个(未经测试):
function DoSomething(X:Double):Double;
var
Temp : double;
asm
MOVQ qword ptr Temp,X
FLD Temp
//do something
FST Temp
MOVQ xmm0,qword ptr Temp
end;
答案 2 :(得分:0)
您不需要在x86-64代码中使用旧版x87堆栈寄存器,因为SSE2是基准,是x86-64 ISA的必需部分。 您可以并且应该使用XMM寄存器上的addsd
,mulsd
,sqrtsd
等进行标量FP数学运算。 (或addss
表示浮动)
如果Windows x64调用约定是函数的前四个arg之一,则它们在XMM0..3中传递float / double FP args。 (即,如果是FP,则第三个总arg进入xmm2,而不是xmm2进入第三个 FP arg。)它以XMM0返回FP值。
仅在函数内部确实需要80位精度时才使用x87。 (fsin
和fyl2x
之类的指令并不快,通常可以使用SSE / SSE2指令由普通的数学库来完成。
function times2(X:Double):Double;
asm
addsd xmm0, xmm0 // upper 8 bytes of XMM0 are ignored
ret
end
存储到内存中并重新加载到x87寄存器中会花费大约10个周期的延迟,这毫无益处。 SSE / SSE2标量指令与x87等价指令一样快,甚至更快,并且因为您不需要fxch
,因此更易于编程和优化。它是平面寄存器设计,而不是基于堆栈的设计。 (https://agner.org/optimize/)。另外,您有15个XMM寄存器。
当然,您通常通常根本不需要嵌入式asm。如果编译器没有为您进行手动矢量化,则可能会有用。