浮点数的运算在一组与整数运算不同的寄存器上面执行,最新的成果被称为AVX(Advanced Vector Extension),高级向量扩展,这个体系中的寄存器名称是 %ymm0~%ymm15,它有256bits,可以存储4个64位数据或者8个32位数据。它的低128位名称为 %xmm0~%xmm15,来自于AVX的前一个迭代版本。
这组寄存器的本意是实现单指令多数据(SIMD, 读作sim-dee),如一个乘法指令同时处理多个地位相同的乘法。从意义上有点像numpy的所谓 “广播特性”,相当于多个数据被打包一个向量中同时并行计算。
AVX寄存器中可以放多个整型或者浮点数,浮点数一定只能在AVX寄存器中处理。
C语言只进行标量处理,只用看%xmm即可(虽然GCC有应用向量计算的C语言扩展),后面指令中用 X 表示%xmm寄存器,用R 表示整数寄存器。
一、AVX寄存器用处设定
%ymm0保存返回值(两用)
%ymm0~%ymm7按顺序保存8个参数。
剩下的是调用者保存。
二、浮点数据传送
操作数,对内存和寄存器值的引用和普通整型寄存器操作数完全一样。但是不支持浮点数的立即数(后面详细说)
浮点数传送指令:
(约定:M32为内存中32位空间,M64为内存中64位空间,ss是float,sd是double)
指令 | 描述 |
---|---|
vmovss M | 传送单精度数到寄存器X |
vmovss X M | 方向和上面的反过来 |
vmovsd M | 传送双精度数到寄存器X |
vmovsd X M | 方向和上面的反过来 |
vmovaps X X | 传送对齐封装好的单精度数(向量) |
vmovapd X X | 传送对齐封装好的双精度数 |
三、类型转换
1)单双精度浮点数类型转换(si是int,siq是long,2是to)
(VCVTT?)
指令 | 描述 |
---|---|
vcvttss2si X/M | 截断方法单精度转换为整数int |
vcvttsd2si X/M | 截断方法双精度转换为整数int |
vcvttss2siq X/M | 截断方法单精度转换为long |
vcvttsd2siq X/M | 截断方法双精度转换为long |
2)整数转浮点数(VCVT?) | |
指令 | 效果 |
:-: | :-: |
vcvtsi2ss M | 整数转换为单精度 |
vcvtsi2sd M | 整数转换为双精度 |
vcvtsi2ssq M | long转换为单精度 |
vcvtsi2sdq M | long转换为双精度 |
是少见的三操作数。其中第一个是源,第三个是目标寄存器,第二个只和高位有关,在C中用不上,可以忽略。
3)浮点数之间转换,很自然想到如下指令:
vcvtss2sd M/R X1 X2
这没有问题,但是GCC不会用这个,而是用了一个很奇怪的方法,此处省略。
//待转换浮点数在%xmm0中,见《深入理解计算机系统》P207
vunpcklps %xmm0 %xmm0 %xmm0
vcvtps2pd %xmm0 %xmm0
四、浮点数运算
1)浮点运算(运算前,要提前将数据扩展为范围较大的类型,同步)
指令 S1 S2 D | 效果 |
---|---|
vaddss / vaddsd | S1+S2—>D |
vsubss / vsubsd | S2-S1—>D |
vmulss / vmulsd | S1*S2—>D |
vdivss / vdivsd | S2/S1—>D |
vminss / vminsd | min(S1,S2)—>D |
vmaxss / vmaxsd | max(S1,S2)—>D |
都是三操作数,都有单双精度版本。
特殊指令:平方根:
sqrtss / sqrtsd S1 D | sqrt(S1)—>D |
---|
2)浮点数位运算:
指令 S1 S2 D | 效果 |
---|---|
vxorps / xorpd | S1^S2—>D |
vandps / andpd | S1&S2—>D |
同样有单双精度版本,注意双精度的没有v.
3)浮点立即数(即浮点常数)
浮点常数要保存在内存中,计算的时候由内存读取。但并不额外给多一个变量,而是存储这个数后,用一个标签(即地址*Operand)表示这个数在哪,而怎么读也有讲究。
如:
double cel2fahr(double temp)
{
return 1.8 * temp + 32.0;
}
这个1.8和32.0放在内存中。在将1.8从内存中读到寄存器里进行下一步计算,会用如下机器代码:
vmulsd .LC2(%rip), %xmm0, %xmm0;
LC2:
.long 3435973837 //lower 4 bytes of 1.8
.long 1073532108 //higher 4 bytes of 1.8
Intel机器是小端法,地址小的存低位,靠上的代码地址小,存低4字节。
从LC2计算浮点常数:这两个数都是10进制 的!把这两个十进制数无符号转换为4字节(8位)16进制数,从高四位中截取阶码,把高四位剩下的和低四位全部合在一起就成了需要的浮点数。
五、比较与条件码
1)比较
指令 | 原理 | 描述 |
---|---|---|
vucomiss S1,S2 | S2-S1 | 比较单精度值 |
vucomisd S1,S2 | S2-S1 | 比较双精度值 |
类似CMP族指令,会设置条件码。
2)条件码
零标志位ZF
进位标志位CF
奇偶标志位PF
最后一个就是对最低字节的奇偶校验。如果最低字节有偶数个1,则PF为1.
整数运算中也有,但是很少用。浮点运算中,PF可以用来判断两个操作数是否有任何一个是NaN。