gcc最適化(O1/O2)アセンブラ比較


アニメ『火ノ丸相撲』

格闘技の中で相撲が一番強いのでは、と思えてきます。倒れない足腰、カッコいいですねえ。

今回もアセンブラです。
gccの最適化オプションはたくさんあります。

       最適化オプション
              -fcaller-saves -fcse-follow-jumps -fcse-skip-blocks
              -fdelayed-branch -felide-constructors -fexpensive-optimizations
              -ffast-math -ffloat-store -fforce-addr -fforce-mem
              -finline-functions -fkeep-inline-functions -fmemoize-lookups
              -fno-default-inline -fno-defer-pop -fno-function-cse -fno-inline
              -fno-peephole -fomit-frame-pointer -frerun-cse-after-loop
              -fschedule-insns -fschedule-insns2 -fstrength-reduce
              -fthread-jumps -funroll-all-loops -funroll-loops -O -O2 -O3 -O0
              -Os

今回は、-O、-O1、-O2でコンパイルした時の、アセンブラコードを比較してみます。

-O、-O1の説明を読むと、

最適化オプション
       これらのオプションは様々な種類の最適化処理を制御します。

       -O

       -O1    最適化を行います。最適化コンパイルは幾分長めの処理時間と、大きな
              関数に対 する非常に多くのメモリを必要とします。

              `-O'  が指定されなかった場合は、コンパイラの目標はコンパイルのコ
              ストを  低減することや、目的の結果を得るためのデバッグを可能とす
              ることに置かれ    ます。それぞれの文は独立しています。つまり、ブ
              レークポイントでプログラムを  停止させることによって、任意の変数
              に新し  い値を代入したり、プログラムカウンタを他の文へと変更する
              ことを可能とし、  そのソースコードにプログラマが望む正しい結果を
              得ることを可能にします。


-Oと-O1は同じ意味のようです。
確認してみましょう。今回もこのソースです。

takk@deb9:~/tmp$ cat -n t.c
     1  int main()
     2  {
     3          int a=10;
     4          int b;
     5          if(a == 10)
     6                  b = 100;
     7          else
     8                  b = 200;
     9  }
takk@deb9:~/tmp$

-Oオプション指定時と、-O1指定時の出力アセンブラを比較します。

takk@deb9:~/tmp$ gcc -o t-O.s -S -O t.c
takk@deb9:~/tmp$ gcc -o t-O1.s -S -O1 t.c
takk@deb9:~/tmp$ diff t-O.s t-O1.s
takk@deb9:~/tmp$

差分なしです。manの通り-Oと-O1は同じオプションってことですね。

次は-O2オプション。

       -O2    さらに最適化を行います。サポートされている最適化手段のうち、  空
              間と速度のトレードオフを含まないものはほとんどの全て使用されま
              す。  例えばループのアンローリングや関数のインライン化は行われま
              せん。 -O と比較して、このオプションはコンパイル時間と生成コード
              の性能の双方を増加 させます。

-O1よりも、さらに最適化をするオプションのようです。

-O1と生成アセンブラを比較してみます。

takk@deb9:~/tmp$ gcc -o t-O2.s -O2 -S t.c
takk@deb9:~/tmp$ diff t-O.s t-O2.s
2c2,3
<       .text
---
>       .section        .text.startup,"ax",@progbits
>       .p2align 4,,15
8c9
<       movl    $0, %eax
---
>       xorl    %eax, %eax
takk@deb9:~/tmp$

-O/-O1では、eaxレジスタへ0を入れるときに、mov命令でeaxレジスタに0格納していますが、
-O2では、eaxレジスタをxor(排他的論理和)しています。同値をxorすると0になります。レジスタのみ使用する命令は、値が必要な命令よりも、効率的なのでしょう。xorを利用した初期化で最適化しているんですね。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA