SIMD register to bitmask
SIMDレジスタの各レーンについて、1/0のマスクがある(典型的には、0xff..ffと0x00..00)状態から、各レーンの1/0を1ワードにパックする操作
code:bitmask
0000|ffff|0000|0000|ffff|0000|ffff|ffff
↓
0b01001011 (0x4b)
x86 (SSE, AVX)では、(v)pmovmskbで各バイトの最上位ビットを取れるので、バイト単位ならこれでよい
bitmask + 水平加算
各レーンで異なるビット位置を取り出すように、1ビットずつずらしたマスクを適用し、水平加算
code:mask + hadd
0000|ffff|0000|0000|ffff|0000|ffff|ffff
0080|0040|0020|0010|0008|0004|0002|0001
↓ (bitwise and)
0000|0040|0000|0000|0008|0000|0002|0001
↓ (horizontal add)
0b01001011 (0x4b)
内積
内積命令があるような場合、マスクを取り、シフトを取り、水平加算までが1発でできる
基本戦略: 0x00/0xffを0/1にして、1個ずつずらしてシフトし、水平加算すればよい
0x00/0xff->0/1は-1を掛ければよく、シフトは乗算に置き換えられる、内積の加算部分で水平加算が行われる
ただし、符号付き乗算で
code: dot
0000|ffff|0000|0000|ffff|0000|ffff|ffff
fe00|ff80|ffc0|ffe0|fff8|fffc|fffe|ffff
↓ (signed integer mul)
0000|0040|0000|0000|0008|0000|0002|0001
↓ (horizontal add)
0b01001011 (0x4b)