侧边栏壁纸
  • 累计撰写 16 篇文章
  • 累计创建 17 个标签
  • 累计收到 1 条评论

浮点体系结构

xiuxiubiu
2021-11-28 / 0 评论 / 0 点赞 / 1,327 阅读 / 2,186 字 / 正在检测是否收录...

寄存器

以下内容基于AVX2,当给定命令行参数-mavx2时,GCC会生成AVX2代码。

AVX浮点体系结构允许数据存储在16个YMM寄存器中,它们的名字为%ymm0%ymm15。每个YMM寄存器都是256位(32字节)。当对标量数据操作时,这些寄存器只保存浮点数,而且只使用低32位(对于float)或64位(对于double)。汇编代码用寄存器的SSE XMM寄存器名字%xmm0%xmm15来引用他们,每个XMM寄存器都是对应的YMM寄存器的低128位(16字节)。

image.png

浮点传送指令

以下表格为在内存和XMM寄存器之间以及从一个XMM寄存器到另一个不用做任何转换的传浮点数的指令。引用内存的指令都是标量指令,即他们只对单个而不是一组封装好的数据值进行操作。数据要么保存在内存中(M32或M64指明),要们保存在XMM寄存器中(X表示)。无论数据对齐与否,这些指令都能正确执行,不过代码优化规则建议32位内存数据满足4字节对齐,64位数据满足8字节对齐。内存引用的制定法方式与整数MOV指令一样,包括偏移量、基址寄存器、变址寄存器和伸缩因子的所有可能组合。

指令目的描述
vmovssM32X传送单精度数
vmovssXM32传送单精度数
vmovsdM64X传送双精度数
vmovssXM64传送双精度数
vmovapsXX传送对齐的封装好的单精度数
vmovapdXX传送对齐的封装好的双精度数

浮点转换指令

以下给出了在浮点数和整数类型之间以及不同浮点格式之间进行转换的指令集合。这些都是对单个数据值进行操作的标量指令。

一字整数 等于 2字节
四字整数 等于 8字节

浮点数转换整数指令

以下指令把一个从XMM寄存器或内存中读出的浮点值进行转换,并将结果写入一个通用寄存器(例如:%rax、%ebx等)。把浮点值转换成整数时,指令会执行截断(truncation),把值向0进行舍入。

指令目的描述
vcvttss2tiX/M32R32用截断的方法把单精度数转换成整数
vcvttsd2siX/M64R32用截断的方法把双精度数转换成整数
vcvttss2siqX/M32R64用截断的方法把单精度数转换成四字整数
vcvttsd2siqX/M64R64用截断的方法把双精度数转换成四字整数

整数转换浮点数指令

以下指令把整数转换成浮点数。他们使用的是不太常见的三操作数格式,有两个源和一个目的。

指令源1源2目的描述
vcvtsi2ssM32/R32XX把整数转换成单精度数
vcvtsi2sdM32/R32XX把整数转换成双精度数
vcvtsi2ssqM64/R64XX把四字整数转换成单精度数
vcvtsi2sdqM64/R64XX把四字整数转换成双精度数

第一个操作数读自于内存或一个通用目的寄存器。这里可以忽略第二个操作数,因为它的值只会影响结果的高位字节,而我们的目标必须是XMM寄存器。在最常见的使用场景中,第二个源和目的操作数都是一样的,就像下面这标指令:

vectsi2sdq %rax, %xmm1, %mm1

浮点数相互转换指令

GCC使用如下代码将单精度值转换成双精度值:

Conversion from single to double precision
vunpcklps %xmm0, %xmm0, %xmm0	Replicate first vector element
vcvtps2pd %xmm0, %xmm0		Convert two vector elements to double

vunpcklps指令通常用来交叉放置来自XMM寄存器的值,把它们存储到第三个寄存器中。也就是说,如果一个源寄存器的内容为字[s3, s2, s1, s0],另一个源寄存器为字[d3, d2, d1, d0],因为单精度占用二字(4字节,32位),那么目的寄存器的值会是[s1, d1, s0, d0],四字就可以保存两个单精度所有的字。在上面的代码中,我们看到三个操作数使用同一个寄存器,所有如果原始寄存器的值x为[x0, x0, x0, x0],那么该指令会将寄存器的值更新为[x1, x1, x0, x0]。

vcvtps2pd指令把源XMM寄存器中的两个低位单精度值扩展成目的XMM寄存器中的两个双精度值。对前面vunpcklps指令的结果应用这条指令会得到值[dx0, dx0],这里的dx0是将x转换成四字双精度后的结果,也就是一个dx0代表四字8字节64位,即%xmm0中存储了两份相同的x的双精度值。我们不太清楚为什么会生成这样的代码,这样做既没有好处,也没有必要在XMM寄存器中把这个值再复制一遍。

GCC使用如下代码将双精度值转换为单精度值:

Conversion from double to single precision
vmovddup   %xmm0, %xmm0		Replicate first vector element
vcvtpd2psx %xmm0, %xmm0		Convert two vector elements tosingle

假设寄存器%xmm0保存着两个双精度值[x1, x0]。然后vmovddup指令把它设置为[x0, x0]。vcvtpd2psx指令把俩个值转换成单精度,再存放到该寄存器(xmm寄存器16位)的低位(8字节)一半(4字节)中,并将高位一半设置为0,得到结果[0.0, 0.0, x0, x0],此结果中x0为单精度值,占用二字4字节32位,即寄存器保存了两份单精度值。

0

评论