SIMD(单道指令多道数据流)指令(MMX/SSE1/SSE2)详解(中文).

SIMD(单道指令多道数据流)指令(MMX/SSE1/SSE2)详解(中文).还有更多的多媒体指令集,SSE3,SSE4

SIMD(单道指令多道数据流)指令(MMX/SSE1/SSE2)详解(中文).还有更多的多媒体指令集,SSE3,SSE4,可惜我不会.
在这里拜托AoGo老大,把此贴挂的时间长点,算是对我辛苦劳动的一点支持吧.
此贴请多多顶顶,多多转贴,这可是我从Intel文档上边看边试边翻译出来的,不容易呀,网上实在找不到如此详细的SIMD指令中文说明了,
这也算是我对ASM初学者一点帮助吧,中间可能有错误,发现后请立即发贴指正,并在转贴时修改,免得误人子弟,但要注明原文内容.
我想看懂了 MMX 指令的肯定很容易理解 SSE 指令的,至少我是这样,所以我 SSE 的例子就少加了点.
其中有一些指令我也搞不懂,主要是关于标志位的,毕竟是E文的,所以我没写上去,知道的补充一下,我知道该论坛上有很多E文高手的.
转贴请注明作者与出处.
还有浏览时请把文档后缀名改为.asm,然后用ASM编辑器浏览,这样关键字可以以不同颜色标出,增加可读性.
作者:HAM(参考资料:Intel PDF文档)
完成日期:2007年8月20日
本文档所在网站:www.aogosoft.com
注:其中有的指令6.14版本的ml.exe无法编译,比如SSE2指令集,masm32软件包中的编译器无法编译,大家可去下载6.15版本,或找宏代替.

 

对于SIMD指令我想大家不会没听说过吧,那是Intel Pentium Pro CPU上开始增加的专用于多媒体处理的指令集,算算有10年了,
时间过得可真快,技术发展如此之迅速,那时的我还没见过电脑呢,如今已有了自己的第一台小黑,可惜是单核的.
不过用好SIMD多媒体指令还真得下点工夫,用好了速度会明显上升,用不好速度反儿变慢,这一点我有感觉,我现在不太会用多媒体
指令,Intel 文档上都是E文的,看了实在累,为了翻译这些指令的用途就花了我一个星期,更别谈指令优化了,可恨从初中开始
没有认真学习英语,不知哪位大哥恳详谈一下指令优化的一些知识,我指的是针对当前主流CPU的速度上的优化,网上一些文章都是
                     ﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌
老一代的CPU,甚有8086,8088的,如今的CPU都用上了什么超流水,超线程等等,这些技术我发现对指令的前后顺序十分敏感,即使指令
条数相同,指令用得也一样,就是前后顺序不一样,速度上也会相差甚远,现在的CPU汇编语言真是越来越难掌握了,不只是学习
指令用法与算法,看来高级语言还是有优势的,可能算法一样,速度都会比一个菜鸟用汇编语言写的运行的快.
    ▍


MMX指令有8个64位寄存器(MM0~MM7),不过可惜都是借的FPU的, FPU原来有8个80位寄存器(st(0)~st(7)),现在用在了MMX
上,所以用之后要加上一条EMMS指令,用以复位.
MMX寄存器有64位,可以同时进行8对字节或4对字或2对双字同时相同操作,还可以进行饱和运算,也就是运算结果有个顶点,
不会溢出,当然也可以进行普通运算.
    MM表示64位MMX寄存器.
    r32表示32位通用寄存器或esi,edi
    m32表示32位内存变量
    m64表示64位内存变量
    m128表示128位内存变量
    imm8表示8位立即数
    左操作数为目的操作数,右操作数为源操作数
    '|'字符表示每组数据之间的间隔分隔符
    'MM'与'XMM'必须为大写,如果写成小写,就必须在ml的命令行参数后加上' /Cp','/'前要加一个空格,'C'大写,'p'小写.
    
MMX:
        movd MM,r32/m32
        把 r32/m32 值赋给 MM 的低32位,高32位清零.
        movd r32/m32,MM
        把 MM 的低32位值赋给 r32/m32.
        例:
        当MM0 == 1234567887654321 h,eax == 0abc h时,执行movd MM0,eax,则MM0 == 0abc h
        当MM0 == 1234567887654321 h,eax == 0abc h时,执行movd eax,MM0,则eax == 87654321 h
        
        movq MM,MM/m64
        把源MM/m64的值送入目的MM.
        例:
        当MM0 == 1234567887654321 h,MM1 == 3141592653 h时,执行movq MM0,MM1,则MM0 == 3141592653 h
        
        paddsb MM,MM/m64
        按字节对齐,饱和有符号数(补码)相加(结果= -128~+127,80h~7fh),值送入目的MM.
        当结果小于-128时,结果强制转为80h,当结果大于+127时,结果强制转为7fh.
        例:
        当MM0 ==  00 c0 fe 7e 11 h,
          MM1 ==  12 a6 9c 10 02 h时,执行 paddsb MM0,MM1,
        则MM0 ==  12 80 9a 7f 13 h
        0c0h = -64,0a6h = -90,-64 + (-90) = -154,-154 < -128,所以结果为80h
        7eh=126,10h=16,126+16=142,142>127,所以结果为7fh
        其余的未饱和所以结果正常.
        
        paddsw MM,MM/m64
        按字对齐,饱和有符号数(补码)相加(结果= -32768~+32767,8000h~7fffh),值送入目的MM.
        运算与paddsb类似,当结果小于-32768时,结果强制转为8000h,当结果大于,+32767时,结果强制转为7fffh.
        
        paddusb MM,MM/m64
        按字节对齐,饱和无符号数相加(结果= 0~255,0h~0ffh),值送入目的MM.
        当结果大于255时,结果强制转为0ffh.
        例:
        当MM0 == 23 11 h,MM1 == fc 22 h时,执行paddusb MM0,MM1,则MM0 == ff 33h
        23h = 35,0fch = 253,35 + 253 = 288,288 > 255,所以结果为0ffh
        
        paddusw MM,MM/m64
        按字对齐,饱和无符号数相加(结果= 0~65535,0h~0ffffh),值送入目的MM.
        运算与paddusb类似,当结果大于65535时,结果强制转为0ffffh.
        
        psubsb MM,MM/m64
        按字节对齐,饱和有符号数(补码)相减(结果= -128~+127,80h~7fh),值送入目的MM.
        运算与paddsb类似,当结果小于-128时,结果强制转为80h,当结果大于,+127时,结果强制转为7fh.
        
        psubsw MM,MM/m64
        按字对齐,饱和有符号数(补码)相减(结果= -32768~+32767,8000h~7fffh),值送入目的MM.
        运算与paddsw类似,当结果小于-32768时,结果强制转为8000h,当结果大于,+32767时,结果强制转为7fffh.
        
        paddb MM,MM/m64
        按字节对齐,普通相加,与add指令类似.
        例:
        当MM0 = 12 34 56 78 ab cd ef feh,
          MM1 = 87 69 86 54 3d ea cb 03h,执行paddb MM0,MM1,
        则MM0 = 99 9d dc cc e8 b7 ba 01h
        
        
        paddw MM,MM/m64
        按字对齐,普通相加,与add指令类似.
        
        paddd MM,MM/m64
        按双字对齐,普通相加.与add指令类似.
        
        paddq MM,MM/m64
        按四字对齐,普通相加.
        例:
        当MM0 == 0fffffffffffffffeh,MM1 == 3h,执行paddq MM0,MM1,则MM0 = 1h
        
        psubb MM,MM/m64
        按字节对齐,普通相减,与sub指令类似.
        
        psubw MM,MM/m64
        按字对齐,普通相减,与sub指令类似.
        
        psubd MM,MM/m64
        按双字对齐,普通相减.与add指令类似.
        
        psubq MM,MM/m64
        按四字对齐,普通相减.
        例:
        当MM0 == 1h,MM1 == 3 h,执行psubq MM0,MM1,则MM0 = 0fffffffffffffffeh
        
        psllw MM,MM/m64    psllw MM,imm8
        把目的寄存器按字由源存储器(或imm8 立即数)指定位数逻辑左移,移出的位丢失.
        低字移出的位不会移入高字.
        例:
        当MM0 = 0ffff ffff ffff ffffh,执行psllw MM0,1
        则MM0 = 0fffe fffe fffe fffeh
        
        psrlw MM,MM/m64   psrlw MM,imm8
        把目的寄存器按字由源存储器(或imm8 立即数)指定位数逻辑右移,移出的位丢失.
        高字移出的位不会移入低字.
        例:
        当MM0 = 0ffff ffff ffff ffffh,执行psrlw MM0,1
        则MM0 = 07fff 7fff 7fff 7fffh
        
        pslld MM,MM/m64   pslld MM,MM imm8
        把目的寄存器按双字由源存储器(或imm8 立即数)指定位数逻辑左移,移出的位丢失.
        低双字移出的位不会移入高双字.
        例:
        当MM0 = 0ffffffff ffffffffh,执行pslld MM0,1
        则MM0 = 0fffffffe fffffffeh
        
        psrld MM,MM/m64   psrld MM,imm8
        把目的寄存器按双字由源存储器(或imm8 立即数)指定位数逻辑右移,移出的位丢失.
        高双字移出的位不会移入低双字.
        例:
        当MM0 = 0ffffffff ffffffffh,执行psrld MM0,1
        则MM0 = 07fffffff 7fffffffh
        
        
        pmullw MM,MM/m64
        按字对齐,有符号(补码)相乘,取结果低16位,放入目的寄存器的对应字.
        例:
        当MM0 == 2 acfeh,MM1 == 9 cef3h,执行 pmulhw,则MM0 = 0000 0000 0012 991ah
        2 * 9 = 18,18 = 0000 0012h,取低16位 0012 为结果.
        0acfeh == -21250,0cef3h == -12557,-21250*-12557 = 266836250 = 0fe7 991a h,取低16位 991a 为结果.
        
        pmulhw MM,MM/m64
        按字对齐,有符号(补码)相乘,取结果高16位,放入目的寄存器的对应字.
        例:
        当MM0 == 2 acfeh,MM1 == 9 cef3h,执行 pmulhw,则MM0 = 0000 0000 0000 0fe7h
        2 * 9 = 18,18 = 0000 0012h,取高16位 0000 为结果.
        0acfeh == -21250,0cef3h == -12557,-21250*-12557 = 266836250 = 0fe7 991a h,取高16位 0fe7 为结果.
        
      ▲注:在MMX指令集中没有除法指令.
           ﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌
        pand MM,MM/m64
        64个位'与'操作,结果放入目的寄存器.
        
        pandn MM,MM/m64
        目的寄存器按位先取'非',再'与'源寄存器,结果放入目的寄存器.
        
        por MM,MM/m64
        64个位'或'操作,结果放入目的寄存器.
        
        pxor MM,MM/m64
        64个位'异或'操作,结果放入目的寄存器.
        
        pmaddwd MM,MM/m64
        按字对齐有符号(补码)向量点乘.
                                  高32位  |   低32位
        目的寄存器:            a0  |  a1  |  a2  |  a3
        源寄存器:              b0  |  b1  |  b2  |  b3
        目的寄存器结果:       a0*b0+a1*b1 | a2*b2+a3*b3
        例:
        当MM0 = 0006 8a11   1234 4321h,
          MM1 = 0154 c239   ae39 2b35h,当执行pmaddwd MM0,MM1
        则MM0 =  1c75a7c1    0583d669h 注意是有符号操作!
        
        pcmpeqb MM,MM/m64
        源寄存器与目的寄存器按字节比较,相等就置目的寄存器对应字节为0ffh,否则为00h
        例:
        当MM0 == 20 11h,MM1 == 21 11h,执行pcmpeqb MM0,MM1,则MM0 = ff ff ff ff ff ff 00 ff h
        注:MM0与MM1的高48为0,因为0 == 0,所以置目的寄存器对应字节为0ffh.
        
        pcmpeqw MM,MM/64
        源寄存器与目的寄存器按字比较,相等就置目的寄存器对应字为0ffffh,否则为0000h
        
        pcmpeqd MM,MM/m64
        源寄存器与目的寄存器按双字比较,相等就置目的寄存器对应双字为0ffffffffh,否则为00000000h
        
        pcmpgtb MM,MM/m64
        源寄存器与目的寄存器按字节(有符号补码)比较,
        当目的寄存器对应字节大于源寄存器就置目的寄存器对应字节为0ffh,否则为00h
        例:
        当MM0 == 80 12 11 h,MM1 == 7f 12 10h,执行pcmpgtb MM0,MM1,则MM0 = 00 00 ffh
        因为80h = -128,7fh = 127,-128<127,所以结果为00h
        
        pcmpgtw MM,MM/m64
        源寄存器与目的寄存器按字(有符号补码)比较,
        当目的寄存器对应字大于源寄存器就置目的寄存器对应字为0ffffh,否则为0000h
        
        pcmpgtd MM,MM/m64
        源寄存器与目的寄存器按双字(有符号补码)比较,
        当目的寄存器对应双字大于源寄存器就置目的寄存器对应双字为0ffffffffh,否则为00000000h
        
        packuswb MM,MM/m64
        把目的寄存器按字有符号数压缩为字节无符号数放入目的寄存器低32位
        把源寄存器按字有符号数压缩为字节无符号数放入目的寄存器高32位
        压缩时负数变为00h,大于255的正数变为0ffh.
                                  高32位  |   低32位
        目的寄存器:            a0  |  a1  |  a2  |  a3
        源寄存器:              b0  |  b1  |  b2  |  b3
        目的寄存器压缩结果:   b0|b1| b2|b3| a0|a1|a2|a3
        例:
        当MM0 == 7fff 8000 1234 00ae h,MM1 == 00ad 0123 80ff 0100 h,
        执行packuswb MM0,MM1,则MM0 = ad ff 00 ff   ff 00 ff ae h.
        
        packsswb MM,MM/m64
        把目的寄存器按字有符号数压缩为字节有符号数放入目的寄存器低32位
        把源寄存器按字有符号数压缩为字节有符号数放入目的寄存器高32位
        压缩时小于-128负数变为80h,大于127的正数变为7fh.
                                  高32位  |   低32位
        目的寄存器:            a0  |  a1  |  a2  |  a3
        源寄存器:              b0  |  b1  |  b2  |  b3
        目的寄存器压缩结果:   b0|b1| b2|b3| a0|a1|a2|a3
        例:
        当MM0 == 0fff ff06 0080 0012 h,MM1 == 0001 8000 ffff 7fff h,
        执行packsswb MM0,MM1,则MM0 = 01 80 ff 7f   7f 80 7f 12 h
        
        packssdw MM,MM/m64
        把目的寄存器按双字有符号数压缩为单字有符号数放入目的寄存器低32位
        把源寄存器按双字有符号数压缩为单字有符号数放入目的寄存器高32位
        压缩时小于-32768负数变为8000h,大于32767的正数变为7fffh.
                                  高32位  |   低32位
        目的寄存器:                a0     |     a1
        源寄存器:                  b0     |     b1
        目的寄存器压缩结果:    b0   | b1  | a0  |  a1
        
        punpcklbw MM,MM/m64
        把目的寄存器与源寄存器的低32位按字节交错排列放入目的寄存器
                                  高32位  |   低32位
        目的寄存器:            a0|a1|a2|a3|a4|a5|a6|a7
        源寄存器:              b0|b1|b2|b3|b4|b5|b6|b7
        目的寄存器结果:        b4|a4|b5|a5|b6|a6|b7|a7
        例:
        当MM0 == 01 02 03 04 05 06 07 08 h,MM1 == 09 0a 0b 0c 0d 0e 0f 00 h
        执行punpcklbw MM0,MM1,则MM0 = 0d 05 0e 06 0f 07 00 08 h
        
        punpcklwd MM,MM/m64
        把目的寄存器与源寄存器的低32位按字交错排列放入目的寄存器
                                 高32位  |   低32位
        目的寄存器:            a0  | a1  | a2  | a3
        源寄存器:              b0  | b1  | b2  | b3
        目的寄存器结果:        b2  | a2  | b3  | a3
        
        punpckldq MM,MM/m64
        把目的寄存器与源寄存器的低32位按双字交错排列放入目的寄存器
                                 高32位  |   低32位
        目的寄存器:                a0    |    a1
        源寄存器:                  b0    |    b1
        目的寄存器结果:            b1    |    a1
        
        punpckhbw MM,MM/m64
        把目的寄存器与源寄存器的高32位按字节交错排列放入目的寄存器
                                  高32位  |   低32位
        目的寄存器:            a0|a1|a2|a3|a4|a5|a6|a7
        源寄存器:              b0|b1|b2|b3|b4|b5|b6|b7
        目的寄存器结果:        b0|a0|b1|a1|b2|a2|b3|a3
        例:
        当MM0 == 01 02 03 04 05 06 07 08 h,MM1 == 09 0a 0b 0c 0d 0e 0f 00 h
        执行punpcklbw MM0,MM1,则MM0 = 09 01 0a 02 0b 03 0c 04 h
        
        punpckhwd MM,MM/m64
        把目的寄存器与源寄存器的高32位按字交错排列放入目的寄存器
                                 高32位  |   低32位
        目的寄存器:            a0  | a1  | a2  | a3
        源寄存器:              b0  | b1  | b2  | b3
        目的寄存器结果:        b0  | a0  | b1  | a1
        
        punpckhdq MM,MM/m64
        把目的寄存器与源寄存器的高32位按双字交错排列放入目的寄存器
                                 高32位  |   低32位
        目的寄存器:                a0    |    a1
        源寄存器:                  b0    |    b1
        目的寄存器结果:            b0    |    a0
        
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
              ★★★★★注:除 movups,movupd 指令外,其它涉及到128位内存变量操作的,
                           内存变量首地址必须要对齐16字节,也就是内存地址低4位为0,
                           否则会引起CPU异常,导致指令执行失败,此错误编译器不检查.
SSE1:
主要是单精度浮点运算
SSE有8个128位独立寄存器(XMM1~XMM7).
        MM指64位MMX寄存器
        XMM指XMM寄存器
        m128指128位内存变量
        
        movaps XMM,XMM/m128  movaps XMM/128,XMM
        把源存储器内容值送入目的寄存器,当有m128时,必须对齐内存16字节,也就是内存地址低4位为0.
                                                                     ﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋
        movups XMM,XMM/m128  movaps XMM/128,XMM
        把源存储器内容值送入目的寄存器,但不必对齐内存16字节.
                                       ﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋
        movlps XMM,m64
        把源存储器64位内容送入目的寄存器低64位,高64位不变,内存变量不必对齐内存16字节.
        
        movhps XMM,m64
        把源存储器64位内容送入目的寄存器高64位,低64位不变,内存变量不必对齐内存16字节.
        
        movhlps XMM,XMM
        把源寄存器高64位送入目的寄存器低64位,高64位不变.
        
        movlhps XMM,XMM
        把源寄存器低64位送入目的寄存器高64位,低64位不变.
        
        addps XMM,XMM/m128
        源存储器内容按双字对齐,共4个单精度浮点数与目的寄存器相加,结果送入目的寄存器,内存变量必须对齐内存16字节.
        例:
        当XMM0 = 0c517e000 44290000 46b6d000 3c4985f0 h
          XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,当执行addps XMM0,XMM1
        则XMM0 = 045992000 44350ccd 4a5b52e0 3c59018e h
        因为XMM0 = -2.43E3 6.76E2   2.34E4   1.23E-2        'xEy'指x * 10^y,如 1.0E2 = 100,1.0E-2 = 0.01,
            XMM1 = 7.33E3  4.82E1   3.57E6   9.45E-4             当中'E'不是16进制中的'e',而是指数'EXP'
        结果XMM0 = 4.9E3   7.242E2  3.5934E6 1.3245E-2
      ◆关于浮点数的转为字符串的程序我已有程序贴在此论坛上(www.aogosoft.com),你只须稍微改动一下,就可用来测试此类指令.
        
        addss XMM,XMM/m32
        源存储器的低32位1个单精度浮点数与目的寄存器的低32位1个单精度浮点数相加,结果送入目的寄存器的低32位
        高96位不变,内存变量不必对齐内存16字节.
        例:
        当XMM0 = 0c517e000 44290000 46b6d000 3c4985f0 h
          XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,当执行addss XMM0,XMM1
        则XMM0 = 0c517e000 44290000 46b6d000 3c59018e h
        
        subps XMM,XMM/m128
        源存储器内容按双字对齐,共4个单精度浮点数与目的寄存器相减(目的减去源),结果送入目的寄存器,
        内存变量必须对齐内存16字节.
        例:
        当XMM0 = 0c517e000 44290000 46b6d000 3c4985f0 h
          XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,当执行addss XMM0,XMM1
        则XMM0 = 0c6188000 441cf333 ca5877a0 3c3a0a52 h
        因为XMM0 = -2.43E3 6.76E2   2.34E4   1.23E-2
            XMM1 = 7.33E3  4.82E1   3.57E6   9.45E-4
        结果XMM0 = -9.76E3 6.278E2 -3.5466E6 1.1355E-2
          
        subss XMM,XMM/m32
        源存储器的低32位1个单精度浮点数与目的寄存器的低32位1个单精度浮点数相减(目的减去源),
        结果送入目的寄存器的低32位,高96位不变,内存变量不必对齐内存16字节.
        例:
        当XMM0 = 0c517e000 44290000 46b6d000 3c4985f0 h
          XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,当执行addss XMM0,XMM1
        则XMM0 = 0c517e000 44290000 46b6d000 3c3a0a52 h
        
        maxps XMM,XMM/m128
        源存储器4个单精度浮点数与目的寄存器4个单精度浮点数比较,较大数放入对应目的寄存器,内存变量必须对齐内存16字节.
        例:
        当XMM0 = 0c517e000 44290000 46b6d000 3c4985f0 h
          XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,当执行maxps XMM0,XMM1
        则XMM0 = 045e51000 44290000 4a59e540 3c4985f0 h
        因为XMM0 = -2.43E3 6.76E2   2.34E4   1.23E-2
            XMM1 = 7.33E3  4.82E1   3.57E6   9.45E-4
        结果XMM0 = 7.33E3  6.76E2   3.57E6   1.23E-2
        
        maxss XMM,XMM/m32
        源存储器低32位1个单精度浮点数与目的寄存器低32位1个单精度浮点数比较,较大数放入目的寄存器低32位,高96位不变
        内存变量不必对齐内存16字节.
        例:
        当XMM0 = 045e51000 4240cccd 4a59e540 3a77b9e0 h
          XMM1 = 0c517e000 44290000 46b6d000 3c4985f0 h,当执行maxss XMM0,XMM1
        则XMM0 = 045e51000 4240cccd 4a59e540 3c4985f0 h
        
        minps XMM,XMM/m128
        源存储器4个单精度浮点数与目的寄存器4个单精度浮点数比较,较小数放入对应目的寄存器,内存变量必须对齐内存16字节.
        
        minss XMM,XMM/m32
        源存储器低32位1个单精度浮点数与目的寄存器低32位1个单精度浮点数比较,较小数放入目的寄存器低32位,高96位不变
        内存变量不必对齐内存16字节.
        
        rcpps XMM,XMM/m128
        源存储器4个单精度浮点数的倒数放入对应目的寄存器,内存变量必须对齐内存16字节.
        注:比如2.0E0的倒数为1÷2.0E0 = 5.0E-1
        例:
        当XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,执行rcpps XMM0,XMM1
        则XMM0 = 0390f0800 3ca9f800 34966000 44844800 h
        因为XMM1 = 7.33E3  4.82E1   3.57E6   9.45E-4
        结果XMM0 = 1.36E-4 2.075E-2 2.8E-7   1.06E3
        
        rcpss XMM,XMM/32
        源存储器低32位1个单精度浮点数的倒数放入目的寄存器低32位,高96位不变
         例:
        当XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,执行rcpss XMM0,XMM1
        则XMM0 = 045e51000 4240cccd 4a59e540 44844800 h
        
        rsqrtps XMM,XMM/m128
        源存储器4个单精度浮点数的开方的倒数放入对应目的寄存器,内存变量必须对齐内存16字节.
                                    _____
        比如2.0E0的开方的倒数为1÷√2.0E0 ≈ 7.0711E-1
        例:
        当XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,执行rsqrtps XMM0,XMM1
        则XMM0 = 03c3f6000 3e138000 3a0ab800 42022000 h
        因为XMM1 = 7.33E3  4.82E1   3.57E6   9.45E-4
        结果XMM0 = 1.17E-2 1.44E-1  5.29E-4  3.25E1
        
        rsqrtss XMM,XMM/32
        源存储器低32位1个单精度浮点数的开方的倒数放入目的寄存器低32位,高96位不变,内存变量不必对齐内存16字节.
        
        mulps XMM,XMM/m128
        源存储器内容按双字对齐,共4个单精度浮点数与目的寄存器相乘,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        mulss XMM,XMM/32
        源存储器的低32位1个单精度浮点数与目的寄存器的低32位1个单精度浮点数相乘,结果送入目的寄存器的低32位,
        高96位不变,内存变量不必对齐内存16字节.
        
        divps XMM,XMM/m128
        目的寄存器共4个单精度浮点数除以源存储器4个单精度浮点数,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        divss XMM,XMM/32
        目的寄存器低32位1个单精度浮点数除以源存储器低32位1个单精度浮点数,结果送入目的寄存器的低32位,
        高96位不变,内存变量不必对齐内存16字节.
        
        andps XMM,XMM/m128
        源存储器128个二进制位'与'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        orps XMM,XMM/m128
        源存储器128个二进制位'或'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        xorps XMM,XMM/m128
        源存储器128个二进制位'异或'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        unpckhps XMM,XMM/m128
        源存储器与目的寄存器高64位按双字交错排列,结果送入目的寄存器,内存变量必须对齐内存16字节.
                                 高64位   |    低64位
        目的寄存器:            a0  |  a1  |  a2  |  a3
        源存储器:              b0  |  b1  |  b2  |  b3
        目的寄存器结果:        b0  |  a0  |  b1  |  a1
        例:
        当XMM0 = 0c517e000 44290000 46b6d000 3c4985f0 h
          XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,当执行unpckhps XMM0,XMM1
        则XMM0 = 045e51000 c517e000 4240cccd 44290000 h
        
        unpcklps XMM,XMM/m128
        源存储器与目的寄存器低64位按双字交错排列,结果送入目的寄存器,内存变量必须对齐内存16字节.
                                 高64位   |    低64位
        目的寄存器:            a0  |  a1  |  a2  |  a3
        源存储器:              b0  |  b1  |  b2  |  b3
        目的寄存器结果:        b2  |  a2  |  b3  |  a3
        例:
        当XMM0 = 0c517e000 44290000 46b6d000 3c4985f0 h
          XMM1 = 045e51000 4240cccd 4a59e540 3a77b9e0 h,执行unpcklps XMM0,XMM1
        则XMM0 = 04a59e540 46b6d000 3a77b9e0 3c4985f0 h
        
        cvtpi2ps XMM,MM/m64
        源存储器64位两个32位有符号(补码)整数转为两个单精度浮点数,放入目的寄存器低64中,高64位不变.
      ★注:源寄存器是'MM',不是'XMM',但编译时写成'XMM'不会报错,反汇编后发现实际为'MM',所以务必小心!
                      ﹌       ﹌
        例:
        当XMM0 = 2315d4d7 930d9761 82748383 ed2782cb h
                             MM0 = 0001e240 fffe1dc0 h,执行cvtpi2ps XMM0,MM0
        则XMM0 = 2315d4d7 930d9761 c7f12000 47f12000 h
        因为0001e240h(有符号整数) =  123456 =  1.23456E5 =  47f12000h(单精浮点)
            fffe1dc0h(有符号整数) = -123456 = -1.23456E5 = 0c7f12000h(单精浮点)
        
        cvtsi2ss XMM,r32/m32
        源存储器1个32位有符号(补码)整数转为1个单精度浮点数,放入目的寄存器低32中,高96位不变.
        
        cvtps2pi MM,XMM/m64
        把源存储器低64位两个32位单精度浮点数转为两个32位有符号(补码)整数,放入目的寄存器.
        当XMM0 = 2315d4d7 930d9761 c7f12000 47f12000 h,执行cvtps2pi XMM0,MM0
                             MM0 = 0001e240 fffe1dc0 h
      ★注:目的寄存器是'MM',不是'XMM',但编译时写成'XMM'不会报错,反汇编后发现实际为'MM',所以务必小心!
        
        cvtss2si r32,XMM/m32
        把源存储器低32位1个单精度浮点数转为1个32位有符号(补码)整数,放入目的寄存器.
        
        pavgb MM,MM/m64     pavgb XMM,XMM/m128
        把源存储器与目的寄存器按字节无符号整数相加,再除以2,结果四舍五入为整数放入目的寄存器,
        源存储器为m128时,内存变量必须对齐内存16字节.
        注:此运算不会产生溢出.
        例:
        当MM0 = 9a bc de f0 12 34 56 78 h
          MM1 = 8d ec 5b f8 98 25 71 47 h,执行pavgb MM0,MM1
        则MM0 = 94 d4 9d f4 55 2d 64 60 h
          9ah = 154,8dh = 141,154+141 = 295,295÷2 = 147.5 ≈ 148(四舍五入) = 94h
        
        pavgw MM,MM/m64     pavgw XMM,XMM/m128
        把源存储器与目的寄存器按字无符号整数相加,再除以2,结果四舍五入为整数放入目的寄存器,
        源存储器为m128时,内存变量必须对齐内存16字节.
        
        pextrw r32,MM,imm8   pextrw r32,XMM,imm8   imm8为8位立即数(无符号)
        从源寄存器中选第imm8(0~3 或 0~7)个字送入目的寄存器的低16位,高16位清零.
      ★注:imm8范围为 0~255,当源寄存器为'MM'时,有效值= imm8 mod 4,当目的寄存器为'XMM'时,有效值= imm8 mod 8
        
        pinsrw MM,r32/m32,imm8     pinsrw XMM,r32/m32,imm8
        把源存储器的低16位内容送入目的寄存器第imm8(0~3 或 0~7)个字,其余字不变.
        注:imm8范围为 0~255,当目的寄存器为'MM'时,有效值= imm8 mod 4,当目的寄存器为'XMM'时,有效值= imm8 mod 8
        例:
                     7    6    5    4    3    2    1    0
        当XMM0 = 0ffff ffff ffff ffff ffff ffff ffff ffff h
           eax = 01234 5678 h,执行pinsrw XMM0,eax,3
                       ﹌﹌
        则XMM0 = 0ffff ffff ffff ffff 5678 ffff ffff ffff h
                                      ﹌﹌
          执行pinsrw XMM0,eax,9
        则XMM0 = 0ffff ffff ffff ffff ffff ffff 5678 ffff h
                                                ﹌﹌
        
        pmaxsw MM,MM/m64     pmaxsw XMM,XMM/m128
        把源存储器与目的寄存器按字有符号(补码)整数比较,大数放入目的寄存器对应字,
        源存储器为m128时,内存变量必须对齐内存16字节.
        
        pmaxub MM,MM/m64     pmaxsw XMM,XMM/m128
        把源存储器与目的寄存器按字节无符号整数比较,大数放入目的寄存器对应字节,
        源存储器为m128时,内存变量必须对齐内存16字节.
        
        pminsw MM,MM/m64     pmaxsw XMM,XMM/m128
        把源存储器与目的寄存器按字有符号(补码)整数比较,较小数放入目的寄存器对应字,
        源存储器为m128时,内存变量必须对齐内存16字节.
        
        pminub MM,MM/m64     pmaxsw XMM,XMM/m128
        把源存储器与目的寄存器按字节无符号整数比较,较小数放入目的寄存器对应字节,
        源存储器为m128时,内存变量必须对齐内存16字节.
        
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

SSE2:
主要是双精度浮点运算
SSE2与SSE1使用相同寄存器
        
        movapd XMM,XMM/m128      movapd XMM/m128,XMM
        把源存储器内容值送入目的寄存器,当有m128时,必须对齐内存16字节.
        
        movupd XMM,XMM/m128      movapd XMM/m128,XMM
        把源存储器内容值送入目的寄存器,但不必对齐内存16字节.
        我感觉这两条指令同movaps 和 movups 指令一样,不过又不确定.
        
        movlpd XMM,m64     movlpd m64,XMM
        把源存储器64位内容送入目的寄存器低64位,高64位不变,内存变量不必对齐内存16字节.
        
        movhpd XMM,m64     movhpd m64,XMM
        把源存储器64位内容送入目的寄存器高64位,低64位不变,内存变量不必对齐内存16字节.
        
        addpd XMM,XMM/m128
        源存储器内容按四字对齐,共两个双精度浮点数与目的寄存器相加,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        addsd XMM,XMM/m64
        源存储器的低64位1个双精度浮点数与目的寄存器的低64位1个双精度浮点数相加,结果送入目的寄存器的低64位
        高64位不变,内存变量不必对齐内存16字节.
        
        subpd XMM,XMM/m128
        把目的寄存器内容按四字对齐,两个双精度浮点数,减去源存储器两个双精度浮点数,
        结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        subsd XMM,XMM/m128
        把目的寄存器的低64位1个双精度浮点数,减去源存储器低64位1个双精度浮点数,结果送入目的寄存器的低64位
        高64位不变,内存变量不必对齐内存16字节.
        
        mulpd XMM,XMM/m128
        源存储器内容按四字对齐,共两个双精度浮点数与目的寄存器相乘,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        mulsd XMM,XMM/m128
        源存储器的低64位1个双精度浮点数与目的寄存器的低64位1个双精度浮点数相乘,结果送入目的寄存器的低64位,
        高64位不变,内存变量不必对齐内存16字节.
        
        divpd XMM,XMM/m128
        目的寄存器共两个双精度浮点数除以源存储器两个双精度浮点数,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        divsd XMM,XMM/m128
        目的寄存器低64位1个双精度浮点数除以源存储器低64位1个双精度浮点数,结果送入目的寄存器的低64位,
        高64位不变,内存变量不必对齐内存16字节.
        
        sqrtpd XMM,XMM/m128
        源存储器两个双精度浮点数的开方放入对应目的寄存器,内存变量必须对齐内存16字节.
        
        sqrtsd XMM,XMM/m128
        源存储器低64位1个双精度浮点数的开方放入目的寄存器低64位,高64位不变,内存变量不必对齐内存16字节.
        
        maxpd XMM,XMM/m128
        源存储器两个双精度浮点数与目的寄存器两个双精度浮点数比较,较大数放入对应目的寄存器,内存变量必须对齐内存16字节.
        
        maxsd XMM,XMM/m128
        源存储器低64位1个双精度浮点数与目的寄存器低64位1个双精度浮点数比较,较大数放入目的寄存器低64位,高64位不变
        内存变量不必对齐内存16字节.
        
        minpd XMM,XMM/m128
        源存储器两个双精度浮点数与目的寄存器两个双精度浮点数比较,较小数放入对应目的寄存器,内存变量必须对齐内存16字节.
        
        minsd XMM,XMM/m128
        源存储器低64位1个双精度浮点数与目的寄存器低64位1个双精度浮点数比较,较小数放入目的寄存器低64位,高64位不变
        内存变量不必对齐内存16字节.
        
        andpd XMM,XMM/m128
        源存储器128个二进制位'与'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        andnpd XMM,XMM/m128
        目的寄存器128个二进制位先取'非',再'与'源存储器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        orpd XMM,XMM/m128
        源存储器128个二进制位'或'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        xorpd XMM,XMM/m128
        源存储器128个二进制位'异或'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        ───────────────────────────
        
        cvtps2pd XMM,XMM/m64
        把源存储器低64位两个单精度浮点数变成两个双精度浮点数,结果送入目的寄存器.
        
        cvtss2sd XMM,XMM/m32
        把源存储器低32位1个单精度浮点数变成1个双精度浮点数,结果送入目的寄存器的低64位,高64位不变.
        
        cvtpd2ps XMM,XMM/m128
        把源存储器两个双精度浮点数变成两个单精度浮点数,结果送入目的寄存器的低64位,高64位清零,
        内存变量必须对齐内存16字节.
        例:
        当XMM0 = 011112222 33334444 55556666 77778888 h,
          XMM1 = 0dd1a5e1f35aec736   41132a4000000000 h,执行cvtpd2ps XMM0,XMM1
        则XMM0 = 000000000 00000000 ff800000 48995200 h
                                   ^特殊状态 ^3.14E5
        
        因为XMM1 = -3.14E140         3.14E5
        而单精浮点最小可表示1.18E-38(规格化),-3.14E140已远超过,所以变成一种特殊状态,
        指数位全为1,尾数全为0,符号位不变,3.14E5则变为正常的单精度3.14E5
        
        
        cvtsd2ss XMM,XMM/m64
        把源存储器低64位1个双精度浮点数变成1个单精度浮点数,结果送入目的寄存器的低32位,高96位不变.
        
        cvtpd2pi MM,XMM/m128
        把源存储器两个双精度浮点数变成两个双字有符号整数,结果送入目的寄存器,内存变量必须对齐内存16字节.
        如果结果大于所能表示的范围,那么转化为80000000h(正数也转为此值).
        当XMM1 = 0dd1a5e1f35aec736   41132a4000000000 h,执行cvtpd2pi MM0,XMM1
        则 MM0 = 80000000 0004ca90 h
        因为0dd1a5e1f35aec736h(双精度浮点数) = -3.14E140 超过 80000000h所以变为80000000h
        而41132a4000000000h(双精度浮点数) = 3.14E5,所以转为314000 = 0004ca90h(有符号整数)
        
        cvtpi2pd XMM,MM/m64
        把源存储器两个双字有符号整数变成两个双精度浮点数,结果送入目的寄存器.
        
        cvtpd2dq XMM,XMM/m128
        把源存储器两个双精度浮点数变成两个双字有符号整数(此运算与cvtpd2pi类似但目的寄存器变为XMM),
        结果送入目的寄存器的低64位,高64位清零,内存变量必须对齐内存16字节.
        
        cvtdq2pd XMM,XMM/m128
        把源存储器低64位两个双字有符号整数变成两个双精度浮点数,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        cvtsd2si r32,XMM/m64
        把源存储器低64位1个双精度浮点数变成1个双字有符号整数,结果送入目的寄存器.
        
        cvtsi2sd XMM,r32/m32
        把源存储器1个双字有符号整数变成1个双精度浮点数,结果送入目的寄存器的低64位,高64位不变.
        
        cvtps2dq XMM,XMM/m128
        把源存储器4个单精度浮点数变成4个双字有符号整数,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        cvtdq2ps XMM,XMM/m128
        把源存储器4个双字有符号整数变成4个单精度浮点数,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        ───────────────────────────
        
        movdqa XMM,XMM/m128     movdqa XMM/m128,XMM
        把源存储器内容值送入目的寄存器,当有m128时,必须对齐内存16字节.
        
        movdqu XMM,XMM/m128     movdqu XMM/m128,XMM
        把源存储器内容值送入目的寄存器,但不必对齐内存16字节.
        
        paddd XMM,XMM/m128
        把源存储器与目的寄存器按双字对齐无符号整数普通相加,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        paddq XMM,XMM/m128
        把源存储器与目的寄存器按四字对齐无符号整数普通相加,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        paddq MM,MM/m64
        把源存储器与目的寄存器四字无符号整数普通相加,结果送入目的寄存器.
        
        psubd XMM,XMM/m128
        把目的寄存器与源存储器按双字对齐无符号整数普通相减,结果送入目的寄存器,
        内存变量必须对齐内存16字节.(目的减去源)
        
        psubq XMM,XMM/m128
        把目的寄存器与源存储器按四字对齐无符号整数普通相减,结果送入目的寄存器,
        内存变量必须对齐内存16字节.(目的减去源)
        
        psubq MM,MM/m64
        把目的寄存器与源存储器四字无符号整数普通相减,结果送入目的寄存器.(目的减去源)
        
        pmuludq XMM,XMM/m128
        把源存储器与目的寄存器的低32位无符号整数相乘,结果变为64位,送入目的寄存器低64位,
        把源存储器与目的寄存器的高64位的低32位无符号整数相乘,结果变为64位,送入目的寄存器高64位.
        内存变量必须对齐内存16字节.
                                 高64位   |    低64位
        目的寄存器:            a0  |  a1  |  a2  |  a3
        源存储器:              b0  |  b1  |  b2  |  b3
        目的寄存器结果:          b1*a1    |    b3*a3
        
        pmuludq MM,MM/m64
        把源存储器与目的寄存器的低32位无符号整数相乘,结果变为64位,送入目的寄存器.
                                 高32位   |    低32位
        目的寄存器:                a0     |      a1
        源存储器:                  b0     |      b1
        目的寄存器结果:                 b1*a1
        
        pslldq XMM,imm8
        把目的寄存器128位按imm8(立即数)指定字节数逻辑左移,移出的字节丢失.
        imm8 == 1时,代表左移8位,imm8 == 2时,代表左移16位.
        
        psrldq XMM,imm8
        把目的寄存器128位按imm8(立即数)指定字节数逻辑右移,移出的字节丢失.
        imm8 == 1时,代表右移8位,imm8 == 2时,代表右移16位.
        
        psllw XMM,XMM/m128   psllw XMM,imm8
        把目的寄存器按字由源存储器(或imm8 立即数)指定位数逻辑左移,移出的位丢失.
        低字移出的位不会移入高字,内存变量必须对齐内存16字节.
        
        psrlw XMM,XMM/m128   psrlw XMM,imm8
        把目的寄存器按字由源存储器(或imm8 立即数)指定位数逻辑右移,移出的位丢失.
        高字移出的位不会移入低字,内存变量必须对齐内存16字节.
        
        pslld XMM,XMM/m128   pslld XMM,XMM imm8
        把目的寄存器按双字由源存储器(或imm8 立即数)指定位数逻辑左移,移出的位丢失.
        低双字移出的位不会移入高双字,内存变量必须对齐内存16字节.
        
        psrld XMM,XMM/m128   psrld XMM,imm8
        把目的寄存器按双字由源存储器(或imm8 立即数)指定位数逻辑右移,移出的位丢失.
        高双字移出的位不会移入低双字,内存变量必须对齐内存16字节.
        
        movq2dq XMM,MM
        把源寄存器内容送入目的寄存器的低64位,高64位清零.
        
        movdq2q MM,XMM
        把源寄存器低64位内容送入目的寄存器.
        
        pmaddwd XMM,XMM/m128
        把源存储器与目的寄存器分4组进行向量点乘(有符号补码操作),内存变量必须对齐内存16字节..
                                        高64位          |           低64位
        目的寄存器:            a0  |  a1  |  a2  |  a3  |  a4  |  a5  |  a6  |  a7
        源存储器:              b0  |  b1  |  b2  |  b3  |  b4  |  b5  |  b6  |  b7
        目的寄存器结果:       a0*b0+a1*b1 | a2*b2+a3*b3 | a4*b4+a5*b5 | a6*b6+a7*b7
        
        paddsb XMM,XMM/m128
        源存储器与目的寄存器按字节对齐有符号补码饱和相加,内存变量必须对齐内存16字节.
        
        paddsw XMM,XMM/m128
        源存储器与目的寄存器按字对齐有符号补码饱和相加,内存变量必须对齐内存16字节.
        
        psubsb XMM,XMM/m128
        源存储器与目的寄存器按字节对齐有符号补码饱和相减(目的减去源),内存变量必须对齐内存16字节.
        
        psubsw XMM,XMM/m128
        源存储器与目的寄存器按字对齐有符号补码饱和相减(目的减去源),内存变量必须对齐内存16字节.
        
        paddusb XMM,XMM/m128
        源存储器与目的寄存器按字节对齐无符号饱和相加,内存变量必须对齐内存16字节.
        
        paddusw XMM,XMM/m128
        源存储器与目的寄存器按字对齐无符号饱和相加,内存变量必须对齐内存16字节.
        
        psubusb XMM,XMM/m128
        源存储器与目的寄存器按字节对齐无符号饱和相减(目的减去源),内存变量必须对齐内存16字节.
        
        psubusw XMM,XMM/m128
        源存储器与目的寄存器按字对齐无符号饱和相减(目的减去源),内存变量必须对齐内存16字节.
        
        paddb XMM,XMM/m128
        源存储器与目的寄存器按字节对齐无符号普通相加,内存变量必须对齐内存16字节.
        
        paddw XMM,XMM/m128
        源存储器与目的寄存器按字对齐无符号普通相加,内存变量必须对齐内存16字节.
        
        paddd XMM,XMM/m128
        源存储器与目的寄存器按双字对齐无符号普通相加,内存变量必须对齐内存16字节.
        
        paddq XMM,XMM/m128
        源存储器与目的寄存器按四字对齐无符号普通相加,内存变量必须对齐内存16字节.
        
        psubb XMM,XMM/m128
        源存储器与目的寄存器按字节对齐无符号普通相减(目的减去源),内存变量必须对齐内存16字节.
        
        psubw XMM,XMM/m128
        源存储器与目的寄存器按字对齐无符号普通相减(目的减去源),内存变量必须对齐内存16字节.
        
        psubd XMM,XMM/m128
        源存储器与目的寄存器按双字对齐无符号普通相减(目的减去源),内存变量必须对齐内存16字节.
        
        psubq XMM,XMM/m128
        源存储器与目的寄存器按四字对齐无符号普通相减(目的减去源),内存变量必须对齐内存16字节.
        
        pmulhw XMM,XMM/m128
        源存储器与目的寄存器按字对齐有符号补码饱和相乘,取结果的高16位放入目的寄存器对应字中.
        内存变量必须对齐内存16字节.
        
        pmullw XMM,XMM/m128
        源存储器与目的寄存器按字对齐有符号补码饱和相乘,取结果的低16位放入目的寄存器对应字中.
        内存变量必须对齐内存16字节.
        
        pcmpeqb XMM,XMM/m128
        目的寄存器与源存储器按字节比较,如果对应字节相等,就置目的寄存器对应字节为0ffh,否则为00h,
        内存变量必须对齐内存16字节.
        
        pcmpeqw XMM,XMM/m128
        目的寄存器与源存储器按字比较,如果对应字相等,就置目的寄存器对应字为0ffffh,否则为0000h,
        内存变量必须对齐内存16字节.
        
        pcmpeqd XMM,XMM/m128
        目的寄存器与源存储器按双字比较,如果对应双字相等,就置目的寄存器对应双字为0ffffffffh,否则为00000000h,
        内存变量必须对齐内存16字节.
        
        pcmpgtb XMM,XMM/m128
        目的寄存器与源存储器按字节(有符号补码)比较,如果目的寄存器对应字节大于源存储器,就置目的寄存器对应字节为0ffh,
        否则为00h,内存变量必须对齐内存16字节.
        
        pcmpgtw XMM,XMM/m128
        目的寄存器与源存储器按字(有符号补码)比较,如果目的寄存器对应字大于源存储器,就置目的寄存器对应字为0ffffh,
        否则为0000h,内存变量必须对齐内存16字节.
        
        pcmpgtd XMM,XMM/m128
        目的寄存器与源存储器按双字(有符号补码)比较,如果目的寄存器对应双字大于源存储器,
        就置目的寄存器对应双字为0ffffffffh,否则为00000000h,内存变量必须对齐内存16字节.
        
        movd XMM,r32/m32
        把源存储器32位内容送入目的寄存器的低32位,高96位清零.
        
        movd r32/m32,XMM
        把源寄存器的低32位内容送入目的存储器32位.
        
        movq XMM,XMM/m64
        把源存储器低64位内容送入目的寄存器的低64位,高64位清零.
        
        movq m64,XMM
        把源寄存器的低64位内容送入目的存储器.
        
        pand XMM,XMM/m128
        源存储器128个二进制位'与'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
      ◎我发现与andpd功能差不多,就不知其它特性是否一样.
        
        pandn XMM,XMM/m128
        目的寄存器128个二进制位先取'非',再'与'源存储器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        por XMM,XMM/m128
        源存储器128个二进制位'或'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        pxor XMM,XMM/m128
        源存储器128个二进制位'异或'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
        
        packuswb XMM,XMM/m128   (此指令与前面的MMX指令packuswb MM,MM/m64操作相同,只是变成了128位)
        把目的寄存器按字有符号数压缩为字节无符号数放入目的寄存器低64位
        把源寄存器按字有符号数压缩为字节无符号数放入目的寄存器高64位
        压缩时负数变为00h,大于255的正数变为0ffh,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:            a0  |   a1  |  a2  |  a3  |  a4  |  a5  |  a6  |  a7
        源寄存器:              b0  |   b1  |  b2  |  b3  |  b4  |  b5  |  b6  |  b7
        目的寄存器压缩结果:   b0|b1| b2| b3| b4|b5| b6|b7| a0|a1| a2|a3| a4|a5| a6| a7
        
        packsswb XMM,XMM/m128   (此指令与前面的MMX指令packsswb MM,MM/m64操作相同,只是变成了128位)
        把目的寄存器按字有符号数压缩为字节有符号数放入目的寄存器低64位
        把源寄存器按字有符号数压缩为字节有符号数放入目的寄存器高64位
        压缩时小于-128负数变为80h,大于127的正数变为7fh,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:            a0  |   a1  |  a2  |  a3  |  a4  |  a5  |  a6  |  a7
        源寄存器:              b0  |   b1  |  b2  |  b3  |  b4  |  b5  |  b6  |  b7
        目的寄存器压缩结果:   b0|b1| b2| b3| b4|b5| b6|b7| a0|a1| a2|a3| a4|a5| a6| a7
        
        packssdw XMM,XMM/m128
        把目的寄存器按双字有符号数压缩为字有符号数放入目的寄存器低64位
        把源寄存器按双字有符号数压缩为字有符号数放入目的寄存器高64位
        压缩时小于-32768负数变为8000h,大于32767的正数变为7fffh,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:                a0      |      a1     |      a2     |      a3
        源寄存器:                  b0      |      b1     |      b2     |      b3
        目的寄存器压缩结果:    b0  |   b1  |  b2  |  b3  |  a0  |  a1  |  a2  |  a3
        
        punpckldq XMM,XMM/m128
        把源存储器与目的寄存器低64位按双字交错排列,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:                a0      |      a1     |      a2     |      a3
        源寄存器:                  b0      |      b1     |      b2     |      b3
        目的寄存器排列结果:        b2      |      a2     |      b3     |      a3
        
        punpckhdq XMM,XMM/m128
        把源存储器与目的寄存器高64位按双字交错排列,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:                a0      |      a1     |      a2     |      a3
        源寄存器:                  b0      |      b1     |      b2     |      b3
        目的寄存器排列结果:        b0      |      a0     |      b1     |      a1
        
        punpcklwd XMM,XMM/m128
        把源存储器与目的寄存器低64位按字交错排列,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:            a0  |   a1  |  a2  |  a3  |  a4  |  a5  |  a6  |  a7
        源寄存器:              b0  |   b1  |  b2  |  b3  |  b4  |  b5  |  b6  |  b7
        目的寄存器排列结果:    b4  |   a4  |  b5  |  a5  |  b6  |  a6  |  b7  |  a7
        
        punpckhwd XMM,XMM/m128
        把源存储器与目的寄存器高64位按字交错排列,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:            a0  |   a1  |  a2  |  a3  |  a4  |  a5  |  a6  |  a7
        源寄存器:              b0  |   b1  |  b2  |  b3  |  b4  |  b5  |  b6  |  b7
        目的寄存器排列结果:    b0  |   a0  |  b1  |  a1  |  b2  |  a2  |  b3  |  a3
        
        punpcklbw XMM,XMM/m128
        把源存储器与目的寄存器低64位按字节交错排列,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:           a0|a1| a2| a3| a4|a5| a6|a7| a8|a9| aA|aB| aC|aD| aE| aF
        源寄存器:             b0|b1| b2| b3| b4|b5| b6|b7| b8|b9| bA|bB| bC|bD| bE| bF
        目的寄存器排列结果:   b8|a8| b9| a9| bA|aA| bB|aB| bC|aC| bD|aD| bE|aE| bF| aF
        
        punpckhbw XMM,XMM/m128
        把源存储器与目的寄存器高64位按字节交错排列,内存变量必须对齐内存16字节.
                                         高64位          |           低64位
        目的寄存器:           a0|a1| a2| a3| a4|a5| a6|a7| a8|a9| aA|aB| aC|aD| aE| aF
        源寄存器:             b0|b1| b2| b3| b4|b5| b6|b7| b8|b9| bA|bB| bC|bD| bE| bF
        目的寄存器排列结果:   b0|a0| b1| a1| b2|a2| b3|a3| b4|a4| b5|a5| b6|a6| b7| a7
        
        ───────────────────────────
        shufps XMM,XMM/m128,imm8(0~255)    SSE1指令
        把源存储器与目的寄存器按双字划分,由imm8(立即数)八个二进制位(00~11,00^11,00~11,00~11)指定排列,
        内存变量必须对齐内存16字节.目的寄存器高64位放源存储器被指定数,目的寄存器低64位放目的寄存器被指定数.
        '( )'中的都是二进制数.
                                            高64位             |              低64位
        目的寄存器:                a(11)      |      a(10)     |      a(01)     |      a(00)
        源寄存器:                  b(11)      |      b(10)     |      b(01)     |      b(00)
        目的寄存器排列结果:      b(00~11)     |    b(00~11)    |    a(00~11)    |    a(00~11)
        目的寄存器压缩结果'( )'中的值由imm8对应的两位二进制位指定.
        例:
                 (  11  ) (  10  ) (  01  ) (  00  )           (  11  ) (  10  ) (  01  ) (  00  )
        当XMM0 = 090a0b0c 0d0e0f11 01020304 05060708 h,XMM1 = 0aabbccdd eeff1234 22334455 66778899 h,
                                    imm8       ══>        (XMM1 10) (XMM1 01) (XMM0 11) (XMM0 00)
        执行shufps XMM0,XMM1,10 01 11 00 b(二进制),则XMM0 = 0eeff1234  22334455   090a0b0c 05060708 h
        由例子中我们发现imm8=10011100b,imm8的高4位选的是源存储器,低4位选的是目的寄存器,imm8的最高两位
        为 10b 那么就选则XMM1中的第 2(从0开始选择) 个双字,发现为0eeff1234h,就放入XMM0的高32位(原来的
        值已经自动保护起来了),01b就选择XMM1中的第2个,11选择XMM0中的第3个,00选择XMM0中的第0个.
        当然imm8中4个选则也可以相同,比如shufps XMM0,XMM1,10 10 10 10 b,那么结果为:
        XMM0 = 0eeff1234 eeff1234 0d0e0f11 0d0e0f11 h.
        
        
        shufpd XMM,XMM/m128,imm8(0~255)      imm8(操作值) = imm8(输入值) mod 4
        把源存储器与目的寄存器按四字划分,由imm8(立即数)4个二进制位(0~1,0^1,0~1,0~1)指定排列,
        内存变量必须对齐内存16字节.目的寄存器高64位放源存储器被指定数,目的寄存器低64位放目的寄存器被指定数.
                                            高64位             |              低64位
        目的寄存器:                          a(1)              |               a(0)
        源寄存器:                            b(1)              |               b(0)
        目的寄存器排列结果:                 b(0~1)             |              a(0~1)
        例:
        当XMM0 = 1111111122222222 3333333344444444 h
          XMM1 = 5555555566666666 aaaaaaaacccccccc h,执行shufpd XMM0,XMM1,101001 1 0 b
        则XMM0 = 5555555566666666 3333333344444444 h
        因为101001 1 0 b mod 4(101001 1 0 b & 11b),得到操作值为1 0b,
        1选择XMM1的第1位5555555566666666h,0选择XMM0的第0位3333333344444444.
        
        pshuflw XMM,XMM/m128,imm8(0~255)
        先把源存储器的高64位内容送入目的寄存器的高64位,然后用imm8将源存储器的低64位4个字选入
        目的寄存器的低64位,内存变量必须对齐内存16字节.
                                                            低64位
        源寄存器低64位:           b(11)      |      b(10)     |      b(01)     |      b(00)
        目的寄存器低64位排列结果: b(00~11)   |    b(00~11)    |    b(00~11)    |    b(00~11)
        例:
        当XMM0 = 1111111122222222 3333 4444 5555 6666 h
          XMM1 = 5555555566666666 7777 8888 9999 cccc h,执行pshuflw XMM0,XMM1,10 10 01 10 b
        则XMM0 = 5555555566666666 8888 8888 9999 8888 h
        
        pshufhw XMM,XMM/m128,imm8(0~255)
        先把源存储器的低64位内容送入目的寄存器的低64位,然后用imm8将源存储器的高64位4个字选入
        目的寄存器的高64位,内存变量必须对齐内存16字节.
                                                            高64位
        源寄存器高64位:           b(11)      |      b(10)     |      b(01)     |      b(00)
        目的寄存器高64位排列结果: b(00~11)   |    b(00~11)    |    b(00~11)    |    b(00~11)
        例:
        当XMM0 = 3333 4444 5555 6666 1111111122222222 h
          XMM1 = 7777 8888 9999 cccc 5555555566666666 h,执行pshufhw XMM0,XMM1,10 10 01 10 b
        则XMM0 = 8888 8888 9999 8888 5555555566666666 h
        
        pshufd XMM,XMM/m128,imm8(0~255)
        将源存储器的4个双字由imm8指定选入目的寄存器,内存变量必须对齐内存16字节.
                                           高64位             |              低64位
        源寄存器:                 b(11)      |      b(10)     |      b(01)     |      b(00)
        目的寄存器排列结果:       b(00~11)   |    b(00~11)    |    b(00~11)    |    b(00~11)
        例:
        当XMM1 = 11111111 22222222 33333333 44444444 h,执行pshufd XMM0,XMM1,11 01 01 10b
        则XMM0 = 11111111 33333333 33333333 22222222 h
        
        
        
▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁


    啊!不容易,终于写好了,那手敲了累呀,不过能为许多初学者带来一点方便我还是很开心的,因为网上真的很难找到如此详细
的中文说明了,我刚学时也到网上去搜索,就是找不到满意的,而很多高手不知是因为忙,还是嫌这个太初级了,不高兴写,哎…,难
怪我国的IT事业如此落后,如果多几个像 罗云彬 这样的人,我国的软件事业肯定会更上几个台阶,可惜太少了,悲哉.
    本人就是通过学习 罗云彬 的《windows环境下32位汇编语言程序设计》开始win32编程的,算算学了有半年了,从中学了不少
知识,看他的书学习效率实在太高了,认识此书也是我在网上搜索win32汇编教程的时发现的,当时下载的是完整的chm文挡,阅读了
几天,发现写了实在太好了,十分适合我这个已学了半年D0S汇编的菜鸟,所以我就去网上书店买了一本第二版的,从此遍开始了我
的汇编之旅,学习的中间充满了辛酸,同学的冷笑,老师的劝解,说什么年代了还在钻研汇编语言,只要了解就可以了,现在应该去学
习C++,JAVA,Delphi等等,但是我没有改变我的立场,我坚信学好汇编以后会对我将来学习高级语言带来莫大的帮助,可以打下坚实
的基础,因为汇编语言是一门非常基础的语言,掌握她可以更好的对高级语言中的一些包装好的一些东西有本质上的认识,这对于
一名优秀的程式设计师来说是十分必要的,当然光学习汇编语言是不行的,还得去深入学习数据结构与算法,这些才是最最重要的,
比熟练API还重要.

你可能感兴趣的:(SIMD(单道指令多道数据流)指令(MMX/SSE1/SSE2)详解(中文).)