LoginSignup
5
8

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-01-09

Cortex-M4のFPUでは単精度浮動小数点数しかサポートされていません。そのためC言語のソース上では可能な限りdoubleを使わずにfloatのみで書くことが望まれます。しかし、C言語の言語仕様として浮動小数点数はデフォルトでdoubleなので、ちょっとしたミスで内部的にdoubleで演算してしまうということが発生してしまいます。

もしもsqrtf() をsqrt() と書いてしまったら

前回の記事 gccでCortex-M4のsqrtf()の呼び出しの代わりにFPU命令一発のコードを出力をさせる方法 でsqrtfを扱いましたが、もしこれをsqrtとタイプミスしたらどうなるかを見てみます。

wrong_sqrt.c
#include <math.h>

float a(float x) 
{
    return sqrt(x);   // typo of sqrtf !!
}
arm-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Ofast wrong_sqrt.c
arm-eabi-objdump -d wrong_sqrt.o

このときコンパイラは何の警告メッセージも出してくれません!

00000000 <a>:
   0:   b508        push    {r3, lr}
   2:   ee10 0a10   vmov    r0, s0
   6:   f7ff fffe   bl  0 <__aeabi_f2d>
   a:   ec41 0b10   vmov    d0, r0, r1
   e:   f7ff fffe   bl  0 <sqrt>
  12:   ec51 0b10   vmov    r0, r1, d0
  16:   f7ff fffe   bl  0 <__aeabi_d2f>
  1a:   ee00 0a10   vmov    s0, r0
  1e:   bd08        pop {r3, pc}

ぎゃああ。
せっかく速いコードを生成しようとしたのに台無し。
floatからdoubleに変換して、doubleのsqrtを呼び出し、doubleからfloatに変換するというコードになっています。
しかもこれらはFPUでは処理できないので全てソフトウェアのライブラリで行っています。
演算結果としてはほぼ同じですが、処理速度はとても遅いはずです。
このように逆アセンブル表示しない限り発見のしにくいバグになりそうです。

役に立ちそうなgccの警告オプション

-Wfloat-conversion

doubleからfloatに暗黙で変換されたときに警告します。明示的にキャストした場合は大丈夫。

-Wdouble-promotion

内部演算でfloatからdoubleに暗黙の変換があったといに警告します。(しかしdoubleの関数の引数にfloatを渡したときには警告されないようです。)

-Wunsuffixed-float-constants

浮動小数点数の定数に型を示すサフィックスが無いときに警告します。

これらのオプションをつけてコンパイルしてみる

さきほどのwrong_sqrt.cでは

arm-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Ofast -Wdouble-promotion -Wfloat-conversion -Wunsuffixed-float-constants wrong_sqrt.c
wrong_sqrt.c: In function ‘a’:
wrong_sqrt.c:5:9: warning: conversion to ‘float’ from ‘double’ may alter its value [-Wfloat-conversion]
  return sqrt(x);
         ^~~~~~~

警告出ました。

さらに、gccのマニュアルに載っている例ですが、

f2.c
float area(float radius)
{
   return 3.14159 * radius * radius;
}

本来は 3.14159f と書くべきところでfを忘れています。そのために無駄なfloat<->doubleの変換が発生してしまっています。

arm-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Ofast -Wdouble-promotion -Wfloat-conversion -Wunsuffixed-float-constants f2.c
f2.c: In function ‘area’:
f2.c:3:4: warning: unsuffixed float constant [-Wunsuffixed-float-constants]
    return 3.14159 * radius * radius;
    ^~~~~~
f2.c:3:19: warning: implicit conversion from ‘float’ to ‘double’ to match other operand of binary expression [-Wdouble-promotion]
    return 3.14159 * radius * radius;
                   ^
f2.c:3:28: warning: implicit conversion from ‘float’ to ‘double’ to match other operand of binary expression [-Wdouble-promotion]
    return 3.14159 * radius * radius;
                            ^
f2.c:3:28: warning: conversion to ‘float’ from ‘double’ may alter its value [-Wfloat-conversion]
    return 3.14159 * radius * radius;
~~~~~~~~~~~~~~~~~^~~~~~~~

警告出ました。

gccの警告メッセージに関するコマンドラインオプションについてはこちらを参照してください。
https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Warning-Options.html#Warning-Options

追記 (2018.1.12)

最適化オプションで -fsingle-precision-constant というものを見つけました。
これは浮動小数点数の定数のデフォルトの型をdoubleからfloatに変更します。
https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Optimize-Options.html#Optimize-Options
-Wunsuffixed-float-constants をつけたときに警告がたくさんありすぎて修正しきれないときに使うとよさそうです。

5
8
1

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
5
8