sse2 指令解析


  pxor      zero, zero
  neg       strideD

自己跟自己异或,相当于清零,NEG取反操作;

lea       pSrcRow,    [pSrc]

这个就是讲pSrc的地址给pSrcRow,此时pSrcRow和pSrc具有不同的名字但是指向同一个内存;

mov       pSrcRow,    pSrc

这个相当于把pSrc的内容复制一次给pSrcRow,pSrcRow值的变动不会影响pSrc

imul      strideD,    4

这个是无符号乘法,strideD = strideD*4;

这个等同于逻辑左移或算数左移

shl strideD, 2
sal strideD, 2

逻辑右移高位用0补,而算数右移高位不变(用原有的符号位补,负数为1,正数为0);

同时,

imul      strideS, strideD,    4

也是合法的;

movq       srcShift0, [pSrcCol]

这个是从内存[pSrcCol]读取64位到mm寄存器

指令后缀解读:

b;字节-8bit
w;字-16bit
d;双字-32bit
q;四字-64bit
a;align,对齐
u;unalign,不对齐
p;package,打包,128位同时处理
s;single,不打包,只处理部分
s;single precision,单精度,32bit
d;double precision,双精度,64Bit
l;低64位
h;高64位

下面摘自文章《Intro_to_Intel_Avx》
许多指令都是紧缩或标量形式:
即它们在寄存器的多个并行元素或者一个单一元素上执行——标记为 [P/S];
条目长度分为双精度或单精度浮点(简称为双精度和单精度),标记为 [D/S];
整数形式分为字节、字、双字和四字,标记为 [B/W/D/Q]。
整数形式有时还分为带符号形式和无符号形式,标记为 [S/U] ;
有些指令在寄存器的高区或低区运行,标记为 [H/L];

比如:

paddb,按字节对齐相加,paddw,按字对齐相加,paddd,按双字对齐相加。。。。

movlps,将源64位的两个单精度(s,32x2)的值打包(p)移到目的寄存器的低(l)64位中;

movss,将单精度(s)的值不打包(s)移致目的寄存器的低32位;

 

位数扩展指令:

punpcklbw  srcShift0, zero;在低(l)64位,将字节(b)扩展成字(w),变成128位,原来的高64位被覆盖
12345678,-> 01020304
同理,有

punpckhbw, punpcklwd, punpckhwd....

移位指令:

pslldq ,按双四字(dq)(128bit)逻辑(l)左移(l)
pslld, 按双字(32位)逻辑左移
psllw,按字逻辑左移
psrlw,按字逻辑右移

psraw,按字算术右移
psrad,按双字算术右移

pshufd dst,src,imm

这个指令的意思是从src中取双字(32bit)按照imm(8位)的顺序复制给dst:

imm=01 11 00 00(1,3,0,0)

则: dst[0] = src[0]

      dst[1] =src[0]

      dst[2] = src[3]

      dst[3] = src[1]

 

 pshufd    tmp,  srcHigh, 01000001B 

 srcHigh的值:

tmp的值:

执行以上操作后:

验证!

 

movdqu m0,   [t1 + t2],

[]内不能有内存

t1:寄存器/立即数

t2:寄存器/立即数

且t1,t2至少一个是寄存器,t1,和t2不能是内存

经典的用法是:movdqu m0,   [t1 + 2*t2 + 3],其中t1,t2都是寄存器

当寄存器不够使用时(win32下只有7个可以使用),可以定义一个临时寄存器tmp,参数存在内存s1上,那么可以这么做:

mov  tmp, s1

movdqu m0,   [t1 + tmp],

这样不会报错,而

movdqu m0,   [t1 + s1],会报错,其他例子如,s3是放在栈上的参数,栈上的参数是不能当做目的操作数的,在add,sub,mul等中只能做源操作数,为了改变s3,可以借助临时寄存器:

mov tmp, s3

dec tmp

mov s3, tmp

sub,cmp,test

sub:会改变目的操作室,cmp和test不会改变目的操作数,所以如果不想改变dst值,则可以

cmp dst, 8

改变的话则

sub dst, 8


psadbw

这个是按字节打包计算绝对差的和,低64位的绝对差和放在第一个字处[0:15],高64位的绝对差和放在第五个字处[64:79],其他字为0,

m0: 按字节,1-1 1-1- 1-1-1-1 -1-1-1-1-1-1-1-1 

m1:按字节, 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0

psadbw:m0,m1

得m0,按字,8-0-0-0-8-0-0-0 

pavgb

这个是按字节打包计算平均值,结果仍然为字节

m0: 按字节,6-16-10-14-21-21-2-10-2-2-1-8-99-6-22-8

m1:按字节, 0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0

pagv m0, m1

得m0:3-8-5-7-10-10-1-5-1-1-0-4-49-3-11-4

pslldq

这个是按字节左移,而其他非dq结尾的移位操作都是以bit为单位进行移位,psrld,m1, 24.m1逻辑向右移位24bit,也就是3bytes,而pslldq m1,1表示逻辑左移1byte

移位操作可以配合paddd实现水平求和,如

m0按字为:6-16-10-14-21-21-2-10

如果计算低64位和,可以这么做:

punpcklwd m0,zer0

得按双字,6-16-10-14

pslldq m0,4

得0-6-16-10

重复,得到

6-16-10-14

0- 6- 16-10

0- 0-  6- 16

0- 0-  0-  6

利用paddd即可愿意得到结果

6-22-32-46

packssdw,packuswb

这两个指令某种意义上是punpckxxx的逆操作;

假如,m0按字节为152-0-0-0-123-0-0-0-140-0-0-0-78-0-0-0,我想把152-123-140-78store进一个连续(字节类型)的内存中,

如果直接store,保存的是152-0-0-0,达不到目的;

执行packssdw,m0

得152-0-123-0-140-0-78-152-0-123-0-140-0-78-0

执行packuswb,m0

得152-123-140-78-152-123-140-78-152-123-140-78-152-123-140-78

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值