⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 simd.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 5 页
字号:
SIMD(单道指令多道数据流)指令(MMX\SSE1\SSE2)详解(中文).还有更多的多媒体指令集,SSE3,SSE4 By ham(于2007-8-30 20:25:01发表) 

--------------------------------------------------------------------------------
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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -