前回、浮動小数の積和演算はfused演算だということで、fused演算とそうでない計算の微妙な差を味わいました。今回は残りの積和演算命令を一気にやってみます。というか4つ並べて実行してその差をみるとようやく4個ある意味が良く分かるから。A64の命令多すぎるからさっさとやりたいというのも心の底にあり?
※「ぐだぐだ低レベルプログラミング」投稿順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
浮動小数点(スカラー)の4種積和演算命令
FMADD、FMSUB、FNMADD、FNMSUBと浮動小数の積和演算命令のニーモニックを上げていくと何だかサッパリなのですが、以下の表にまとめたらスッキリ。ホントか?
命令 | 積算(和)レジスタ | 乗算ソース1 | 乗算ソース2 |
---|---|---|---|
FMADD | — | — | — |
FMSUB | — | NEG | — |
FNMADD | NEG | NEG | — |
FNMSUB | NEG | — | — |
積和演算命令には3つのソースレジスタ指定がありますが、上記のようにそのうち2つをネゲート(符合反転)するか否かの組み合わせなんであります。つまるところは。前回 fused演算で使ったFMADDはまったくネゲートしない「プレイン風味」だと。
勿論、4つすべて fused演算です。
今回実験のアセンブリ言語関数
いつものように手抜きな、関数プロローグもエピローグもない1命令1関数スタイルです。倍精度も単精度もおなじようなもんだと踏みつぶして、単精度だけで実験しています。ほんと手抜き。また丸めについてはfpcr指定の「成り行き」で適用されます。デフォルトでは最近接awayの筈。
.globl fmaddS, fmsubS, fnmaddS, fnmsubS .text .balign 4 fmaddS: fmadd s0, s1, s2, s3 ret fmsubS: fmsub s0, s1, s2, s3 ret fnmaddS: fnmadd s0, s1, s2, s3 ret fnmsubS: fnmsub s0, s1, s2, s3 ret
C言語記述のmain関数
これまた手抜きなC言語記述のテスト駆動部が以下に。前回のfused計算で使った数字の組み合わせをそのまま流用してます。そのせいで数字がなんか微妙。今回は4種命令に全て同じ引数を与えているので、その差が一目瞭然な筈。
#include <stdio.h> #include <stdint.h> extern float fmaddS(float, float, float, float); extern float fmsubS(float, float, float, float); extern float fnmaddS(float, float, float, float); extern float fnmsubS(float, float, float, float); int main(void) { float fin; union { float s; uint32_t u; } u32a, u32b, u32c, u32d; fin = 0.0009992f; u32a.s = fmaddS (0.0f, fin, 1.1f, 0.000003f); u32b.s = fmsubS (0.0f, fin, 1.1f, 0.000003f); u32c.s = fnmaddS (0.0f, fin, 1.1f, 0.000003f); u32d.s = fnmsubS (0.0f, fin, 1.1f, 0.000003f); printf ("fmadd =%2.8f(%08x)\n", u32a.s, u32a.u); printf ("fmsub =%2.8f(%08x)\n", u32b.s, u32b.u); printf ("fnmadd=%2.8f(%08x)\n", u32c.s, u32c.u); printf ("fnmsub=%2.8f(%08x)\n", u32d.s, u32d.u); return 0; }
実行結果
ビルドして実行したものが以下に。前回の流用コードなので%fでも無用に長めの10進浮動小数表示しているだけでなく、()内に16進表記も併記しております。
上記結果の検算を行うために表計算ソフトにお願いしました。DST、一致しておりますぞ。
念のため、表計算ソフトに入力した計算式が以下です。最初の表のとおりです。
積和算4種の差は分かった。ホントか?