SSE floating-point data types (SSE中的浮点数据类型):除了前面章节介绍的几个标准浮点数据类型外,在SSE技术中还引入了两种高级的浮点数据类型:128-bit packed single-precisio...

    本文由zengl.com站长对
    http://pan.baidu.com/share/link?shareid=3717576860&uk=940392313 汇编教程英文版相应章节进行翻译得来。
    另外再附加一个英特尔英文手册的共享链接地址:
    http://pan.baidu.com/share/link?shareid=2345340326&uk=940392313 (在某些例子中会用到)

    本篇翻译对应汇编教程英文原著的第221页到第231页,前7章翻译完 (注意这里的页数不是页脚的页数,而是pdf电子档顶部,分页输入框中的页数,也就是包含了目录,前言部分的总页数,pdf电子档总页数是577,当前已翻译完的页数为231 / 577)。

SSE floating-point data types (SSE中的浮点数据类型):

    除了前面章节介绍的几个标准浮点数据类型外,在SSE技术中还引入了两种高级的浮点数据类型:
  • 128-bit packed single-precision floating-point (in SSE)
    128位压缩单精度浮点数 (在SSE中引入)
  • 128-bit packed double-precision floating-point (in SSE2)
    128位压缩双精度浮点数 (在SSE2中引入)
    为了能够容纳这些压缩浮点数,SSE中就引入了XMM0 , XMM1 ........ XMM7这8个128位的XMM寄存器,压缩浮点数和压缩整数的概念是一样的,并不会对数据进行真正的压缩操作,只是多个相同尺寸的浮点数填充到一个大容量寄存器中,处理器就可以在一个时钟周期内同时处理多个浮点数,这样处理器生成结果的速度就要比一般的按顺序依次处理这些浮点数的速度要快很多。

    压缩浮点数在XMM寄存器中的存储情况如下图所示:

图1

    从上图中可以看到,一个128位XMM寄存器中可以同时填充4个32位的单精度浮点数,或者填充2个64位的双精度浮点数,SSE中引入的两种压缩浮点数不能用于FPU或MMX寄存器中,只能用于XMM寄存器中,并且只有在支持SSE或SSE2技术的处理器上才能使用这两种压缩浮点数,处理这些浮点数还需要用到一些特殊的指令,下面就介绍下SSE浮点数的传值指令。

Moving SSE floating-point values SSE浮点数的传值操作:

    IA-32平台中包含对SSE中新增浮点数据类型的操作指令,这些指令被分为两种,一种是用于处理压缩单精度浮点数的SSE指令,另一种是用于处理压缩双精度浮点数的SSE2指令。

SSE floating-point values SSE传值指令:

    SSE中引入的压缩单精度浮点数的传值指令如下表所示:

Instruction
指令
Description
描述
MOVAPS Move four aligned, packed single-precision values to XMM registers or memory
将4个对齐的压缩单精度浮点数加载到XMM寄存器或内存中
MOVUPS Move four unaligned, packed single-precision values to XMM registers or memory
将4个非对齐的压缩单精度浮点数加载到XMM寄存器或内存中
MOVSS Move a single-precision value to memory or the low doubleword of a register
将一个单精度浮点数加载到内存中或加载到一个寄存器的低32位
MOVLPS Move two single-precision values to memory or the low quadword of a register
将2个单精度浮点数加载到内存中或加载到一个寄存器的低64位
MOVHPS Move two single-precision values to memory or the high quadword of a register
将2个单精度浮点数加载到内存中或加载到一个寄存器的高64位
MOVLHPS Move two single-precision values from the low quadword to the high quadword
将2个单精度浮点数从寄存器的低64位传值到高64位
MOVHLPS Move two single-precision values from the high quadword to the low quadword
将2个单精度浮点数从寄存器的高64位传值到低64位

    这些指令都是使用128位的XMM寄存器来完成浮点数的传值操作的,你除了可以操作完整的4个压缩单精度浮点数,还可以对其中的2个或单个浮点数进行操作。

    下面的ssefloat.s就是使用SSE浮点传值指令的例子:

# ssefloat.s - An example of moving SSE FP data types
.section .data
value1:
    .float 12.34, 2345.543, -3493.2, 0.44901
value2:
    .float -5439.234, 32121.4, 1.0094, 0.000003
.section .bss
    .lcomm data, 16
.section .text
.globl _start
_start:
    nop
    movups value1, %xmm0
    movups value2, %xmm1
    movups %xmm0, %xmm2
    movups %xmm0, data

    movl $1, %eax
    movl $0, %ebx
    int $0x80

    上面的代码中在value1和value2标签处分别定义了4个单精度浮点数,通过movups指令就可以一次将4个连续的浮点数一起填充到指定的XMM寄存器中,这里没有使用movaps是因为代码中没有使用.align之类的伪操作符进行数据对齐,所以只能用movups非对齐指令来传值。

    对代码进行汇编调试:

$ as -gstabs -o ssefloat.o ssefloat.s
$ ld -o ssefloat ssefloat.o
$ gdb -q ssefloat

Reading symbols from /home/zengl/Downloads/asm_example/ssetest/ssefloat...done.
(gdb) break *_start+1
Breakpoint 1 at 0x8048075: file ssefloat.s, line 13.
(gdb) r
Starting program: /home/zengl/Downloads/asm_example/ssetest/ssefloat

Breakpoint 1, _start () at ssefloat.s:13

13        movups value1, %xmm0
(gdb) s
14        movups value2, %xmm1
(gdb) s
15        movups %xmm0, %xmm2
(gdb) s
16        movups %xmm0, data
(gdb) print $xmm0
$1 = {v4_float = {12.3400002, 2345.54297, -3493.19995, 0.449010015},
  v2_double = {5.6204289471764299e+24, 1.0439462282443856e-05},
  v16_int8 = {-92, 112, 69, 65, -80, -104, 18, 69, 51, 83, 90, -59, -92, -28, -27, 62},
  v8_int16 = {28836, 16709, -26448, 17682, 21299, -15014, -7004, 16101},
  v4_int32 = {1095069860, 1158846640, -983936205, 1055253668},
  v2_int64 = {4977208420974555300, 4532279996355072819},
  uint128 = 0x3ee5e4a4c55a5333451298b0414570a4}

(gdb) print $xmm1
$2 = {v4_float = {-5439.23389, 32121.4004, 1.00940001, 3.00000011e-06},
  v2_double = {8.7452727745837517e+33, 3.4658329842889617e-47},
  v16_int8 = {-33, -7, -87, -59, -51, -14, -6, 70, 5, 52, -127, 63, -100, 83, 73, 54},
  v8_int16 = {-1569, -14935, -3379, 18170, 13317, 16257, 21404, 13897},
  v4_int32 = {-978716193, 1190851277, 1065432069, 910775196},
  v2_int64 = {5114667292431088095, 3911749681893422085},
  uint128 = 0x3649539c3f81340546faf2cdc5a9f9df}

(gdb) print $xmm2
$3 = {v4_float = {12.3400002, 2345.54297, -3493.19995, 0.449010015},
  v2_double = {5.6204289471764299e+24, 1.0439462282443856e-05},
  v16_int8 = {-92, 112, 69, 65, -80, -104, 18, 69, 51, 83, 90, -59, -92, -28, -27, 62},
  v8_int16 = {28836, 16709, -26448, 17682, 21299, -15014, -7004, 16101},
  v4_int32 = {1095069860, 1158846640, -983936205, 1055253668},
  v2_int64 = {4977208420974555300, 4532279996355072819},
  uint128 = 0x3ee5e4a4c55a5333451298b0414570a4}

(gdb)

    在通过s命令单步执行完前三条movups指令后,xmm0寄存器中就存放了value1标签处定义的四个浮点数:$1 = {v4_float = {12.3400002, 2345.54297, -3493.19995, 0.449010015},xmm1寄存器中则存放了value2标签处定义的四个浮点数:$2 = {v4_float = {-5439.23389, 32121.4004, 1.00940001, 3.00000011e-06} ,通过movups %xmm0, %xmm2指令将xmm0里的4个packed压缩浮点数传值到xmm2中,这样xmm2里也存放了和xmm0里一样的值了。

    继续执行最后一条movups指令:

16        movups %xmm0, data
(gdb) s
18        movl $1, %eax
(gdb) x/4wf &data
0x80490c0 <data>:    12.3400002    2345.54297    -3493.19995    0.449010015
(gdb)

    value1标签处的值先传递给xmm0寄存器,最后由xmm0传值到data缓冲区域中,value1处定义的几个浮点数在经过编译器编译后,在内存中就会存在二进制精度误差,例如上面的12.3400002与代码定义中的12.34就存在这样的精度误差,详细原因在前一章浮点数中已经讲解过,下面我们通过x命令来对比下data缓冲区域和value1内存位置处的浮点数二进制值:

(gdb) x/16bx &data
0x80490c0 <data>:	0xa4  0x70  0x45  0x41  0xb0  0x98  0x12  0x45
0x80490c8 <data+8>:	0x33  0x53  0x5a  0xc5  0xa4  0xe4  0xe5  0x3e
(gdb) x/16bx &value1
0x804909c <value1>:	0xa4  0x70  0x45  0x41  0xb0  0x98  0x12  0x45
0x80490a4 <value1+8>:	0x33  0x53  0x5a  0xc5  0xa4  0xe4  0xe5  0x3e
(gdb)

    可以看到data和value1处的值完全匹配,说明从value1定义那一刻开始浮点精度误差就已经存在了。

SSE2 floating-point values SSE2传值指令:

    下表显示了IA-32平台中和SSE2压缩双精度浮点数相关的传值指令:

Instruction
指令
Description
描述
MOVAPD Move two aligned, double-precision values to XMM registers or memory
将两个对齐的双精度浮点数加载到XMM寄存器或内存中
MOVUPD Move two unaligned, double-precision values to XMM registers or memory
将两个非对齐的双精度浮点数加载到XMM寄存器或内存中
MOVSD Move one double-precision value to memory or the low quadword of a register
将一个双精度浮点数加载到内存中或加载到一个寄存器的低64位中
MOVHPD Move one double-precision value to memory or the high quadword of a register
将一个双精度浮点数加载到内存中或加载到一个寄存器的高64位中
MOVLPD Move one double-precision value to memory or the low quadword of a register
将一个双精度浮点数加载到内存中或加载到一个寄存器的低64位中

    上面的指令可以在XMM寄存器和内存之间传递压缩双精度浮点数,除了可以使用MOVAPD和MOVUPD指令来传递完整的两个压缩双精度浮点数外,还可以使用其余指令来对单个双精度浮点数进行传值操作。

    下面的sse2float.s程式就是使用SSE2传值指令的例子:

# sse2float.s - An example of moving SSE2 FP data types
.section .data
value1:
    .double 12.34, 2345.543
value2:
    .double -5439.234, 32121.4
.section .bss
    .lcomm data, 16
.section .text
.globl _start
_start:
    nop
    movupd value1, %xmm0
    movupd value2, %xmm1
    movupd %xmm0, %xmm2
    movupd %xmm0, data

    movl $1, %eax
    movl $0, %ebx
    int $0x80

    和前面的例子不同的是,这里value1和value2处使用.double来定义2个双精度浮点数,这两个连续的双精度浮点数一起构成了一个完整的压缩双精度浮点数,接着代码中movupd指令就可以一次完成2个双精度浮点数的传值工作。

    下面对代码进行汇编,调试:

$ as -gstabs -o sse2float.o sse2float.s
$ ld -o sse2float sse2float.o
$ gdb -q sse2float

Reading symbols from /home/zengl/Downloads/asm_example/ssetest/sse2float...done.
(gdb) break *_start+1
Breakpoint 1 at 0x8048075: file sse2float.s, line 13.
(gdb) r
Starting program: /home/zengl/Downloads/asm_example/ssetest/sse2float

Breakpoint 1, _start () at sse2float.s:13
13        movupd value1, %xmm0

(gdb) s
14        movupd value2, %xmm1
(gdb) s
15        movupd %xmm0, %xmm2
(gdb) s
16        movupd %xmm0, data
(gdb) s
18        movl $1, %eax
(gdb) print $xmm0
$1 = {v4_float = {5.84860315e+35, 2.63562489, 1.79352231e-36, 5.07264233},
 
v2_double = {12.34, 2345.5430000000001},
  v16_int8 = {-82, 71, -31, 122, 20,-82, 40, 64, 117, -109, 24, 4, 22, 83, -94, 64},
  v8_int16 = {18350, 31457,-20972, 16424, -27787, 1048, 21270, 16546},
  v4_int32 = {2061584302,1076407828, 68719477, 1084379926},
  v2_int64 = {4623136420479977390,4657376318677619573},
  uint128 = 0x40a25316041893754028ae147ae147ae}

(gdb) print $xmm1
$2 = {v4_float = {-1.11704749e+24, -5.66396856, -1.58818684e-23, 6.98026705},
 
v2_double = {-5439.2340000000004, 32121.400000000001},
  v16_int8 = {68, -117,108, -25, 59, 63, -75, -64, -102, -103, -103, -103, 89, 94, -33, 64},
  v8_int16 = {-29884, -6292, 16187, -16203, -26214, -26215, 24153, 16607},
  v4_int32 = {-412316860, -1061863621, -1717986918, 1088380505},
  v2_int64 = {-4560669521124488380, 4674558677155944858},
  uint128 = 0x40df5e599999999ac0b53f3be76c8b44}

(gdb) print $xmm2
$3 = {v4_float = {5.84860315e+35, 2.63562489, 1.79352231e-36, 5.07264233},
 
v2_double = {12.34, 2345.5430000000001},
  v16_int8 = {-82, 71, -31, 122, 20,-82, 40, 64, 117, -109, 24, 4, 22, 83, -94, 64},
  v8_int16 = {18350, 31457,-20972, 16424, -27787, 1048, 21270, 16546},
  v4_int32 = {2061584302,1076407828, 68719477, 1084379926},
  v2_int64 = {4623136420479977390,4657376318677619573},
  uint128 = 0x40a25316041893754028ae147ae147ae}

(gdb) x/2gf &data
0x80490c0 <data>:    12.34    2345.5430000000001
(gdb)

    上面在movupd指令完成传值操作后,xmm0寄存器,xmm2寄存器及data缓冲区域中就存放了value1里的两个双精度浮点数:v2_double = {12.34, 2345.5430000000001},xmm1中则存放了value2里定义的两个双精度浮点数:v2_double = {-5439.2340000000004, 32121.400000000001}

    这里需要注意的是12.34没有出现精度误差,你可以用上一章提到的方法将12.34这个小数转为二进制格式,然后会发现12.34对应的二进制格式刚好可以全部存放到64位双精度浮点格式中,不会出现二进制舍入问题,所以本例中也就没有出现浮点精度问题。

    查看data里的数据时,使用的是 x/2gf 命令,g表示将8字节即64位的数据按照浮点格式来输出显示,64位浮点格式也就是双精度格式,这个在前面的章节中提到过。

SSE3 instructions SSE3指令:

    SSE3技术出现在奔腾4及以后的处理器中,SSE3中为了方便浮点传值,引入了额外的三个传值指令:
  • MOVSHDUP:将内存或XMM寄存器中的4个单精度浮点数传值到目标XMM寄存器中,
    同时将目标寄存器中第2个浮点数拷贝覆盖掉第1个浮点数,第4个浮点数拷贝覆盖掉第3个浮点数。
  • MOVSLDUP:将内存或XMM寄存器中的4个单精度浮点数传值到目标XMM寄存器中,
    同时将目标寄存器中第1个浮点数拷贝覆盖掉第2个浮点数,第3个浮点数拷贝覆盖掉第4个浮点数。
  • MOVDDUP:将内存或XMM寄存器中的一个双精度浮点数传值到目标XMM寄存器的低64位,
    再将目标寄存器低64位拷贝到高64位。
    为了测试上面的MOVSHDUP和MOVSLDUP指令,可以将前面的ssefloat.s例子做如下改动:

# ssefloat.s - An example of moving SSE FP data types
.section .data
.align 16
value1:
    .float 12.34, 2345.543, -3493.2, 0.44901
value2:
    .float -5439.234, 32121.4, 1.0094, 0.000003
.section .bss
    .lcomm data, 16
.section .text
.globl _start
_start:
    nop
    movups value1, %xmm0
    movups value2, %xmm1
    movshdup %xmm0, %xmm2
    movups %xmm0, data
    movsldup data,%xmm1

    movl $1, %eax
    movl $0, %ebx
    int $0x80

    首先在data数据段下面使用 .align 16 对齐伪操作符将data里的数据按16字节边界对齐,因为MOVSHDUP和MOVSLDUP指令要求源操作数如果在内存中就必须按16字节对齐,否则会出现保护异常,下面是代码在gdb中的调试输出情况:

(gdb) s
16        movshdup %xmm0, %xmm2
(gdb) s
17        movups %xmm0, data
(gdb) print $xmm0
$1 = {v4_float = {12.3400002, 2345.54297, -3493.19995, 0.449010015},
...................... //省略其他输出
(gdb) print $xmm2
$2 = {v4_float = {2345.54297, 2345.54297, 0.449010015, 0.449010015},
...................... //省略其他输出
(gdb)

    上面输出中xmm0寄存器里存放的是value1中的4个浮点数,通过movshdup指令将xmm0中的4个浮点数传值给xmm2寄存器的时候,xmm2中的第2个浮点数2345.54297拷贝覆盖掉了第1个浮点数,第4个浮点数0.449010015则拷贝覆盖掉了第3个浮点数。

    上面调试了movshdup,接着调试movsldup指令:

17        movups %xmm0, data
(gdb) s
18        movsldup data,%xmm1
(gdb) s
20        movl $1, %eax
(gdb) x/4wf &data
0x80490d0 <data>:    12.3400002    2345.54297    -3493.19995    0.449010015
(gdb) print $xmm1
$4 = {v4_float = {12.3400002, 12.3400002, -3493.19995, -3493.19995},
...................... //省略其他输出
(gdb)

    上面输出显示xmm0寄存器的值先传值到data缓冲区域中,接着通过movsldup指令将data里的值加载到xmm1寄存器中,同时xmm1寄存器中的第1个浮点数12.3400002拷贝覆盖掉了第2个浮点数,第3个浮点数-3493.19995拷贝覆盖掉了第4个浮点数。

    下面为了测试最后一个MOVDDUP指令,可以将前面的sse2float.s例子做如下改动:

# sse2float.s - An example of moving SSE2 FP data types
.section .data
value1:
    .double 12.34, 2345.543
value2:
    .double -5439.234, 32121.4
.section .bss
    .lcomm data, 16
.section .text
.globl _start
_start:
    nop
    movddup value1, %xmm0
    movupd value2, %xmm1
    movupd %xmm0, %xmm2
    movupd %xmm0, data

    movl $1, %eax
    movl $0, %ebx
    int $0x80

    MOVDDUP指令就不需要设置数据对齐,下面是gdb中的调试输出情况:

13        movddup value1, %xmm0
(gdb) s
14        movupd value2, %xmm1
(gdb) x/2gf &value1
0x80490a0 <value1>:    12.34    2345.5430000000001
(gdb) print $xmm0
...................... //省略其他输出
  v2_double = {12.34, 12.34},
...................... //省略其他输出
(gdb)

    上面通过s单步调试命令执行完movddup value1, %xmm0指令后,value1中的双精度浮点数12.34就传值到xmm0寄存器中,同时xmm0的低64位12.34拷贝到了高64位,所以xmm0里的值就变为:v2_double = {12.34, 12.34}

    注意:SSE3中的指令只能用于奔腾4及以后的处理器中

Conversions 数据类型转换:

[zengl pagebreak]

Conversions 数据类型转换:

    IA-32平台还提供了一些数据类型转换指令,可以将一种数据类型转为另一种数据类型,例如将浮点数转为整数等。

Conversion instructions 转换指令:

    下表显示了数据类型转换相关的指令:


Instruction
指令
Converts
转换描述
CVTDQ2PD Packed doubleword integers to packed double-precision FP (XMM) 
将2个32位压缩整数转为2个压缩双精度浮点数(目标为XMM寄存器)
CVTDQ2PS Packed doubleword integers to packed single-precision FP (XMM) 
将4个32位压缩整数转为4个压缩单精度浮点数(目标为XMM寄存器)
CVTPD2DQ Packed double-precision FP to packed doubleword integers (XMM) 
将2个压缩双精度浮点数转为2个32位压缩整数(目标为XMM寄存器)
CVTPD2PI Packed double-precision FP to packed doubleword integers (MMX) 
将2个压缩双精度浮点数转为2个32位压缩整数(目标为MMX寄存器)
CVTPD2PS Packed double-precision FP to packed single-precision FP (XMM) 
将2个压缩双精度浮点数转为2个压缩单精度浮点数(目标为XMM寄存器)
CVTPI2PD Packed doubleword integers to packed double-precision FP (XMM) 
将2个32位压缩整数转为2个压缩双精度浮点数(目标为XMM寄存器,源为MMX寄存器或存放2个32位整数的内存地址)
CVTPI2PS Packed doubleword integers to packed single-precision FP (XMM) 
将2个32位压缩整数转为2个压缩单精度浮点数(目标为XMM寄存器,源为MMX寄存器或内存地址)
CVTPS2DQ Packed single-precision FP to packed doubleword integers (XMM) 
将4个压缩单精度浮点数转为4个32位压缩整数(目标为XMM寄存器)
CVTPS2PD Packed single-precision FP to packed double-precision FP (XMM) 
将2个压缩单精度浮点数转为2个压缩双精度浮点数(目标为XMM寄存器)
CVTPS2PI Packed single-precision FP to packed doubleword integers (MMX) 
将2个单精度浮点数转为2个32位整数(目标为MMX寄存器)
CVTTPD2PI Packed double-precision FP to packed doubleword integers (MMX, truncated) 
将2个压缩双精度浮点数转为2个32位压缩整数(目标为MMX寄存器,直接截掉小数,不会发生四舍五入)
CVTTPD2DQ Packed double-precision FP to packed doubleword integers (XMM, truncated) 
将2个压缩双精度浮点数转为2个32位压缩整数(目标为XMM寄存器,直接截掉小数,不会发生四舍五入)
CVTTPS2DQ Packed single-precision FP to packed doubleword integers (XMM, truncated) 
将4个单精度浮点数转为4个32位整数(目标为XMM寄存器,直接截掉小数,不会发生四舍五入)
CVTTPS2PI Packed single-precision FP to packed doubleword integers (MMX, truncated) 
将2个单精度浮点数转为2个32位整数(目标为MMX寄存器,直接截掉小数,不会发生四舍五入)

    转换指令较多,详细的解释可以在google中进行如下的搜索:

CVTTPS2PI site:www.jaist.ac.jp

    在谷歌搜索框中进行上面的搜索,该搜索会在www.jaist.ac.jp网站中查找CVTTPS2PI指令相关的页面,基本上搜索出来的结果中第一条就是详细介绍页面,进去后就可以看到相当详细的解释。

    下面的convtest.s例子演示了转换指令的用法:

# convtest.s - An example of data conversion
.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
.globl _start
_start:
    nop
    cvtps2dq value1, %xmm0
    cvttps2dq value1, %xmm1
    cvtdq2ps value2, %xmm2
    movdqu %xmm0, data
    movl $1, %eax
    movl $0, %ebx
    int $0x80

    对上面代码进行汇编调试:

$ as -gstabs -o convtest.o convtest.s
$ ld -o convtest convtest.o
$ gdb -q convtest

Reading symbols from /home/zengl/Downloads/asm_example/ssetest/convtest...done.
(gdb) break *_start+1
Breakpoint 1 at 0x8048075: file convtest.s, line 13.
(gdb) r
Starting program: /home/zengl/Downloads/asm_example/ssetest/convtest

Breakpoint 1, _start () at convtest.s:13
13        cvtps2dq value1, %xmm0

(gdb) s
14        cvttps2dq value1, %xmm1
(gdb) s
15        cvtdq2ps value2, %xmm2
(gdb) s
16        movdqu %xmm0, data
(gdb) s
17        movl $1, %eax
(gdb) print $xmm0
...................... //省略其他输出
 v4_int32 = {1, 125, 200, -312},
...................... //省略其他输出
(gdb) print $xmm1
...................... //省略其他输出
 v4_int32 = {1, 124, 200, -312},
...................... //省略其他输出
(gdb) print $xmm2
$3 = {v4_float = {1, -435, 0, -25},
...................... //省略其他输出
(gdb) x/4wd &data
0x80490c0 <data>:    1    125    200    -312
(gdb)

    上面代码中第一条指令cvtps2dq value1, %xmm0将value1中的4个单精度浮点数转为4个32位压缩整数,结果存储在xmm0寄存器中,通过print $xmm0的输出结果 v4_int32 = {1, 125, 200, -312} 可以看到value1中的4个浮点数通过将小数部分进行四舍五入得到了4个整数值。

    第二条cvttps2dq value1, %xmm1指令以截断的方式,将value1中的4个浮点数转为了4个整数,存储到xmm1寄存器中,print $xmm1命令输出结果:v4_int32 = {1, 124, 200, -312} 中的124就是value1中的124.79直接截掉小数部分后的整数值。

    第三条cvtdq2ps value2, %xmm2指令将value2标签处定义的4个整数转为4个单精度浮点数,存储到xmm2寄存器中,由print $xmm2命令的输出结果$3 = {v4_float = {1, -435, 0, -25}就可以看到这4个转换后的浮点数。

    最后的movdqu %xmm0, data代码使用了前面章节中提到过的movdqu指令来将xmm0寄存器中的4个整数给传值到data缓冲区域中,由x/4wd &data命令输出的结果可以看到和xmm0中的4个整数值是一样的。

    剩下的就是些总结,限于篇幅就不多说了,下一章开始介绍汇编中的数学运算指令。

    转载请注明来源:www.zengl.com

    OK,到这里,休息,休息一下 o(∩_∩)o~~

上下篇

下一篇: 基本数学运算 (一)

上一篇: 汇编数据处理 (三) 浮点数

相关文章

IA-32平台(一)

什么是汇编语言(一) 汇编底层原理,指令字节码

使用内联汇编 (二)

汇编函数的定义和使用 (一)

汇编开发示例 (二) 示例介绍结束篇

汇编函数的定义和使用 (二)