鬱猫のつぶやき

鬱猫が日々思っていることをつづります

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 について擬似コード付きで説明した。 新しく命令勉強したら更新していくことにする。