« 画像フォーマットの変更(automator) | メイン | アフィン変換とBresenham »

コンパイラの癖を知る

 コンパイルした後はコンパイラが吐き出したアセンブリコードを見る習慣を付けよと日々申しておりますが(嘘)、今回はちょっとした癖のお話。

 下のプログラムと Xcode 2.4.1(powerpc-apple-darwin8-gcc-4.0.1) でコンパイルした結果。

void copy1( int bytes, const int * a, int * b )
{
	int count = bytes;

	count /= sizeof(int);
	if ( count > 0 ) printf( "foo\n" );
	
	for ( ; count > 0; count--, a++, b++ )
	{
		*b = *a;
	}
}

void copy2( int bytes, const int * a, int * b )
{
	int count = bytes;

	if ( count > sizeof(int) ) printf( "foo\n" );
	
	for ( count /= sizeof(int); count > 0; count--, a++, b++ )
	{
		*b = *a;
	}
}
_copy1:
……省略……
L4:
	lwz   r0,  0(r30)  ; r0 = *a
	addi  r29, r29, -1 ; count--
	addi  r30, r30, 4  ; a++
	cmpwi cr4, r29, 0  ; cr4 = count > 0
	stw   r0,  0(r31)  ; *b = r0
	addi  r31, r31, 4  ; b++
L8:
	bgt   cr4, L4      ; if (count > 0) goto L4
……省略……

_copy2:
L14:
	lwz  r0,  0(r30) ; r0 = *a
	addi r30, r30, 4 ; a++
	stw  r0,  0(r31) ; *b = r0
	addi r31, r31, 4 ; b++
L13:
	bdnz L14         ; if (--count > 0) goto L14
……省略……

 違いは一目瞭然。
 途中の if (...) printf() のくだりは帯域的な最適化がかかりにくくなるように、わざと count の計算と for() の間に挟んだ物。

 実は Xcode のデフォルトの Release の最適化オプション「最も高速で最小(-Os)」でのみ起こり、-O1 から -O3 では copy1 は copy2 と同じコードを吐く。
 現実にはこのような些細な違いで速度に影響は出てこないが、日頃からコンパイラの出力を見る癖を付けておくと、こういった癖に気づいたり最適化の勉強になったりするはず。

 <独り言>Visual C++ なんかは割と賢く最適化してくれるが、出力を見ているとレジスタが余っているのに極力最小限のレジスタで済まそうとしていて時にイラっと来る事も。</独り言>

トラックバック

このエントリーのトラックバックURL:
http://yoffy.dyndns.org/cgi-bin/mt/mt-tb.cgi/525

コメントを投稿

About

2006年11月27日 02:14に投稿されたエントリーのページです。

ひとつ前の投稿は「画像フォーマットの変更(automator)」です。

次の投稿は「アフィン変換とBresenham」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.35