はなかなか面白い命令で好きでした。 2 つの quad word レジスタから、 byte ごとに好きな位置の byte を取って来れる命令。普通に 8bit 単位の rotate/shift/and などとして機能するし、 8bit 単位で selb 的な命令にもなる。
例えば、
((r1 & 0xffffffff_ffffffff_ffffffff_ffff0000) << 1)
と
((r2 & 0xffff0000_00000000_00000000_00000000) << 17)
(ただし r1 と r2 は quad word で << は左 rotate)で or を取りたいような部分があったのですが、
shufb $r, $r1, $r2, $filter rotqbii $r, $r, 1
とかの 2 命令でできちゃう。 filter は以下のようなもので、
static vector unsigned char filter = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x11, };
16進で上のケタが 0 なら 1 つ目のレジスタから持ってくることを指定し、 1 なら 2 つ目から取ってくることを指定する。下のケタは byte で指定した位置。この filter の場合は、 1-14 byte 目までは r1 レジスタから取ってきてもらって、 15, 16 bit 目は r2 の先頭の部分を取ってくる。この時ついでに << 16 もすませてしまっているわけ。よって最後は << 1 だけやってやれば OK 、と。
最終的なコードでは、もう一箇所もう少しだけややこしいシーンで shufb を使ったのですけど、こっちは説明しにくいし、なんか長くて optimal じゃない気もするのでいいや。
あとは even pipeline にある and を odd pipeline に入れるために shufb 使ったりとかもしました。まぁとにかく色々便利。
あと、本来は 2 quad word 間で byte 単位で rotate して隣あったメモリ位置の両方に触る値を取り出したい時なんかがメインの用途だと思います。 ABCD EFGH から CDEF を取りだしたい、など。