SSE2技术是SSE技术的扩展,它与SSE一样,也使用的是XMM寄存器,只不过SSE2技术提供了一些指令,可以对压缩的双精度浮点数,压缩的32位整数,以及压缩的64位整数进行操作。此外,与SSE类似的是,SSE2既可以处理压缩浮点数,也可以处理标量浮点数,标量浮点数的含义在上一节已经解释过了...

    本文由zengl.com站长对汇编教程英文版相应章节进行翻译得来。

    汇编教程英文版的下载地址:点此进入原百度盘   , 点此进入Dropbox网盘   , 点此进入Google Drive  (Dropbox与Google Drive里是Assembly_Language.pdf文档)

    另外再附加一个英特尔英文手册的共享链接地址:
    点此进入原百度盘点此进入Dropbox网盘点此进入Google Drive  (在某些例子中会用到,Dropbox与Google Drive里是intel_manual.pdf文档)

    Dropbox与Google Drive可能需要通过代理访问。

    本篇翻译对应汇编教程英文原著的第535页到第541页,为第17章的结束篇,同时也是整个汇编教程的结束篇。

    上一篇介绍了SSE相关的指令,这一篇就介绍SSE2及SSE3技术所提供的指令。

Using SSE2 Instructions 使用SSE2指令:

    SSE2技术是SSE技术的扩展,它与SSE一样,也使用的是XMM寄存器,只不过SSE2技术提供了一些指令,可以对压缩的双精度浮点数,压缩的32位整数,以及压缩的64位整数进行操作。此外,与SSE类似的是,SSE2既可以处理压缩浮点数,也可以处理标量浮点数,标量浮点数的含义在上一节已经解释过了,对于SSE2而言,就是可以对XMM寄存器中的低64位的双精度浮点数进行数学运算,与压缩浮点数不同的是,标量只对单个浮点数进行运算。

    下面就介绍下,如何在汇编程式里使用SSE2的指令。

Moving data 数据传值指令:

    在之前的"汇编数据处理 (四) 数据处理结束篇"的文章里,我们已经介绍了5个和SSE2相关的传值指令,完整的传值指令如下表所示:

Instruction
指令
Description
描述
MOVAPD Moves two aligned, double-precision values to XMM registers or memory
将两个对齐的双精度浮点数加载到XMM寄存器或内存中,当源或目标操作数为内存位置时,该内存位置必须是16字节对齐的,否则就会产生#GP(通用保护异常)
MOVUPD Moves two unaligned, double-precision values to XMM registers or memory
将两个非对齐的双精度浮点数加载到XMM寄存器或内存中,当源或目标操作数为内存位置时,该内存位置可以不是16字节对齐的。
MOVDQA Moves two aligned, quadword integer values to XMM registers or memory
将两个对齐的64位整数加载到XMM寄存器或内存中,当源或目标操作数为内存位置时,该内存位置必须是16字节对齐的,否则就会产生#GP(通用保护异常)
MOVDQU Moves two unaligned, quadword integer values to XMM registers or memory
将两个非对齐的64位整数加载到XMM寄存器或内存中,当源或目标操作数为内存位置时,该内存位置可以不是16字节对齐的。
MOVSD Moves one double-precision value to memory or the low quadword of a register
将单个双精度浮点数(标量双精度浮点数)加载到内存中,或者加载到XMM寄存器的低64位中。
MOVHPD Moves one double-precision value to memory or the high quadword of a register
将单个双精度浮点数从XMM寄存器的高64位传值到64位内存中,或者从64位内存传值到XMM寄存器的高64位。
MOVLPD Moves one double-precision value to memory or the low quadword of a register
将单个双精度浮点数从XMM寄存器的低64位传值到64位内存中,或者从64位内存传值到XMM寄存器的低64位。

    这些指令的具体描述信息可以参考 http://x86.renejeschke.de 该链接对应的页面。

    从上表可以看出,与SSE类似的是,SSE2的传值指令也有对齐和非对齐之分,例如:如果要在汇编里使用MOVAPD和MOVDQA指令的话,内存里的数据就必须是16字节对齐的,否则就会产生通用保护异常,在GNU汇编中,可以使用.align的伪指令来实现内存对齐:

.section .data
.align 16
packedvalue1:
	.double 10.235, 289.1
packedvalue2:
	.int 10, 20, 30, 40
.section .text
.globl _start
_start:
	movapd packedvalue1, %xmm0
	movdqa packedvalue2, %xmm1


    上面的代码片段里,就演示了.align的用法,通过.align 16伪指令,gnu汇编器就会让后面的packedvalue1标签所在的内存位置按照16字节对齐。

Processing data SSE2的数学运算指令:

    SSE2提供了一些数学运算指令,可以用于对XMM寄存器里的压缩双精度浮点数,压缩字整数,压缩双字整数,或者压缩四字整数进行数学运算,每种运算针对不同的数据类型,都有不同的指令代码。例如,下表所示的就是SSE2针对不同数据类型的加法指令:

Instruction
指令
Description
描述
ADDPD Adds packed double-precision floating-point values
将源与目标操作数里的压缩双精度浮点数相加
ADDSD Adds scalar double-precision floating-point values
将源与目标操作数里的低64位的标量双精度浮点数相加
PADDSB Adds packed signed byte integer values
将源与目标操作数里的有符号压缩字节整数相加
PADDSW Adds packed signed word integer values
将源与目标操作数里的有符号压缩字整数相加
PADDD Adds packed doubleword integer values
将源与目标操作数里的压缩双字整数相加
PADDQ Adds packed quadword integer values
将源与目标操作数里的压缩四字整数相加

    上表里的PADDSB,PADDSW,PADDD,PADDQ指令既可以用于MMX寄存器,也可以用于XMM寄存器,当用于MMX寄存器时,只能对64位的压缩整数进行运算,当用于XMM寄存器时,则可以对128位的压缩整数进行运算,详情可以参考 http://x86.renejeschke.de/ 该页面下这些指令的具体描述页面。

    SSE2中的其他数学运算,如乘法、除法运算等,也和上面的加法运算类似,对于不同的数据类型,也都有不同的指令代码,如:MULPD,MULSD,DIVPD,DIVSD等。

    除了加减乘除的基本运算外,SSE2还提供了一些计算平方根,求最大值,最小值的指令,如:SQRTPD指令就可以计算出压缩双精度浮点数的平方根,MAXPD指令可以从源与目标操作数的压缩双精度浮点数里求出最大值,MINPD指令可以从压缩双精度浮点数里求出最小值。

    下面的sse2math.s程式就演示了,如何在汇编中使用SSE2指令:

# sse2math.s - An example of using SSE2 arithmetic instructions
.section .data
.align 16
value1:
	.double 10.42, -5.330
value2:
	.double 4.25, 2.10
value3:
	.int 10, 20, 30, 40
value4:
	.int 5, 15, 25, 35
.section .bss
	.lcomm result1, 16
	.lcomm result2, 16
.section .text
.globl _start
_start:
	nop
	movapd value1, %xmm0
	movapd value2, %xmm1
	movdqa value3, %xmm2
	movdqa value4, %xmm3
	mulpd %xmm1, %xmm0
	paddd %xmm3, %xmm2
	movapd %xmm0, result1
	movdqa %xmm2, result2
	movl $1, %eax
	movl $0, %ebx
	int $0x80


    上面的汇编程式里,由于使用了MOVAPD与MOVDQA指令来加载数据到XMM寄存器,因此,.data数据段就必须使用.align 16伪指令来让value1,value2,value3及value4所对应的内存位置按照16字节对齐。在数据都加载到XMM寄存器后,上面代码中就使用MULPD指令将XMM1与XMM0里的压缩双精度浮点数相乘,结果存储在XMM0里,并通过PADDD指令将XMM3与XMM2里的压缩双字整数相加,结果存储在XMM2中。执行完乘法与加法指令后,最后再通过MOVAPD与MOVDQA指令将结果存储到result1与result2的内存位置处。

    在经过汇编链接后,可以在gdb调试器里查看到指令的执行情况:

$ as -gstabs -o sse2math.o sse2math.s 
$ ld -o sse2math sse2math.o
$ gdb -q sse2math
Reading symbols from /root/asm_example/adv/sse2math...done.
(gdb) b _start 
Breakpoint 1 at 0x8048074: file sse2math.s, line 18.
(gdb) r
Starting program: /root/asm_example/adv/sse2math 

Breakpoint 1, _start () at sse2math.s:18
18		nop
(gdb) n
19		movapd value1, %xmm0
(gdb) n
20		movapd value2, %xmm1
(gdb) n
21		movdqa value3, %xmm2
(gdb) n
22		movdqa value4, %xmm3
(gdb) n
23		mulpd %xmm1, %xmm0
(gdb) print $xmm0
$1 = ............................................
  v2_double = {10.42, -5.3300000000000001},
  ...............................................
(gdb) print $xmm1
$2 = ............................................
  v2_double = {4.25, 2.1000000000000001}, 
  ...............................................
(gdb) print $xmm2
$3 = ............................................
  v4_int32 = {10, 20, 30, 40}, 
  ...............................................
(gdb) print $xmm3
$4 = ............................................
  v4_int32 = {5, 15, 25, 35},
  ...............................................
(gdb) 


    通过print指令,可以看到XMM寄存器里的值与value1到value4中定义的值相同,其中XMM0与XMM1里存储的是两个64位的双精度浮点数,XMM2与XMM3里存储的是4个32位的整数。

    在执行完乘法与加法运算,并将结果存储到result1与result2所在的内存位置后,我们可以在gdb中查看到最终的运算结果:

(gdb) x/2gf &result1
0x8049100 :	44.284999999999997	-11.193000000000001
(gdb) x/4wd &result2
0x8049110 :	15	35	55	75
(gdb) 


    可以看到,乘法运算与加法运算的结果,和预期的相一致。

SSE3 Instructions ---- SSE3相关的指令:

    SSE3技术并没有提供任何新的数据类型,它只提供了一些新的指令,SSE3所提供的指令如下所示:
  • FISTTP: Converts the first FPU register value to an integer (with rounding) and pops it from the FPU stack
    FISTTP: 将FPU的ST0里的值转换为整数(使用截断的舍入方式),并弹出ST0里的值
     
  • LDDQU: Loads a 128-bit unaligned data value from memory quickly
    LDDQU: 从内存里快速的加载一个128位的数据到XMM寄存器中
     
  • MOVSHDUP: Moves a 128-bit value, duplicating the second and fourth 32-bit data elements
    MOVSHDUP: 对128位的值进行传值操作,同时拷贝第二个与第四个32位的值,伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_199.html
    
    MOVSHDUP xmm1, xmm2/m128 (intel汇编语法)
    
    if(source == m128) {
    	//load instruction
    	xmm1[0..31] = m128[32..63];
    	xmm1[32..63] = m128[32..63]
    	xmm1[64..95] = m128[96..127];
    	xmm1[96..127] = m128[96..127];
    }
    else {
    	//move instruction
    	xmm1[0..31] = xmm2[32..63];
    	xmm1[32..63] = xmm2[32..63];
    	xmm1[64..95] = xmm2[96..127];
    	xmm1[96..127] = xmm2[96..127];
    }
    
    
     
  • MOVSLDUP: Moves a 128-bit value, duplicating the first and third 32-bit data elements
    MOVSLDUP: 对128位的值进行传值操作,同时拷贝第一个与第三个32位的值,伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_200.html
    
    MOVSLDUP xmm1, xmm2/m128 (intel汇编语法)
    
    if(source == m128) {
    	//load instruction
    	xmm1[0..31] = m128[0..31];
    	xmm1[32..63] = m128[0..31]
    	xmm1[64..95] = m128[64..95];
    	xmm1[96..127] = m128[64..95];
    }
    else {
    	//move instruction
    	xmm1[0..31] = xmm2[0..31];
    	xmm1[32..63] = xmm2[0..31];
    	xmm1[64..95] = xmm2[64..95];
    	xmm1[96..127] = xmm2[64..95];
    }
    
    
     
  • MOVDDUP: Moves a 64-bit value, duplicating the value to make a 128-bit value
    MOVDDUP: 对一个64位的值进行传值操作,同时拷贝该值,从而组建为一个128位的值,伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_182.html
    
    MOVDDUP xmm1, xmm2/m64 (intel汇编语法)
    
    if(Source == m64) {
    	//Load instruction
    	xmm1[0..63] = m64;
    	xmm1[64..127] = m64;
    }
    else {
    	//Move instruction
    	xmm1[0..63] = xmm2[0..63];
    	xmm1[64..127] = xmm2[0..63];
    }
    
    
     
  • ADDSUBPS: With packed single-precision floating-point values, performs an addition on the second and fourth 32-bit values, and a subtraction on the first and third 32-bit values
    ADDSUBPS: 对源与目标操作数里的压缩单精度浮点数进行加减运算,将其中的第二对与第四对浮点数执行加运算,将第一对与第三对浮点数执行减运算,伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_11.html
    
    ADDSUBPS xmm1, xmm2/m128 (intel汇编语法)
    
    xmm1[0..31] = xmm1[0..31] - xmm2/m128[0..31];
    xmm1[32..63] = xmm1[32..63] + xmm2/m128[32..63];
    xmm1[64..95] = xmm1[64..95] - xmm2/m128[64..95];
    xmm1[96..127] = xmm1[96..127] + xmm2/m128[96..127];
    
    
     
  • ADDSUBPD: With packed double-precision floating-point values, performs an addition on the second pair of 64-bit values, and a subtraction on the first pair
    ADDSUBPD:对源与目标操作数里的压缩双精度浮点数进行加减运算,将第二对双精度浮点数执行加运算,将第一对双精度浮点数执行减运算,伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_10.html
    
    ADDSUBPD xmm1, xmm2/m128 (intel汇编语法)
    
    xmm1[0..63] = xmm1[0..63] - xmm2/m128[0..63];
    xmm1[64..127] = xmm1[64..127] + xmm2/m128[64..127];
    
    
     
  • HADDPS: Performs a single-precision floating-point addition on contiguous data elements of the operands
    HADDPS:将源与目标操作数里的单精度浮点数两个为一对,依次相加(需要查看下面的伪操作才能理解),伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_133.html
    
    HADDPS xmm1, xmm2/m128 (intel汇编语法)
    
    xmm1[0..31] = xmm1[0..31] + xmm1[32..63];
    xmm1[32..63] = xmm1[64..95] + xmm1[96..127];
    xmm1[64..95] = xmm2/m128[0..31] + xmm2/m128[32..63];
    xmm1[96..127] = xmm2/m128[64..95] + xmm2/m128[96..127];
    
    
     
  • HADDPD: Performs a double-precision floating-point addition on contiguous data elements of the operands
    HADDPD: 将源与目标操作数里的双精度浮点数两个为一对,依次相加,伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_132.html
    
    HADDPD xmm1, xmm2/m128 (intel汇编语法)
    
    xmm1[0..63] = xmm1[0..63] + xmm1[64..127];
    xmm1[64..127] = xmm2/m128[0..63] + xmm2/m128[64..127];
    
    
     
  • HSUBPS: Performs a single-precision floating-point subtraction on contiguous data elements of the operands
    HSUBPS: 将源与目标操作数里的单精度浮点数两个为一对,依次相减,伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_136.html
    
    HSUBPS xmm1, xmm2/m128 (intel汇编语法)
    
    xmm1[0..31] = xmm1[0..31] - xmm1[32..63];
    xmm1[32..63] = xmm1[64..95] - xmm1[96..127];
    xmm1[64..95] = xmm2/m128[0..31] - xmm2/m128[32..63];
    xmm1[96..127] = xmm2/m128[64..95] - xmm2/m128[96..127];
    
    
     
  • HSUBPD: Performs a double-precision floating-point subtraction on contiguous data elements of the operands
    HSUBPD:将源与目标操作数里的双精度浮点数两个为一对,依次相减,伪操作如下所示:

    from http://x86.renejeschke.de/html/file_module_x86_id_135.html
    
    HSUBPD xmm1, xmm2/m128 (intel汇编语法)
    
    xmm1[0..63] = xmm1[0..63] - xmm1[64..127];
    xmm1[64..127] = xmm2/m128[0..63] - xmm2/m128[64..127];
    
    
    以上就是SSE3相关的指令,剩下就是第17章的Summary(总结)部分,这里就不多说了。

    到此,汇编教程所有内容都翻译完毕,第17章之后,都是索引部分,索引是为了方便在书籍中进行查找操作,不过在网站上,就不需要索引了,需要查找时,可以直接在栏目页面的搜索框中进行搜索。此外,还可以在google中进行全站搜索,可以使用类似如下的语法:


图1

    即输入要搜索的内容后,再接一个site:www.zengl.com的站点信息,这样google就会将本站中的相关页面给显示出来了。

    OK,全书翻译完毕,就到这里,休息,休息一下 o(∩_∩)o~~
 
上下篇

下一篇: 暂无

上一篇: 使用IA-32平台提供的高级功能 (三) SSE相关指令

相关文章

使用内联汇编 (一)

Moving Data 汇编数据移动 (二)

汇编数据处理 (二)

基本数学运算 (一)

调用汇编模块里的函数 (一)

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