8
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

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

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 をつけたときに警告がたくさんありすぎて修正しきれないときに使うとよさそうです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
8
Help us understand the problem. What are the problem?