(57)【要約】【課題】ｃａｌｌｅｅ−ｓａｖｅレジスタの回復コードでｐｏｐ命令を用いながら、不要な回復コードを削減する。【解決手段】関数出口において回復不要なレジスタを検出し、回復不要なレジスタを考慮してｃａｌｌｅｅ−ｓａｖｅレジスタの退避順序と回復順序を決定し、回復不要なレジスタの回復コードを生成せず、回復不要になったレジスタの合計サイズをスタックレジスタの更新サイズに反映させる機能を有する。【選択図】図１
2010122820.tif 000002
【特許請求の範囲】
【請求項１】
演算処理を行う第１のプロセッサと、前記プロセッサが利用する情報を格納する記憶部と、を備えて、関数を含むソースプログラムを読み込んでスタック操作命令を含むオブジェクトプログラムを生成するコンパイル装置において、
前記ソースプログラムを読み込んで中間コードを生成する構文解析部と、
前記中間コードを読み込んで、前記オブジェクトプログラムを実行する計算機を構成する第２のプロセッサのレジスタを前記中間コードに割り付けるレジスタ割り付け部と、
前記レジスタに割り付けた中間コードからオブジェクトコードを生成し、オブジェクトプログラムを出力するコード生成部、とを備え、
前記記憶部は、
前記第２のプロセッサのレジスタの情報を格納したターゲット情報と、
前記関数に割り付けられた前記レジスタの情報を格納する第１のレジスタ情報と、
前記レジスタの退避順序と回復順序を格納する第２のレジスタ情報と、
を有し、
前記コード生成部は、
前記関数の入口及び出口に割り付けられた前記レジスタの情報を収集して前記第１のレジスタ情報に格納する定義レジスタ情報収集部と、
前記第１のレジスタ情報を読み込んで、前記関数の入口及び出口に割り付けられた前記レジスタの退避順序と回復順序を決定する退避・回復順序決定部と、
前記退避・回復順序決定部が決定した退避順序と回復順序に従って前記レジスタの退避コードと回復コードを生成する退避・回復コード生成部と、を有し、
退避・回復コード生成部は、
前記レジスタの退避順序に従ってレジスタの退避コードを前記関数の入口に生成し、前記第１のレジスタ情報と前記退避順序及び回復順序から前記関数の入口から出口に至るパス上で割り付けられているレジスタに対して、前記関数の出口毎にそれぞれ回復コードを生成し、前記パス上で定義されてないレジスタのサイズの和を求め、前記関数の出口でスタックアドレスを前記レジスタのサイズの和だけ補正するスタックアドレスの更新命令を生成することを特徴とするコンパイル装置。
【請求項２】
請求項１に記載のコンパイル装置であって、
前記退避・回復順序決定部は、
前記関数の出口に割り付けられたレジスタについて重み付けを行い、前記重みの順位に基づいて回復コードを生成するレジスタの順位を決定することを特徴とするコンパイル装置。
【請求項３】
請求項２に記載のコンパイル装置であって、
前記ターゲット情報は、前記第２のプロセッサで前記オブジェクトプログラムを実行したときの関数出口の実行回数を予め格納し、
前記退避・回復順序決定部は、
前記ターゲット情報から関数出口の実行回数を読み込んで、前記実行回数の大きさから前記重みを求めることを特徴とするコンパイル装置。
【請求項４】
請求項１に記載のコンパイル装置であって、
前記退避コードは、前記レジスタのサイズに相当するバイト数でスタックアドレスを減算した後、減算後のスタックアドレスが指す領域に前記レジスタのデータをストアし、
前記回復コードは、前記スタックアドレスの指す領域から前記レジスタにデータをロードした後、当該レジスタのサイズに相当するバイト数を前記スタックアドレスに加算することを特徴とするコンパイル装置。
【請求項５】
演算処理を行う第１のプロセッサと、前記プロセッサが利用する情報を格納する記憶部と、を備えて、関数を含むソースプログラムを読み込んでスタック操作命令を含むオブジェクトプログラムを生成するコンパイル装置において、
前記ソースプログラムを読み込んで中間コードを生成する構文解析部と、
前記中間コードを読み込んで、前記オブジェクトプログラムを実行する計算機を構成する第２のプロセッサのレジスタを前記中間コードに割り付けるレジスタ割り付け部と、
前記レジスタに割り付けた中間コードからオブジェクトコードを生成し、オブジェクトプログラムを出力するコード生成部、とを備え、
前記記憶部は、
前記第２のプロセッサのレジスタの情報を格納したターゲット情報と、
前記関数に割り付けられた前記レジスタの情報を格納する第１のレジスタ情報と、
を有し、
前記コード生成部は、
前記関数の入口及び出口に割り付けられた前記レジスタの情報を収集して前記第１のレジスタ情報に格納する定義レジスタ情報収集部と、
前記定義レジスタ情報収集部が割り付けた前記レジスタの退避コードと回復コードを生成する退避・回復コード生成部と、を有し、
退避・回復コード生成部は、
前記第１のレジスタ情報を読み込んで、前記関数の入口に割り付けられたレジスタの退避コードを生成し、前記関数の入口から出口に至るパス上で割り付けられているレジスタに対して前記関数の出口毎にそれぞれ回復コードを生成し、前記パス上で定義されてないレジスタについて当該レジスタのサイズに応じてスタックアドレスを補正するスタックアドレスの更新命令を生成することを特徴とするコンパイル装置。
【請求項６】
請求項５に記載のコンパイル装置であって、
前記スタックアドレスの更新命令が連続して生成されることを検出する検出部と、
前記検出結果に従ってスタックアドレスの更新命令の値を修正する更新値修正部と、を有し、
前記更新値修正部は、
前記検出部がスタックアドレスの更新命令を連続して生成する際には、連続する２つめ以降のスタックアドレス更新命令を生成せず、最初に生成したスタックアドレス更新命令の値を、複数のスタックアドレスの補正値に修正することを特徴とするコンパイル装置。
【請求項７】
演算処理を行う第１のプロセッサと、前記プロセッサが利用する情報を格納する記憶部と、を備えた第１の計算機で、関数を含むソースプログラムを読み込んでスタック操作命令を含むオブジェクトプログラムを生成するコンパイル方法において、
前記第１のプロセッサが、前記ソースプログラムを読み込んで中間コードを生成するステップと、
前記第１のプロセッサが、前記中間コードを読み込んで、前記オブジェクトプログラムを実行する第２の計算機を構成する第２のプロセッサのレジスタを前記中間コードに割り付けるステップと、
前記第１のプロセッサが、前記レジスタに割り付けた中間コードからオブジェクトコードを生成し、オブジェクトプログラムとして出力するステップ、とを含み、
前記レジスタに割り付けた中間コードからオブジェクトコードを生成し、オブジェクトプログラムとして出力するステップは、
前記関数の入口及び出口に割り付けられた前記レジスタの情報を収集して前記記憶部に設定した第１のレジスタ情報に格納するステップと、
前記第１のレジスタ情報を読み込んで、前記関数の入口及び出口に割り付けられた前記レジスタの退避順序と回復順序を決定するステップと、
前記決定した退避順序と回復順序に従って前記レジスタの退避コードと回復コードを生成するステップと、を有し、
前記決定した退避順序と回復順序に従って前記レジスタの退避コードと回復コードを生成するステップは、
前記レジスタの退避順序に従ってレジスタの退避コードを前記関数の入口に生成し、前記第１のレジスタ情報と前記退避順序及び回復順序から前記関数の入口から出口に至るパス上で割り付けられているレジスタに対して、前記関数の出口毎にそれぞれ回復コードを生成し、前記パス上で定義されてないレジスタのサイズの和を求め、前記関数の出口でスタックアドレスを前記レジスタのサイズの和だけ補正するスタックアドレスの更新命令を生成することを特徴とするコンパイル方法。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、計算機の利用技術において、オブジェクトプログラムのコードサイズと実行時間を削減するコンパイル装置、コンパイル方法及びコンパイラに関する。特に、ｐｕｓｈ／ｐｏｐ命令等のスタック操作命令を利用したｃａｌｌｅｅ−ｓａｖｅレジスタの回復コード削減方法に関し、命令数を増加させることなく関数出口において必要なｃａｌｌｅｅ−ｓａｖｅレジスタのみを回復するコード列を生成することで、ｃａｌｌｅｅ−ｓａｖｅレジスタの回復コードを削減し、コードサイズが小さく、かつ、実行性能の良いオブジェクトプログラムを生成するｃａｌｌｅｅ−ｓａｖｅレジスタの回復コード削減するコンパイル装置、コンパイル方法及びコンパイラに関する。
【背景技術】
【０００２】
ソースコードを実行コードに変換するコンパイラでは、関数呼び出しを行う場合、関数の呼び出し先でレジスタの退避と回復が必要になる。このように関数の呼び出し先で退避と回復する必要のあるレジスタを一般にｃａｌｌｅｅ−ｓａｖｅレジスタと呼んでいる。このｃａｌｌｅｅ−ｓａｖｅレジスタの退避、回復場所は通常、予めメモリ上に設定されたスタック上に確保される。また、関数呼び出し直後にスタックの先頭位置を指し示す値（スタックポインタ）を格納するレジスタも用意されており、このレジスタのことを本明細書ではスタックレジスタ（以下、ＳＰと記載する）と呼ぶことにする。
【０００３】
一般に行われているデータの退避と回復処理の一例を示すと、関数入口のコードは、図１２（ａ）に示すとおり、ｃａｌｌｅｅ−ｓａｖｅレジスタの退避を、ＳＰのレジスタサイズ分のアドレスを減算した後、減算後のＳＰが指すスタック上にｃａｌｌｅｅ−ｓａｖｅレジスタのデータをストアする命令（ｐｕｓｈ命令）で実行した後、関数内で利用するワーク領域（図示の−αに相当）を確保するために、スタックレジスタの更新命令をａｄｄ命令で実行する。
【０００４】
一方関数出口のコードは、図１２（ｂ）に示すとおり、スタックレジスタＳＰの更新命令をａｄｄ命令で実行した後、ｃａｌｌｅｅ−ｓａｖｅレジスタの回復を、ＳＰが指すスタック上からｃａｌｌｅｅ−ｓａｖｅレジスタにデータをロードした後、ＳＰにレジスタサイズ分のアドレスを加算する命令（ｐｏｐ命令）で実行する。
【０００５】
上記のようなｃａｌｌｅｅ−ｓａｖｅレジスタの退避と回復については、特許文献１に開示される技術が知られている。
【特許文献１】特開２００８−７１０６５号
【発明の開示】
【発明が解決しようとする課題】
【０００６】
ここで、関数出口が複数存在し、関数入口からある関数出口に至るパス上で、退避したｃａｌｌｅｅ−ｓａｖｅレジスタの一部しか定義していない場合の回復コード（ｐｏｐ命令）について考える。この場合、関数出口においては、定義されているｃａｌｌｅｅ−ｓａｖｅレジスタのみを回復すれば良いため、必要なレジスタのみの回復コードをｐｏｐ命令で生成したとする。しかし、ｐｏｐ命令は、スタックからレジスタへ値を回復する機構の他に、スタックアドレスを更新する機構を含む命令である。そのため、単純に回復コードを削減しただけでは、回復するレジスタにおいて、退避時と異なるスタックアドレスから値を回復することになり、不正なコード実行することになる。
【０００７】
そこで、本発明の目的は、ｃａｌｌｅｅ−ｓａｖｅレジスタの回復コードでｐｏｐ命令を利用しながら、不要な回復コードを削減できる手段を提供することにある。
【課題を解決するための手段】
【０００８】
本発明は、演算処理を行う第１のプロセッサと、前記プロセッサが利用する情報を格納する記憶部と、を備えて、関数を含むソースプログラムを読み込んでスタック操作命令を含むオブジェクトプログラムを生成するコンパイル装置において、前記ソースプログラムを読み込んで中間コードを生成する構文解析部と、前記中間コードを読み込んで、前記オブジェクトプログラムを実行する計算機を構成する第２のプロセッサのレジスタを前記中間コードに割り付けるレジスタ割り付け部と、前記レジスタに割り付けた中間コードからオブジェクトコードを生成し、オブジェクトプログラムを出力するコード生成部、とを備え、前記記憶部は、前記第２のプロセッサのレジスタの情報を格納したターゲット情報と、前記関数に割り付けられた前記レジスタの情報を格納する第１のレジスタ情報と、前記レジスタの退避順序と回復順序を格納する第２のレジスタ情報と、を有し、前記コード生成部は、前記関数の入口及び出口に割り付けられた前記レジスタの情報を収集して前記第１のレジスタ情報に格納する定義レジスタ情報収集部と、前記第１のレジスタ情報を読み込んで、前記関数の入口及び出口に割り付けられた前記レジスタの退避順序と回復順序を決定する退避・回復順序決定部と、前記退避・回復順序決定部が決定した退避順序と回復順序に従って前記レジスタの退避コードと回復コードを生成する退避・回復コード生成部と、を有し、退避・回復コード生成部は、前記レジスタの退避順序に従ってレジスタの退避コードを前記関数の入口に生成し、前記第１のレジスタ情報と前記退避順序及び回復順序から前記関数の入口から出口に至るパス上で割り付けられているレジスタに対して、前記関数の出口毎にそれぞれ回復コードを生成し、前記パス上で定義されてないレジスタのサイズの和を求め、前記関数の出口でスタックアドレスを前記レジスタのサイズの和だけ補正するスタックアドレスの更新命令を生成する。
【発明の効果】
【０００９】
したがって、本発明によれば、複数の出口を有する関数のオブジェクトコードを生成する場合には、ｃａｌｌｅｅ−ｓａｖｅレジスタの不要な回復コードが削減可能になるため、オブジェクトプログラムのコードサイズを増加させることなく、実行性能の良いオブジェクトプログラム（実行コード）を生成することが可能になる。
【発明を実施するための最良の形態】
【００１０】
以下、本発明の一実施形態を添付図面に基づいて説明する。
【００１１】
＜第１実施形態＞
図１は、本発明によるコンパイラが稼動する計算機システム（コンパイル装置）の構成図である。この計算機システム２００は、演算処理を行うＣＰＵ（またはプロセッサ）２０１と、情報の表示を行うディスプレイ装置２０２と、情報の入力を行うキーボード２０３と、ＣＰＵ２０１が利用する情報を格納する主記憶装置２０４、および情報を格納する外部記憶装置２０５より構成されている。キーボード２０３により、ユーザからのコンパイラ起動命令を受け付ける。コンパイラ終了メッセージやエラーメッセージは、ディスプレイ装置２０２に表示される。外部記憶装置２０５はＨＤＤや不揮発性メモリで構成され、ソースプログラム２０６とオブジェクトプログラム２０７が格納される。主記憶装置２０４には、ソースプログラム２０６を読み込んでオブジェクトプログラム２０７を生成するコンパイラ２０８と、コンパイル過程で必要となる中間コード２０９と定義レジスタ情報テーブル２１０とレジスタ情報テーブル２１１及びターゲット情報テーブル２１２が格納される。コンパイル処理はＣＰＵ２０１がコンパイラ（プログラム）２０８を実行することにより行われる。
【００１２】
ターゲット情報テーブル２１２は、オブジェクトプログラム２０７を実行する計算機システム（ターゲットシステム）２５０（図２参照）の構成に関する情報を予め格納したものである。ターゲット情報テーブル２１２は、例えば、ターゲットシステム２５０のＣＰＵの種類や利用可能なレジスタの種類、数及びターゲットシステムで稼働するＯＳの種類などが予め格納されている。コンパイラ２０８は、ターゲット情報テーブル２１２からターゲットシステムの構成を読み込んでオブジェクトプログラム２０７を生成するコンパイル処理を実行する。
【００１３】
コンパイラ２０８は、コンパイル処理を行う過程で、ターゲットシステム２５０のレジスタの割り付け（定義）状態を保持する定義レジスタ情報テーブル２１０を後述するように作成し、また、定義レジスタ情報テーブル２１０に格納されたターゲットシステムのレジスタの重要度を設定するレジスタ情報テーブル２１１を後述のように生成する。
【００１４】
なお、外部記憶装置２０５は、コンパイラ２０８を格納する記憶媒体として機能する。ＣＰＵ２０１は、キーボード２０３からコンパイラ起動命令を受け付けると、外部記憶装置２０５からコンパイラ２０８を主記憶装置２０４に読み込み、ソースプログラム２０６を読み込んで、コンパイル処理を実行する。このとき、ターゲット情報テーブル２１２は予め主記憶装置２０４に読み込んでおくものとする。
【００１５】
なお、図１の主記憶装置２０４には図示しないＯＳが読み込まれ、ＣＰＵ２０１によってＯＳが実行され、このＯＳ上でコンパイラ２０８を実行しても良い。
【００１６】
図２は、本発明のコンパイラ２０８が生成したオブジェクトプログラム２０７を実行する計算機システム（以下、ターゲットシステムとする）２５０の構成図である。このターゲットシステム２５０は、演算処理を行うＣＰＵ（またはプロセッサ）２５１と、情報の表示を行うディスプレイ装置２５２と、情報の入力を行うキーボード２５３と、ＣＰＵ２５１が利用する情報を格納する主記憶装置２５４、および情報を格納する外部記憶装置２５５より構成されている。キーボード２５３により、ユーザからオブジェクトプログラム２０７の起動命令を受け付ける。オブジェクトプログラム２０７の実行結果や終了メッセージまたはエラーメッセージは、ディスプレイ装置２５２に表示される。外部記憶装置２５５はＨＤＤや不揮発性メモリで構成され、コンパイル装置２００で生成されたオブジェクトプログラム２０７が格納される。主記憶装置２５４には、ＯＳ２７０とオブジェクトプログラム２０７が格納される。ＯＳ２７０は主記憶装置２５４上にスタック領域２６０を確保する。
【００１７】
この例では、ＣＰＵ２５１のレジスタとしてＲ１、Ｒ２、Ｒ３、…、Ｒｎ、ＳＰ（スタックレジスタ）が存在し、ＳＰに格納されたスタックポインタがスタック領域２６０のアドレスを指し示す。なお、Ｒ１〜Ｒ３、…、Ｒｎは、例えば、汎用レジスタを示す。
【００１８】
ＣＰＵ２５１は、キーボード２５３からオブジェクトプログラム２０７の起動命令を受け付けると、外部記憶装置２５５からオブジェクトプログラム２０７を主記憶装置２５４に読み込んで実行する。なお、オブジェクトプログラム２０７は、図示しないネットワークなどにより、コンパイル装置２００からターゲットシステム２５０に転送されるものとする。
【００１９】
図３は、図１の計算機システム２００で稼動するコンパイラ２０８の処理手順を示す。
【００２０】
コンパイラ２０８の処理は、ソースプログラム２０６の構文解析３０１と、コード最適化３０２と、レジスタ割り付け３０３と、オブジェクトコードをオブジェクトプログラム２０７として生成するコード生成３０４の順で行う。
【００２１】
構文解析３０１では、コンパイラ２０８がソースプログラム２０６を入力として構文解析を行い、中間コード２０９を出力する。コード最適化３０２では、コンパイラ２０８が中間コード２０９を入力し、ループ構造変換や部分冗長性削除などの最適化を適用し、その結果を変換後の中間コード２０９として出力する。
【００２２】
レジスタ割り付け３０３では、コンパイラ２０８が中間コード２０９の各ノード（各処理要素）に対しターゲットシステム２５０のプロセッサ２５１のレジスタＲ１〜Ｒ３、…、Ｒｎを割り付ける。コード生成３０４では、コンパイラ２０８が中間コード２０９をオブジェクトプログラム２０７に変換してオブジェクトプログラム２０７として出力する。上記構文解析３０１、コード最適化３０２及びレジスタ割り付け３０３は、公知または周知の技術を適用すれば良い。
【００２３】
ｃａｌｌｅｅ−ｓａｖｅレジスタ（以下、ｃａｌｌｅｅレジスタと略す）退避コード及び回復コード削減処理３０５は、ソースプログラム２０６で記述される関数の入口または出口において必要とされる退避コード（Ｐｕｓｈ命令）または回復コード（Ｐｏｐ命令）だけを生成し、出力されるオブジェクトプログラム２０７のコードサイズを削減する処理であり、コード生成３０４内で実施される。
【００２４】
なお、退避コードは、ターゲットシステム２５０のスタック領域２６０に、ターゲットシステム２５０のｃａｌｌｅｅレジスタ（例えばＲ１〜Ｒ３）の内容を退避させ、スタックポインタを更新する命令コードである。特に、ｐｕｓｈ命令は、退避するレジスタのサイズ分だけスタックアドレスを減算した後、減算後のスタックアドレスの指す領域に該レジスタのデータをストアする命令である。
【００２５】
また、回復コードは、ターゲットシステム２５０のスタック領域２６０から、ターゲットシステム２５０のｃａｌｌｅｅレジスタ(例えばＲ１〜Ｒ３)の内容を復帰させ、スタックポインタを更新する命令コードである。特に、ｐｏｐ命令は、スタックアドレスの指す領域から該レジスタにデータをロードした後、当該レジスタのサイズ分だけスタックアドレスを加算する命令である。
【００２６】
図４に、定義レジスタ情報テーブル２１０の一例を示す。コンパイラ２０８により主記憶装置２０４上に生成される。定義レジスタ情報テーブルは、出口ブロック８０１、定義レジスタ集合８０２、重み８０３、処理済フラグ８０４などの欄からなる。
【００２７】
出口ブロック８０１は、ソースプログラム２０６で記述される関数内に存在する出口ブロック情報を登録する。出口ブロックとは、呼び出された関数で最後に実行される基本ブロックを指すものとする。これに対し、入口ブロックとは、呼び出された関数で最初に実行される基本ブロックを指すものとする。図１１に示すソースプログラム２０６において、入口ブロックは、関数の実際の処理が行われる第３行目の処理を示し、出口ブロックは、呼び出し元に戻る第５行目または第１１行目の処理を示し、図１１の例では、条件分岐命令の「if」によって関数の出口ブロックが２つ存在する例を示す。
【００２８】
定義レジスタ集合８０２は、関数の入口ブロックから、出口ブロックに至るパス（処理過程）上で中間コード２０９に定義されているｃａｌｌｅｅレジスタの集合を登録する。ここで、ｃａｌｌｅｅレジスタの集合とは、コンパイラ２０８が上記図３のレジスタ割り付け３０３の処理で、ある関数についてブロック毎にターゲットシステムのＣＰＵ２５１のレジスタを割り付け（定義）られるので、関数の出口ブロックごとに、入口ブロックから当該出口ブロックまでのパス上で定義（割り付け）されたレジスタの番号（名称）または識別子を列記したものである。
【００２９】
また、重み８０３は、各出口ブロックの重要度を登録する。ここで、重要度とは、各出口ブロックがどの程度実行されるかを示した指標であり、重要度が高いほど、その出口ブロックの実行頻度が高いことを示す。この重要度を求める手法としては、コンパイラ２０８がコンパイル時に求める方法（これを静的手法と呼ぶ）や、コンパイラ２０８が生成したオブジェクトプログラム２０７を実行することで求める方法（これを動的手法と呼ぶ）などが考えられる。処理済フラグ８０４は、コンパイラ２０８内の各種処理で対応する出口ブロックの処理が終了しているか否かを判定する際に用いるフラグである。
【００３０】
図５（ａ）に、レジスタ情報テーブル２１１の一例を示す。レジスタ情報テーブル２１１は、コンパイラ２０８により主記憶装置２０４上に生成される。レジスタ情報テーブル２１１は、レジスタ番号９０１、重み９０２、処理済フラグ９０３などの欄からなる。
【００３１】
レジスタ番号９０１は、ターゲットシステム２５０のＣＰＵ２５１のレジスタ番号（または識別子）のうち中間コード２０９で定義されているｃａｌｌｅｅレジスタ番号（または識別子）を登録する。重み９０２は、各レジスタの重要度を登録する。重要度とは、そのレジスタの回復コードがどの程度実行されるかを示した指標であり、重要度が高いほど、そのレジスタの回復コードの実行頻度が高いことを示す。この重要度は、定義レジスタ情報テーブル２１０の、定義レジスタ集合８０２と、重み８０３から計算することができる。詳細は、図８で説明する。処理済フラグ９０３は、各種処理で対応するレジスタの処理が終了しているか否かを判定する際に用いるフラグである。なお、図５（ａ）は、レジスタ情報テーブル２１１のソート前の状態を示し、図５（ｂ）は、ｃａｌｌｅｅレジスタ退避コード及び回復コード削減処理３０５でソートを行った後の状態を示す。
【００３２】
図６に、図３に示したｃａｌｌｅｅレジスタ退避コード及び回復コード削減処理３０５の処理手順を示す。ステップ１０１で、コンパイラ２０８は、ソースプログラム２０６の入口ブロックから、出口ブロックに至るパス上で定義されているレジスタ情報を収集する。なお、ステップ１０１の処理は、関数毎やサブルーチン毎に行うことができる。
【００３３】
ステップ１０２は、コンパイラ２０８がｃａｌｌｅｅレジスタの退避順序または回復順序を決定する。ステップ１０３では、コンパイラ２０８が関数の入口ブロックにｃａｌｌｅｅレジスタの退避コード（例えば、Ｐｕｓｈ命令）を生成する。ステップ１０４は、コンパイラ２０８が関数の出口ブロックに、ステップ１０２で求めた回復順序を考慮したｃａｌｌｅｅレジスタの回復コード（例えば、Ｐｏｐ命令）を生成する。この回復順序を考慮することで、不要な回復コードをオブジェクトプログラム２０７から削減することができる。図６のフローチャートに示したそれぞれの処理の詳細は、図７、図８、図９、図１０で説明する。
【００３４】
図７に、図６で示した定義レジスタ情報収集１０１の処理手順を示す。ステップ４０１では、コンパイラ２０８が中間コード２０９を読み込んで、関数内にあるすべての出口ブロックを出口ブロック集合に登録する。なお、出口ブロック集合は変数としてコンパイラ２０８が主記憶装置２０４上に所定の領域を確保する。以下に説明する基本ブロック集合、処理済基本ブロック集合等も同様に変数としてコンパイラ２０８が主記憶装置２０４上に所定の領域を確保する。
【００３５】
ステップ４０２では、コンパイラ２０８が出口ブロック集合が空であるか否かを判定する。空でなければ、処理の終了していない出口ブロックが存在しているということなので、ステップ４０３に進む。ステップ４０３では、処理の終了していない出口ブロックに対応する定義レジスタ集合８０２を初期化のため空にする。ステップ４０４では、処理済基本ブロック集合を初期化のため空にする。これは、同じ基本ブロックを何度も処理しないために設けている。なお、基本ブロックは、ひとつの関数（またはサブルーチン）のうち、一連の演算処理を示し、例えば、図１１のソースプログラム２０６に記述された１行を基本ブロックとして扱う。
【００３６】
ステップ４０５では、基本ブロック集合に出口ブロック集合を登録する。ステップ４０６では、基本ブロック集合が空か否かを判定する。基本ブロック集合が空の場合は、ステップ４１１に進む。基本ブロック集合が空でない場合は、ステップ４０７に進む。ステップ４０７では、基本ブロック集合から先頭要素を取り出す。取り出した先頭要素は基本ブロック集合から削除する。
【００３７】
ステップ４０８では、コンパイラ２０８がステップ４０７で取り出した基本ブロックに対し、基本ブロック内の全命令を辿り、それぞれの命令で定義されているレジスタを定義レジスタ情報テーブル２１０の定義レジスタ集合８０２に登録していく。ステップ４０９では、処理の終了した基本ブロックを、処理済基本ブロック集合に登録する。ステップ４１０では、ステップ４０７で取り出した基本ブロックの直前に実行される基本ブロックを辿り、直前に実行される基本ブロックが処理済基本ブロック集合に登録されていなければ、当該基本ブロックを基本ブロック集合に登録し、ステップ４０６に戻る。
【００３８】
上記ステップ４０６〜ステップ４１０の処理を繰り返すことで、入口ブロックからある出口ブロックに至るパス上で定義されている定義レジスタ集合を求めることができる。
【００３９】
定義レジスタ集合を求めた後は、基本ブロック集合が空になっているはずなので、ステップ４０６の判定により、ステップ４１１に進む。ステップ４１１では、出口ブロックと定義レジスタ集合の組を定義レジスタ情報テーブル２１０へ登録する。
【００４０】
コンパイラ２０８が定義レジスタ情報テーブル２１０へ定義レジスタ情報８０２を登録することにより、入口ブロックから出口ブロックに至るパス上で定義されているレジスタ情報が図４で示すように明確になる。定義レジスタ情報テーブル２１０に定義されているレジスタは、出口ブロックにおいて回復の必要なレジスタとなる。よって、入口ブロックで退避されたレジスタであっても、この定義レジスタ集合に登録されてないレジスタは、回復不要なレジスタとみなすことができる。この回復不要なレジスタを抽出することで、オブジェクトプログラム２０７に挿入する回復コードが削減可能となるのである。つまり、ソースプログラム２０６で記述された処理の手順でコンパイル処理を行った場合、オブジェクトプログラム２０７に生成される回復コードのうち、実際には機能しない回復コードを抽出して、当該回復コードをオブジェクトプログラム２０７に加えるのを阻止することができる。
【００４１】
ステップ４１２では、処理の終了した出口ブロックを、出口ブロック集合から削除し、ステップ４０２に戻る。ステップ４０２では、出口ブロック集合が空の場合、つまり、すべての出口ブロックの処理が終了した場合は、ステップ４１３に進む。ステップ４１３では、定義レジスタ情報テーブルに登録されている出口ブロックに対し、そのブロックの重要度を表現する重みという値を設定する。この重みが重い（大きい）ほど、その出口ブロックの定義レジスタ集合に登録されているレジスタの重要度が高くなる。
【００４２】
この重みを設定する手法として、上述したような静的に設定する手法と、動的に設定する手法などが存在する。静的に設定する手法は、コンパイラ２０８自身が各出口ブロックの重みを決定するものである。動的に設定する手法は、予め関数出口の実行回数をカウントするコードを埋め込んだオブジェクトプログラムを実行させ、関数出口の実行回数情報を取得した後、取得した実行回数情報をコンパイラ２０８が読み込み、実行回数からコンパイラ２０８が重みを計算して設定する。この動的な関数出口の重み付けの場合では、関数出口の実行回数情報を、ターゲット情報テーブル２１２で関数毎に設定しておけばよい。静的に設定する手法は、一度のコンパイルで重みを決定するため、オブジェクトプログラム２０７を実行しなくて良いという利点があるが、コンパイラ２０８の決めた重みと実際のプログラム（オブジェクトプログラム２０７）の動作が大きく異なる可能性があるという欠点がある。
【００４３】
一方、動的に重みを設定する手法では、オブジェクトプログラム２０７をターゲットシステム２５０で一度実行させる手間がかかるという欠点があるが、得られた情報が実際のプログラム動作と一致しているという利点がある。
【００４４】
図８に、ｃａｌｌｅｅレジスタの退避順序及び回復順序の決定１０２の処理手順を示す。ステップ５０１では、コンパイラ２０８がレジスタ情報テーブル２１１の重みをクリアして初期化する。ステップ５０２では、コンパイラ２０８が定義レジスタ情報テーブル２１０の処理済フラグをクリアして初期化する。
【００４５】
ステップ５０３では、コンパイラ２０８が定義レジスタ情報テーブル２１０の処理済フラグ８０４を読み込んで、すべての出口ブロックが処理済か否かを判定する。出口ブロックが処理済か否かは、定義レジスタ情報テーブル２１０に登録されている出口ブロックに対する処理済フラグ８０４がすべて設定されているか否かで判定する。すべての出口ブロックが処理済の場合は、ステップ５０９に進む。一方、すべての出口ブロックが処理済でない場合は、ステップ５０４に進む。
【００４６】
ステップ５０４では、コンパイラ２０８が処理対象とした出口ブロックに対応する定義レジスタ情報テーブル２１０の処理済みフラグをセットする。ステップ５０５では、コンパイラ２０８がまだ処理されてない出口ブロックに対応する定義レジスタ集合を定義レジスタ情報テーブル２１０から取り出し、ステップ５０６に進む。
【００４７】
ステップ５０６では、前記取り出した定義レジスタ集合をすべて処理したか否かを判定する。取り出した定義レジスタ集合がすべて処理済の場合は、ステップ５０３に戻り、次の出口ブロックの処理を行う。一方、取り出した定義レジスタ集合が、まだ処理されてない場合は、ステップ５０７に進む。ステップ５０７では、定義レジスタ集合から１つレジスタを取り出し、このレジスタの重みをステップ５０８で設定する。
【００４８】
ステップ５０８では、出口ブロック情報から定義レジスタ情報テーブル２１０に登録されている重み８０３を取り出す。さらに、処理対象のレジスタのレジスタ情報テーブル２１１に、ステップ５０８で取り出した重みを加算する。
【００４９】
上記ステップ５０３〜ステップ５０８までを繰り返すことで、定義レジスタ情報テーブル２１０の定義レジスタ集合に対してコンパイラ２０８が設定した重み８０３が、各レジスタに対する重みとしてレジスタ情報テーブル２１１に加算される。すべてのレジスタの重みが設定された後は、ステップ５０９に進み、重みが降順になるようにレジスタ情報テーブル２１１をソートする。ソート後は、図５（ｂ）のように、レジスタ情報テーブル２１１の先頭（図中最上方のエントリ）から、重要と判定したレジスタが配置される。
【００５０】
図９に、ｃａｌｌｅｅレジスタの退避コード生成１０３の処理手順を示す。ステップ６０１では、コンパイラ２０８が中間コード２０９を読み込んで、入口ブロック集合に入口ブロックを登録する。なお、入口ブロック集合は変数としてコンパイラ２０８が主記憶装置２０４上に所定の領域を確保する。また、入口ブロックは、図１１で示したように、ひとつの関数（またはサブルーチン）のうち最初の演算処理を行う基本ブロックであり、図１１のソースプログラム２０６において、関数の最初の演算処理を行う行を指す。
【００５１】
ステップ６０２では、入口ブロック集合が空か否かを判定する。空の場合は、処理を終了する。入口ブロック集合が空でない場合は、ステップ６０３に進む。ステップ６０３では、入口ブロック集合から先頭要素を取り出す。そして、取り出した先頭要素は基本ブロック集合から削除する。
【００５２】
ステップ６０４では、処理対象としている入口ブロックで、退避コードを挿入するための基準点となる命令を登録する。本実施形態では、ターゲットシステム２５０のスタックアドレス（スタックポインタ）を保持するスタックレジスタＳＰの更新を行う命令（例えば、add命令）を基準点として登録する。
【００５３】
ステップ６０５では、コンパイラ２０８がレジスタ情報テーブル２１１の処理済フラグ９０３をすべてクリアして初期化する。ステップ６０６では、すべてのレジスタの退避コードが生成されているか否かを判定する。この判定は、レジスタ情報テーブル２１１の処理済フラグ９０３がすべてセットされているか否かで行う。処理済フラグ９０３がすべてセットされている場合は、ステップ６０２に戻る。処理済フラグ９０３がすべてセットされてない場合は、ステップ６０７に進む。
【００５４】
ステップ６０７では、コンパイラ２０８がレジスタ情報テーブル２１１の先頭（図中最上方のエントリ）から後方（図中最下方のエントリ）へテーブルを辿りながら、処理済フラグ９０３がセットされてないレジスタの退避コードを生成する。退避コードは、例えば、ｐｕｓｈ命令を用いる。ステップ６０７で生成された退避コードは、ステップ６０４で設定した、挿入基準命令の直前に挿入する。
【００５５】
ステップ６０８では、コンパイラ２０８が退避コードの生成を終えたレジスタに対応する、レジスタ情報テーブル２１１の処理済フラグ９０３をセットする。
【００５６】
上記ステップ６０６〜ステップ６０８までの処理を繰り返すことで、ソースプログラム２０６で記述された基本ブロックの入口ブロックにおいて必要なｃａｌｌｅｅレジスタの退避コードを生成することができる。
【００５７】
図１０に、ｃａｌｌｅｅレジスタの回復コード生成１０４の処理手順を示す。ステップ７０１では、コンパイラ２０８が定義レジスタ情報テーブル２１０の処理済フラグ８０４をすべてクリアして初期化する。ステップ７０２では、全ての出口ブロックが処理済か否かを判定する。この判定は、定義レジスタ情報テーブル２１０の処理済フラグ８０４がすべてセットされているか否かで行う。処理済フラグ８０４がすべてセットされている場合は、処理を終了する。
【００５８】
一方、処理済フラグ８０４がすべてセットされてない場合は、ステップ７０３に進む。ステップ７０３では、処理対象とした出口ブロックに対応する定義レジスタ情報テーブル２１０の処理済みフラグ８０４をセットする。ステップ７０４では、処理対象としている出口ブロックで、回復コードを挿入するための基準点となる命令を登録する。基準点となる命令は、上述の入口ブロックの基準点と同様に、スタックレジスタＳＰの更新を行う命令（例えば、Ｐｏｐ命令）とする。
【００５９】
ステップ７０５では、コンパイラ２０８が回復コード削減サイズの初期化を行う。この回復コード削減サイズが、０であるか否かを判定することで、ある出口ブロックにおいて回復コードを削減したか否かが判定可能となる。なお、回復コード削減サイズは、コンパイラ２０８が変数として主記憶装置２０４上に確保する。
【００６０】
ステップ７０６では、コンパイラ２０８がレジスタ情報テーブル２１１の処理済フラグ９０３をすべてクリアする。ステップ７０７では、すべてのレジスタが処理済か否かを判定する。この判定は、レジスタ情報テーブル２１１の処理済フラグ９０３がすべてセットされているか否かで行う。処理済フラグ９０３がすべてセットされている場合は、ステップ７１２に進む。処理済フラグ９０３がすべてセットされてない場合は、ステップ７０８に進む。
【００６１】
ステップ７０８では、レジスタ情報テーブル２１１の先頭から後方へテーブルを辿りながら、最初に見つけた処理済フラグ９０３の設定されてないレジスタ番号に対し、当該出口ブロックで回復コードが必要か否かを判定する。この判定は、当該出口ブロックに対応する定義レジスタ情報テーブル２１０の定義レジスタ集合８０２に、当該レジスタが登録されているか否かで行う。当該出口ブロックに対応する定義レジスタ情報テーブル２１０の定義レジスタ集合８０２に、当該レジスタが登録されてない場合は、入口ブロックから当該出口ブロックに至るパス上で、このレジスタの定義が行われてないと判定されるので、回復コードを生成する必要はなく、ステップ７１０に進む。
【００６２】
ステップ７１０では、削減したレジスタのサイズを記憶しておくために、コンパイラ２０８が上記ステップ７０８で回復コードの必用がないと判定したレジスタのサイズを回復コード削減サイズに加算する。
【００６３】
一方、定義レジスタ情報テーブル２１０の定義レジスタ集合８０２に当該レジスタが登録されている場合は、回復コードが必要になるため、ステップ７０９で回復コードを生成し、ステップ７０４で設定した挿入基準点の直後に挿入する。回復コードは、例えば、ｐｏｐ命令を用いる。
【００６４】
ステップ７１１では、コンパイラ２０８が上記回復コードの処理を終えたレジスタに対応するレジスタ情報テーブル２１１の処理済フラグ９０３をセットし、ステップ７０７に戻る。ステップ７１２では、当該出口ブロックでの回復コード削減サイズが０であるか否かを判定する。回復コード削減サイズが０の場合は、回復コードの削減が行われてないと判定して、ステップ７０２に戻る。回復コード削減サイズが０以外の場合は、回復コードの削減が行われていると判定して、ステップ７１３に進む。
【００６５】
ステップ７１３では、コンパイラ２０８が回復コードの削減が行われた出口ブロックに対し、出口ブロックのスタックレジスタＳＰの更新命令に削減サイズを反映させる。この反映処理により、ｐｕｓｈ／ｐｏｐ命令利用時に回復コードを削減しても正しいコードを生成することができる。
【００６６】
以上の処理により、関数の出口毎に回復コードが挿入されるが、関数の出口が複数存在する場合は、各関数出口で関数の入口で挿入した退避コードに対応するすべてのレジスタについて回復する必用はなく、関数入口から当該関数出口までのパス上で割り付けられたレジスタのみについて回復コードを生成することになる。この結果、前記従来例では、関数入口で退避したレジスタについて、関数出口ですべてのレジスタに対して回復コードを生成したのに対し、本発明では、関数入口から関数出口のパス上で定義されていないレジスタについては退避コードの生成を行わず、オブジェクトプログラム２０７のサイズを削減できる。そして、回復コードを削減したレジスタについては、レジスタのサイズに相当するスタックアドレスを補正することで、回復コードの生成を省略しながら正常なオブジェクトプログラム２０７を生成することができる。
【００６７】
図１１のプログラム（ソースプログラム２０６）例を参照して本実施形態における回復コード削減処理手順を示す。
【００６８】
図１１のプログラム例はＣ言語で記述してある。このソースプログラム２０６、引数で渡された配列とその要素数から、配列要素の合計を求めるものである。また、４行目で配列が存在しない場合は５行目で配列要素の合計として０を返却し、配列が存在する場合は、８行目から１０行目の繰り返し文により、配列要素の合計を計算し、１１行目で合計を返却する。そのため、このソースプログラム２０６では、関数出口が５行目と１１行目の２箇所存在する。この２箇所の関数出口が上述した出口ブロックとしてコンパイラ２０８で処理され、また、関数の入口となる３行目が入口ブロックとしてコンパイラ２０８で処理される。なお、１行目などは、コンパイラ２０８に対する定義分であるため、コード生成３０４では基本ブロックとして扱わないものとする。
【００６９】
本ソースプログラム２０６に対し、コンパイラ２０８がレジスタ割り付けを行った結果、入口から１１行目の出口１に至るパス上で定義されたレジスタが図１で示したターゲットシステム２５０のＣＰＵ２５１のレジスタＲ１、Ｒ２、Ｒ３であり、入口から５行目の出口２に至るパス上で定義されたレジスタがＲ３であったとし、それぞれの出口ブロックの重みが出口１で０．８、出口２で０．２であったとする。この状態でステップ１０１の定義レジスタ情報収集処理を適用すると、図４の定義レジスタ情報テーブル２１０が求められる。
【００７０】
次に、図４の定義レジスタ情報テーブルに対し、コンパイラ２０８はステップ１０２のｃａｌｌｅｅレジスタの退避・回復順序を決定する処理を適用した結果を図５（ａ）に示す。
【００７１】
図４の定義レジスタ情報テーブル２１０において、まず、出口１では、定義レジスタ集合８０２にレジスタＲ１、Ｒ２、Ｒ３が定義されており、出口ブロックの重みが０．８と登録されているため、図５（ａ）のレジスタ情報テーブル２１１のＲ１、Ｒ２、Ｒ３の重みに０．８がそれぞれ設定される。図４の定義レジスタ情報テーブル２１０の出口２では、定義レジスタ集合８０２にレジスタＲ３だけが定義されており、出口ブロックの重みが０．２と登録されているため、レジスタ情報テーブル２１１のレジスタＲ３だけに重み０．２を加算する。その結果図５（ａ）で示す状態のレジスタ情報テーブル２１１が得られる。図５（ａ）のレジスタ情報テーブル２１１に対し、重み９０２に従って降順にソートした結果が図５（ｂ）のレジスタ情報テーブル２１１である。
【００７２】
図５（ｂ）において、レジスタＲ３は、出口１から出る場合でも出口２から出る場合でもレジスタの回復コードが必要になるため、レジスタＲ１やレジスタＲ２よりも重要であると判定されている。つまり、出口１では、入口で退避したすべてのレジスタＲ１〜Ｒ３の回復が必用になるのに対し、出口２では、入口から出口２までのパス上でレジスタＲ３のみが定義されるだけである。このため、コンパイラ２０８は、出口２ではレジスタＲ３のみの退避コードを生成し、レジスタＲ１、Ｒ２の退避コードを省略することができる。
【００７３】
従来技術において図１１のソースプログラム２０６の退避コードと、回復コードを生成した例を図１２に示す。図１２（ａ）の退避コードでは、レジスタＲ１、Ｒ２、Ｒ３が順番にスタック上にｐｕｓｈ命令で退避され、その後でワーク領域を確保するためにスタックアドレス更新命令（add  SP、−α）が実行されている。また、従来技術による図１２（ｂ）の回復コードでは、まずワーク領域を解放するためにスタックアドレス更新命令（add  SP、α）が実行された後、レジスタＲ３、Ｒ２、Ｒ１の順番でスタック上からｐｏｐ命令で回復されている。
【００７４】
次に、図４の定義レジスタ情報テーブルと、図５（ａ）、図５（ｂ）のレジスタ情報テーブルから生成される本実施形態による退避コード及び回復コードの例を図１３、図１４に示す。
【００７５】
図１３（ａ）、図１３（ｂ）は、本発明により回復レジスタの削減がない出口１で退避コードと回復コードを生成した例を示している。
【００７６】
図１３（ａ）の退避コードでは、重み付けに応じた順序でレジスタＲ３、Ｒ１、Ｒ２がスタック領域上にｐｕｓｈ命令で退避され、その後でワーク領域を確保するためにスタックアドレス更新命令（add  SP、−α）が実行されている。また、図１３（ｂ）の回復コードでは、まずワーク領域を解放するためにスタックアドレス更新命令（add  SP、α）が実行された後、重み付けに応じた順序でレジスタＲ２、Ｒ１、Ｒ３がスタック上からｐｏｐ命令で回復されている。前記従来例の図１２（ｂ）の回復コードは、退避したレジスタの逆順でレジスタの回復が行われる。この従来例に対して、本発明では図１３（ｂ）で示すように、ＰＯＰ命令を実行するレジスタの順序が重みに応じてＲ２、Ｒ１、Ｒ３の順でレジスタの回復を実行する。なお、関数入口のレジスタの退避コードの順位は、関数出口の重みの順位を援用する。
【００７７】
図１４（ｂ）は、回復レジスタの削減がある出口２での回復コードを示している。レジスタの重要度を考慮してレジスタの退避順序と回復順序を決定することにより、図１４（ｂ）の回復コードでレジスタＲ１とレジスタＲ２の回復コードを削減した場合でも、回復コードであるｐｏｐ命令でのスタックアドレス更新サイズ（＝削減レジスタサイズ）を、スタックレジスタ更新命令の更新サイズα＋８に反映させることにより、上記従来例のように余計な命令を挿入することなく、回復コードの削減を行うことができる。
【００７８】
すなわち、図１４（ａ）の退避コードでは、上記出口１と同様に、重み付けに応じた順でレジスタＲ３、Ｒ１、Ｒ２がスタック領域上にｐｕｓｈ命令で退避され、その後でワーク領域を確保するためにスタックアドレス更新命令（add  SP、−α）が実行される。
【００７９】
そして、図１４（ｂ）の回復コードでは、まずワーク領域を解放するためにスタックアドレス更新命令が実行されるが、このとき、回復コードを削除するレジスタの数に応じてスタックアドレスが補正される。この例では、レジスタＲ１、Ｒ２の回復コードを削除するので、各レジスタＲ１〜Ｒ３のサイズを４バイトとすると、２つのレジスタ分の８バイトが削除レジスタサイズとなる。このため、スタックアドレス更新命令は、（add  SP、α＋８）となって、２つ分のレジスタに相当するスタックアドレスがシフトする。
【００８０】
スタックアドレス更新命令が実行された後、重み付けに応じて選択されたレジスタＲ３のみがスタック領域からｐｏｐ命令で回復されている。
【００８１】
このように関数出口２では、連続したレジスタＲ１とＲ２の回復が不要とコンパイラ２０８は判定し、レジスタＲ３のみを回復すればよい。このため、コンパイラ２０８は、２つのｐｏｐ命令の代わりに１つのスタックアドレス更新命令（ａｄｄ  ＳＰ＋８）を実行して、削除するレジスタの数に応じてスタックアドレスを補正してからレジスタＲ３のＰＯＰ命令を生成する。この結果、ターゲットシステム２５０でオブジェクトプログラム２０７を実行すると、図１４（ａ）の退避コードでレジスタＲ３，Ｒ１、Ｒ２の順でスタック領域２６０に各レジスタの内容を退避させてからαバイトのワーク領域を確保する。
【００８２】
関数出口２では、αバイトのワーク領域を解放し、かつ、スタックアドレスに回復コードを削除した２つのレジスタＲ１、Ｒ２のサイズに相当する８バイトを加算してからレジスタＲ３をＰＯＰ命令で回復する。これにより、２つの回復コードを削減しながらスタックレジスタＳＰのスタックアドレスを各レジスタＲ１〜Ｒ３の退避以前の状態に復帰させて、オブジェクトプログラム２０７を正常に実行させることができる。
【００８３】
このように、本第１の実施形態によれば、複数の関数出口が存在する関数のオブジェクトコードを生成する場合には、ｃａｌｌｅｅ−ｓａｖｅレジスタの不要な回復コードが削減可能となって、オブジェクトプログラム２０７のコードサイズを削減し、実行性能の良いオブジェクトプログラム（実行コード）を生成することが可能になる。
【００８４】
また、不要な回復コードの生成を削除した分、スタックアドレスを補正するが、このとき作成しなかった回復コードのそれぞれについてスタックレジスタの更新命令を生成すると、オブジェクトコードの削減ができないが、本発明のように、関数出口のレジスタに重みを設定して、重みの降順にソートしてから複数のレジスタ更新命令を一つにまとめるようにしたので、コンパイラ２０８が生成するオブジェクトコードのサイズを低減することが可能となる。
【００８５】
＜第２実施形態＞
図１５、図１６に、ｃａｌｌｅｅレジスタ退避・回復コード削減処理の第２の実施形態を示す。
【００８６】
図１５は、前記第１の実施形態の図３に示したｃａｌｌｅｅレジスタ退避コード及び回復コード削減処理３０５の第２の処理手順を示すフローチャートである。
【００８７】
ステップ１０１では、コンパイラ２０８が前記第１の実施形態と同様に中間コード２０９を読み込んで、入口ブロックから、出口ブロックに至るパス上で定義されているレジスタ情報を収集する。ステップ１０３では、コンパイラ２０８が関数入口ブロックにｃａｌｌｅｅレジスタの退避コードを生成する。ステップ１５０４は、コンパイラ２０８がｃａｌｌｅｅレジスタの回復コードを生成する。
【００８８】
図１６に、図１５で示したｃａｌｌｅｅレジスタの回復コード生成１５０４の処理手順を示す。この回復コード生成処理１５０４では、回復が不要と判定したレジスタに対し、ｐｏｐ命令の代わりに、スタックアドレスを更新する命令を挿入する。スタックアドレス更新命令とは、スタックアドレスを保持するスタックレジスタ（ＳＰ）に、レジスタサイズ分の定数を加算するものである。そして、スタックアドレスを更新する命令が連続して挿入された場合、当該連続する命令を１つの命令にまとめることで、回復コードの削減を行うものである。例えば、連続する２命令を１命令にまとめた場合、スタックアドレス更新命令の定数部分は、レジスタサイズ×２となる。以下、回復コード生成処理１５０４の処理手順を説明する。
【００８９】
ステップ１６０１では、コンパイラ２０８が定義レジスタ情報テーブル２１０の処理済フラグ８０４をすべてクリアして初期化する。ステップ１６０２では、全ての出口ブロックが処理済か否かを判定する。この判定は、定義レジスタ情報テーブル２１０の処理済フラグ８０４がすべてセットされているか否かで行う。処理済フラグ８０４がすべてセットされている場合は、処理を終了する。一方、処理済フラグ８０４がすべてセットされてない場合は、ステップ１６０３に進む。ステップ１６０３では、処理対象とした出口ブロックに対応する定義レジスタ情報テーブル２１０の処理済みフラグ８０４をセットする。ステップ１６０４では、処理対象としている出口ブロックで、回復コードを挿入するための基準点となる命令を登録する。基準点となる命令は、前記第１の実施形態で述べたように入口ブロックの基準点と同様に、スタックレジスタの更新を行う命令とする。
【００９０】
ステップ１６０５では、コンパイラ２０８が連続するスタックアドレス更新命令を１つにまとめる際に利用する領域を初期化し、スタックアドレス更新命令を未登録の状態にする。ステップ１６０６では、レジスタ情報テーブル２１１の処理済フラグ９０３をすべてクリアして初期化する。ステップ１６０７では、すべてのレジスタが処理済か否かを判定する。この判定は、レジスタ情報テーブル２１１の処理済フラグ９０３がすべてセットされているか否かで行う。処理済フラグ９０３がすべてセットされている場合は、ステップ１６０２に戻る。一方、処理済フラグ９０３がすべてセットされてない場合は、ステップ１６０８に進む。ステップ１６０８では、レジスタ情報テーブル２１１の先頭から後方へテーブルを辿りながら、最初に見つけた処理済フラグ９０３がセットされてないレジスタ番号に対し、当該出口ブロックで回復コードが必要か否かを判定する。この判定は、当該出口ブロックに対応する定義レジスタ情報テーブル２１０の定義レジスタ集合８０２に、当該レジスタが登録されているか否かで行う。定義レジスタ集合８０２に当該レジスタが登録されている場合は、回復コードが必要になるため、ステップ１６０９で回復コードを生成し、ステップ１６０４で設定した挿入基準点の直後に挿入する。回復コードは、例えば、ｐｏｐ命令を用いる。
【００９１】
ステップ１６１０では、スタックアドレス更新命令の登録状態（変数）を初期化し、スタックアドレス更新命令を未登録の状態にする。スタックアドレス更新命令は、連続したスタックアドレス命令を１つにまとめるためのものなので、回復コードでｐｏｐ命令が生成された場合は、登録状態を初期化する必要がある。ステップ１６０８で、コンパイラ２０８は、定義レジスタ集合８０２に当該レジスタが登録されてない場合は、入口ブロックから当該出口ブロックに至るパス上で、このレジスタの定義が行われてないと判定されるので、回復コードを生成する必要はなく、ステップ１６１１に進む。
【００９２】
ステップ１６１１では、スタックアドレス更新命令が登録済か否かを判定する。この判定は、スタックアドレス更新命令の登録状態（変数）を参照して既登録であるか否かを判定すればよい。スタックアドレス更新命令が登録されている場合は、コンパイラ２０８が回復コードで連続してスタックアドレス更新命令が生成されたと判定するので、命令の削減処理を行う。命令の削減は、当該レジスタに対するアドレス更新命令を生成せず、当該レジスタのサイズ分を、スタックアドレス更新命令として登録されている命令の定数加算部分に反映させることで行える。
【００９３】
この定数加算値を修正する処理をステップ１６１２で行う。ステップ１６１１で、スタックアドレス更新命令の登録状態に登録されてない場合は、ステップ１６１３に進む。ステップ１６１３では、回復コードが不要と判定されたものについて、スタックアドレス更新命令を作成し、ステップ１６０４で設定した挿入基準点の直後に挿入する。そして、ステップ１６１４で、スタックアドレス更新命令を登録する。これらの処理が終了した後は、ステップ１６１５でレジスタ情報テーブル２１１の処理済フラグ９０３を設定し、ステップ１６０７に戻る。
【００９４】
上記処理によって、連続するレジスタの回復コードが不要と判定された場合、ｐｏｐ命令を利用せず、１つのスタックアドレス更新命令でスタックアドレスを操作することにより、回復コードサイズを削減することができる。
【００９５】
次に、図４の定義レジスタ情報テーブルと、図５（ａ）、図５（ｂ）のレジスタ情報テーブルから生成される本第２実施形態による回復コードの例を図１７（ｂ）に示す。前記従来例の図１２（ｂ）では、回復レジスタの削減がない出口１での回復コードを示している。本第２の実施形態の図１７（ｂ）は、回復レジスタの削減がある出口２での回復コードを示している。図１７（ｂ）に示す出口２では、連続したレジスタＲ１とＲ２の回復が不要と判定されているため、２つのｐｏｐ命令の変わりに１つのアドレス更新命令（ａｄｄ  ＳＰ，８）が生成されるため、回復コードサイズを削減することができる。この例ではひとつのレジスタサイズを４バイトとしているため、スタックアドレス更新命令の定数部分は８（＝４×２）となる。
【００９６】
以上のように、第２の実施形態においても、ｃａｌｌｅｅ−ｓａｖｅレジスタの不要な回復コードが削減可能となって、オブジェクトプログラムのコードサイズを削減し、実行性能の良いオブジェクトプログラム（実行コード）を生成することが可能になる。
【００９７】
なお、上記各実施形態においては、ソースプログラム２０６からオブジェクトプログラム２０７を生成する計算機と、オブジェクトプログラム２０７を実行する計算機（ターゲットシステム２５０）が異なる例を示したが、ひとつの計算機で、コンパイル処理とオブジェクトプログラム２０７の実行を行っても良い。この場合、ターゲット情報テーブル２１２は、計算機２００のリソースについて記載しておけばよい。
【産業上の利用可能性】
【００９８】
以上のように、本発明では、ソースプログラムをオブジェクトプログラムに変換する処理でスタック操作命令（ｐｕｓｈ／ｐｏｐ命令）を利用してｃａｌｌｅｅ−ｓａｖｅレジスタ退避コードおよび回復コードを生成するコンパイル装置、コンパイラに適用できる。
【図面の簡単な説明】
【００９９】
【図１】本発明に係るコンパイラが稼動する計算機システムのブロック図である。
【図２】図１のコンパイラで生成したオブジェクトプログラムを実行するターゲットシステムのブロック図である。
【図３】第１の実施形態を示し、コンパイラの処理手順を示すフローチャート。
【図４】第１の実施形態を示し、定義レジスタ情報テーブルの一例を示す説明図。
【図５】第１の実施形態を示し、レジスタ情報テーブルの一例を示す説明図で、（ａ）はソート前の状態を示し、（ｂ）はソート後の状態を示す。
【図６】図３に示したｃａｌｌｅｅレジスタ退避コード及び回復コード生成の処理手順を示すフローチャート。
【図７】第１の実施形態を示し、図６で示した定義レジスタ情報収集１０１の処理手順を示すフローチャート。
【図８】第１の実施形態を示し、図６で示したｃａｌｌｅｅレジスタの退避順序及び回復順序の決定の処理手順を示すフローチャート。
【図９】第１の実施形態を示し、図６で示したｃａｌｌｅｅレジスタの退避コード生成の処理手順を示すフローチャート。
【図１０】第１の実施形態を示し、図６で示したｃａｌｌｅｅレジスタの回復コード生成の処理手順を示すフローチャート。
【図１１】第１の実施形態を示し、ソースプログラムの一例を示す説明図。
【図１２】従来技術による退避コードと回復コードの生成例を示し、（ａ）は退避コードを示し、（ｂ）は退避コードに対応する回復コードを示す。
【図１３】第１の実施形態を示し、回復コードを削減しない場合の退避コードと回復コードの生成例を示しており、（ａ）は退避コードを示し、（ｂ）は退避コードに対応する回復コードを示す。
【図１４】第１の実施形態を示し、回復コードを削減する場合の退避コードと回復コードの生成例を示しており、（ａ）は退避コードを示し、（ｂ）は退避コードに対応する回復コードを示す。
【図１５】第２の実施形態を示し、ｃａｌｌｅｅレジスタ退避コード及び回復コード生成の処理手順を示すフローチャート
【図１６】第２の実施形態を示し、図１５で示したｃａｌｌｅｅレジスタの回復コード生成１５０４の処理手順を示すフローチャート。
【図１７】第２の実施形態を示し、回復コードを削減する場合の退避コードと回復コードの生成例を示しており、（ａ）は退避コードを示し、（ｂ）は退避コードに対応する回復コードを示す。
【符号の説明】
【０１００】
１０１  定義レジスタ情報収集処理
１０２  退避・回復順序の決定処理
１０３  退避コード生成処理
１０４  回復コード生成処理
２００  計算機システム（コンパイル装置）
２０６  ソースプログラム
２０７  オブジェクトプログラム
２０８  コンパイラ
２１０  定義レジスタ情報テーブル
２１１  レジスタ情報テーブル
２１２  ターゲット情報テーブル
２５０  計算機システム（ターゲットシステム）
【図１】
2010122820.tif 000003
【図２】
2010122820.tif 000004
【図３】
2010122820.tif 000005
【図４】
2010122820.tif 000006
【図５】
2010122820.tif 000007
【図６】
2010122820.tif 000008
【図７】
2010122820.tif 000009
【図８】
2010122820.tif 000010
【図９】
2010122820.tif 000011
【図１０】
2010122820.tif 000012
【図１１】
2010122820.tif 000013
【図１２】
2010122820.tif 000014
【図１３】
2010122820.tif 000015
【図１４】
2010122820.tif 000016
【図１５】
2010122820.tif 000017
【図１６】
2010122820.tif 000018
【図１７】
2010122820.tif 000019