今回よりA64の論理演算命令に入ってまいります。AND、OR、EOR、NOTくらいさらっと撫でて終わりっしょ、と思うとさにあらず。便利な合わせ技あり、例によってのエイリアス、そして細かい凸凹もありです。今回は論理演算命令中の大族、AND系命令一族を練習してまいりたいと思います。
※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら
※動作確認は普及価格帯のAndroidスマホで行っています。Cortex-A73/Cortex-A53 各4コアの bigLITTLE 、64ビット。Android上にインストールしたTermux環境にWindowsPCからSSH接続し、clang/llvmのツールチェーンでビルドしております。
AND(論理積)一族
ここで扱いますAND命令は、ビット演算のAND命令であります。以下のような特徴を持つモノドモが含まれます。
-
- 第1ソースと第2ソース間で素直にビットワイズのAND演算を行うもの。
- 第2ソースを反転(NOT)してから第1ソースとの間でAND演算するもの。
- フラグに影響するもの
- 演算結果をデスティネーションに書き込まないエイリアス
- 32ビット幅演算か64ビット幅演算か
- 第2ソースオペランドとして即値をとるもの
- 第2ソースオペランドとして演算前にシフト可能なレジスタをとるもの
1はAND/ANDS命令。2はBIC/BICS命令。3はANDS/BICS命令。4はTST命令(ANDS命令のデスティネーションをゼロレジスタに向けたもの。)5は各命令でWレジスタをオペランドにとったときが32ビット、Xレジスタであれば64ビット。6はAND/ANDSのみ設定あり。7は一族全命令に設定ありです。まとめたものが以下に。
特定ビットを取り出すときにANDしますが、特定ビットをクリアしたいときにはBIC命令がお役立ちです。また、コマケーことを言うと、32ビット幅命令でとれる即値は13ビットですが、64ビット幅命令では14ビットなど微妙な凸凹があります。
今回実験するアセンブラコード
今回は、以下の3点をWレジスタとXレジスタについて確認したいと思います。
-
- 即値の幅13ビットと14ビット
- AND
- BIC
例によってほぼほぼ1命令=1アセンブラ関数スタイルの実験コードが以下に。
.globl andImmW, andImmX, andW, andX, bicW, bicX .text .balign 4 andImmW: and w0, w1, #0x1FFF ret andImmX: and x0, x1, #0x3FFF ret andW: and w0, w1, w2 ret andX: and x0, x1, x2 ret bicW: bic w0, w1, w2 ret bicX: bic x0, x1, x2 ret
実験に使用したC言語ソース
上記のアセンブリ言語ソースで定義された関数を呼び出して結果を観察するためのC言語コードが以下に。
#include <stdio.h> extern uint32_t andImmW(uint32_t, uint32_t); extern uint64_t andImmX(uint64_t, uint64_t); extern uint32_t andW(uint32_t, uint32_t, uint32_t); extern uint64_t andX(uint64_t, uint64_t, uint32_t); extern uint32_t bicW(uint32_t, uint32_t, uint32_t); extern uint64_t bicX(uint64_t, uint64_t, uint32_t); int main(void) { int32_t result; int64_t resultX; result = andImmW(0, 0xFFFF); printf ("andImmW(0, 0xFFFF): 0x%x\n", result); resultX = andImmX(0, 0xFFFF); printf ("andImmmX(0, 0xFFFF): 0x%lx\n", resultX); result = andW(0, 0xFFFFFFFF, 1); printf ("andW(0, 0xFFFFFFFF, 1): 0x%x\n", result); resultX = andX(0, 0x1FFFFFFFF, 1); printf ("andX(0, 0x1FFFFFFFF, 1): 0x%lx\n", resultX); result = bicW(0, 0xFFFFFFFF, 1); printf ("bicW(0, 0xFFFFFFFF, 1): 0x%x\n", result); resultX = bicX(0, 0x1FFFFFFFF, 1); printf ("bicX(0, 0x1FFFFFFFF, 1): 0x%lx\n", resultX); return 0; }
ビルドして実行
例によってTermux上でのビルドは clang 使用です(多分、gccでも同じようにできる筈。知らんけど。)
$ clang -g -O0 -o and and.c and.s
実行結果が以下に。
全部予定通り。あたりまえか。ちゃきちゃきやらないと命令多いから終わらんよ。