ぐだぐだ低レベルプログラミング(69) ARM64(AArch64)、論理命令AND一族#1

Joseph Halfmoon

今回より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. 第1ソースと第2ソース間で素直にビットワイズのAND演算を行うもの。
    2. 第2ソースを反転(NOT)してから第1ソースとの間でAND演算するもの。
    3. フラグに影響するもの
    4. 演算結果をデスティネーションに書き込まないエイリアス
    5. 32ビット幅演算か64ビット幅演算か
    6. 第2ソースオペランドとして即値をとるもの
    7. 第2ソースオペランドとして演算前にシフト可能なレジスタをとるもの

1はAND/ANDS命令。2はBIC/BICS命令。3はANDS/BICS命令。4はTST命令(ANDS命令のデスティネーションをゼロレジスタに向けたもの。)5は各命令でWレジスタをオペランドにとったときが32ビット、Xレジスタであれば64ビット。6はAND/ANDSのみ設定あり。7は一族全命令に設定ありです。まとめたものが以下に。

AndTable

特定ビットを取り出すときに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

実行結果が以下に。

results

全部予定通り。あたりまえか。ちゃきちゃきやらないと命令多いから終わらんよ。

ぐだぐだ低レベルプログラミング(68) ARM64(AArch64)、算術命令エイリアス#2 へ戻る

ぐだぐだ低レベルプログラミング(70) ARM64(AArch64)、論理命令AND一族#2 へ戻る