ビット操作系の命令は多くのCPUにあり、各種のアルゴリズムを高速化することに役立っています。
オープンな命令セットのRISC-Vにもビット操作系の命令を拡張命令として導入しようという機運があり、どういった命令を追加するべきか議論されているようです。
とりあえずVersion 0.92版のpdfを見てまとめていきます。
riscv-bitmanip/bitmanip-0.92.pdf at master · riscv/riscv-bitmanip · GitHub
ビットカウント系命令
clz
count leading zeros です。二進数としてあらわした時、上位ビットから何ビット0が続くかを数えます。
ctz
count trailing zeros です。二進数としてあらわした時、下位ビットから何ビット0が続くかを数えます。「その数が2kの倍数である」が成り立つ最大のkを求めることになります。
pcnt
pop count です。二進数としてあらわした時の1の数を数えます。三オペランド命令(二引数命令)にし、第二引数がゼロレジスタであるときの挙動がpop countと一致するような命令にしたほうが便利との提案が出されています。 github.com
ビット毎論理演算命令
andn
rs1 & ~rs2
を計算します。
orn
rs1 | ~rs2
を計算します。
xnor
rs1 ^ ~rs2
を計算します。
パック命令
pack
二つのレジスタの下位半分を連結した値を計算します。 0xffff0000ffff0000のような数を二命令で生成することができます。 また、16bit/32bitのローテート操作の実現に利用可能です。 さらに、ゼロ拡張にも使えます。
packu
二つのレジスタの上位半分を連結した値を計算します。
packh
二つのレジスタの下位八ビットを連結した十六ビット値を計算します。
最大・最小を求める命令
min
/max
rs1
とrs2
を符号付き整数として解釈した時、両者のうち大きくないほう/小さくないほうの値を計算します。
max
は絶対値を求めるのにも使えます。
また、飽和演算にも役立てられます。
minu
/maxu
rs1
とrs2
を符号無し整数として解釈した時、両者のうち大きくないほう/小さくないほうの値を計算します。
サブワード符号拡張命令
sext.b
下位八ビットの内容を符号拡張した数を計算します。
sext.h
下位十六ビットの内容を符号拡張した数を計算します。
その他
zext.b
はandi rd, rs, 255
で実現可能です。zext.h
は32bitの場合はpack rd, rs, zero
、64bitの場合はpackw rd, rs, zero
で実現可能です。zext.w
はpack rd, rs, zero
で実現可能です(64bitの場合のみ利用価値があるため、64bitの場合を前提としています)。sext.w
はaddiw rd, rs, 0
で実現可能です。
一ビット操作命令
sbset
/sbseti
rs1
のrs2
/imm
ビット目を1にした数を計算します。
sbclr
/sbclri
rs1
のrs2
/imm
ビット目を0にした数を計算します。
sbinv
/sbinvi
rs1
のrs2
/imm
ビット目を反転した数を計算します。
sbext
/sbexti
rs1
のrs2
/imm
ビット目を計算します。計算される値は、0か1のどちらかです。
一のシフト系命令
(うまい訳語がないので「一のシフト」としました)
slo
/sloi
左シフトですが、下位ビットは1で埋められます。
~(~rs1 << (rs2 & XLEN-1))
と書けます。
0xffffff
みたいな数を一命令で生成することができます。
sro
/sroi
右シフトですが、上位ビットは1で埋められます。
~(~rs1 >> (rs2 & XLEN-1))
と書けます。