AArch64 アセンブリ UBFM UBFIZ UBFX
はじめに
最近はArmv8アセンブリを読むことが多いのが、ビット演算系の命令を頻繁に忘れて何回もググっているので、一回まとめておく。 公式ドキュメント、擬似コード (or 具体例) を載っけて欲しい。
ubfm
Unsigned Bit Field Move の頭文字をとって ubfm と呼ぶらしい。 他のビット演算系の命令を見る上で基本となる。
ubfm Xd, Xn, #imm6r, #imm6s
- imm6s には source register から移動させる一番左のビット番号を指定
- imm6r には destination register に挿入させる位置の一番右のビット番号を指定
右とか左とか言っているが、LSB first の場合になる。
擬似コードで書けば以下のような感じ。
Xd[:] = 0; Xd[(64 - imm6r + imm6s + 1):(64 - imm6r)] = Xn[imm6s + 1:0];
Pythonで同じ操作に当たるコードを書くとこんな感じ。
Xd = (Xn & ((1 << (imm6s + 1)) - 1)) << (64 - imm6r)
まず Xn の下位 imm6s + 1 bitを取り出す。その取り出したbitを 64 - imm6r bit 分だけ左シフトしたものをXdに代入する。
例がこのサイトに上がっていたので載っけておく。
x2 : 823456789ABCDEF0 x5 : 5555555555555555 UBFM X5, X2, #60, #23 --> 000000000BCDEF00 # x2 のうち下位24bitsを取り出す (今回だとBCDEF0) # そのあと、64 - 60 = 4 bits だけ左シフトしてx5に代入すれば完成
ubfiz
Unsigned Bit Field Insert in Zero の頭文字をとって ubfiz。
ubfiz Xd, Xn, #lsb, #width
これは以下と同じになる。
ubfm Xd, Xn, #(-lsb MOD 64), #(width-1)
source register の内容のうち、下位 width bit を取り出す。これを lsb 分左シフトしたものを作成し、destination register に格納する。
擬似コードで書くとこんな感じ。
Xd[:] = 0; Xd[width + lsb:lsb] = Xn[width:0]
これも具体例で考えてみる。
x2 : 823456789ABCDEF0 x5 : 5555555555555555 UBFIZ X5, X2, #4, #24 --> 000000000BCDEF00
ubfm の具体例を ubfiz で書き直した例を作ってみた。lsb = 4, width = 24 としたら、さっきの ubfm の具体例と一致することがわかると思う。
ubfx
Unsigned Bit Field eXtract を省略して ubfx
これは以下と同じになる。
ubfm Xd, Xn, #lsb, #(lsb+width-1)
擬似コードでかくとこんな感じ。
Xd[:] = 0; Xd[width:0] = Xn[lsb + width:lsb];
具体例を一個載っけておく。
x2 : 823456789ABCDEF0 x5 : 5555555555555555 UBFX X5, X2, #4, #24 --> 00000000000BCDEF
おわりに
UBFM UBFIZ UBFX について擬似コード付きで説明した。 新しく命令勉強したら更新していくことにする。