|
IA-32 指令集中包含众多指令,用于把以一种数据类型表示的数据转换为另一种数据类型。程序需要把浮点数据转换为整数值(或者相反的情况)的情况并不少见。这些指令提供完成这种操作的简便方式,无须编写自己的算法。
有很多指令用于转换数据类型,因为有不同的数据类型需要进行相互转换。下表列出这些指令:
指令
| 转换
| CVTDQ2PD
| 打包双字整数到打包双精度FP(XMM)
| CVTDQ2PS
| 打包双字整数到打包单精度FP(XMM)
| CVTPD2DQ
| 打包双精度FP到打包双字整数(XMM)
| CVTPD2PI
| 打包双精度FP到打包双字整数(MMX)
| CVTPD2PS
| 打包双精度FP到打包单精度FP(XMM)
| CVTPI2PD
| 打包双字整数到打包双精度FP(XMM)
| CVTPI2PS
| 打包双字整数到打包单精度FP(XMM)
| CVTPS2DQ
| 打包单精度FP到打包双字整数(XMM)
| CVTPS2PD
| 打包单精度FP到打包双精度FP(XMM)
| CVTPS2PI
| 打包单精度FP到打包双字整数(MMX)
| CVTTPD2PI
| 打包双精度FP到打包双字整数(MMX,截断)
| CVTTPD2DQ
| 打包双精度FP到打包双字整数(XMM,截断)
| CVTTPS2DQ
| 打包单精度FP到打包双字整数(XMM,截断)
| CVTTPS2PI
| 打包单精度FP到打包双字整数(MMX,截断)
| 上表中“转换”一栏里,后面的括号中表示的是存放结果的目标寄存器,目标寄存器可以是 MMX 或者 XMM 。另外,最后 4 条指令是截断的转换。在其他指令中,如果转换不精确,就会由 XMM MXCSR 寄存器的 13 位和 14 位控制进行舍入。这些位确定值是被向上还是向下舍。在截断的转换中,会自动执行向零方向的舍入。
源值可以是从内存位置、MMX 寄存器(对于64位值)或者 XMM 寄存器(对于 64 位或者 128 位值)获得。
下面是测试程序:
.section .data
value1:
.float 1.25, 124.79, 200.0, -312.5
value2:
.int 1, -435, 0, -25
.section .bss
.lcomm data, 16
.section .text
.global _start
_start:
nop
cvtps2dq value1, %xmm0
cvttps2dq value1, %xmm1
cvtdq2ps value2, %xmm2
movdqu %xmm0, data
movl $1, %eax
movl $0, %ebx
int $0x80 上面程序里,在内存位置 value1 定义了一个打包单精度浮点值,在内存位置位置 value2 定义一个打包双字整数值。
在执行第一条指令后(nop的下一条),观察 xmm0 寄存器:(gdb) print $xmm0
$1 = {v4_float = {1.40129846e-45, 1.75162308e-43, 2.80259693e-43, -nan(0x7ffec8)}, v2_double = {
2.6524947387115311e-312, -nan(0xffec8000000c8)}, v16_int8 = {1, 0, 0, 0, 125, 0, 0, 0, -56, 0,
0, 0, -56, -2, -1, -1}, v8_int16 = {1, 0, 125, 0, 200, 0, -312, -1}, v4_int32 = {1, 125, 200,
-312}, v2_int64 = {536870912001, -1340029796152}, uint128 = 0xfffffec8000000c80000007d00000001} 由上可见,单精度浮点值被打包成了整数值,这里在转换时用的是一般转换(四舍五入),如把 124.79 舍入为 125 。
步过第 2 条指令,查看 xmm1 寄存器中的内容:(gdb) print $xmm1
$2 = {v4_float = {1.40129846e-45, 1.7376101e-43, 2.80259693e-43, -nan(0x7ffec8)}, v2_double = {
2.6312747808018783e-312, -nan(0xffec8000000c8)}, v16_int8 = {1, 0, 0, 0, 124, 0, 0, 0, -56, 0,
0, 0, -56, -2, -1, -1}, v8_int16 = {1, 0, 124, 0, 200, 0, -312, -1}, v4_int32 = {1, 124, 200,
-312}, v2_int64 = {532575944705, -1340029796152}, uint128 = 0xfffffec8000000c80000007c00000001} cvttps2dq 指令用的是截断舍入,截断转换是将要转换的数向 0 的方向舍入,如 124.79 会转换为 124 。
最后,在执行 movdqu 指令后,查看一下 data 内存位置处的内容:(gdb) x/4d &data
0x80490c0 <data>: 1 125 200 -312 由输出可见,内存位置 data 的值被转换为打包双字整数后,被正确的存储。 |
|