2009年07月07日

gccのビルトイン関数 (数学関数)

前回に続いてもう少しgccのビルドイン関数を見ていきます。

gccはとてもたくさんのビルトイン関数があります。

オンラインマニュアルのこのページにリストがあります。

http://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Other-Builtins.html#Other-Builtins

標準の数学関数はほとんどがビルトイン関数になっています。引数が定数の場合にはコンパイル時に計算されてしまいます。

具体例を見てみましょう。



#include 

double sin0()
{
    return sin(0.0);
}

double sqrt3()
{
    return sqrt(3.0);
}

これをコンパイルした時に生成されるコードは以下の通り。

(ARMのコードです。見やすくするために -O オプションをつけました。)

        ...
sin0:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	mov	r0, #0
	mov	r1, #0
	bx	lr
	.size	sin0, .-sin0
	.align	2
	.global	sqrt3
	.type	sqrt3, %function
sqrt3:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	ldr	r0, .L5
	ldr	r1, .L5+4
	bx	lr
.L6:
	.align	2
.L5:
	.word	-396866390
	.word	1073460858
	.size	sqrt3, .-sqrt3
	.ident	"GCC: (GNU) 4.3.3"

ライブラリのdouble sin(double) も double sqrt(double) も呼ばれません。コンパイル時に計算しておいた値を取り出してきて返しています。

ARMではVFPの命令でsqrtを計算できます。

#include 

double sqrt_n(int n)
{
    return sqrt(n);
}

これはこんなコードが出ます。

        ...
sqrt_n:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	str	lr, [sp, #-4]!
	sub	sp, sp, #4
	fmsr	s15, r0	@ int
	fsitod	d6, s15        # intからdoubleに変換
	fsqrtd	d7, d6         # VFPのsqrt命令
	fcmpd	d7, d7
	fmstat
	beq	.L2
	fmrrd	r0, r1, d6
	bl	sqrt           # ライブラリのsqrt呼び出し
	fmdrr	d7, r0, r1
.L2:
	fmrrd	r0, r1, d7
	add	sp, sp, #4
	ldmfd	sp!, {pc}

VFPのsqrt命令の後に何やら比較をして再度ライブラリのsqrtを呼び出すようなコードが出ています。これはどういうことでしょう?

sqrtは引数が負の値の場合は結果がNaNになります。NaNとNaNの比較は偽になると定義されています。

	fcmpd	d7, d7
	fmstat
	beq	.L2

この部分では d7がNaNかどうかのチェックをしています。

NaNでなければ、その結果を返します。

NaNの場合にはライブラリのsqrtを呼び出すことで、エラー処理(変数errnoに値をセットするなど)がなされるようになっています。

(追記 2009.7.10)

同じプログラムに -fno-math-errno をつけると以下のようなすっきりしたコードが生成されます。

sqrt_n:
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        @ link register save eliminated.
        fmsr    s12, r0 @ int
        fsitod  d7, s12
        fsqrtd  d6, d7
        fmrrd   r0, r1, d6
        bx      lr

errnoをチェックしない場合はこっちの方がいいですね。

-fno-math-errno に関してはこちらを。

http://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Optimize-Options.html#Optimize-Options



トラックバックURL

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード