ぐだぐだ低レベルプログラミング(63) ARM64(AArch64)、フラグの観察 adds

Joseph Halfmoon

前回はArmの64ビット命令の即値Addを眺めてみました。それだけでも4形式の命令があったのですが、前回作成した命令表には、まったく同等な加算動作を行う命令Addsが隣に並んでいます。整数加算することはAddと同じですが、副作用、フラグを立てたり下ろしたりする、ということのみが違う命令です。なお演習はスマホ上です。

※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら

古典的なマイクロプロセッサでは Addしたら、何も指定しなくても条件フラグを操作する、というのが普通でした。Armも32ビットの頃まではそうでした。しかし、Armも64ビットになるにあたって考え直したのでしょう。普通のAdd命令では条件フラグを操作しないことにしたのでした。何といってもスーパースカラー、投機的実行(スペキュラティブ・イクゼーキューション)といった高性能化において、用もないのに副作用があるというのは足を引っ張るからだと思います。これが進むとRISC-Vのように条件フラグなど無し、という境地?に到達するのだと思います。しかしAArch64ではそこまではいかなかったようです。フラグ操作が必要な命令だけフラグを操作してね、という塩梅。

参照するのはArm社の以下のドキュメントであります。

Arm Architecture Reference Manual for A-profile architecture

今回は条件演算フラグを操作するだけなのですが、動作確認に使う gdb が32ビット幅のフラグ・レジスタのイメージ CPSR(この呼び方は32ビットのArmまでで、64ビットのマニュアルには出てこないと思います)を表示してくれるので、該当の必要部分のみ図としてみました。条件フラグで今回命令の影響を受けるのは緑色の最上位4ビットのみです。ざっくりしたフラグの意味は以下のとおり。

    • N ネガティブ(演算結果を2の補数として解釈したときにマイナス)
    • Z ゼロ
    • C キャリー(符号無で最上位ビットからのキャリーあり)
    • V オーバーフロー(2の補数の符号ビットへ桁あふれなどあり)

以下の図で紫色の部分は例外等の制御/ステータスなので、アプリレベルで命令を操作している今回のケースでは手を出せませぬ。

Flags

紫色部分の中で1ビットだけ水色にしてあるがSoftware Step(x86式にいうと、Single Step)フラグです。デバッガのステップ実行に使うもの。今回GDBでシングルステップかけて1命令づつ動かしながら条件フラグのON/OFFを観察しています。よって、今回のフラグレジスタイメージでは、常にこのビットは1が立っているように見えます。

なお、AArch64の条件フラグは、64ビット幅のレジスタイメージの中の4ビットだけのフラグとしても表現されるようです。ちょっと空虚な。

実験に使ったコード

実験につかったコードは前回のものと同様です。修正点としては、add命令をadds命令に置き換えただけです(つられてラベルなど変更してますが。)演算そのものは前回とまったく同じです。かなりな手抜きですが、今回完全にアンドロイドスマホ上で編集からビルドまで行ったので勘弁してくだされ。アンドロイド上で gdb 動かしている様子を冒頭のアイキャッチ画像に掲げました。

実動作の確認

スマホのスクリーンキャプチャは撮った後がまた面倒なので、GDBでのシングルステップの様子は、パソコンからスマホにSSH接続して取得しています。注目すべきaddsの「副作用」はキャプチャの一番上に表示されている cpsr という反転表示の部分につきます。

32ビット幅の即値addsその1、実行前

実行前にN(ネガティブ)フラグが立っているのはこれ以前の履歴です。

addsimmW1before

32ビット幅の即値addsその1、実行後

演算結果は十進で433なので、立っていたNを含め全フラグがクリアされています。

addsimmW1after

32ビット幅の即値addsその2、実行前

履歴上、キャリーとゼロフラグが立っています。

addsimmW2before

32ビット幅の即値addsその2、実行後

32ビットの最上位を超えて結果がラップしているので、キャリーフラグが立ちました。いっぽうゼロではないのでゼロフラグはクリアされてます。

addsimmW2after

64ビット幅の即値addsその1、実行前

以下でのオペランドは上記の「32ビットの即値addsその2」と同じですが、演算幅が64ビットになっています。

addsimmX1before

64ビット幅の即値addsその1、実行後

64ビット幅であると32ビット幅のときと違いキャリーは立ちません。当たり前か。

addsimmX1after

32ビット幅の即値adds シフト12ビット付き、実行前

再びキャリーとゼロが立った状態でテストに入ってきています。

addsimm12W1before

32ビット幅の即値adds シフト12ビット付き、実行後

演算した結果、全条件フラグはクリア。

addsimm12W1after

64ビット幅の即値adds シフト12ビット付き、実行前

再びキャリーとゼロが立ってます。

addsimm12X1before

64ビット幅の即値adds シフト12ビット付き、実行後

演算した結果、全条件フラグはクリア。

addsimm12X1after

当たり前だけれども adds 命令で条件フラグが変わることが確かめられました。ちょっと(かなり)手抜きだけれども。スマホだし。

ぐだぐだ低レベルプログラミング(62) ARM64(AArch64)、Add命令その1即値 へ戻る

ぐだぐだ低レベルプログラミング(64) ARM64(AArch64)、シフト付きadd へ進む