(57)【特許請求の範囲】
【請求項１】
ソースプログラムに基づいてオブジェクトコードを生成するコンパイラにおいて、
前記ソースプログラム中に記述された、第１のオブジェクトコードを指示する第１の演算指示情報と、第２のオブジェクトコードを指示する第２の演算指示情報と、前記第１および第２のオブジェクトの間に開けるべきサイクル数または命令数とを記述した命令スケジューリング情報を検出する命令検出部と、
前記第１および第２のオブジェクトコードの間に、これらオブジェクトコードが使用するハードウェアリソースを使用せずに別のハードウェアリソースを使用するオブジェクトコードを前記サイクル数または命令数分だけ挿入するオブジェクトコード挿入部と、を備え、
前記命令スケジューリング情報は、前記第１及び第２の演算指示情報と、これら第１及び第２の演算指示情報に対応するオブジェクトコード間に開けるべきサイクル数または命令数と、を引数とする特定の関数であることを特徴とするコンパイラ。
【請求項２】
前記オブジェクトコード挿入部は、前記第１の演算指示情報に対応するオブジェクトコードと前記第２の演算指示情報に対応するオブジェクトコードとの間に、これらオブジェクトコードが使用するハードウェアリソースを使用せずに別のハードウェアリソースを使用する他のオブジェクトコードを前記サイクル数または命令数分だけ挿入することを特徴とする請求項１に記載のコンパイラ。
【請求項３】
前記ハードウェアリソースは、演算レジスタ及びメモリの少なくとも一方であることを特徴とする請求項１または２に記載のコンパイラ。
【請求項４】
前記第１の演算指示情報に対応するオブジェクトコードの直前に実行される予定のオブジェクトコードを他のコード位置に移動可能か否かを判定する第１移動判定部と、
前記第１移動判定部により移動可能と判定されたオブジェクトコードが使用するハードウェアリソースが前記第１の演算指示情報に対応するオブジェクトコードが使用するハードウェアリソースと衝突するか否かを判定する第１リソース判定部と、を備え、
前記オブジェクトコード挿入部は、前記第１リソース判定部により衝突しないと判定されたオブジェクトコードを、前記第１の演算指示情報に対応するオブジェクトコードと前記第２の演算指示情報に対応するオブジェクトコードとの間に移動させることを特徴とする請求項２または３に記載のコンパイラ。
【請求項５】
前記第２の演算指示情報に対応するオブジェクトコードの直後に実行される予定のオブジェクトコードを他のコード位置に移動可能な否かを判定する第２移動判定部と、
前記第２移動判定部により移動可能と判定されたオブジェクトコードが使用するハードウェアリソースが前記第２の演算指示情報に対応するオブジェクトコードが使用するハードウェアリソースと衝突するか否かを判定する第２リソース判定部と、を備え、
前記オブジェクトコード挿入部は、前記第２リソース判定部により衝突しないと判定されたオブジェクトコードを、前記第１の演算指示情報に対応するオブジェクトコードと前記第２の演算指示情報に対応するオブジェクトコードとの間に移動させることを特徴とする請求項２乃至４のいずれかに記載のコンパイラ。
【請求項６】
前記オブジェクトコード挿入部は、移動可能な他のオブジェクトコードが存在しない場合は、前記第１の演算指示情報に対応するオブジェクトコードと前記第２の演算指示情報に対応するオブジェクトコードとの間にｎｏｐコードを挿入することを特徴とすることを特徴とする請求項１乃至５のいずれかに記載のコンパイラ。
【請求項７】
前記特定の関数は、ソースプログラムの記述言語に新たに追加された予約語であることを特徴とする請求項１乃至６のいずれかに記載のコンパイラ。
【請求項８】
前記特定の関数は、ISO/JISのＣ言語の規格で規定されている予約語以外の語句で構成されることを特徴とする請求項７に記載のコンパイラ。
【請求項９】
前記命令スケジューリング情報は、前記第１及び第２の演算指示情報と、これら第１及び第２の演算指示情報に対応するオブジェクトコード間に開けるべきサイクル数または命令数と、を記述したISO/JISのＣ言語の規格で規定されている前処理指令であることを特徴とする請求項１乃至５のいずれかに記載のコンパイラ。
【請求項１０】
前記命令スケジューリング情報は、Ｃ言語のISO/IEC 9899:1999 で規定されているinline関数として宣言される関数中に含まれ、
前記オブジェクトコード挿入部は、前記第１の演算指示情報に対応するオブジェクトコードと前記第２の演算指示情報に対応するオブジェクトコードとの間に、ソースプログラム中に展開される前記命令スケジューリング情報の前後に位置する命令に対応するオブジェクトコードを挿入することを特徴とする請求項１乃至６のいずれかに記載のコンパイラ。
【請求項１１】
前記第１及び第２の演算指示情報は、プロセッサとは別個に設けられる演算装置が実行する演算指示情報であることを特徴とする請求項１乃至１０のいずれかに記載のコンパイラ。
【請求項１２】
前記演算装置は、プロセッサに付属するコプロセッサであることを特徴とする請求項１１に記載のコンパイラ。
【請求項１３】
ソースプログラムに基づいて生成されるオブジェクトコードに従って演算処理を行う演算処理システムにおいて、
前記ソースプログラム中に記述された、第１のオブジェクトコードを指示する第１の演算指示情報と、第２のオブジェクトコードを指示する第２の演算指示情報と、前記第１および第２のオブジェクトの間に開けるべきサイクル数または命令数とを記述した命令スケジューリング情報に基づいて、前記第１および第２のオブジェクトコードの間に、これらオブジェクトコードが使用するハードウェアリソースを使用せずに別のハードウェアリソースを使用するオブジェクトコードを前記サイクル数または命令数分だけ挿入したオブジェクトコード群に基づいて演算処理を行う演算処理部を備え、
前記命令スケジューリング情報は、前記第１及び第２の演算指示情報と、これら第１及び第２の演算指示情報に対応するオブジェクトコード間に開けるべきサイクル数または命令数と、を引数とする特定の関数であることを特徴とする演算処理システム。
【請求項１４】
プロセッサと、
このプロセッサとは別個に設けられる演算装置と、を備え、
前記演算処理部は、前記演算装置に内蔵されることを特徴とする請求項１３に記載の演算処理システム。
【請求項１５】
前記演算装置は、プロセッサに接続されるコプロセッサであることを特徴とする請求項１４に記載の演算処理システム。
【請求項１６】
ソースプログラムに基づいてオブジェクトコードを生成する演算処理方法において、
前記ソースプログラム中に記述された、第１のオブジェクトコードを指示する第１の演算指示情報と、第２のオブジェクトコードを指示する第２の演算指示情報と、前記第１および第２のオブジェクトの間に開けるべきサイクル数または命令数とを記述した命令スケジューリング情報を命令検出部により検出するステップと、
前記第１および第２のオブジェクトコードの間に、これらオブジェクトコードが使用するハードウェアリソースを使用せずに別のハードウェアリソースを使用するオブジェクトコードを前記サイクル数または命令数分だけオブジェクトコード挿入部により挿入するステップと、を備え、
前記命令スケジューリング情報は、前記第１及び第２の演算指示情報と、これら第１及び第２の演算指示情報に対応するオブジェクトコード間に開けるべきサイクル数または命令数と、を引数とする特定の関数であることを特徴とする演算処理方法。
【発明の詳細な説明】
【０００１】
【発明の属する技術分野】
本発明は、高級言語で代表されるソースプログラムに基づいてオブジェクトコードを生成するコンパイラ及び演算処理方法と、この種のコンパイラで生成されたオブジェクトコードに基づいて演算処理を行う演算処理システムとに関する。
【０００２】
【従来の技術】
１サイクルで終わらない処理をプロセッサで行う場合、処理を開始する命令と結果を受け取る命令とが特定の専用命令の組合せであれば、コンパイラでも簡易にスケジューリングを行うことができる。
【０００３】
例えば、乗算を行うmul命令と、乗算結果の下位３２ビットを受け取るmflo命令（mul命令とmflo命令はRISC型プロセッサの一例であるMIPSアーキテクチャの命令であり、本明細書のアセンブリ命令は、MIPSアーキテクチャの命令を使用している）とを実行するのに、システムクロックの４サイクルを必要とする場合、図２７に示すように、mul命令とmflo命令の間に無関係な命令を３命令を入れることで、ストールを起こすことなく、処理を行うことができる。
【０００４】
図２７の場合、mul 命令と mflo 命令の間の3命令は、HIレジスタとLOレジスタにアクセスしない命令で、かつmflo命令で定義するレジスタを使用しない命令であるという予め定めた規則をコンパイラに組み込むことにより、コンパイラがmul命令とmflo命令を生成した場合だけでなく、プログラマが mul 命令と mflo 命令を 組み込み関数（intrinsics関数）にて記述した場合にも、コンパイラによる命令スケジューリングが可能になる。ちなみに、組み込み関数（intrinsics関数）とは、コンパイラが直接生成できないような機械命令をＣ言語のソース中に関数形式で記述する方法である。
【０００５】
【発明が解決しようとする課題】
しかしながら、プロセッサに接続された演算装置で演算を行う場合、使用する命令は特別の命令ではなく、プロセッサに接続された演算装置や周辺装置にアクセスするための通常の命令（sw命令やlw命令など）であるため、上述したmul命令やmflo命令等の特別な命令の組合せによるスケジューリング手法では対応できない。
【０００６】
例えば、演算装置のレジスタにsw命令で書き込んだ内容で演算を行い、その４サイクル後に、演算装置のレジスタからlw命令で演算結果を読み出せるようにした場合、図２８のように記述する。なお、レジスタｒ２には、すでに演算装置のレジスタのアドレスが格納されているものとする。
【０００７】
sw命令とlw命令の両方とも、通常のメモリアクセスに使用する命令であるため、mul 命令や mflo 命令等の特定命令の組み合わせのスケジューリングの規則と同様の規則をコンパイラに予め組み込むことはできない。このため、sw命令やlw命令を実行する場合は、プログラマが スケジューリングを考えてプログラムを記述する必要があった。
【０００８】
本発明は、このような点に鑑みてなされたものであり、その目的は、オブジェクトコードの実行性能に優れ、コードサイズも削減可能なコンパイラ、演算処理システム及び演算処理方法を提供することにある。
【０００９】
【課題を解決するための手段】
本発明の一態様によれば、ソースプログラムに基づいてオブジェクトコードを生成するコンパイラにおいて、前記ソースプログラム中に記述された、第１のオブジェクトコードを指示する第１の演算指示情報と、第２のオブジェクトコードを指示する第２の演算指示情報と、前記第１および第２のオブジェクトの間に開けるべきサイクル数または命令数とを記述した命令スケジューリング情報を検出する命令検出部と、前記第１および第２のオブジェクトコードの間に、これらオブジェクトコードが使用するハードウェアリソースを使用せずに別のハードウェアリソースを使用するオブジェクトコードを前記サイクル数または命令数分だけ挿入するオブジェクトコード挿入部と、を備え、前記命令スケジューリング情報は、前記第１及び第２の演算指示情報と、これら第１及び第２の演算指示情報に対応するオブジェクトコード間に開けるべきサイクル数または命令数と、を引数とする特定の関数であることを特徴とするコンパイラが提供される。
【００１０】
また、本発明の一態様によれば、ソースプログラムに基づいて生成されるオブジェクトコードに従って演算処理を行う演算処理システムにおいて、前記ソースプログラム中に記述された、第１のオブジェクトコードを指示する第１の演算指示情報と、第２のオブジェクトコードを指示する第２の演算指示情報と、前記第１および第２のオブジェクトの間に開けるべきサイクル数または命令数とを記述した命令スケジューリング情報に基づいて、前記第１および第２のオブジェクトコードの間に、これらオブジェクトコードが使用するハードウェアリソースを使用せずに別のハードウェアリソースを使用するオブジェクトコードを前記サイクル数または命令数分だけ挿入したオブジェクトコード群に基づいて演算処理を行う演算処理部を備え、前記命令スケジューリング情報は、前記第１及び第２の演算指示情報と、これら第１及び第２の演算指示情報に対応するオブジェクトコード間に開けるべきサイクル数または命令数と、を引数とする特定の関数であることを特徴とする演算処理システムが提供される。
【００１１】
【発明の実施の形態】
以下、本発明に係るコンパイラ、演算処理システム及び演算処理方法について、図面を参照しながら具体的に説明する。
【００１２】
図１は本発明に係るコンパイラの一実施形態の概略構成を示すブロック図である。図１のコンパイラは、パーソナルコンピュータ等のコンピュータ機器に読み込まれて実行されるプログラムであり、ユーザから与えられたＣ言語等で記述されたソースプログラムを、プロセッサが実行可能なオブジェクトコードに変換するものである。なお、コンパイラをハードウェアで実装することも可能である。この場合、プロセッサと同一チップに内蔵させてもよいし、プロセッサとは別チップに実装してもよい。
【００１３】
図１のコンパイラは、字句解析部１と、構文解析部２と、中間コード生成部３と、中間コード最適化部４と、コード生成部５と、コード最適化部６と、コード出力部７とを備えている。
【００１４】
字句解析部１は、ソースプログラムを意味のある最小単位である字句ごとに分割する。例えば図２のようなＣ言語のソースプログラムの場合、「void」、「ｘ」、「（」、「）」、「｛」、「int」、「ａ」、「；」、「｝」のそれぞれが字句である。
【００１５】
構文解析部２は、分割された字句それぞれが、ソースプログラムの言語で定められた文法に従って記述されているか否かをチェックする。この構文解析部２では、関数の各引数の記述に誤りがないか否かのチェックも行う。
【００１６】
中間コード生成部３は、アセンブリ言語よりも高水準で、高級言語よりも低水準の言語である中間コードを生成する。中間コード最適化部４は、1+1のような定数同士の演算等の最適化を行う。
【００１７】
ソースプログラムから直接オブジェクトコードを生成せずに、いったん中間コードに変換するのは、高級言語が異なっていても中間コードは共通化でき、中間コードを生成してからオブジェクトコードを生成するまでの処理を複数の高級言語で共用できるためである。このため、中間コードの段階で命令の最適化処理を行うようにすれば、個々の高級言語ごとに別個に最適化処理を開発する必要がなくなる。
【００１８】
コード生成部５は、構文解析結果に基づいて、オブジェクトコードを生成する。コード最適化部６は、生成されたオブジェクトコードに対して最適化処理を行う。このコード最適化部６は、図１に示すように、命令検出部１１と、オブジェクトコード挿入部１２とを有する。
【００１９】
命令検出部１１は、ソースプログラムに後述する特定の関数が含まれているか否かを検出する。オブジェクトコード挿入部１２は、検出された特定の関数の引数に基づいて、一部のオブジェクトコードの移動やnopコードの挿入を行って、最終的なオブジェクトコードを生成する。生成されたオブジェクトコードは、コード出力部７から出力される。
【００２０】
なお、中間コードを生成せずに、ソースプログラムから直接オブジェクトコードを生成してもよい。この場合のブロック構成は図３のようになり、中間コード生成部３と中間コード最適化部４が不要になる。
【００２１】
図４は図１のコンパイラが生成したオブジェクトコードに基づいて演算処理を行うプロセッサシステムの概略構成を示すブロック図である。図示のように、メインの演算処理を行うコアプロセッサ１３と、コアプロセッサ１３とは別個に演算処理を行うプロセッサ外演算装置１４と、コアプロセッサ１３及びプロセッサ外演算装置により読み書きが可能なメモリ１５とを備えている。
【００２２】
以下に、本実施形態のコンパイラの使用方法について説明する。まず、単純な例として、コアプロセッサ１３に接続されるプロセッサ外演算装置１４のレジスタに、sw命令でデータを書き込んで演算を開始し、プロセッサ外演算装置１４のレジスタからlw命令で演算結果を読み出す場合について説明する。ここでは、プロセッサ外演算装置１４のレジスタは、コアプロセッサ１３のメモリ空間上に固有のアドレスを持っているものとする。
【００２３】
例えば、プロセッサ外演算装置１４のレジスタ（アドレス0x1000番地）に値を書き込んで、その値を二乗する演算を開始し、演算結果をレジスタ（アドレス0x1000番地）に設定するものとする。これをＣ言語で記述すると、図５のようなソースプログラムになる。
【００２４】
図５のソースプログラムを所定のコアプロセッサ１３でコンパイルすると、図６のようなオブジェクトコードが得られる。なお、図６では、オブジェクトコードをアセンブリ言語で表している。
【００２５】
図６において、addiu r2, r0, 0x1000では、レジスタr2にレジスタr0＋0x1000を入れる。ここで、レジスタr0は常にゼロである。sw r4, 0 (r2)では、レジスタr2のアドレスのメモリ１５に、レジスタr4の値（ソースプログラムのpara）を書き込む。lw r2, 0 (r2)では、レジスタr2のアドレスのメモリ１５から読み込んだ内容を、レジスタr2に入れる。jr raでは、関数を終了して、呼び出し元に戻る。
【００２６】
プロセッサ外演算装置１４の演算が 1サイクルで終了する場合は、図６のオブジェクトコードのままで特に問題ないが、例えば、上記の演算に必ず4サイクルかかり、sw命令とlw命令の間を 3サイクル分(１命令の実行サイクル数が１の場合は３命令)空ける必要がある場合は、図７のようにソースプログラム中にnop()を記述する必要がある。
【００２７】
図7のnop() は、組み込み関数（intrinsics関数）によるnop命令の記述である。図７のソースプログラムをコンパイルすると、図８に示すように、sw命令とlw命令の間に3つのnop命令が配置される。
【００２８】
図８のようなオブジェクトコードを得るには、予めプログラマがコアプロセッサ１３の処理スケジューリングを考慮に入れて、図７のようなソースプログラムを記述しなければならず、プログラマの負担が大きい。
【００２９】
そこで、本実施形態では、特定の関数形式（例えば、__order）によって命令スケジューリング情報をソースプログラム中に記述し、これにより、コンパイラにスケジューリングを行わせる点に特徴がある。このような特定の関数形式__orderを利用して図７のソースプログラムの書き直すと、図９のようになる。
【００３０】
図９のソースプログラムをコンパイルすると、図８と同様のコンパイル結果が得られる。
【００３１】
図９に示す__order は、命令のスケジューリングを行うために独自に追加した予約語である。本実施形態では、特定の関数形式として__order を使用しているが、ISO/JIS C 言語規格 で規定されている予約語以外の任意の語句で表すことができる。
【００３２】
__order は、関数コールの形式で記述される。より具体的には、__order は３つの引数を持っており、第１引数と第２引数にはスケジューリングの対象となる式が記述され、第３引数には第１引数と第２引数から生成されたオブジェクトコードの間に開けるべき必要なサイクル数が記述される。すなわち、第１引数には第１の演算指示情報が記述され、第２引数には第２の演算指示情報が記述され、第３引数には、第１の演算指示情報に対応するオブジェクトコードと第２の演算指示情報に対応するオブジェクトコードとの間に開けるべきサイクル数が記述される。
【００３３】
図９のソースプログラムをコンパイルして得られる図８のオブジェクトコードは、sw命令とlw命令の間に配置されたnop命令を有するが、このnop命令はコンパイラが自動的に挿入する。このため、プログラマが予めソースプログラムにnop命令を記述する必要がなくなり、プログラムの開発負担を軽減できる。
【００３４】
また、ソースプログラム中の__order文の近くに、他の命令文が存在する場合は、sw命令とlw命令とは無関係で、移動可能なnop命令以外の命令を sw命令とlw命令の間に挿入する。これにより、生成されたオブジェクトコードの実行性能の向上とコードサイズの削減が図れる。
【００３５】
このように、ソースプログラム中に__order文があると、その第１引数に対応するオブジェクトコードと第２引数に対応するオブジェクトコードとの間に、これらオブジェクトコードとは無関係なオブジェクトコードが第３引数で指定されるサイクル数だけ挿入される。一例を具体的に説明すれば、第１引数に対応するオブジェクトコードと第２引数に対応するオブジェクトコードとの間に、これらオブジェクトコードが使用するハードウェアリソースを使用せずに別のハードウェアリソースを使用する他のオブジェクトコードが第３引数で指定されるサイクル数だけ挿入される。
【００３６】
図１０は__order文の近くに他の命令文ary[x][y] = retが存在する場合のソースプログラムの一例を示している。図１０のソースプログラムは、配列ary[x][y]に演算結果を入れるものである。このソースプログラムをコンパイルし、sw命令と lw命令の間にnop命令を挿入すると、コンパイル結果を示すオブジェクトコードは図１１のようになる。
【００３７】
図１１において、ary[x][y] = retのコンパイル結果は、lw r7,0(r2)、sll r4,r6,2、sll r8,r5,4、addiu r3,gp,sdaoff(_ary)、addu r2,r3,r8、addu r2,r2,r4である。lw r7,0(r2)では、レジスタr2のアドレスのメモリ１５から読み込んだ内容をレジスタr7に入れる。sll r4,r6,2では、図１０のソースプログラム中のｙを記憶しているレジスタr6を左に２ビットシフトして、レジスタr4に入れる。すなわち、ｙを４倍する。sll r8,r5,4では、ソースプログラム中のｘを記憶しているレジスタr5を左に４ビットシフトして、レジスタr8に入れる。すなわち、ｘを１６倍する。addiu r3,gp,sdaoff(_ary)では、レジスタgpとsdaoff(_ary)を加算して、_aryの先頭アドレスをレジスタr3に入れる。addu r2,r3,r8では、レジスタr3とr8を加算して、レジスタr2に入れる。これにより、ary[x][0]のアドレスが計算される。addu r2,r2,r4では、レジスタr2とr4を加算して、レジスタr2に入れる。これにより、ary[x][y]のアドレスが計算される。
【００３８】
これら命令列のうち、sll r4,r6,2やsll r8,r5,4は、lw r7,0(r2)の演算処理とは無関係に実行可能である。そこで、本実施形態のコンパイラは、図１１のオブジェクトコードの一部の命令列の順序を入れ替えて、図１２のようなオブジェクトコードを生成する。図１２では、sw r4,0(r2)とlw r7,0(r2)との間に、sll r4,r6,2、sll r8,r5,4及びaddiu r3,gp,sdaoff(_ary)を配置する。
【００３９】
図１１のオブジェクトコードは１４命令で構成されるのに対し、図１２のオブジェクトコードは１１命令で構成されている。
【００４０】
このように、本実施形態のコンパイラは、__orderの近くに、無関係な命令文が存在する場合には、この無関係な命令をnop命令の代わりに挿入するため、生成されるオブジェクトコードの実行性能が向上し、かつ命令数も削減できるため、コードサイズを減少させることができる。
【００４１】
これに対して、プログラマがＣ言語等のソースプログラムの中で命令スケジューリングを行う場合、図１３のようにソースプログラムの記述を修正する必要がある。図１３では、*p=paraでメモリ１５にparaを入力した後に、ap=&ary[x][y]を挿入して、ary[x][y]のアドレスを求めてapに入れる処理を行っている。
【００４２】
図１３のように、プログラマ自身でソースプログラムの記述を修正すると、プログラマの負担が大きくなる。また、ソースプログラム上でスケジューリングを行っても、コンパイラの最適化処理により、期待した通りのオブジェクトコードが生成されない場合もある。
【００４３】
本実施形態では、プログラマがソースプログラムを修正するのではなく、プログラマはコンパイラに命令のスケジューリング情報を与えるだけである。このスケジューリング情報に基づいて、コンパイラは無関係で移動可能な命令を見つけて、指定された２つの演算命令中に挿入する。また、コンパイラは、無関係で移動可能な命令が必要サイクル分見つからない場合のみ、nopを挿入する。
【００４４】
図１のコンパイラは、ソースプログラム中に上述した特定の関数__orderを見つけると、以下のような処理を行う。字句解析部１は、__orderを予約語として認識する。構文解析部２はまず、__orderの各引数の記述内容をチェックし、第１及び第２引数が意味のある式であるか否かをチェックする。例えば、__order(1, 2, 3)のように第１及び第２引数に定数が記述されている場合、スケジューリングすべき命令が生成されないので、エラーとする。また、第３引数が正の整数型定数であるか否かをチェックする。第３引数に定数以外の変数などを記述した場合、コンパイル時にはその値がわからないので、エラーとする。
【００４５】
中間コードを生成する場合は、第１及び第２引数の式から生成される通常の中間コードと、この中間コードの前後に__orderで記述されたことを示す目印となる中間コードと、__orderの第３引数で指定された値を示す中間コードとが中間コード生成部３にて生成される。
【００４６】
コード生成部５は、__orderの第１及び第２引数に基づいてオブジェクトコードを生成する。__orderで付加されたことを示す目印となる中間コードと第３引数の値を示す中間コードはオブジェクトコードには変換されないが、第１及び第２引数に基づいて生成されたオブジェクトコードに関連するデータとして記憶される。
【００４７】
コード最適化部６は、__orderで付加されたことを示す目印と第３引数に基づいて、命令のスケジューリングを行う。
【００４８】
図１４はコード最適化部６の処理手順を示すフローチャートである。まず、__orderの第1引数から生成されたオブジェクトコードで定義されたリソース（例えば、レジスタやメモリ１５など）d1と、演算に使用するリソースu1とを求める（ステップＳ１）。例えば、図１２では、第1引数から生成されたオブジェクトコードは sw r4,0(r2) で、この命令の定義するリソース d1はメモリ１５で、使用するリソース u1は r4,r2である。
【００４９】
__orderの第1引数から生成されたオブジェクトコードの直前に配置された命令を別の場所に移動可能か否かを調べる（ステップＳ２）。分岐命令等の移動不可能な命令の場合は、__orderの前方からの移動は不可能なので、第2引数から生成されたオブジェクトコードの後方からの命令移動の処理に移る。
【００５０】
直前の命令が移動可能である場合、この命令が定義するリソース d2と使用するリソース u2 を求める（ステップＳ３）。図１２の場合、直前の命令は addiu r2,r0,0x10000 で、この命令の定義するリソース d2はr2で、使用するリソースはなしである。r0は常に0のレジスタで、0x10000は定数のオペランドなので、リソースに含めない。
【００５１】
次に、直前の命令に関するリソースd2,u2が、第１引数から生成されたオブジェクトコードのリソースd1,u1と衝突するか否かを調べる（ステップＳ４）。リソースが衝突しない場合は移動可能と判断する。
【００５２】
ここで、リソースが衝突していないという条件は、d1 と u1 の論理和と d2 の論理積が空であり((d1|u1) & d2)、かつ、d1 と u2 の論理(d1 & u2)積が空である場合である。図１２の場合、リソースu1とd2がともにr2であり、リソースが衝突するため、移動ができない。
【００５３】
移動可能であると判断されると、直前の命令を、第1引数から生成されたオブジェクトコードと第2引数から生成されたオブジェクトコードの間に移動させる（ステップＳ５）。この命令の移動によって、指定したサイクル数分の命令を移動させた場合は、スケジューリングは終了である。まだ、第3引数で指定した指定したサイクル数分の命令を移動していない場合は、更に前方の命令が移動できるかを調べる（ステップＳ６）。
【００５４】
ステップＳ４でリソースが衝突すると判断されると、移動不可能と判断して（ステップＳ７）、リソースの集合を論理和でまとめる（ステップＳ８）。定義するリソースはd1 にまとめ (d1 = d1 | d2)、使用するリソース はu1 にまとめる (u1 = u1 | u2)。これにより、リソース d1,u1が移動される間にある命令のリソースとなるので、次の直前の命令が移動可能かどうかを調べる場合にも、d1,u1 だけを調べるだけでよい。
【００５５】
図１２でのリソースをまとめた結果、定義するリソースd1はレジスタr2とメモリ１５、使用するリソースu1は レジスタr4,r2である。ステップＳ８の処理が終了すると、ステップＳ２以降の処理を行う。
【００５６】
一方、第1引数から生成されたオブジェクトコードの前方の命令だけでは、指定したサイクル数分の命令が挿入できなかった場合、あるいは、__orderの第1引数から生成されたオブジェクトコードの直前に配置された命令を別の場所に移動できないと判断された場合は、第2引数から生成されたオブジェクトコードの後方の命令についてもスケジューリングの対象とする。例えば、図１２の場合、addiu命令の直前の命令は存在しないので、第2引数から生成されたオブジェクトコード群の後方の命令についてスケジューリングの対象とする。
【００５７】
まず、第2引数から生成されたオブジェクトコードが定義するリソースd3と使用するリソースu3 を求める（ステップＳ９）。図１２では、第2引数から生成されたオブジェクトコードは lw r7,0(r2)であるので、定義するリソース d3は レジスタr7,使用するリソース u3 はレジスタr2となる。第2引数から生成されたオブジェクトコードの直後の命令が移動可能か否かを調べる（ステップＳ１０）。
【００５８】
分岐命令など移動不可能な命令の場合は、もう移動できる命令がないので、第3引数で指定したサイクル数分に足らない分だけnop命令を挿入し（ステップＳ１１，Ｓ１２）、このスケジューリングを終了する。
【００５９】
直後の命令が移動可能である場合、この命令の定義するリソース d4 と使用するリソース u4 を求める（ステップＳ１３）。図１２では、では、直後の命令は sll r4,r6,2 で、定義するリソース d4 は r4、使用するリソース u4は r6、メモリ１５である。
【００６０】
次に、直前の命令に関するリソースd4,u4が、第１引数から生成されたオブジェクトコードのリソースd3,u3と衝突するか否かを調べる（ステップＳ１４）。リソースが衝突しない場合は移動可能と判断する。
【００６１】
ここで、リソースが衝突していないという条件は、d3 と u3 の論理和と d4 の論理積が空であり((d3|u3) & d4)、かつ、d3 と u4 の論理積(d3 & u4)が空である場合である。図１２では、lw r7,0(r2)とsll r4,r6,2に衝突するリソースはないので、sll r4,r6,2は移動可能である。
【００６２】
移動可能であると判断されると、直前の命令を、第1引数から生成されたオブジェクトコードと第2引数から生成されたオブジェクトコードの間に移動させる（ステップＳ１５）。この命令の移動によって、指定したサイクル数分の命令を移動させた場合は、スケジューリングは終了である。まだ、第3引数で指定した指定したサイクル数分の命令を移動していない場合は、更に前方の命令が移動できるかを調べる（ステップＳ１６）。
【００６３】
ステップＳ１４でリソースが衝突すると判断されると、移動不可能と判断して（ステップＳ１７）、リソースの調停処理を行った後（ステップＳ１８）、ステップＳ１０以降の処理を行う。
【００６４】
図１４のフローチャートでは、第1引数の前から移動させる方を先に行ったが、第2引数の後ろから移動させる方を先に行った場合でも、同様の最適化処理が可能である。
【００６５】
なお、第3引数のサイクル数の定義は、第1引数から生成されたオブジェクトコード群の最後から 第2引数から生成されたオブジェクトコード群の先頭までに必要なサイクル数とするのが普通である。しかし、このスケジューリング機能の外部仕様として、第1引数から生成されたオブジェクトコード群の最後から 第2引数から生成されたオブジェクトコード群の最後までに必要なサイクル数と定義することもまた可能である。これは、双方の最後の命令がスケジューリング対象の命令となっていると仮定して、サイクル数をカウントしている。
【００６６】
また、コンパイル時に 命令のサイクル数の見積が困難な場合は、第3引数をサイクル数から命令数にしてもよい。
【００６７】
図１４のフローチャートの処理手順をコンパイラに実装することによって、__order で指定した命令形式の命令スケジューリングを行うことが可能となる。
【００６８】
このように、第１の実施形態では、特定の関数に基づいて、リソースが衝突しないように命令の順序を入れ替えるため、nop命令を入れる必要がなくなり、オブジェクトコードの実行性能の向上が図れる。また、オブジェクトコードのサイズも削減できる。
【００６９】
（第２の実施形態）
第１の実施形態では、ソースプログラムに記述された特定の関数（例えば、__order）に基づいて命令スケジューリングを行う例を説明したが、別の記述方法で命令スケジューリングを行うことも可能である。
【００７０】
#pragma は、ISO/JISＣ言語規格に規定されている前処理指令の一つであり、処理系によって独自の拡張が許されている。本実施形態では、#pragma の後に order を付加した #pragma order を用いて 命令スケジューリングの指定を行う。
【００７１】
図９のソースプログラムを #pragma order を用いて書き直すと、図１５のようになる。
【００７２】
「#pragma order {」と「#pragma order 3」によって挟まれた式が前半の式で、「#pragma order 3」と「#pragma }」によって挟まれた式が後半の式である。その間の「#pragma order 3」で示された３の定数値が、前半の式と後半の式の間に挿入すべきサイクル数の指定である。4サイクル必要な場合は、「#pragma order 4」と記載される。
【００７３】
第１及び第２の実施形態からわかるように、ソースプログラム中に記述する必要がある付加情報は、スケジューリングすべき第１及び第２の演算指示情報とその間に挿入すべき実行サイクル数である。これらの情報をどのような形態で実現するかは特に問わない。
【００７４】
図１のコンパイラは、ソースプログラム中の#pragma orderを以下の手順で処理する。
【００７５】
字句解析部１は、字句分割を行って、#pragma order文を見つける。構文解析部２は、#pragma order文の記述内容を調べる。まず、{ ,定数,} の順で並んでいるかをチェックする。#pragma order文の先頭部分が「#pragma order {」と記述されていない場合や、{,定数,}の途中で 関数の定義が終了した場合などは、エラーである。また、#pragma order を関数定義中以外で使用した場合もエラーである。定数は、正の整数型定数であるか否かをチェックする。
【００７６】
#pragma order文で挟まれた 前半と後半の二つの式についても、構文解析部２でチェック可能であれば、#pragma orderに特有のチェックを行う。しかし、コンパイラの実装上、構文解析部２で式の内容がチェックできない場合などは、後段側のコード生成部５などでチェックを行ってもよい。チェックすべき項目は、スケジューリングすべき意味がある式が記述されているかどうかである。前半、後半の式が記述されていなかったり、意味がないため生成されるオブジェクトコードがないような式を記述した場合は、エラーとなる。
【００７７】
#pragma orderから生成される中間コードは、#pragma orderの前方の式から生成される中間コードと後方の式から生成される中間コードとの間に付加される。#pragma orderから生成される中間コードは、#pragma orderの前方と後方の式から生成されたことを示すための目印と挿入すべきサイクル数を示す値とを意味する。
【００７８】
中間コードを生成した段階では、第１の実施形態と同じコードになる。このため、以下のコード生成部５、コード最適化部６の構成は第１の実施形態と同じである。
【００７９】
このように、第２の実施形態では、Ｃ言語等の高級言語で規定されている前処理指令を用いて、オブジェクトコード間のサイクル数を指定するため、第１の実施形態のような関数形式で記述するのと同様に、オブジェクトコードの実行性能の向上とオブジェクトコードサイズの削減が図れる。
【００８０】
（第３の実施形態）
第３の実施形態は、図４で示したプロセッサ外演算装置として、コプロセッサを用いたものである。
【００８１】
図１６はコアプロセッサ１３にコプロセッサ１６とメモリ１５が接続されているプロセッサシステムの一例を示すブロック図である。
【００８２】
図１６のコプロセッサ１６のレジスタにアクセスするための命令は、メモリ１５にアクセスするためのロード命令やストア命令とは異なる。このため、コンパイラが自動的に命令スケジューリングができる可能性もあるが、コプロセッサ１６の演算の種類によって、演算サイクルが異なる場合には、コンパイラが自動的にスケジューリングするのは一般には困難である。
【００８３】
本実施形態は、このような場合でも、プログラマがコプロセッサ１６の演算の種類に応じたサイクル数を予めソースプログラム中に指定することにより、コンパイラが最適な命令スケジューリングを行うことができる。
【００８４】
図１７のソースプログラムは、コプロセッサ１６のレジスタの書き込みにCTC2命令を用い、コプロセッサ１６の演算の実行にCOP2命令を用い、コプロセッサ１６のレジスタの読込みにCFC2命令を用い、組み込み関数（intrinsics関数）を用いてＣ言語で記述した従来の記述例である。
【００８５】
図１７のソースプログラムでは、コプロセッサ１６のレジスタ２に演算パラメータを設定し、cop2命令で設定されるパラメータ(function number)が１で演算を開始し、より具体的には例えば、コプロセッサ１６のレジスタ２から値を読み込んで、その値を二乗する演算を行い、その演算結果を４サイクル後にコプロセッサ１６のレジスタ１へ書き込む。図１７の場合、コプロセッサ１６の演算に時間がかかるため、３つのnop命令を挿入する必要がある。
【００８６】
この例を __order を用いて記述すると、図１８のようになる。
【００８７】
図１８のソースプログラムをコンパイルすると、図１９のようなオブジェクトコードが生成される。
【００８８】
図１９の例では、挿入すべき無関係な命令がないため、４つのnop命令が挿入されている。
【００８９】
次に無関係な命令を入れた場合の例を挙げる。図２０は、配列ary[x][y]に演算結果を入れるプログラムを示している。
【００９０】
図２０のコンパイル結果は、図２１のようになる。図２０のary[x][y]=retは、図２１の５つの命令sll r4,r6,2、sll r8,r5,4、addiu r3,gp,sdaoff(_ary)、addu r2,r3,r8、addu r2,r2,r4に相当し、そのうちの前者３つがcop2(1)とcfc2 r7,1の間に挿入される。
【００９１】
これにより、図１９のようにnop命令を挿入する必要がなくなり、生成されるオブジェクトコードの実行性能が向上し、nop命令が減る分、コードサイズも削減できる。
【００９２】
このように、第３の実施形態では、コプロセッサ１６に対して演算を行わせるためのオブジェクトコードを生成する場合でも、オブジェクトコードの実行性能の向上とオブジェクトコードサイズの削減が図れる。
【００９３】
（第４の実施形態）
あるアプリケーション・プログラムで、非常によく利用される関数、すなわちプログラム全体の実行時間に占める割合が大きい関数を、コアプロセッサ１３の通常命令による演算からハードウェアでの演算に置き換えることにより、アプリケーション・プログラムの全体の性能向上を図ることができる。
【００９４】
図２２はソースプログラムの一例であり、このプログラム中で、mul255が非常によく利用される関数であると仮定する。この場合、関数mul255をハードウェア化したプロセッサ外演算装置をコアプロセッサ１３に接続する。この演算装置で関数mul255の演算処理を実行する場合の外部仕様を以下のように定める。
【００９５】
関数mul255の引数a を設定するレジスタのアドレスが 0x1000 番地、引数 b を設定するレジスタのアドレスが 0x1004番地、演算結果を受け取るレジスタのアドレスが 0x1000番地とする。
【００９６】
プロセッサ外演算装置は、0x1000番地のレジスタに値が書き込まれた場合、既に0x1004番地のレジスタに設定してある内容と0x1000番地のレジスタに書き込まれた内容とを乗算し、この乗算結果が255以下の場合はその値のまま、256以上の場合は255 を0x1000番地のレジスタに設定する。演算にかかるサイクル数は、0x1000番地のレジスタに書き込んでから、0x1000番地のレジスタから演算結果を受け取るまで、4サイクル必要とする。
【００９７】
プログラマは、このような演算装置の仕様に従って関数mul255の記述を変更する必要がある。__orderを用いて関数mul255を記述すると、図２３のようになる。
【００９８】
ところが、図２３のように関数の内部をレジスタのアクセスに変更しただけでは、__orderの前後に無関係な命令が存在しないため、nop命令が挿入される可能性が高い。図２３のソースプログラム をコンパイルすると図２４のようになり、nop命令が挿入され、実行性能が落ち、かつコードサイズも増大する。
【００９９】
nop命令の挿入を避けるためには、記述を変更した関数mul255をインライン関数として宣言する必要がある。インライン関数にすると、関数コールでなく、関数を呼び出した場所に関数の中身が展開される。このようにすると、展開の前後に無関係な命令が存在する可能性が高くなり、その結果、__orderでnop命令が挿入される可能性が低くなる。なお、インライン関数は、C言語では ISO/IEC 9899:1999 で追加された機能で、以前の仕様 ISO/IEC 9899:1990 には存在していない。
【０１００】
上述した関数mul255 をインライン関数として記述すると、図２５のようになり、関数mul255の先頭に インライン関数の目印であるinline が追加されている。
【０１０１】
上記の例のインライン関数を図２２の関数testに適用した場合のコンパイル結果は、図２６のようになる。sw r2,0(r5)とlw r1,0(r5)との間に無関係な３命令sll r3,r2,3、addiu r6,gp,sdaoff(_ary)、addu r3,r6,r3が挿入され、また、sw r2,0(r5)とlw r1,0(r5)の間にも無関係な３命令sll r3,r2,3、addiu r6,gp,sdaoff(_ary+4)、addu r3,r6,r3が挿入されている。これにより、nop命令を挿入する必要がなくなる。
【０１０２】
このように、第４の実施形態では、コアプロセッサ１３とは別の演算装置（プロセッサ外演算装置１４）を制御する関数をinline関数として指定することにより、展開される周囲に無関係な命令が存在する可能性が高くなり、第１〜第３の実施形態と同様に、オブジェクトコードの実行性能の向上とオブジェクトコードサイズの削減が図れる。
【０１０３】
【発明の効果】
以上詳細に説明したように、本発明によれば、特定の関数に基づいて、リソースが衝突しないように命令の順序を入れ替えるため、nop命令を入れる必要がなくなり、オブジェクトコードの実行性能の向上が図れる。また、オブジェクトコードのサイズも削減できる。
【図面の簡単な説明】
【図１】本発明に係るコンパイラの一実施形態の概略構成を示すブロック図。
【図２】Ｃ言語のソースプログラムの一例を示す図。
【図３】中間コードを生成しないコンパイラの一実施形態の概略構成を示すブロック図。
【図４】図１のコンパイラが生成したオブジェクトコードに基づいて演算処理を行うプロセッサシステムの概略構成を示すブロック図。
【図５】Ｃ言語のソースプログラムの一例を示す図。
【図６】図５に対応するオブジェクトコードを示す図。
【図７】図５のソースプログラム中にnop()を追加した例を示す図。
【図８】図７に対応するオブジェクトコードを示す図。
【図９】図７のソースプログラムを__orderを用いて書き直したソースプログラムを示す図。
【図１０】  __order文の近くに他の命令文ary[x][y] = retが存在する場合のソースプログラムの一例を示す図。
【図１１】図１０のソースプログラムのコンパイル結果を示すオブジェクトコードを示す図。
【図１２】図１１のオブジェクトコードの一部の命令列の順序を入れ替えた図。
【図１３】プログラマがソースプログラムの記述を修正した例を示す図。
【図１４】コード最適化部６の処理手順を示すフローチャート。
【図１５】図９のソースプログラムを #pragma order を用いて書き直した図。
【図１６】コアプロセッサ１３にコプロセッサ１６とメモリ１５が接続されているプロセッサシステムの一例を示すブロック図。
【図１７】コプロセッサに演算をさせる場合のソースプログラムの一例を示す図。
【図１８】図１７のソースプログラムを__orderを用いて書き直した例を示す図。
【図１９】図１８のソースプログラムをコンパイルしたオブジェクトコードを示す図。
【図２０】配列ary[x][y]に演算結果を入れるプログラムを示す図。
【図２１】図２０のコンパイル結果を示す図。
【図２２】関数mul255が記述されたソースプログラムの一例を示す図。
【図２３】  __orderを用いて関数mul255を記述した例を示す図。
【図２４】図２３のソースプログラムのコンパイル結果を示す図。
【図２５】関数mul255 をインライン関数として記述した例を示す図。
【図２６】図２５のインライン関数のコンパイル結果を示す図。
【図２７】  mul命令とmflo命令の間に無関係な命令を３命令を入れたオブジェクトコードの一例を示す図。
【図２８】  sw命令とlw命令の間に３つのnop命令を入れたオブジェクトコードの一例を示す図。
【符号の説明】
１  字句解析部
２  構文解析部
３  中間コード生成部
４  中間コード最適化部
５  コード生成部
６  コード最適化部
７  コード出力部
１１  命令検出部
１２  オブジェクトコード挿入部
【図１】
0003840149.tif 000002
【図２】
0003840149.tif 000003
【図３】
0003840149.tif 000004
【図４】
0003840149.tif 000005
【図５】
0003840149.tif 000006
【図６】
0003840149.tif 000007
【図７】
0003840149.tif 000008
【図８】
0003840149.tif 000009
【図９】
0003840149.tif 000010
【図１０】
0003840149.tif 000011
【図１１】
0003840149.tif 000012
【図１２】
0003840149.tif 000013
【図１３】
0003840149.tif 000014
【図１４】
0003840149.tif 000015
【図１５】
0003840149.tif 000016
【図１６】
0003840149.tif 000017
【図１７】
0003840149.tif 000018
【図１８】
0003840149.tif 000019
【図１９】
0003840149.tif 000020
【図２０】
0003840149.tif 000021
【図２１】
0003840149.tif 000022
【図２２】
0003840149.tif 000023
【図２３】
0003840149.tif 000024
【図２４】
0003840149.tif 000025
【図２５】
0003840149.tif 000026
【図２６】
0003840149.tif 000027
【図２７】
0003840149.tif 000028
【図２８】
0003840149.tif 000029