前回は浮動小数を浮動小数フォーマットのまま整数に丸めるFRINTx命令でした。今回は浮動小数を丸めて「ホンモノの」整数表現に変換してしまうFCVTxy命令です。前回は丸めモードフラグに影響される命令が2個ありましたが、今回は相当する命令はありません。命令減ったの?とみれば増えとります。変換先が2種類あるから。
※「ぐだぐだ低レベルプログラミング」投稿順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
ARMv8もいろいろレベルがあり、Arm Cortex-A72はARMv8の中でもベーシックな(命令数の少ない)ARMv8p0です。
※A64の最新のマニュアルは以下でダウンロード可能です。
Arm Architecture Reference Manual for A-profile architecture
FCVTxy命令
前回の浮動小数フォーマットのまま整数相当の値に丸めるFRINTx命令では丸めモードをニーモニックに含む命令が5種、丸めモードはFPCRレジスタの丸めモードフラグに従うもの2種の合計7種がありました。今回のFCVTxy命令では丸めモードフラグに従う命令は無いので丸めモードは全てニーモニックに含まれ5種です。これがFCVTxyのxに入ります。しかし、変換後の整数値が符号付き(s)か符号無(u)かでyに2種類入るので合計は10種です。いつものことだけれどもA64の命令多過ぎ(充実?)
Mnemonic | Source | Destination | Rounding mode |
---|---|---|---|
FCVTAS | FP | 符号付整数 | nearest with ties to away |
FCVTAU | FP | 符号無整数 | nearest with ties to away |
FCVTMS | FP | 符号付整数 | toward minus infinity |
FCVTMU | FP | 符号無整数 | toward minus infinity |
FCVTNS | FP | 符号付整数 | nearest with ties to even |
FCVTNU | FP | 符号無整数 | nearest with ties to even |
FCVTPS | FP | 符号付整数 | toward positive infinity |
FCVTPU | FP | 符号無整数 | toward positive infinity |
FCVTZS | FP | 符号付整数 | toward zero |
FCVTZU | FP | 符号無整数 | toward zero |
実験につかったアセンブリ言語記述の被テスト関数
例によって手抜きの関数プロローグ、エピローグ無の被テスト関数のソースが以下に。ターゲット機は例によって半精度浮動小数のサポートがなく、単精度か倍精度なので単精度だけ練習してます。手抜きだな、自分。
.globl fcvtas4V, fcvtau4V, fcvtms4V, fcvtmu4V, fcvtns4V, fcvtnu4V, fcvtps4V, fcvtpu4V, fcvtzs4V, fcvtzu4V .text .balign 4 fcvtas4V: ld1 {v0.4S, v1.4S}, [x0] fcvtas v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtau4V: ld1 {v0.4S, v1.4S}, [x0] fcvtau v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtms4V: ld1 {v0.4S, v1.4S}, [x0] fcvtms v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtmu4V: ld1 {v0.4S, v1.4S}, [x0] fcvtmu v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtns4V: ld1 {v0.4S, v1.4S}, [x0] fcvtns v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtnu4V: ld1 {v0.4S, v1.4S}, [x0] fcvtnu v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtps4V: ld1 {v0.4S, v1.4S}, [x0] fcvtps v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtpu4V: ld1 {v0.4S, v1.4S}, [x0] fcvtpu v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtzs4V: ld1 {v0.4S, v1.4S}, [x0] fcvtzs v0.4S, v1.4S st1 {v0.4S}, [x0] ret fcvtzu4V: ld1 {v0.4S, v1.4S}, [x0] fcvtzu v0.4S, v1.4S st1 {v0.4S}, [x0] ret
C言語記述のmain関数
上記のアセンブリ言語関数を呼び出すmain関数が以下に。
#include <stdio.h> #include <stdint.h> #include <float.h> #define MAXMEM (8) typedef union { float f; uint32_t u; int32_t s; } t32; t32 TargetMEM[MAXMEM]; extern void fcvtas4V(t32 *); extern void fcvtau4V(t32 *); extern void fcvtms4V(t32 *); extern void fcvtmu4V(t32 *); extern void fcvtns4V(t32 *); extern void fcvtnu4V(t32 *); extern void fcvtps4V(t32 *); extern void fcvtpu4V(t32 *); extern void fcvtzs4V(t32 *); extern void fcvtzu4V(t32 *); void initTGT() { TargetMEM[0].f = 0.0f; TargetMEM[1].f = 0.0f; TargetMEM[2].f = 0.0f; TargetMEM[3].f = 0.0f; TargetMEM[4].f = 2.5f; TargetMEM[5].f = 2.51f; TargetMEM[6].f = -2.5f; TargetMEM[7].f = -2.51f; } void initTGT2() { TargetMEM[0].f = 0.0f; TargetMEM[1].f = 0.0f; TargetMEM[2].f = 0.0f; TargetMEM[3].f = 0.0f; TargetMEM[4].f = 1.5f; TargetMEM[5].f = 1.51f; TargetMEM[6].f = -1.5f; TargetMEM[7].f = -1.51f; } void dumpTGTs(const char *arg) { printf("%s\n", arg); for (int i=0; i<4; i++) { printf("%02d: %f -(%s)-> %d\n", i, TargetMEM[i+4].f, arg, TargetMEM[i].s); } } void dumpTGTu(const char *arg) { printf("%s\n", arg); for (int i=0; i<4; i++) { printf("%02d: %f -(%s)-> %d\n", i, TargetMEM[i+4].f, arg, TargetMEM[i].u); } } int main(void) { initTGT(); fcvtns4V(TargetMEM); dumpTGTs("fcvtns"); initTGT(); fcvtnu4V(TargetMEM); dumpTGTu("fcvtnu"); initTGT(); fcvtas4V(TargetMEM); dumpTGTs("fcvtas"); initTGT(); fcvtau4V(TargetMEM); dumpTGTu("fcvtau"); initTGT2(); fcvtzs4V(TargetMEM); dumpTGTs("fcvtzs"); initTGT2(); fcvtzu4V(TargetMEM); dumpTGTu("fcvtzu"); initTGT2(); fcvtms4V(TargetMEM); dumpTGTs("fcvtms"); initTGT2(); fcvtmu4V(TargetMEM); dumpTGTu("fcvtmu"); initTGT2(); fcvtps4V(TargetMEM); dumpTGTs("fcvtps"); initTGT2(); fcvtpu4V(TargetMEM); dumpTGTu("fcvtpu"); return 0; }
実機実行結果の確認
以下のようにしてビルドして実行しています。
$ gcc -g -O0 simdFCVTxy.c simdFCVTxy.s $ ./a.out
-
- FCVTAy、FCVTNy
AwayのAとNearestのyを同じ入力値に対して適用してみました。こんな感じ。
-
- FCVTZy、FCVTMy、FCVTPy
丸めモードと符号付き、符号無での挙動の違い、全部分かった。ホントか?