RISC-Vのビット操作系拡張(B拡張)のまとめ(その1)

ビット操作系の命令は多くの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のローテート操作の実現に利用可能です。 さらに、ゼロ拡張にも使えます。

f:id:lpha_z:20200706001707p:plain
pack命令の動作(32bitの場合)

packu

二つのレジスタの上位半分を連結した値を計算します。

f:id:lpha_z:20200706001759p:plain
packu命令の動作(32bitの場合)

packh

二つのレジスタの下位八ビットを連結した十六ビット値を計算します。

f:id:lpha_z:20200706001740p:plain
packh命令の動作

最大・最小を求める命令

min/max

rs1rs2を符号付き整数として解釈した時、両者のうち大きくないほう/小さくないほうの値を計算します。 maxは絶対値を求めるのにも使えます。 また、飽和演算にも役立てられます。

minu/maxu

rs1rs2を符号無し整数として解釈した時、両者のうち大きくないほう/小さくないほうの値を計算します。

サブワード符号拡張命令

sext.b

下位八ビットの内容を符号拡張した数を計算します。

sext.h

下位十六ビットの内容を符号拡張した数を計算します。

その他

  • zext.bandi rd, rs, 255で実現可能です。
  • zext.hは32bitの場合はpack rd, rs, zero、64bitの場合はpackw rd, rs, zeroで実現可能です。
  • zext.wpack rd, rs, zeroで実現可能です(64bitの場合のみ利用価値があるため、64bitの場合を前提としています)。
  • sext.waddiw rd, rs, 0で実現可能です。

一ビット操作命令

sbset/sbseti

rs1rs2/immビット目を1にした数を計算します。

sbclr/sbclri

rs1rs2/immビット目を0にした数を計算します。

sbinv/sbinvi

rs1rs2/immビット目を反転した数を計算します。

sbext/sbexti

rs1rs2/immビット目を計算します。計算される値は、0か1のどちらかです。

一のシフト系命令

(うまい訳語がないので「一のシフト」としました)

slo/sloi

左シフトですが、下位ビットは1で埋められます。 ~(~rs1 << (rs2 & XLEN-1))と書けます。 0xffffffみたいな数を一命令で生成することができます。

sro/sroi

右シフトですが、上位ビットは1で埋められます。 ~(~rs1 >> (rs2 & XLEN-1))と書けます。

条件分岐内蔵命令