今日の雑記

生きることでいっぱいいっぱい

GCC の最適化

ちょっと前のネタですが。新堂さんちから。
Hena Hena Nikki http://quruli.ivory.ne.jp/diary/?date=20060819#p04

ずっと SH でソフトウェア開発している方に、「for ループはインクリメントよりデクリメントの方が速いよ」と言われ、実験してみた。

ふーんそうなんだー?と思いつつ、ボクの環境(Windows2000/Cygwin)で試してみた。gcc のバージョンは 3.4.4.


#include

static const int loop_max = 1000000;

int loop_function_inc(void)
{
int i, ret = 0;

for( i = 0; i < loop_max; i++){
ret++;
}

return ret;
}

int loop_function_dec(void)
{
int i, ret = 0;

for( i = loop_max; i > 0; i--){
ret++;
}

return ret;
}

int main(int argc, char *argv[])
{
printf("inc loop ret = %d", loop_function_inc());
printf("dec loop ret = %d", loop_function_dec());

return 0;
}

これを新堂さんと同様に gcc -O2 main.c -S して main.s を開くと...。

.p2align 4,,15
.globl _loop_function_inc
.def _loop_function_inc; .scl 2; .type 32; .endef
_loop_function_inc:
pushl %ebp
movl $999999, %eax
movl %esp, %ebp
.p2align 4,,15
L5:
decl %eax
jns L5
popl %ebp
movl $1000000, %eax
ret

.p2align 4,,15
.globl _loop_function_dec
.def _loop_function_dec; .scl 2; .type 32; .endef
_loop_function_dec:
pushl %ebp
movl $1000000, %eax
movl %esp, %ebp
.p2align 4,,15
L13:
decl %eax
testl %eax, %eax
jg L13
popl %ebp
movl $1000000, %eax
ret
本当だ。「loop_function_inc」のループ変数が加算から減算になってる。
まあこのサンプルは簡単なループなので、ループ内で関数呼び出ししたりとかするとまた変わった結果になるんだろうけど。後ループ変数の使い方次第でも変わるでしょうし。
考えられることとしては、減算にすることで直後に比較ジャンプ命令(上記で言うところの "jns" や "jg")がそのまま記述できる点か(というかそれしか思いつかない)。加算だと該当する値と比較する必要があるし("cmpl $1000000, %eax" とかみたいな)。
ん?ということは...?

#include

static const int loop_min = 100;
static const int loop_max = 1000000;

int loop_function_inc(void)
{
int i, ret = 0;

for( i = loop_min; i < loop_max; i++){
ret++;
}

return ret;
}

int loop_function_dec(void)
{
int i, ret = 0;

for( i = loop_max; i > loop_min; i--){
ret++;
}

return ret;
}

int main(int argc, char *argv[])
{
printf("inc loop ret = %d", loop_function_inc());
printf("dec loop ret = %d", loop_function_dec());

return 0;
}

こんなソースを用意して hogehoge してみるとどうなる...?

.p2align 4,,15
.globl _loop_function_inc
.def _loop_function_inc; .scl 2; .type 32; .endef
_loop_function_inc:
pushl %ebp
movl $999899, %eax
movl %esp, %ebp
.p2align 4,,15
L5:
decl %eax
jns L5
popl %ebp
movl $999900, %eax
ret

.p2align 4,,15
.globl _loop_function_dec
.def _loop_function_dec; .scl 2; .type 32; .endef
_loop_function_dec:
pushl %ebp
movl $1000000, %eax
movl %esp, %ebp
.p2align 4,,15
L13:
decl %eax
cmpl $100, %eax
jg L13
popl %ebp
movl $999900, %eax
ret
「_loop_function_inc」の方は、わざわざループ初期値を調整してる。「_loop_function_dec」の方はさすがに比較命令が入ってますねえ。
最適化って、色々頑張ってるなあ。そんな話。