5

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

function DoSomething(X:Double):Double;
asm

  FLD    X
   // Do Something ..
  FST Result

end;

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

4

3 回答 3

5

Delphi 继承了Microsoft x64 Calling Convention。因此,如果函数/过程的参数是浮点/双精度,它们将在 XMM0L、XMM1L、XMM2L 和 XMM3L 寄存器中传递。

但是您可以使用varbefore 参数作为解决方法,例如:

function DoSomething(var X:Double):Double;
asm
  FLD  qword ptr [X]
  // Do Something ..
  FST Result
end;
于 2013-04-03T14:04:20.683 回答
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;
于 2013-04-03T12:20:00.880 回答
0

您不需要在 x86-64 代码中使用旧版 x87 堆栈寄存器,因为 SSE2 是基线,是 x86-64 ISA 的必需部分。 您可以并且应该在 XMM 寄存器上使用addsdmulsdsqrtsd进行标量 FP 数学运算。(或addss浮动)

Windows x64 调用约定在 XMM0..3 中传递浮点/双 FP 参数,如果它们是函数的前四个参数之一。(即,如果它是 FP,则第 3 个总 arg 进入 xmm2,而不是 xmm2 中的第 3 个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 寄存器。


当然,您通常根本不需要内联汇编。如果编译器不为您执行此操作,它可能对手动向量化很有用。

于 2018-09-04T04:20:22.640 回答