我在x64位中的FLD指令有一点问题...想要将st0加载到st0寄存器中的堆栈指针FPU,但它似乎是不可能的。在Delphi x32中,我可以使用以下代码:
function DoSomething(X:Double):Double;
asm
FLD X
// Do Something ..
FST Result
end;
不幸的是,在x64中,相同的代码不起作用。
在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;
德尔福继承了qazxsw poi。因此,如果函数/过程的参数是float / double,则它们将在XMM0L,XMM1L,XMM2L和XMM3L寄存器中传递。
但您可以在参数之前使用Microsoft x64 Calling Convention作为解决方法,如:
var
您不需要在x86-64代码中使用旧版x87堆栈寄存器,因为SSE2是基线,是x86-64 ISA的必需部分。你可以而且应该在XMM寄存器上使用function DoSomething(var X:Double):Double;
asm
FLD qword ptr [X]
// Do Something ..
FST Result
end;
,addsd
,mulsd
等进行标量FP数学运算。 (或sqrtsd
浮动)
Windows x64调用约定在XMM0..3中传递float / double FP args,如果它们是函数的前四个args之一。 (即,如果它是FP,则第3个总arg以xmm2为单位,而不是以xmm2为单位的第3个FP arg。)它返回XMM0中的FP值。
如果您的功能内部确实需要80位精度,则仅使用x87。 (像addss
和fsin
这样的指令并不快,通常也可以通过使用SSE / SSE2指令的普通数学库来完成。
fyl2x
存储到内存并重新加载到x87寄存器会花费大约10个周期的延迟而没有任何好处。 SSE / SSE2标量指令与x87等效指令一样快或更快,更容易编程和优化,因为你从不需要function times2(X:Double):Double;
asm
addsd xmm0, xmm0 // upper 8 bytes of XMM0 are ignored
ret
end
;它是一个扁平寄存器设计而不是基于堆栈的设计。 (fxch
)。此外,您有15个XMM寄存器。
当然,您通常根本不需要内联asm。如果编译器不为您执行此操作,则可能对手动矢量化很有用。