📄 simd.txt
字号:
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 + -