ぐだぐだ低レベルプログラミング(84)ARM64(AArch64)、条件選択命令群その2

Joseph Halfmoon

前回は、数多い条件選択命令群のうち「表」の4命令を動かしてみました。今回は「裏(エイリアス)」の5命令を動かしてみたいと思います。共通しているのは、「表」の命令と条件判断がひっくりかえっていること、そして本来3オペランドの「表」命令のソースオペランドに制限を加えていることです。

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

※以下は下記にて動作確認しています。

    • Raspberry Pi 4 model B、Cortex-A72コア ARMv8-A
    • Raspberry Pi OS (64bit) bullseye
    • gcc (Debian 10.2.1-6) 10.2.1 20210110
条件選択命令、エイリアス

「表」の条件選択命令は、条件を判定し、真であれば第1ソースをデスティネーションにおくり、偽であったら第2ソースに命令により異なる「加工」をしてデスティネーションにおくるという命令でした。C言語などの3項演算子のような命令です。

上記を踏まえて条件の真偽を反転し、ソースオペランドに制約を加えると以下のエイリアス命令となります。

    1. CINC、第1ソースと第2ソースに同レジスタ指定の真偽反転CSINC命令
    2. CSET、第1ソースと第2ソースがゼロレジスタの真偽反転CSINC命令
    3. CINV、第1ソースと第2ソースに同レジスタ指定の真偽反転CSINV命令
    4. CSETM、第1ソースと第2ソースがゼロレジスタの真偽反転CSINV命令
    5. CNEG、第1ソースと第2ソースに同レジスタ指定の真偽反転CSNEG命令
実験用のアセンブリ言語ソースとアセンブル結果

今回の実験用アセンブラ関数は以下のステップです。

    1. cmp命令で第1引数と第2引数を比較し、条件を既知の状態にしておく
    2. 「表の」命令エンコードでの表現
    3. エイリアス命令としての表現

2と3は同一の命令を2つ重ねていることになります。逆アセンブル・ダンプにより2と3が一致していることを確かめます。

まずはCINC命令。

.globl	cincW, cincX, csetW, csetX, cinvW, cinvX, csetmW, csetmX, cnegW, cnegX
.text
.balign	4

cincW:
    cmp w0, w1
    csinc w0, w2, w2, NE
    cinc w0, w2, EQ
    ret

cincX:
    cmp x0, x1
    csinc x0, x2, x2, NE
    cinc x0, x2, EQ
    ret

その逆アセンブルリスト。逆アセンブル時には、「わかりにくい」表の命令表現でなく、エイリアス命令の表現が優先されるようです。cincLis

つづいて CSET命令。

csetW:
    cmp w0, w1
    csinc w0, wzr, wzr, NE
    cset w0, EQ
    ret

csetX:
    cmp x0, x1
    csinc x0, xzr, xzr, NE
    cset x0, EQ
    ret

その逆アセンブル。csetLis

CINV命令。

cinvW:
    cmp w0, w1
    csinv w0, w2, w2, NE
    cinv w0, w2, EQ
    ret

cinvX:
    cmp x0, x1
    csinv x0, x2, x2, NE
    cinv x0, x2, EQ
    ret

その逆アセンブル。

cinvLis2

CSETM命令。

csetmW:
    cmp w0, w1
    csinv w0, wzr, wzr, NE
    csetm w0, EQ
    ret

csetmX:
    cmp x0, x1
    csinv x0, xzr, xzr, NE
    csetm x0, EQ
    ret

その逆アセンブル。

csetmLis

CNEG命令。

cnegW:
    cmp w0, w1
    csneg w0, w2, w2, NE
    cneg w0, w2, EQ
    ret

cnegX:
    cmp x0, x1
    csneg x0, x2, x2, NE
    cneg x0, x2, EQ
    ret

その逆アセンブル。

cnegLis

実験に使用したC言語ソース

各命令とも、W(32ビット・レジスタ)とX(64ビット・レジスタ)の2種類あります。それぞれについて真の場合と偽の場合を通してます。テストケース手抜きですが、一応触ったということで。

#include <stdio.h>
#include <stdint.h>

extern uint32_t cincW(uint32_t, uint32_t, uint32_t);
extern uint64_t cincX(uint64_t, uint64_t, uint64_t);
extern uint32_t csetW(uint32_t, uint32_t);
extern uint64_t csetX(uint64_t, uint64_t);
extern uint32_t cinvW(uint32_t, uint32_t, uint32_t);
extern uint64_t cinvX(uint64_t, uint64_t, uint64_t);
extern uint32_t csetmW(uint32_t, uint32_t);
extern uint64_t csetmX(uint64_t, uint64_t);
extern uint32_t cnegW(uint32_t, uint32_t, uint32_t);
extern uint64_t cnegX(uint64_t, uint64_t, uint64_t);

int main(void)
{
    uint32_t uresult;
    uint64_t uresultX;

    uresult = cincW(9, 0, 2);
    printf ("cincW(9, 0, 2): %d\n", uresult);
    uresult = cincW(9, 9, 2);
    printf ("cincW(9, 9, 2): %d\n", uresult);
    uresultX = cincX(9, 0, 2);
    printf ("cincX(9, 0, 2): %ld\n", uresultX);
    uresultX = cincX(9, 9, 2);
    printf ("cincX(9, 9, 2): %ld\n", uresultX);

    uresult = csetW(9, 0);
    printf ("csetW(9, 0): %d\n", uresult);
    uresult = csetW(9, 9);
    printf ("csetW(9, 9): %d\n", uresult);
    uresultX = csetX(9, 0);
    printf ("csetX(9, 0): %ld\n", uresultX);
    uresultX = csetX(9, 9);
    printf ("csetX(9, 9): %ld\n", uresultX);

    uresult = cinvW(9, 0, 2);
    printf ("cinvW(9, 0, 2): %08x\n", uresult);
    uresult = cinvW(9, 9, 2);
    printf ("cinvW(9, 9, 2): %08x\n", uresult);
    uresultX = cinvX(9, 0, 2);
    printf ("cinvX(9, 0, 2): %016lx\n", uresultX);
    uresultX = cinvX(9, 9, 2);
    printf ("cinvX(9, 9, 2): %016lx\n", uresultX);

    uresult = csetmW(9, 0);
    printf ("csetmW(9, 0): %08x\n", uresult);
    uresult = csetmW(9, 9);
    printf ("csetmW(9, 9): %08x\n", uresult);
    uresultX = csetmX(9, 0);
    printf ("csetmX(9, 0): %016lx\n", uresultX);
    uresultX = csetmX(9, 9);
    printf ("csetmX(9, 9): %016lx\n", uresultX);


    return 0;
}
実行確認

ビルドのコマンドラインは以下です。

gcc -g -O0 -o csel2 csel2.c csel2.s

実行結果が以下に。

csel2_result

なんてことはないですが、さらっと触るだけでも数が多いのでメンドイ。

ぐだぐだ低レベルプログラミング(83)ARM64(AArch64)、条件選択命令群その1 へ戻る

ぐだぐだ低レベルプログラミング(85)ARM64(AArch64)、整数演算命令その1 へ進む