第20回 GCC2.95から追加変更のあったオプションの補足と検証(その8)

岸 哲夫

 今回も引き続きGCC2.95から追加変更のあったオプションの補足と検証を行う.今回は,「最適化オプション」について扱う.最適化オプションには,ここで紹介するほかにも“SSA”(Static Single Assignment)の試験サポートがある.これに関しては最適化オプションの最後に説明する.(筆者)

space

-fnew-ra

 このオプションは試験的に提供されたものですが,どうやら失敗作だったようです.処理を遅くするだけのコードを生成するようで,評価は良くありません.これを再度評価する意味もなさそうなので,検証は行いません.

-fno-guess-branch-probability

 分岐予測による最適化を行わず,同一のソースをコンパイルしたときに,つねに同じアセンブラ・コードを生成するように指定するオプションです.分岐の予測を行う最適化が行われた際,場合によっては同じソースから別のコードが生成されることがあります.それが組み込みシステムの設計に影響を及ぼすこともあるので,それを防止します.

-fno-inline

 キーワードinlineを無視します.このオプションは,関数のインライン展開をいっさい行わせないために使われます.メリットは,メモリが少ないという理由で実行コードが不安定な場合,実行が安定するという点です.

 オプションの指定の方法は次のとおりです.

  • 指定なし

  •   gcc test226.c -S -finline

  • 指定あり

  •   gcc test226.c -S -fno-inline

 ソースと生成されたコードをリスト1リスト5に示します.

 単純にaをインクリメントしている関数test1は-finlineではソース中に展開されていますが,-fno-inlineの指定では関数として存在しています.

-fno-branch-count-reg

 たとえば,古いソースと新しいソースをリンクしたいときに古いソースの中に関数「test1」が存在して,新しいソースの中にも関数「test1」が存在している場合には,新しいソース中の関数にinlineキーワードを付加し,オプション-finlineを付けることによってシンボル・リストからも名前を消すことができ,正常にリンクすることが可能です.

 リスト6リスト7の例ではエラーになります.コンパイル時のようすを下記に示します.

  $ gcc test228.c test227.c -o test227.o 
                   -finline
  /tmp/cc8cJJqr.o(.text+0x0)
                   : In function `test1':
  : multiple definition of `test1'
  /tmp/ccSOBchX.o(.text+0x0)
                   : first defined here
  /usr/bin/ld: Warning: size of symbol 
`test1' changed from 16 in /tmp/ccSOBchX.o 
                   to 23 in /tmp/cc8cJJqr.o
  collect2: ld  1 
  $ 

 しかし,リスト7とリスト8の例では問題ありません.コンパイル時および実行時のようすを下記に示します.

  $ gcc test228.c test229.c -o test227
  $ ./test227
  1
  2
  100
  $ 

 リスト9に示すオブジェクト・ダンプを見ると,二つの関数test1は別のアドレスとして認識されています.test229.c中のtest1はローカル関数として扱われています.

  $ gcc test228.c test229.c -o test227 -O3
  $ objdump -D test227 > test227a.txt

 最適化オプション-O3を付加すると,ソース中の関数を効率が上がるならばインライン展開するように最適化します(リスト10).

 その結果,test228.c中の関数test1をインライン展開しています.

 インライン展開は,ソース単位のコードに対して行われます.つまり,extern関数はインライン展開されません.関数に__inlineを指定した場合,ほかのソースからは呼び出せなくなります.

-fno-math-errno

 このオプションを指定すると数値演算後のエラー・チェックを行いません.よってループ中にそのコードがあった場合には.指定すると多少速くなるでしょう.

-fno-peephole

 このオプションを指定すると「のぞき穴」最適化を行いません.-fno-peephole2も同様です.マシン固有の最適化や,比較的細かい最適化を行わないようにします.この最適化によって,冗長な処理または変数が排除された場合に,このコードとリンクした別の単位のコードに影響をおよぼすおそれがあります.そんなときは冗長なコードを排除しないように,このオプションを付ければ問題は起きません.

 リスト11を例にして最適化のようすを示します.

 関数のアドレスをレジスタに置かないようにします.ある関数を呼び出す命令は,それぞれ関数のアドレスを明示的に保持するようにします.

  $gcc test230.c -O -S

 リスト12に,最適化-Oで生成されたアセンブラ・ソースを示します.

  $gcc test230.c -fno-peephole -S

 リスト13に,「のぞき穴」最適化を禁止して生成されたアセンブラ・ソースを示します.

  $gcc test230.c -O3 -S

 リスト14に,最適化-O3で生成されたアセンブラ・ソースを示します.

 このように,リスト13には冗長なコードが残っています.最適化を強くすればするほど冗長なコードは整理されます.

-fno-sched-interblock

 ターゲット・マシン上でこのフラグがサポートされている場合,必要なデータを利用可能になるまで待つことによる実行の遅延を防ぐために,命令の順番の変更を行うことができますが,デバッグが難しくなってしまいます.

 このオプションをデバッグ中に指定しておけば,GDBなどのデバッグ・ツールで混乱することもなく,正常にデバッグできます.

-fno-sched-spec,-fsched-spec-load,-fsched-spec-load-dangerous

 このオプションも同様です.

-fno-trapping-math

 このオプションを指定すると浮動小数点式のトラップを生成しません.ただし,本当に生成しなくて良いのか,よく考えて使用してください.

 最適化の例となるプログラムをリスト15に示します.

  • 生成するコンパイル・オプション(リスト16

  •   $ gcc test231.c -ftrapping-math -S

  • 生成しないコンパイル・オプション(リスト17

  •   $ gcc test231.c -ffast-math -fomit-frame
                       -pointer -O3

-fno-zero-initialized-in-bss

 このオプションは本来はBSSセクションに置かれた定数をゼロ・クリアしないためのものですが,無視されているようです.

 BSSセクションに置いたものは,必ず初期化されるようです.初期化されたくない場合は,別の方法で行うべきです.

 テスト・プログラムをリスト18に示します.

  • 初期化するコンパイル・オプション(リスト19

  •   $ gcc test232.c -S -fno-zero-initialized
                       -in-bss -fno-common

  • 初期化しないコンパイル・オプション(リスト20

  •   $ gcc test232.c -S -fzero-initialized-in
                       -bss -fno-common

 また,オブジェクトのダンプをリスト21に示します.

 このオプションを指定してもしなくてもアセンブラ・ソース中でゼロ・クリアされています.このオプションの意味がなくなったのか,バグなのかわかりませんが,あまり使わない処理なのかもしれません.

*          *

 次回も引き続き「最適化オプション」の補足を行います.


NEW記事内インデックス    連載インデックスはこちら   Interfaceのトップ
◆最適化オプション
リスト
リスト(続き)

Copyright 2004 岸 哲夫

Copyright 1997-2004 CQ Publishing Co.,Ltd.