GCC4.0.0で遊ぶ
帰宅も遅かったし新たなネタをやるのは自粛して、GCCで遊んでみます。
お題はこんなソースコード。所謂末尾再帰ってやつですね。
末尾再帰はループで表わせるので、ループっぽいアセンブラコードを吐いてくれると嬉しいのですけど。果たして。
int add(int n) { if (n <= 1) { return n; } return n * add(n - 1); }
gcc 3.4.2 -O3 -march=athlon-xp での結果。
_Z3addi: pushl %ebp movl %esp, %ebp pushl %ebx subl $4, %esp movl 8(%ebp), %ebx cmpl $1, %ebx movl %ebx, %eax jle .L1 leal -1(%ebx), %eax movl %eax, (%esp) call _Z3addi imull %ebx, %eax .L1: addl $4, %esp popl %ebx leave ret
うーん、最高に面白くないコードですね。
gcc 4.0.0 -O3 -march=athlon-xp での結果。
_Z3addi: pushl %ebp movl %esp, %ebp subl $40, %esp movl %ebx, -12(%ebp) movl 8(%ebp), %ebx movl %esi, -8(%ebp) movl %edi, -4(%ebp) cmpl $1, %ebx jle .L2 leal -1(%ebx), %esi cmpl $1, %esi jle .L4 leal -2(%ebx), %edi cmpl $1, %edi jle .L6 leal -3(%ebx), %eax movl %eax, -36(%ebp) decl %eax jle .L8 leal -4(%ebx), %eax movl %eax, -32(%ebp) decl %eax jle .L10 leal -5(%ebx), %eax movl %eax, -28(%ebp) decl %eax jle .L12 leal -6(%ebx), %eax movl %eax, -24(%ebp) decl %eax jle .L14 leal -7(%ebx), %eax movl %eax, -20(%ebp) decl %eax jle .L16 leal -8(%ebx), %eax movl %eax, -16(%ebp) decl %eax jle .L18 leal -9(%ebx), %eax movl %eax, (%esp) call _Z3addi imull -16(%ebp), %eax movl %eax, -16(%ebp) .L18: movl -20(%ebp), %eax imull -16(%ebp), %eax movl %eax, -20(%ebp) .L16: movl -24(%ebp), %eax imull -20(%ebp), %eax movl %eax, -24(%ebp) .L14: movl -28(%ebp), %eax imull -24(%ebp), %eax movl %eax, -28(%ebp) .L12: movl -32(%ebp), %eax imull -28(%ebp), %eax movl %eax, -32(%ebp) .L10: movl -36(%ebp), %eax imull -32(%ebp), %eax movl %eax, -36(%ebp) .L8: imull -36(%ebp), %edi .L6: imull %edi, %esi .L4: imull %esi, %ebx .L2: movl %ebx, %eax movl -8(%ebp), %esi movl -12(%ebp), %ebx movl -4(%ebp), %edi leave ret
頑張っている感が出てます。
更にもっと頑張ってみましょう。(あんまり考えずにオプション入れてます)
g++-4.0.0 -O3 -march=athlon-xp -ftree-based-profiling -ftree-dominator-opts -ftree-lrs -ftree-ccp -ftree-ch -ftree-combine-temps -ftree-loop-im -ftree-loop-ivcanon -ftree-loop-linear -ftree-loop-optimize -ftree-vectorize
_Z3addi: pushl %ebp movl %esp, %ebp subl $40, %esp movl %ebx, -12(%ebp) movl 8(%ebp), %ebx movl %esi, -8(%ebp) movl %edi, -4(%ebp) cmpl $1, %ebx jg .L22 .L2: movl %ebx, %eax movl -8(%ebp), %esi movl -12(%ebp), %ebx movl -4(%ebp), %edi leave ret .L22: leal -1(%ebx), %esi cmpl $1, %esi jg .L23 imull %esi, %ebx jmp .L2 .L23: leal -2(%ebx), %edi cmpl $1, %edi jg .L24 imull %edi, %esi .L26: imull %esi, %ebx jmp .L2 .p2align 4,,7 .L24: leal -3(%ebx), %eax movl %eax, -36(%ebp) decl %eax jg .L25 imull -36(%ebp), %edi (中略) .L32: leal -9(%ebx), %eax movl %eax, (%esp) call _Z3addi imull -16(%ebp), %eax movl %eax, -16(%ebp) jmp .L18
うぬ、かなりお腹一杯です。果たしてこれって差が出るんでしょうか?
ということで1000!を1000万回実行した結果です。
- 4.14 sec gcc 4.0.0 -O3 -march=athlon-xp
- 4.45 sec gcc 4.0.0 -O3 -march=athlon-xp -ftree-...
- 6.59 sec gcc 3.4.2 -O3 -march=athlon-xp
ということで下手にtree_ssa周りをonにすると痛い目を見るよという結果になりました。がっくし。(T_T)
しかしgcc 4.0.0は賢いなぁと再認識する結果となりました。
可能ならばループに展開してくれると最高なんですけどね。
ちなみにループで実装するとこんな感じ。
- 0.96 sec gcc 3.4.2 -O3 -march=athlon-xp
- 1.41 sec gcc 4.0.0 -O3 -march=athlon-xp -ftree-...
- 1.42 sec gcc 4.0.0 -O3 -march=athlon-xp
あれ?なんかgcc4.0.0負けてますけど...、細かいことは気にしないで寝よう。