ぐだぐだ低レベルプログラミング(17) Arm NEONを使ってみる2

JosephHalfmoon

ぐだぐだです。前回は、NEONを使ってみると書いておりましたが、今日見直してみれば、本当の意味のNEONじゃありませんでした。すみません。最近では、ArmのVFP(Vector Floating Point. 一応「ベクトル」計算機だったのね)は、NEONお供というか補完用の命令セットでなっているみたいです。NEONが1レジスタに複数の要素を入れて同時に処理できるのに比べるとVFPはパイプライン方式のベクトル化(昔はこれが本道だったような気もしますが)。1レジスタには1要素であります。こちらの命令が生成されていた。ま、今じゃNEONの一部と言えないこともないですが、狙いは1レジスタに複数要素のSIMDなので違う。狙い通りのコードを生成するにはどうするの?

それで、gccの NEON関係のオプションを調べてみましたぜ。ちなみに対象は、以下のバージョンです。

$ gcc --version
gcc (Raspbian 8.3.0-6+rpi1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

さて、NEONが使用するレジスタの幅を制御してくれそうなオプションはと言えば、

  • -mneon-for-64bits
  • -mvectorize-with-neon-double
  • -mvectorize-with-neon-quad

この辺のオプションは、ターゲットスペシフィックのところに入っとります。さて、上から総当たりで確かめてみます。

最初の -mneon-for-64bits です。gccの説明を引用させていただくと、

Use Neon to perform 64-bits operations rather than core registers.

とあります。64ビット幅、レジスタ名としては、d0とか、dのつくレジスタが使われるような気がします。前回のサンプルをばコンパイルしてみれば

確かに、d付きのレジスタ操作(=NEON命令)が織り込まれてくるのですが、肝心の掛け算部分は、sから始まる32ビットレジスタ名、これは中途半端だ。演算する肝心の部分を64ビットでdチョメチョメとか、64ビット2本つなげて128ビットのqチョメチョメという名前で扱ってもらいたいのに。

その次、-mvectorize-with-neon-doubleはどうか、これまたgccのhelpを引用させていただくと、

Use Neon double-word (rather than quad-word) registers for vectorization.

です。期待が高まります。これに違いない!期待どおりにやってくれるか?

おっと、駄目です。がっかりだ。これはイケない。-mvectorize-with-neon-quadもやってみますが、駄目。どうも、これらの指定だけでは不足ということか。苦し紛れの全般的なオプション、浮動小数点計算にムチを入れるやつ。

-ffast-math

どうでしょう。これまたhelpを引用させていただくと、恐ろしいことに、このオプションは、

This option lacks documentation.

とあります。しかし、

-mvectorize-with-neon-double -ffast-math

とすると、とうとう現れました。64ビット幅のNEON命令が。

vmul.f32 d16, d16, d17

-mvectorize-with-neon-quad -ffast-math

ならばどうでしょうか。

vmul.f32 q8, q8, q9

おお、ようやくNEONらしいコードを得ました。しかし、逆アセンブルリストを眺めてみれば、かなり複雑。前回のコードのシンプルさは無し。この解析はまた次回。

ぐだぐだ低レベルプログラミング(16) Arm NEONを使ってみる1

ぐだぐだ低レベルプログラミング(18) Arm NEONを使ってみる3