为啥 Free Pascal 会自动将记录数据传递给 xmm 寄存器?

Posted

技术标签:

【中文标题】为啥 Free Pascal 会自动将记录数据传递给 xmm 寄存器?【英文标题】:Why Free Pascal automatically pass record data to xmm registers?为什么 Free Pascal 会自动将记录数据传递给 xmm 寄存器? 【发布时间】:2017-02-07 04:06:11 【问题描述】:

我的数据类型名为TVector,如下所示:

type
   TVector = record
       x,y,z,w : single;
   end; 

我有名为 v1v2 的变量,其中包含以下数据:

v1.x:=1;
v1.y:=2;
v1.z:=3;
v1.w:=4;

v2.x:=5;
v2.y:=6;
v2.z:=7;
v2.w:=8;

两个变量都传递给方法如下:

function TSSEVectorOperation.add(const vect1: TVector; const vect2: TVector): TVector; assembler;
asm
   ...
   addps xmm1, xmm2
   movaps xmm0, xmm1
   ...
end;

当我使用 Lazarus IDE(在 Ubuntu 中)调试并进入 add() 方法时,我了解到最初 xmm0 - xmm3 寄存器包含来自 v1v2 的值,顺序如下

xmm0 = 1,2,0,0
xmm1 = 3,4,0,0
xmm2 = 5,6,0,0
xmm3 = 7,8,0,0

我的问题是为什么 Free Pascal 会这样?为什么不按以下顺序?

xmm0 = 1,2,3,4
xmm1 = 5,6,7,8

或者为什么不让我手动为 xmm 寄存器赋值?比如:

movaps xmm0, vect1
movaps xmm1, vect2

【问题讨论】:

平台调用约定决定了这一点。 有道理。默认调用约定是register,它会尽可能多地将数据传递给寄存器。 没有。在 x64 平台上定义了调用约定,而 register、stdcall、cdecl 等都被忽略了。 是的。如果您为 Windows 或 32 位目标编译,则调用约定会有所不同。 原因是 Linux 上的 x86-64 结构可以通过 XMM 寄存器中的值传递。可以在 here 找到 64 位 Linux ABI 调用约定。传递结构的规则的一个特点是不能在 XMM 寄存器中传递超过 64 位的数据。 2 个浮点数是 8 个字节或 64 位。前两个将在 XMM0 中传递,后两个将在 XMM1 中传递。 【参考方案1】:

正如 Michael Petch 在评论和挖掘 System V ABI 文档后指出的那样。 FreePascal 确实遵循 x86-64 ABI 调用约定(我的 ubuntu 是 14.04 LTS 64 位),它将按照我在问题中提到的顺序将浮点参数传递给 xmm 寄存器。

所以为了将xmm0xmm1寄存器的低位四字组合成xmm0寄存器,我需要使用movlhps指令

 movlhps xmm0, xmm1

xmm2xmm3 寄存器也是如此。

返回浮点值的函数需要将其结果存储在xmm0寄存器中。如果结果大于 64 位浮点,则剩余的 64 位将转到xmm1 寄存器。所以就我而言,应该是

 xmm0 = result.x, result.y, (not used), (not used)
 xmm1 = result.z, result.w, (not used), (not used)

【讨论】:

以上是关于为啥 Free Pascal 会自动将记录数据传递给 xmm 寄存器?的主要内容,如果未能解决你的问题,请参考以下文章

Free Pascal编译的程序运行错误代码解析

Free Pascal 多接口问题

Free Pascal初次体验(有亮点哦)

free pascal的一个集合(set of)最多可放多少个整数?

Free Pascal IDE 下载安装配置

为啥在使用 malloc() 和 free() 后,两个内存位置会发生变化?