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

17.7.10 関数の入口と出口

この節では、関数の入り口(プロローグ)と出口(エピローグ)コード を出力するマクロについて説明する。

FUNCTION_PROLOGUE (file, size)

関数の入り口点のアセンブラコードを出力する C の複文である。 このプロローグコードは、スタックフレームの設定、フレームポインタレジスタの 初期化、セーブしなければならないレジスタのセーブ、局所変数用の size バイト分の記憶域の確保を行なう責任がある。 size は整数である。file は、アセンブラコードの出力先を指定する 標準入出力ストリームである。

関数の開始位置を表すラベルは、このマクロで出力する必要はない。 このマクロが実行されるときに既に済んでいるはずである。

セーブすべきレジスタを決めるために、このマクロは配列 regs_ever_live を参照する。この配列の要素 r は、ハードレジスタ r が この関数内のどこかで使われているならゼロ以外の値となる。 つまり、call-used レジスタの一つでない限り、プロローグコードが レジスタ r をセーブすべきであるということになる。 (FUNCTION_EPILOGUE も同様に regs_ever_live を 使わなければならない。)

レジスタウィンドウを持つマシンでは、関数の入り口点コードは、 レジスタウィンドウにあるレジスタのスタックへのセーブは行なわない。 たとえ、そのレジスタが関数呼びだしの際に保存されるべきものであってもである。 代わりに、その関数内で non-call-used なレジスタが使われている場合は、 レジスタスタックに「プッシュ」するという独特の処理を行なう。

関数のフレームポインタがあってもなくても良いマシンでは、 関数の入り口点コードもフレームポインタの有無に対応して 変わらなければならない。要求されているのであればフレームポインタを設定 しなければならず、要求されていなければ設定してはならない。 フレームポインタが要求されているかどうか決めるために、このマクロから 変数 frame_pointer_needed を参照することが可能である。 実行時には、フレームポインタを必要とする関数の中ではこの変数の値は 1 に なる。See section フレームポインタと引数ポインタの消去

関数の入り口コードには、その関数に必要とされるだけのスタックスペースを 確保する責任がある。このスタックスペースは、以下に示す領域から成る。 多くの場合は、これらの領域は以下の順番に確保され、最後に示した領域が スタックのトップに最も近くなる。スタックのトップは、 STACK_GROWS_DOWNWARD が定義されていれば最下位アドレスになり、 定義されていなければ最上位アドレスになる。 より便利であったり、互換性に理由から必要とされるマシンに対しては、 異なった順番を使っても良い。 規格やデバッガから要求される場合を除き、あるマシンのスタック構成が GCC で使われるものと他のコンパイラで使われるものとが一致しなければ ならない理由はない。

普通は、マクロ FUNCTION_PROLOGUEFUNCTION_EPILOGUE は末端関数を特別に扱う必要がある。C の変数 current_function_is_leaf は、 そういう関数についてはゼロでない値となる。

EXIT_IGNORE_STACK

一個の C の式。リターン命令や関数のエピローグがスタックポインタの 値を無視するならゼロでない値となる。言い換えると、関数から戻る前に スタックポインタの調整を行なう命令を削除しても安全な場合は、 ゼロでない値となる。

このマクロの値が関係するのは、フレームポインタが維持されている関数に 対してだけであることに注意。フレームポインタを持たない関数で、 最後のスタック調整を削除するのは決して安全ではない。 コンパイラは、EXIT_IGNORE_STACK に関わらず、このことを知っている。

EPILOGUE_USES (regno)

C の式を定義するマクロ。この式の値は、エピローグか ‘return’ パターン でレジスタが使われるなら 0 でない値とする。 スタックポインタとフレームポインタレジスタは、既に必要に応じて 使われていると仮定されている。

FUNCTION_EPILOGUE (file, size)

関数の出口点のアセンブラコードを出力する C の複文である。 このエピローグコードは、セーブされたレジスタとスタックポインタの値を 関数が呼び出されたときの値に復帰させ、制御を呼び出し関数に戻す責任が ある。 引数は、マクロ FUNCTION_PROLOGUE と同じである。 復帰すべきレジスタは、同様に、 regs_ever_liveCALL_USED_REGISTERS から決定される。

機種によっては、一個の機械命令で関数からの復帰作業を全て行なう ものがある。そういう機種では、その命令に ‘return’ という 名前を与え、マクロ FUNCTION_EPILOGUE は定義してはならない。

FUNCTION_EPILOGUE を使って欲しいのであれば、 ‘return’ という名前のパターンを定義してはならない。 ターゲットスイッチで、return 命令を使うのか、あるいは、エピローグを 使うのかを制御したい場合は、‘return’ パターンを、 ターゲットスイッチを適切にテストする有効性を検査する条件を付けて 定義すること。 ‘return’ パターンの有効性検査条件が偽であれば、エピローグが使われる。

関数がフレームポインタを持っても持たなくても良い機種では、 関数の終了コードはそれに従って変わらなければならない。 この二つの場合のコードが全く異なるということもある。 フレームポインタを必要とするかどうかを決めるために、このマクロでは 変数 frame_pointer_needed を参照することが出来る。 この変数の値は、コンパイルしている関数がフレームポインタを必要とするなら 1 となる。

通常、FUNCTION_PROLOGUEFUNCTION_EPILOGUE は、 末端関数を特別に取り扱わなくてはならない。 そのような関数については、C の変数 current_function_is_leaf がゼロでない 値となる。See section 末端関数の扱い.

幾つかの機種では、関数によっては、終了時に引数をポップするものがあったり、 呼び出し側にまかせたりするものがある。 例えば、68020 では、‘-mrtd’ オプションを指定すると、固定数の引数 を取る関数の引数はポップする。

マクロ RETURN_POPS_ARGS の定義により、どの関数がその関数自身の 引数をポップするかが決まる。 FUNCTION_EPILOGUE はどちらに決まったかを知る必要がある。 current_function_pops_args という変数が、 ある関数がポップすべき引数のバイト数を表す。See section スカラ関数値の返し方.

DELAY_SLOTS_FOR_EPILOGUE

関数のエピローグに、その関数の他の部分から命令をそこに「移動」可能な 遅延スロットがあるなら、このマクロを定義する。 このマクロの定義は、C の式とし、その値は存在する遅延スロット数とすべきである。

ELIGIBLE_FOR_EPILOGUE_DELAY (insn, n)

insn をエピローグコードの遅延スロット番号 n に 置くことが出来る場合は 1 を返す C の式。

引数 n は、今考えている遅延スロットを特定する整数である (というのは、異なるスロットは異なる適性を持つからである。) この整数は、負になることはなく、常にエピローグにある遅延スロット数 (DELAY_SLOTS_FOR_EPILOGUE が返す値である)より小さい。 ある指定された遅延スロットにある特定の insn を入れることを拒否する場合は、 原則的には、すぐ後ろの遅延スロットに入れられるかどうかが再考される。 また、他の insn が(少なくとも)原則的には、その時点までに埋められていない 遅延スロットに入るかどうかが考慮される。

エピローグコード中の遅延スロットを埋めるべく受け入れられた insn は insn_list オブジェクトで作られた RTL リストに置かれ、 変数 current_function_epilogue_delay_list に格納される。 先頭の遅延スロットに入る insn は、このリストの先頭に来る。 マクロ FUNCTION_EPILOGUE は、このリスト中の insn を出力する ことにより遅延スロットを埋めるように定義すべきである。 これは、普通は final_scan_insn を呼び出すことにより行なわれる。

DELAY_SLOTS_FOR_EPILOGUE を定義しないのなら、このマクロを 定義する必要はない。

ASM_OUTPUT_MI_THUNK (file, thunk_fndecl, delta, function)

C の複文。この複文はサンク関数用のアセンブラコードを出力する。 サンク関数は、C++の、多重継承を持つ仮想関数呼び出しを実装するのに 使われる。サンクは、仮想関数のラッパーとして作用し、 実際の関数へ制御を渡す前に暗黙のオブジェクトパラメータの調整を 行なう。

まず、整数 delta を先頭の入力引数を含む位置に加算するコードを 生成する。この引数はあるポインタを含んであり、C++ で this ポインタを渡すのに使われるものであると仮定する。 これは、関数プロローグの前の入力引数、例えば SPARC では ‘%o0’ である。この加算は、他の全ての入力引数の値を保存しなければ ならない。

この加算の後、function にジャンプするコードを生成する。 functionFUNCTION_DECL である。 これは純粋な直接ジャンプであり、呼び出しではないので、 戻りアドレスはいじらない。つまり、FUNCTION から戻ると、 現在の ‘thunk’ の呼び出し元に戻ることになる。

この効果は、あたかも functionが第一引数を調整したうえで 直接呼び出されたかのようにならなければならない。 このマクロは、サンク関数用のコードを全て生成する責任がある。 FUNCTION_PROLOGUEFUNCTION_EPILOGUE は呼び出されない。

thunk_fndecl は冗長である。(これから、deltafunction が既に抽出済みである。) ターゲットによっては役に立つ可能性もあるが、多分そういうことはないだろう。

このマクロを定義しない場合は、C++ フロントエンドのターゲット非依存コードが、 効率の落ちる、重量級のサンクを生成する。このサンクは、function に ジャンプするのではなく、それを呼び出す。この汎用的な方法は varargs はサポートしない。


This document was generated using texi2html 1.78.