FLD指令x64位

时间:2013-04-03 11:42:34

标签: delphi assembly x86-64 fpu basm

我在x64位中的FLD指令有点问题... 想要将double值加载到st0寄存器中的堆栈指针FPU,但似乎是不可能的。 在Delphi x32中,我可以使用以下代码:

function DoSomething(X:Double):Double;
asm

  FLD    X
   // Do Something ..
  FST Result

end;

不幸的是,在x64中,相同的代码不起作用。

3 个答案:

答案 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寄存器上的addsdmulsdsqrtsd等进行标量FP数学运算。 (或addss表示浮动)

如果Windows x64调用约定是函数的前四个arg之一,则它们在XMM0..3中传递float / double FP args。 (即,如果是FP,则第三个总arg进入xmm2,而不是xmm2进入第三个 FP arg。)它以XMM0返回FP值。

仅在函数内部确实需要80位精度时才使用x87。 (fsinfyl2x之类的指令并不快,通常可以使用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。如果编译器没有为您进行手动矢量化,则可能会有用。