实际上,搞汇编优化的很多时间是在处理如何有效的组织数据,以适应并行计算指令的数据结构。
本小结描述的是数据混洗指令,这类指令使用起来相当的灵活。具体如下:
1. shufps XMM,XMM/m128,imm8(0~255)
描述:
从指令后缀来看,这是一条SSE1指令。
该指令把源存储器与目的寄存器按双字32位划分, 由立即数imm8八个二进制位(00~11,00^11,00~11,00~11)指定排列,
目的寄存器高64位放源存储器被指定数,目的寄存器低64位放目的寄存器被指定数。内存变量地址必须对齐16字节
imm8的高4位选的是源存储器,低4位选的是目的寄存器。
高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 = 0x 090a0b0c 0d0e0f11 01020304 05060708,
XMM1 = 0x 0aabbccdd eeff1234 22334455 66778899,
mm8 ══> (XMM1 10) (XMM1 01) (XMM0 11) (XMM0 00)
执行shufps XMM0,XMM1,10 01 11 00 b(二进制),
则XMM0 = 0x 0eeff1234 22334455 090a0b0c 05060708
假如,shufps XMM0,XMM1,10 10 10 10 b,那么结果为: XMM0 = 0x 0eeff1234 eeff1234 0d0e0f11 0d0e0f11
该指令一个常用用法如下:
float f = 0.5f;
__asm
{
movss xmm2, f // xmm2[0] = 2.8
shufps xmm2, xmm2, 0 // xmm2[1, 2, 3] = xmm2[0]
.....
}
2. shufpd XMM,XMM/m128,imm8(0~255)
描述:
从指令后缀来看,这是一条SSE2指令。
imm8(操作值) = imm8(输入值) mod 4
把源存储器与目的寄存器按四字64位划分,由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 = 0x 1111111122222222 3333333344444444
XMM1 = 0x 5555555566666666 aaaaaaaacccccccc,
执行 shufpd XMM0,XMM1,101001 1 0 b
因为 101001 1 0 b mod 4 (101001 1 0 b & 11b), 得到操作值为1 0b,
高位 1 选择源寄存器 XMM1 的第1位 5555555566666666,
低位 0 选择目的寄存器XMM0的第0位 3333333344444444.
则 XMM0 = 5555555566666666 3333333344444444 h
3. 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 = 0x 1111111122222222 3333 4444 5555 6666
XMM1 = 0x 5555555566666666 7777 8888 9999 cccc ,
执行 pshuflw XMM0,XMM1,10 10 01 10 b
则 XMM0 = 0x 5555555566666666 8888 8888 9999 8888
4. 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 = 0x 3333 4444 5555 6666 1111111122222222
XMM1 = 0x 7777 8888 9999 cccc 5555555566666666,
执行 pshufhw XMM0,XMM1,10 10 01 10 b
则 XMM0 = 0x 8888 8888 9999 8888 5555555566666666
5. pshufd XMM,XMM/m128,imm8(0~255)
描述:
将源存储器的4个双字由imm8指定选入目的寄存器,内存变量必须对齐内存16字节.
高64位 | 低64位
源寄存器: (11) | b(10) | b(01) | b(00)
目的寄存器排列结果: b(00~11) | b(00~11) | b(00~11) | b(00~11)
例:
当 XMM1 = 0x 11111111 22222222 33333333 44444444,
执行 pshufd XMM0,XMM1,11 01 01 10b
则 XMM0 = 0x 11111111 33333333 33333333 22222222
6. pshufw MM, MM/m64, imm8(0~255)
此指令属于MMX的指令。上面描述的pshuflw和pshufhw 都是它的扩展,执行相同的功能。
只是pshuflw执行的是XMM寄存器的低64位,pshufhw执行XMM寄存器的高64位。
这条指令的功能和pshufd 指令执行的操作一样,只是它操作数据的单位是16位的一个字。
小结:
1. SHUFPS和SHUFPD指令运算的结果与源寄存器和目的寄存器有关
2. pshufw、pshuflw、pshufhw、pshufd这3条指令运算的结果与目的寄存器没有关系。