[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.8 最適化オプション

以下のオプションは色々な種類の最適化を制御する。

-O
-O1

最適化を行なう。最適化を行なうコンパイルには幾らか余計に時間がかかり、 大きな関数についてはたくさんのメモリを余計に使う。

-O’ を指定しない場合は、コンパイラの目標はコンパイルのコストを 小さくすることとデバッグが期待どおりの結果にすることである。 各文は独立している。文と文の間にブレークポイントを設定してプログラムを 止めたとき、どの変数にも新たな値を代入できるし、プログラムカウンタを 変更して、その関数内の他のどの文にも飛ばすことができ、そして ソースコードから期待できる結果と全く同じものが得られる。

-O’ を指定しないと、register 宣言した変数しか レジスタに割り当てない。 コンパイル結果のコードは、‘-O’ なしの PCC で作られるよりも やや悪い。

-O’ を指定すると、コードサイズと実行時間を小さくしようとする。

-O’ を指定すると、全機種で ‘-fthread-jumps’ と ‘-fdefer-pop’ を有効にする。遅延スロットのある機種では ‘-fdelayed-branch’ をオンにし、フレームポインタなしでも デバッグをサポートできる機種では ‘-fomit-frame-pointer’ を オンにする。機種によっては、他のオプションをオンにするものもある。

-O2

さらなる最適化を行なう。 GCC は、スペース-速度のトレードオフを含まないほとんど全ての 最適化を実行する。 ‘-O2’ を指定した場合は、ループ展開や関数のインライン展開を 行なわない。 ‘-O’ と比べると、このオプションはコンパイル時間が増え、 生成コードの効率が良くなる。

-O2’ を指定すると、ループ展開と関数のインライン展開、それに 厳密なエイリアシングを除いた 全ての最適化が有効になる。また、全ての機種で ‘-fforce-mem’ オプション を付け、デバッグと干渉しない機種ではフレームポインタの削除を行なう。

-O3

さらに最適化を行なう。‘-O3’ は ‘-O2’ で指定される 全ての最適化を行ない、かつ ‘inline-functions’ オプションを 行なう。

-O0

最適化を行なわない。

-Os

サイズについて最適化する。‘-Os’ を指定すると、 普通はコードサイズを大きくしない ‘-O2’ の最適化を全て有効にする。 また、コードサイズを小さくするよう設計されたさらなる最適化を実行する。

-O’ オプションを複数指定した場合は、最適化レベルの数字が 付いていてもいなくても、最後に指定したオプションが有効になる。

-fflag’ という形のオプションは機種独立のフラグを 指定する。ほとんどのフラグには、肯定形と否定形がある。 ‘-ffoo’ の否定形は ‘-fno-foo’ である。以下の表では、 どちらか一方の形しか列挙していない。デフォルトでないほうを列挙している。 もう一方の形式は、‘no-’ を取り除くか、追加すれば良い。

-ffloat-store

浮動小数点変数をレジスタにストアせず、浮動小数点値を レジスタかメモリから取り出すかどうかを変更する可能性のある オプションを禁じる。

このオプションを指定すると、68000 の様な機種で、好ましくない余分な精度を 使わないようになる。68000 では、(68881 の)浮動小数点レジスタは、 double が持つと想定されているよりも余分の精度を保持している。 x86 アーキテクチャについても同様である。ほとんどのプログラムにとっては、 精度が余分に高いのは利点が加わるだけであるが、幾つかのプログラムは IEEE 浮動小数点の厳密な定義を想定している。そういう プログラムに対しては、適当な中間計算結果を全て変数に格納するように プログラムを修正しておいて、‘-ffloat-store’ を使うこと。

-fno-default-inline

メンバ関数を、それが単にクラススコープで定義されているからといって インライン展開しない(C++ のみ)。これを指定しないと、 ‘-O’ 付きでコンパイルした場合、クラススコープ内で定義されている メンバ関数はデフォルトでインライン展開される。すなわち、 メンバ関数名の前に ‘inline’ を付ける必要がないのである。

-fno-defer-pop

関数呼び出しの度に常に、その関数から戻るとすぐ引数をポップする。 関数呼び出しの後に引数をポップしなければならない機種では、 GCC は普通は複数の関数呼び出しについてスタックに引数を蓄積し、 それらを全て一度にポップする。

-fforce-mem

メモリオペランドについて算術演算を行なう前に、そのメモリオペランドを レジスタに強制的にコピーさせる。この結果、全てのメモリ参照を 潜在的な共通部分式とすることにより、生成コードが良くなる。 これらのメモリ参照が共通部分式でない場合は、命令組合せフェーズが 独立したレジスタへのロードを削除する必要がある。‘-O2’ を 指定するとこのオプションが有効になる。

-fforce-addr

メモリ中のアドレス定数を、それについて算術演算を行なう前にレジスタに コピーすることを強制する。これは、‘-fforce-mem’ と同程度に良い コードを生成する。

-fomit-frame-pointer

フレームポインタを必要としない関数については、フレームポインタを レジスタに保持しないようにする。これにより、フレームポインタを セーブ、設定、リストアする命令をなくすことができる。 また、多くの関数で利用可能なレジスタが一つ増える。 また、機種によってはデバッグが不可能になる。

機種によっては、Vax のように、このオプションの効果がないものもある。 標準の呼び出しシーケンスが自動的にフレームポインタを取扱うので、 フレームポインタが存在しない振りをしても何もセーブされないからである。 マシン記述マクロ FRAME_POINTER_REQUIRED が、 ターゲット機種でこのオプションが使えるかどうかを決定する。 See section レジスタの使用方法.

-fno-inline

キーワード inline に注意を払わない。 普通このオプションは、関数のインライン展開を一切行なわせない ために使われる。最適化を行なわない場合には、どの関数もインライン 展開されることはないことに注意して欲しい。

-finline-functions

単純な関数を全て呼びだし元に統合する。 GCC は、どの関数がこの方法で統合するのに充分単純かを 発見的に決定する。

ある関数に対する全ての呼び出しが統合される場合、その関数が static と宣言されていれば、普通はその関数はアセンブラコードとしては 出力されない。

-finline-limit-n

デフォルトでは、GCC はインライン展開可能な関数の大きさを制限している。 このオプションを指定すると、明示的にインライン展開を行うと印を 付けられている(すなわち、キーワード inline を指定されているか、 C++ のクラス定義の中で定義されている)関数に対するこの制限を調整できるように なる。n は、インライン展開可能な関数の大きさを疑似命令の数 で表したものである(パラメータの取扱いは数えない)。デフォルトの n の値は、10000 である。この値を大きくすると、インライン展開されたコードが 多くなり、コンパイル時間とメモリ消費量が余計にかかるようになる。 この値を小さくすると、普通はコンパイル時間が速くなり、インライン展開 されるコードが少なくなる(これは、恐らくプログラムが遅くなることを 意味するだろう)。このオプションが特に有効なのは、C++ の再帰的 テンプレートに基づくような、インライン展開を非常にたくさん使っている プログラムである。

注意。疑似命令は、今のこの特定の文脈においては、関数の大きさの 抽象的な尺度を表す。アセンブリ命令数を表し、その意味はあるリリースと 別のリリースで変わる可能性がある。

-fkeep-inline-functions

ある関数に対する呼び出しが全部統合され、その関数が static と 宣言されている場合でも、実行時に呼び出し可能な版の関数を別個に 出力する。このオプションは extern inline 宣言された関数には 影響しない。

-fkeep-static-consts

最適化を実行しないときに、static const と宣言されている変数が 参照されていなくても、その変数を出力する。

GCC はこのオプションをデフォルトで有効にする。 最適化の有無に関わらずに、GCC に変数が参照されているかどうかを 検査させたい場合は、‘-fno-keep-static-consts’ オプションを 使えば良い。

-fno-function-cse

関数のアドレスをレジスタに置かないようにする。ある一定の関数を 呼び出す命令は一々その関数のアドレスを明示的に保持するようにする。

このオプションを指定するとコードの効率が悪くなるが、アセンブラの出力を 変にいじったような場合、このオプションを指定しないと実行される 最適化処理が混乱させられる可能性がある

-ffast-math

このオプションを指定すると、実行速度を最適化するという観点から、 ある面で ANSI や IEEE の規則や仕様を破ることを GCC に許す。 例えば、このオプションを指定すると、GCC は、sqrt 関数の引数が 負にならないとか、浮動小数点値がNaN になることはないという 仮定を行なう。

このオプションは、どの ‘-O’ オプションを指定しても有効に なることはない。何故なら、IEEE や ANSI の数学関数の規則/仕様に 厳密に基づいて実装されているプログラムの場合は、出力が 正しくなくなる可能性があるからである。

以下のオプション群は、特定の最適化を制御する。 ‘-O2’ オプションは、‘-funroll-loops’ と ‘-funroll-all-loops’ 、‘-fstrict-aliasing’ オプションを除く、全ての最適化を実行する。 多くの機種では、 ‘-O’ オプションを指定すると、‘-fthread-jumps’ と ‘-fdelayed-branch’ オプションを有効にするが、特定の機種では 別の扱いをする。

以下のオプションは、高度な最適化を行ないたいという場合に使うことが できる。

-fstrength-reduce

ループの強度削減と繰り返し変数の削除の最適化を実行する。

-fthread-jumps

あるジャンプの分岐先に、別のもう一つの比較があり、その比較が最初の 比較に包括されるものかどうかを検査する最適化を実行する。 もし包括されるものなら、最初の分岐の分岐先は、二番目の分岐の分岐先か その直後の地点のどちらかに、二番目の比較条件の真偽が既知かどうかに 従って、変更される。

-fcse-follow-jumps

共通部分式削除(CSE)の際に、ジャンプ命令のうち、そのジャンプ先に他の経路を 通って到達することがないものを探し出す。例えば、CSE が else 節つきの if 文を見つけると、テストされた条件が 偽のときのジャンプに従う。

-fcse-skip-blocks

これは ‘-fcse-follow-jumps’ に良く似ているが、CSE は 条件的にブロックを飛び越すジャンプに従う。CSE が else 節のない if 文を見つけると、if 節の本体のまわりのジャンプに従う。

-frerun-cse-after-loop

ループ最適化の実行後に共通部分式の削除をもう一度実行する。

-frerun-loop-opt

ループ最適化を二回実行する。

-fgcse

グローバル共通部分式削除パスを実行する。 このパスは、グローバルな定数とコピーの伝播も実行する。

-fexpensive-optimizations

比較的コストがかかる、マイナーな最適化を幾つか行なう。

-foptimize-register-moves
-fregmove

移動命令中のレジスタ番号を他の単純な命令のオペランドとして再割当を 行い、レジスタ結合の量を最大にすることを試みる。 これは、とりわけ二オペランド命令の機種で役に立つ。 GCC は、‘-O2’ 以上が指定されたときはデフォルトでこの最適化を 有効にする。

なお、-fregmove-foptimize-register-moves は同じ 最適化である。

-fdelayed-branch

ターゲット機種でサポートされていれば、遅延分岐命令後の 利用可能な命令スロットを利用するように命令の並べ替えを試みる。

-fschedule-insns

ターゲット機種でサポートされていれば、必要とされるデータが利用不可能 なために起こる実行のストールをなくように命令の並べ替えを試みる。 これにより、浮動小数点命令やメモリからのロード命令が遅い機種で、 ロード命令や浮動小数点命令の結果が必要になるまでの間、他の命令を 発行することが出来るようになる。

-fschedule-insns2

-fschedule-insns’ とほぼ同じで、違いはレジスタ割当が 完了した後にもう一度命令スケジューリングのパスを行なうことである。 これがとりわけ役に立つのは、レジスタ数が比較的少なく、メモリからの ロード命令が複数サイクルかかるような機種の場合である。

-ffunction-sections
-fdata-sections

ターゲットが任意個数のセクションを使えるなら、各関数やデータ項目を それぞれ専用のセクションに入れた出力ファイルを作る。 関数名やデータ項目名から、出力ファイルでのセクション名が決まる。

リンカに命令空間の参照の局所性を改善する最適化を行なう機能がある システムでは、これらのオプションを使うと良いだろう。 HP-UX の稼働する HPPA プロセッサと Solaris 2 の稼働する SPARC プロセッサには このような最適化機能のあるリンカが存在する。ELF オブジェクトファイル形式を 使っている他のシステムや、 AIX も将来この最適化機能が加わる可能性がある。

これらのオプションを使うのは、使うことによって著しい御利益がある場合に 限ること。これらのオプションを使うと、アセンブラとリンカが作る、 オブジェクトファイルや実行形式ファイルが大きくなり、そのために 遅くなることもある。このオプションを指定すると、全てのシステムで gprof が使えなくなる。また、‘-g’ と共に指定すると、 デバッグ時に問題が生じる可能性がある。

-fcaller-saves

関数呼び出しにより破壊されるレジスタに値を割り当てることを可能にする。 このために、命令を余分に生成し、呼び出しの前後でレジスタのセーブと リストアを行なう。このような割当が行なわれるのは、他の方法を取るよりも 結果的に良いコードが生成される見込みのある場合だけである。

いくつかの機種ではこのオプションが常にデフォルトで有効になっている。 そういう機種には、代わりに使うべき、呼び出し時保存レジスタが 普通ないのである。

全ての機種で、最適化レベルを 2 以上にするとこのオプションがデフォルトで 有効になる。

-funroll-loops

ループ展開最適化を実行する。これは、コンパイル時か実行時に繰り返し回数が 決められるループにしか行なわれない。 ‘-funroll-loops’ は、‘-fstrength-reduce’ と ‘-frerun-cse-after-loop’ を含む。

-funroll-all-loops

ループ展開最適化を実行する。 これは、全てのループに対して行なわれ、普通はプログラムの実行を遅くする。 ‘-funroll-all-loops’ は、‘-fstrength-reduce’ と ‘-frerun-cse-after-loop’ を含む。

-fmove-all-movables

ループ中の不変な計算を全てループの外に移動する。

-freduce-all-givs

ループ中の一般誘導変数を全て強度削減する。

注意。Fortran で書かれたプログラムをコンパイルするときは ‘-fmove-all-movables’ と ‘-freduce-all-givs’ は、 最適化を行うとデフォルトで有効になる。

これらのオプションで、生成されるコードがよくなることもあるし、 悪くなることもある。結果は、ソースコードでのループに構造に 強く依存する。

この二つのオプションは、ループ最適化を改良する色々な方法の 有効性を知る役目が終わったなら、いつか削除する予定である。

これらのオプションを使うと、読者のコードの性能にどれぐらい効果が あったかを、我々(gcc@gcc.gnu.orgfortran@gnu.org) に知らせて欲しい。これらのオプションが有効になっているときに 遅くなったコードに我々は非常に興味がある。

-fno-peephole

機種固有の覗き穴最適化を無効にする。

-fbranch-probabilities

-fprofile-arcs’ (see section Options for Debugging Your Program or gcc)を付けてコンパイルしたプログラムを実行した後、 二回目は ‘-fbranch-probabilities’ を付けてコンパイルすると、 分岐が起こる経路の推測に基づく最適化を改良する。

-fbranch-probabilities’ を指定すると、GCC は ‘REG_EXEC_COUNT’ というノートを各基本ブロックの最初の命令に付け、‘REG_BR_PROB’ という ノートを各 ‘JUMP_INSN’ と ‘CALL_INSN’ に付ける。 これらを使って最適化を向上させることができる。現在、これらは一箇所で しか使われていない。‘reorg.c’ で、ある分岐がどちらの方向に 起こりそうかを推測する代わりに、‘REG_BR_PROB’ の値を使って より分岐する頻度が高い方向を正確に決定する。

-fstrict-aliasing

GCC に、コンパイルされる言語に取りうる最も厳密な別名規則を取らせる。 C(それに C++)の場合は、これにより式の型にもとづく最適化が有効になる。 特に、一つの型のあるオブジェクトは、同じアドレスに異なる型のオブジェクト が存在することは、それらの型がほとんど同じでない限り、決してないと仮定する。 例えば、unsigned intint の別名になりうるが、 void*double の別名にはなりえない。文字型は他のどんな 型の別名にもなりうる。

以下のようなコードには特別に注意が必要である。

 
union a_union { 
  int i;
  double d;
};

int f() {
  a_union t;
  t.d = 3.0;
  return t.i;
}

共用体の、一番最後に書き込みが行われたメンバとは異なるメンバの値を 呼び出すという手法(「型もじり」、type-punning と呼ばれる)は良く行われている。 ‘-fstrict-aliasing’ を指定しても、型もじりは許されるので、 メモリは共用体型を通じて参照される。このため、上記のコードは期待どおりに 動作する。だが、次のコードは期待どおりにならない。

 
int f() { 
  a_union t;
  int* ip;
  t.d = 3.0;
  ip = &t.i;
  return *ip;
}

言語固有の別名解析を実行したい言語があれば、ある tree ノードが 与えられた場合に、そのノードの別名セットを計算する関数を定義する必要がある。 例えば、C 言語のフロントエンドの関数 c_get_alias_set を参照のこと。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated using texi2html 1.78.