4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

gccでCortex-M4のsqrtf()の呼び出しの代わりにFPU命令一発のコードを出力をさせる方法

Last updated at Posted at 2018-01-09

先日, twitterでgccでCortex-M4のsqrtf()の呼び出しの代わりにFPU命令一発のコードを出力をさせる方法のことが話題に上っていて、少し調べたのですが、せっかくなのでブログにまとめておくことにしました。
なお, 私にとって初のQiita投稿です。

最初に結論

test_sqrtf.c
#include <math.h>

float a(float x) 
{
	return sqrtf(x);
}

これを以下のようにコンパイルして生成されたコードを見ると

arm-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Ofast test_sqrtf.c 
arm-eabi-objdump -d test_sqrtf.o
00000000 <a>:
   0:	eeb1 0ac0 	vsqrt.f32	s0, s0
   4:	4770      	bx	lr
   6:   bf00     	nop

このように、sqrtf()の呼び出しの代わりにvsqrt.f32のFPU命令をひとつ実行するだけになります。
以降は試行錯誤した経緯や、詳細など。

Cortex-M4向けのコンパイルオプション

-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16

Cortex-M4のFPUはARMの他のものと違って、単精度の浮動小数点数しか扱えません。-mfpu=fpv4-sp-d16 を忘れずに。

arm-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 test_sqrtf.c

これでコンパイルするとこうなりました。

00000000 <a>:
   0:	b580      	push	{r7, lr}
   2:	b082      	sub	sp, #8
   4:	af00      	add	r7, sp, #0
   6:	ed87 0a01 	vstr	s0, [r7, #4]
   a:	ed97 0a01 	vldr	s0, [r7, #4]
   e:	f7ff fffe 	bl	0 <sqrtf>
  12:	eef0 7a40 	vmov.f32	s15, s0
  16:	eeb0 0a67 	vmov.f32	s0, s15
  1a:	3708      	adds	r7, #8
  1c:	46bd      	mov	sp, r7
  1e:	bd80 		pop {r7, pc}

sqrtf()はそのまま関数呼び出しとして残っています。

最適化オプション -O をつけてみる

arm-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O test_sqrtf.c 
00000000 <a>:
   0:	b508      	push	{r3, lr}
   2:	ed2d 8b02 	vpush	{d8}
   6:	eeb1 8ac0 	vsqrt.f32	s16, s0
   a:	eeb5 0a40 	vcmp.f32	s0, #0.0
   e:	eef1 fa10 	vmrs	APSR_nzcv, fpscr
  12:	d404      	bmi.n	1e <a+0x1e>
  14:	eeb0 0a48 	vmov.f32	s0, s16
  18:	ecbd 8b02 	vpop	{d8}
  1c:	bd08      	pop	{r3, pc}
  1e:	f7ff fffe 	bl	0 <sqrtf>
  22:  	e7f7  	 	b.n 14  	<a+0x14>

おお、FPU命令のvsqrt.f32が出ました!
でもなんかコードが長いし、sqrtf()の関数呼び出しも残ってる。
よくコードを見てみると、sqrtfの引数が負のときにsqrtf()を呼ぶようになっています。
これは、sqrtfの引数が負の場合にはエラーになり、変数errnoにエラーコードをセットするなどのエラー処理をする必要があります。そのためにライブラリ関数のsqrtf()を呼ぶのです。

しかし、マイコンのプログラミングの場合には変数errnoのセットはいらないから、少しでも速く短いほうがいいということも多いと思います。このように浮動小数点演算の厳密さよりも速さを優先したい場合にうってつけのコンパイルオプションが -ffast-math です。
そして、 -Ofast というのは -O3 -ffast-math と同じ意味です。

最適化オプション -Ofast をつけてみる

arm-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Ofast test_sqrtf.c 

これで冒頭のようなすっきりしたコードになります。

続き

Cortex-M4でFPU演算をするときにつけておきたいgccの警告オプション

参考

使用したgccはgcc-linaro-7.2.1-2017.11-x86_64_arm-eabi で以下のサイトからダウンロードしました。
https://releases.linaro.org/components/toolchain/binaries/latest/arm-eabi/
この記事で使ったコードはgistにも貼っておきました。
https://gist.github.com/tetsu-koba/5a174de0b146cb76b50e459d69800928
gccの最適化オプションについてはこちらを参照してください。
https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Optimize-Options.html#Optimize-Options

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?