図1に、本実施の形態のリニアコード生成装置1のハードウエア構成図を示す。リニアコード生成装置1は、CPU11と、メモリ12と、HDD(Hard Disk Drive)13とを有する。メモリ12は、例えばDRAM(Dynamic Random Access Memory)である。各ハードウエアコンポーネントはバスを介して互いに接続される。
本実施の形態の処理を実行するためのプログラムは、例えばHDD13に格納されており、CPU11によってメモリ12にロードされて実行されることで、図2に示すような各種機能を実現する。図2に、リニアコード生成装置1の機能ブロック図を示す。リニアコード生成装置1は、コンパイラ100と、リンカ140と、データ格納部160とを含む。データ格納部160は、例えば、メモリ12上或いはHDD13上に設けられる。
コンパイラ100は、入力処理部110と、最適化部120と、出力部130と、入出力制御部150とを含む。入力処理部110は、ソースプログラム入力処理部111と、字句解析部112と、意味解析部113と、第1中間コード出力部114とを含む。最適化部120は、第1中間コード入力処理部121と、プログラム解析部122と、プログラム最適化部123と、第2中間コード出力部124とを含む。出力部130は、第2中間コード入力処理部131と、オブジェクト生成部132とを含む。データ格納部160には、ソースプログラム161と、中間コード162と、中間コード163と、オブジェクトファイル164と、実行可能プログラム165とが格納される。
ソースプログラム入力処理部111は、データ格納部160に格納されているソースプログラム161を読み込み、ソースプログラム161に含まれる文字列を字句解析部112に渡す。字句解析部112は、ソースプログラム入力処理部111から受け取った文字列を解析し、トークンに分割して意味解析部113に渡す。意味解析部113は、字句解析部112から受け取ったトークン間の関係を解析し、中間コード162を生成する。第1中間コード出力部114は、生成された中間コード162を含むファイルをデータ格納部160に格納する。
第1中間コード入力処理部121は、データ格納部160に格納されたファイルから中間コード162を読み込み、プログラム解析部122に渡す。プログラム解析部122は、第1中間コード入力処理部121から受け取った中間コード162を解析し、命令情報、ブロック情報、ループ情報、制御グラフ及びデータ依存グラフ等を含む解析結果を生成する。プログラム最適化部123は、解析結果に基づき、中間コード162を最適化して中間コード163を生成する。第2中間コード出力部124は、生成された中間コード163を含むファイルをデータ格納部160に格納する。
第2中間コード入力処理部131は、データ格納部160に格納されたファイルから中間コード163を読み込み、オブジェクト生成部132に渡す。オブジェクト生成部132は、中間コード163からオブジェクトコードを生成し、生成したオブジェクトコードを含むオブジェクトファイル164をデータ格納部160に格納する。リンカ140は、オブジェクトファイル164に含まれるオブジェクトコードと他のオブジェクトコードとをリンクすることで実行可能プログラム165を生成し、生成した実行可能プログラム165をデータ格納部160に格納する。入出力制御部150は、コンパイラ100とデータ格納部160との間でのデータ入出力を制御する。
次に、図3乃至図6を用いて、プログラム解析部122が実行する処理を説明する。プログラム解析部122は、以下で説明する処理を開始するにあたって、図3及び図4に示すようなデータ構造を有するデータをループごとに生成してデータ格納部160に格納しておく。図3及び図4の例では、ループ番号と、ループのタイプと、制御変数(ループインデックスとも呼ばれる)と、制御変数の初期値と、制御変数の終値と、制御変数の増分値(制御変数の変化量に相当する)と、ループの直前に位置するブロックであるプロローグと、ループ本体のブロックであるカーネルと、ループの直後に位置するブロックであるエピローグと、ループ外部で定義又は参照される変数名のリストである外部変数リストと、ループ回転を跨いだデータ依存がある変数名のリストと、本実施の形態の最適化の対象であるか否かを表す最適化対象フラグとについてデータが格納される。命令コード、入力オペランド及び出力オペランドは、SPARC命令セットのアセンブリ言語規則に従っている。メモリアドレスについては、ソースプログラム161中の変数名を使用して表記されている。以降、特に断りが無い限り、コンパイラ100の出力命令列は同様の方法で記述される。var(x)は、変数名がxであるオペランドのオペランド番号を表す。頭文字がtである変数名は、コンパイラ100が内部的に生成した新規変数である。本例では増分値が使用されているが、減分値であってもよい。SPARC命令セットについては、例えば非特許文献1を参照のこと。
なお、レジスタRに関して、Rを定義する命令の後にRを参照する命令が実行される必要があることを、両命令の間に「RAW(Read After Write)のデータ依存がある」という。特に、Rを定義する命令とRを参照する命令とが同一ループ中にあり且つRを定義する命令がRを参照する命令よりも1つ以上前の繰り返しで実行される場合、「ループ回転を跨いだRAWのデータ依存がある」という。つまり「ループ回転を跨いだRAWのデータ依存がある」とは、異なるループインデックス間でのデータ依存があることを意味する。例えば、i=2のときにRを定義する命令が実行され且つその後のi=3のときにRを参照する命令が実行されるようなケースが該当する。逆に、Rを参照する命令の後にRを定義する命令が実行される必要があることを、両命令の間に「WAR(Write After Read)のデータ依存がある」という。
本実施の形態においては、変数及び定数を表現するデータ構造をオペランドと呼ぶ。オペランドについては、以下のようなデータ構造で管理される。具体的には、オペランドごとに割り振られる一意の識別子であるオペランド番号と、オペランド種別(本実施の形態においては、定数、変数またはブロック)と、オペランド種別が定数の場合に設定される定数値と、オペランド種別が変数の場合に設定される変数名と、オペランド種別がブロックである場合に設定され且つブロックの識別に使用されるブロック番号とを使用して管理される。定数値は、コンパイル時点で決定可能な値である。変数名は、実装によってはレジスタ番号などが使用されてもよい。
命令は、以下のようなデータ構造で管理される。具体的には、命令ごとに割り振られる一意の識別子である命令番号と、命令の内容を表す識別子と、命令の入力である入力オペランドと、命令の出力である出力オペランドとを使用して管理される。本実施の形態の説明では、基本的にはSPARC命令セットの命令コードが用いられ、脱出分岐命令については、一般的な条件分岐命令とは異なる命令コードが与えられる。比較結果が等しい場合に最内ループを脱出する脱出分岐命令を「breakeq」命令と定義する。入力オペランド及び出力オペランドは、オペランド番号の配列で表される。なお、脱出分岐命令とは、分岐条件が成立した場合にループからの脱出が行われる条件分岐命令である。
なお、脱出とは、ループ中の脱出分岐命令の分岐条件が成立した時に、ループコード(本実施の形態においては、カーネルと同義)の直後に制御が移ることである。脱出分岐命令を含むループコードをリニアコードに変換する最適化はリニアライズと呼ばれる。リニアコードとは、脱出が行われないループコードのことである。
コンパイラ100は、命令の集合をブロックと呼ばれるデータ構造で管理する。具体的には、ブロックごとに割り振られる一意な識別子であるブロック番号と、実行順に並べられたブロック内の1又は複数の命令を含む命令列とを使用して管理される。命令列は、命令番号の配列で表される。ブロックは条件分岐命令を単位として分割され、命令列の最終要素以外に条件分岐命令が出現することはない。但し、脱出分岐命令はブロックを分割しない特殊な命令として取り扱われ、命令列の最終要素以外にも出現することがある。
図3及び図4に示すようなデータがデータ格納部160に格納された場合に、プログラム解析部122は、当該データを用いて、以下のような処理を実行する。具体的には、プログラム解析部122は、中間コード162内のループのうち未処理のループを1つ特定する(図5:ステップS1)。以下では、ステップS1において特定されたループを対象のループと呼ぶ。
プログラム解析部122は、対象のループのタイプが所定のタイプであるか判定する(ステップS3)。所定のタイプとは、例えばDO_LOOP又はWHILEであり、脱出を考慮しない場合のループ回転数(すなわち、制御変数がとりうる値の数)は制御変数の初期値、終値及び増分値によって決まり、それらの値はループ中で変更されない。
対象のループのタイプが所定のタイプではない場合(ステップS3:Noルート)、処理はステップS21に移行する。一方、対象のループのタイプが所定のタイプである場合(ステップS3:Yesルート)、変数「脱出分岐命令数」に0を設定する(ステップS5)。
プログラム解析部122は、対象のループから未処理の命令を1つ特定し(ステップS7)(以下では、ステップS7において特定された命令を対象の命令と呼ぶ)、対象の命令が脱出分岐命令であるか判定する(ステップS9)。
対象の命令が脱出分岐命令ではない場合(ステップS9:Noルート)、処理は端子Aを介して図6のステップS31に移行する。
図6の説明に移行し、プログラム解析部122は、対象の命令から未処理の出力オペランドを1つ特定する(図6:ステップS31)。以下では、ステップS31において特定された出力オペランドを対象の出力オペランドと呼ぶ。
プログラム解析部122は、対象の出力オペランドについて、ループ回転を跨いだRAWのデータ依存およびループ回転を跨いだWARのデータ依存が無いか判定する(ステップS33)。ステップS33においては、ループ回転を跨いだデータ依存がある変数名のリストを用いて判定が行われる。
対象の出力オペランドについて、ループ回転を跨いだRAWのデータ依存又はループ回転を跨いだWARのデータ依存が有る場合(ステップS33:Noルート)、処理は端子Cを介して図5のステップS21に移行する。
対象の出力オペランドについて、ループ回転を跨いだRAWのデータ依存およびループ回転を跨いだWARのデータ依存が無い場合(ステップS33:Yesルート)、プログラム解析部122は、以下の処理を実行する。具体的には、プログラム解析部122は、対象の出力オペランドの変数名が外部変数リストに含まれるか判定する(ステップS35)。
対象の出力オペランドの変数名が外部変数リストに含まれない場合(ステップS35:Noルート)、処理はステップS39に移行する。
一方、対象の出力オペランドの変数名が外部変数リストに含まれる場合(ステップS35:Yesルート)、プログラム解析部122は、対象の出力オペランドである変数(すなわち、外部変数)への代入が、外部変数への代入についての条件を満たすか判定する(ステップS37)。外部変数への代入についての条件は、詳細には以下のとおりである。
(1.1)代入先のアドレスがループ内で不変である(出力オペランドが、例えば単純変数、添え字が定数である配列要素或いは不変なポインタ変数実態等である)。
(1.2)代入はループ内で脱出分岐命令よりも前に実行される。
(1.3)ループからの脱出が発生しない場合に代入される値(終値)を計算できる。
なお、ループからの脱出が発生しない場合に代入される値の計算については、例えば特許文献2を参照されたい。
対象の出力オペランドである変数への代入が、外部変数への代入についての条件を満たさない場合(ステップS37:Noルート)、処理は端子Cを介して図5のステップS21に移行する。
対象の出力オペランドである変数への代入が、外部変数への代入についての条件を満たす場合(ステップS37:Yesルート)、プログラム解析部122は、対象の命令に未処理の出力オペランドが有るか判定する(ステップS39)。
未処理の出力オペランドが有る場合(ステップS39:Yesルート)、処理はステップS31に戻る。一方、未処理の出力オペランドが無い場合(ステップS39:Noルート)、処理は端子Bを介して図5のステップS15に移行する。
図5の説明に戻り、対象の命令が脱出分岐命令である場合(ステップS9:Yesルート)、プログラム解析部122は、脱出分岐命令数を1インクリメントする(ステップS11)。
プログラム解析部122は、脱出分岐命令数が1以下であるか判定する(ステップS13)。脱出分岐命令数が1以下ではない場合(ステップS13:Noルート)、処理はステップS21に移行する。脱出分岐命令数が1以下である場合(ステップS13:Yesルート)、プログラム解析部122は、対象のループに未処理の命令が有るか判定する(ステップS15)。
未処理の命令が有る場合(ステップS15:Yesルート)、処理はステップS7に戻る。一方、未処理の命令が無い場合(ステップS15:Noルート)、プログラム解析部122は、脱出分岐命令数が1であるか判定する(ステップS17)。
脱出分岐命令数が1ではない場合(ステップS17:Noルート)、処理はステップS21に移行する。一方、脱出分岐命令数が1である場合(ステップS17:Yesルート)、プログラム解析部122は、最適化対象フラグを「true」に設定する(ステップS19)。
プログラム解析部122は、中間コード162に未処理のループが有るか判定する(ステップS21)。未処理のループが有る場合(ステップS21:Yesルート)、処理はステップS1に戻る。一方、未処理のループが無い場合(ステップS21:Noルート)、処理は終了する。
以上のように、プログラム解析部122の処理によって、以下の4つの条件を満たすループが特定される。
(1)外部変数への代入についての条件
(2)ループ中に唯一つの脱出分岐命令を含むという条件
(3)脱出を考慮しない場合のループ回転数は、制御変数の初期値、終値及び増分値によって決まり、それらの値はループ中で変更されないという条件
(4)ループ回転を跨いだデータ依存が存在しないという条件
条件(1)はステップS37にて判定される。条件(2)はステップS13にて判定される。条件(3)はステップS3にて判定される。条件(4)はステップS33にて判定される。
以上のような処理を実行すれば、本実施の形態の最適化に適したループが特定されるようになる。
次に、図7乃至図10を用いて、プログラム最適化部123が実行する処理を説明する。
まず、プログラム最適化部123は、中間コード162内のループのうち未処理のループを1つ特定する(図7:ステップS41)。以下、ステップS41において特定されたループを対象のループと呼ぶ。
プログラム最適化部123は、対象のループの最適化対象フラグが「true」に設定されているか判定する(ステップS43)。
対象のループの最適化対象フラグが「true」に設定されていない場合(ステップS43:Noルート)、処理はステップS47に移行する。一方、対象のループの最適化対象フラグが「true」に設定されている場合(ステップS43:Yesルート)、プログラム最適化部123は、最適化処理を実行する(ステップS45)。最適化処理については、図8乃至図10を用いて説明する。
まず、プログラム最適化部123は、対象のループの制御変数の初期値、終値及び増分値を、所定のルールに従って変更する(図8:ステップS51)。ステップS51においては、元の初期値がsである場合には(s+round_towards_zero((e−s)/d)*d)に変更され、元の終値がeである場合にはsに変更され、元の増分値がdである場合には−dに変更される。このような変更により、制御変数の値は元の終値(但し、厳密には終値ではない場合がある)から元の初期値までdずつ変化することになる。本実施の形態においては、このような操作を「ループの回転方向を反転する」操作と呼ぶ。なお、初期値及び増分値を計算するための命令はループブロックの直前に挿入される。
プログラム最適化部123は、脱出分岐命令の検出フラグを「false」に設定する(ステップS53)。脱出分岐命令の検出フラグは、脱出分岐命令が検出された場合に「true」に設定される。
プログラム最適化部123は、対象のループから未処理の命令を1つ特定する(ステップS55)。以下では、ステップS55において特定された命令を対象の命令と呼ぶ。
プログラム最適化部123は、対象の命令から未処理の入力オペランドを1つ特定する(ステップS57)。以下では、ステップS57において特定された入力オペランドを対象の入力オペランドと呼ぶ。
プログラム最適化部123は、対象の入力オペランドが置換表のkey[]のいずれかに一致するか判定する(ステップS59)。置換表には、key[]とvalue[]とのセットを含むエントリが1又は複数登録される。括弧内にはオペランド番号が格納される。置換表へのエントリの登録については、後で説明する。
対象の入力オペランドが置換表のkey[]のいずれにも一致しない場合(ステップS59:Noルート)、処理はステップS63に移行する。一方、対象の入力オペランドが置換表のkey[]のいずれかに一致する場合(ステップS59:Yesルート)、プログラム最適化部123は、以下の処理を実行する。具体的には、プログラム最適化部123は、該当するkey[]に対応するvalue[]を置換表から読み出し、読み出したvalue[]で対象の入力オペランドを置換する(ステップS61)。
プログラム最適化部123は、未処理の入力オペランドが有るか判定する(ステップS63)。未処理の入力オペランドが有る場合(ステップS63:Yesルート)、処理はステップS57に戻る。一方、未処理の入力オペランドが無い場合(ステップS63:Noルート)、処理は端子Dを介して図9のステップS65に移行する。
図9の説明に移行し、プログラム最適化部123は、対象の命令は脱出分岐命令であるか判定する(図9:ステップS65)。
対象の命令は脱出分岐命令である場合(ステップS65:Yesルート)、処理は端子Eを介して図10のステップS91に移行する。
図10の説明に移行し、プログラム最適化部123は、脱出分岐命令の検出フラグを「true」に設定する(図10:ステップS91)。
プログラム最適化部123は、置換表から未処理のエントリを1つ特定する(ステップS93)。
プログラム最適化部123は、ステップS93において特定されたエントリに含まれるkey[]を代入先とし、value[]を代入元とし且つ対象の命令(すなわち、脱出分岐命令)の分岐条件を条件とする条件付代入命令を生成する。そして、プログラム最適化部123は、生成した条件付代入命令を、対象の命令の直前に追加する(ステップS95)。条件付代入命令とは、条件が成立した場合に代入を行うための命令である。
プログラム最適化部123は、置換表に未処理のエントリが有るか判定する(ステップS97)。未処理のエントリが有る場合(ステップS97:Yesルート)、処理はステップS93に戻る。一方、未処理のエントリが無い場合(ステップS97:Noルート)、プログラム最適化部123は、以下の処理を実行する。具体的には、プログラム最適化部123は、対象の命令(すなわち、脱出分岐命令)を削除する(ステップS99)。処理は端子Fを介して図9のステップS83に移行する。
図9の説明に戻り、対象の命令は脱出分岐命令ではない場合(ステップS65:Noルート)、プログラム最適化部123は、脱出分岐命令の検出フラグが「true」に設定されているか判定する(ステップS67)。
脱出分岐命令の検出フラグが「true」に設定されている場合(ステップS67:Yesルート)、処理はステップS83に移行する。一方、脱出分岐命令の検出フラグが「true」に設定されていない場合(ステップS67:Noルート)、プログラム最適化部123は、対象の命令から未処理の出力オペランドを1つ特定する(ステップS69)。以下、ステップS69において特定された出力オペランドを対象の出力オペランドと呼ぶ。
プログラム最適化部123は、対象の出力オペランドは外部変数リストに含まれるか判定する(ステップS71)。
対象の出力オペランドは外部変数リストに含まれない場合(ステップS71:Noルート)、処理はステップS81に移行する。一方、対象の出力オペランドは外部変数リストに含まれる場合(ステップS71:Yesルート)、プログラム最適化部123は、対象のループに対応するプロローグに、終値の代入命令を追加する(ステップS73)。ステップS73における終値とは、ループからの脱出が発生しない場合に外部変数に代入される値である。場合によってはループからの脱出が発生しないこともあるので、このような処理を実行することで、ループからの脱出が発生しない場合にも外部変数に値を代入しておくことができるようになる。
プログラム最適化部123は、対象の出力オペランドについて一時変数tmpを生成する(ステップS75)。なお、一時変数tmpは、ステップS75の処理が行われる度に異なるものが生成される。
プログラム最適化部123は、key[]が対象の出力オペランドであり且つvalue[]がtmpであるエントリを置換表に追加する(ステップS77)。そして、プログラム最適化部123は、対象の出力オペランドをtmpで置換する(ステップS79)。
プログラム最適化部123は、対象の命令に未処理の出力オペランドが有るか判定する(ステップS81)。未処理の出力オペランドが有る場合(ステップS81:Yesルート)、処理はステップS69に戻る。
一方、未処理の出力オペランドが無い場合(ステップS81:Noルート)、プログラム最適化部123は、対象のループに未処理の命令が有るか判定する(ステップS83)。
対象の命令に未処理の命令が有る場合(ステップS83:Yesルート)、処理は端子Gを介して図8のステップS55に移行する。
一方、対象の命令に未処理の命令が無い場合(ステップS83:Noルート)、プログラム最適化部123は、コピー伝播及び無用コードの除去を実行する(ステップS85)。ステップS85の処理によって、一時変数の定義及び参照は無くなり、代入命令が条件付代入命令で置換されたことになる。そして処理は呼び出し元に戻る。
図7の説明に戻り、プログラム最適化部123は、中間コード162に未処理のループがあるか判定する(ステップS47)。未処理のループが有る場合(ステップS47:Yesルート)、処理はステップS41に戻る。一方、未処理のループが無い場合(ステップS47:Noルート)、処理は終了する。
以上のような処理を実行すれば、ループ回転を跨いだRAWのデータ依存を有する変数を作ることなく、脱出分岐命令を含むループをリニアライズすることができるようになる。これにより、SIMD化及び並列化といった最適化を適用することができるようになり、また、並列度を上げることによって処理にかかる時間を短縮することができるようになる。また、分岐条件が成立したか否かを示すフラグが保持するレジスタ並びにそのレジスタを定義するための命令及び参照するための命令が不要になる。さらに、汎用的な命令だけを用いて実現することができるので、特殊なハードウエアを導入しなくてもよい。
以上のような本実施の形態の処理について、具体例を用いて説明を追加する。ここでは、図3及び図4に示したデータを例として説明する。ソースプログラム161は、図11に示すプログラムであるとする。図11に示すように、ソースプログラム161にはループコードが含まれ、ループコードには脱出分岐命令が含まれる。
ループが最適化の対象である場合、図4における最適化対象フラグは「false」から「true」に変更される。
初期値についてのデータは図12(a)に示すデータから図12(b)に示すデータに変更される。終値についてのデータは図13(a)に示すデータから図13(b)に示すデータに変更される。増分値についてのデータは図14(a)に示すデータから図14(b)に示すデータに変更される。
カーネルにおける命令「mov var(i),var(index)」は、出力オペランドが外部変数リストに含まれるので、一時変数(t3とする)が生成され、プロローグに対して終値の代入処理が追加される。プロローグについてのデータは、終値の代入命令が追加されたことによって、例えば図15(a)に示すデータから図15(b)に示すデータに変更される。また、カーネルについては、図16(a)に示すデータが図16(b)に示すデータに変更される。すなわち、カーネルにおけるvar(index)はvar(t3)で置換される。置換表には、例えば図17に示すようなエントリが追加される。
カーネルにおける命令「ld [var(x)+var(i)],var(t2)」及び「cmp var(t2),var(a)」は、脱出分岐命令ではないこと、入力オペランドvar(x)及びvar(i)は置換表にkeyとして登録されていないこと、並びに出力オペランドvar(t2)は外部変数リストに含まれないので、これらの命令に対する置換等は行われない。
カーネルにおける命令「breakeq %icc」は、脱出分岐命令であるので、以下の処理が行われる。具体的には、置換表に存在する各エントリについて、条件付代入命令が脱出分岐命令「breakeq %icc」の直前に挿入される。また、脱出分岐命令「breakeq %icc」が削除される。このような処理によって、カーネルについては、図18(a)に示すデータが図18(b)に示すデータに変更される。すなわち、命令「move %icc,var(t3),var(index)」が命令「breakeq %icc」の直前に追加され、命令「breakeq %icc」は削除される。
コピー伝播及び無用コードの除去によって一時変数var(t3)は削除されるので、カーネルについてのデータは、図19(a)に示すデータから図19(b)に示すデータに変更される。
以上のような最適化によって、図3及び図4に示したデータは、図20及び図21に示すデータに変更される。最適化の完了後、最適化対象フラグは「false」から「true」に変更される。
図22及び図23を用いて、ループ回転の反転及び外部変数への代入について説明を追加する。図22に、脱出の発生を管理するためのフラグを利用する技術を適用した場合について説明する。図22の例では、制御変数iの初期値が0であり、増分値は1である。i=2の場合に分岐条件が成立し、外部変数に値が代入される。このとき、フラグは0から1に変更される。i=6の場合にも分岐条件が成立するが、フラグが1であるため、値は変数に代入されずに破棄される。このような方法により、最初に分岐条件が成立したときの値を外部変数の値とすることができる。
図23に、本実施の形態の場合について説明する。ループ回転が反転されているので、・・・i=6,i=5、・・・i=0というように処理は実行される。i=6のとき分岐条件が成立し、外部変数に値が代入される。i=2のときも分岐条件が成立し、外部変数に値が代入される。このような方法により、フラグを格納するためのレジスタを別途用意することなく、もともとの実行順序であれば最初に分岐条件が成立したときに代入される値を外部変数の値とすることができる。
図24に、本実施の形態の最適化によって生成された中間コード162を通常の最適化によって生成する場合におけるソースプログラム161のイメージを示す。なお、実際に図24に示すようなプログラムが本実施の形態の処理により生成されるわけではない。ノンフォルティングロード命令については、例えば特許文献1を参照されたい。
図25に、本実施の形態のコンパイラ100により出力されるコードの一例を示す。後で説明する図28と比較すると、ループ中の命令数が8から6に減少し、使用レジスタ数が5から4に減少しており、効率がよいプログラムが生成されている。また、特殊なハードウエアを必要とする命令を使用しておらず、制御変数以外の変数については、ループ回転を跨いだRAWのデータ依存が無い。
命令アドレス0x0028の命令によって、脱出分岐命令の分岐条件が満たされていれば値が代入(上書きの場合もある)される。命令アドレス0x002cの命令によって、元のプログラムでループ脱出の直前に外部変数に保持されていた値が、最終的に保持される値になる。命令アドレス0x0030の命令によって、ループの回転方向が反転される。
元のプログラムとの等価性は、以下の3点により保証されている。
(1)外部変数には、脱出分岐命令の分岐条件が満たされた場合にのみ値が代入される。
(2)ループの回転方向が反転されているため、最後に書き込まれる値が元のプログラムでループの脱出直前に外部変数に保持されている値である。
(3)脱出分岐命令の分岐条件が満たされない場合、ループ前に代入された終値が使用される。
図25に示したコードにおいては、制御変数以外の変数について、ループ回転を跨いだRAWのデータ依存が無いため、SIMD化及び並列化を適用することができる。図26に、並列度2で並列化されたプログラムのイメージを示す。図26に示すように、コード261によって、配列x[]の前半分と後半分とが別々のプロセスで処理されるようになる。コード262によって、後半分の結果がindexに反映されるようになる。コード263によって、前半分のどこかで脱出分岐命令の分岐条件が成立していれば前半分の結果がindexに反映されるようになる。なお、並列化の詳細及び並列化とデータ依存との関係については、例えば"A.V.エイホ, R.セシィ, J.D.ウルマン, その他, "コンパイラ―原理・技法・ツール (Information & Computing)", サイエンス社, 第2版"を参照されたい。
なお、同様の原理でSIMD化も可能である。SIMD化の詳細及びSIMD化とデータ依存との関係については、例えば"Martin Kong, Richard Veras, Kevin Stock, Franz Franchetti, Louis-Noel Pouchet, P.Sadayappan, "When Polyhedral Transformations Meet SIMD Code Generation", Proceedings of the 34th ACM SIGPLAN Conference on Programming Language Design and Implementation, Pages 127-138"を参照されたい。
SIMD化及び並列化を適用した場合、最適化後のループ回転数Noptは、最適化前のループ回転数N、SIMD長L(≧1)及び並列度P(≧1)を用いて、Nopt=N/(L*P)で表わされる。例えば、L=16であり(例えば、4バイト整数演算を512バイトのSIMDレジスタを使用してSIMD化する場合)且つP=16(例えば、16コアのプロセッサの場合)である場合、LP=256であり、脱出分岐命令の分岐条件が成立する制御変数の値が一様乱数である場合には、平均実行時間は最適化前の1/128になる。
但し、分岐条件が成立する制御変数の値が一様乱数ではなく偏りがあり且つ値が比較的小さい場合、又は、回転数Nが少なく1回転あたりの処理命令数が多い場合、さらにプロファイル最適化等を併用し、リニアライズ最適化そのものを抑止した方がよい。プロファイル最適化については、例えば"Pohua P. Chang, Scott A. Mahlke, Wen-mei W. Hwu, "Using Profile Information to Assist Classic Code Optimizations", Software-Practice & Experience archive, Volume 21 Issue 12, Dec. 1991, Pages 1301-1321"を参照されたい。
以上本発明の一実施の形態を説明したが、本発明はこれに限定されるものではない。例えば、上で説明したリニアコード生成装置1の機能ブロック構成は実際のプログラムモジュール構成に一致しない場合もある。
また、上で説明したデータ構成は一例であって、上記のような構成でなければならないわけではない。さらに、処理フローにおいても、処理結果が変わらなければ処理の順番を入れ替えることも可能である。さらに、並列に実行させるようにしても良い。
[付録]
本付録においては、背景技術の欄において述べた2つの技術の説明を追加する。
例えば、図11に示したソースプログラム161に対してアーキテクチャに依存しない最適化を実行した場合にコンパイラが出力する命令列を図27に示す。アーキテクチャに依存しない最適化とは、どのようなアーキテクチャの汎用プロセッサであってもサポートされている命令(例えば、四則演算、条件分岐命令及びメモリアクセス命令など)だけを使用して実現できる最適化である。
図11に示したソースプログラム161のループが複数回実行され、実行される度に脱出時のループインデックス(すなわちi)が異なるような場合、図27における命令アドレス0x0024の脱出分岐命令において分岐予測ミスが多発する可能性がある。背景技術の欄で述べたように、分岐予測ミスの発生は、パイプラインのフラッシュ処理により数十クロックサイクル程度の処理遅延を発生させる。
分岐予測ミスの発生を抑止するため、脱出の発生を管理するためのフラグを利用する場合、例えば図28に示すような命令列が出力される。図28においては、分岐条件が成立したか否かを示すフラグが命令アドレス0x0018の命令によって設定される。命令アドレス0x0020の命令によれば、フラグがセットされている場合には%o4の値が更新されない。従って、命令アドレス0x0024の命令によって同じ値が同じ場所に書き込み続けられることになる(すなわち、実質的に空ループになる)。命令アドレス0x0030の命令によって、分岐条件が成立した場合にはフラグがセットされる。条件付代入命令は、ハードウエアの設計上、少数の基本論理回路の組合せによって実装することが可能であり分岐予測ミスが発生しないので、命令アドレス0x0030の命令はOR(AND(NOT(%icc.z),%o3),AND(%icc.z,1))と等価である。この技術においては、元のループコードから脱出分岐命令を削除する代わりに「現在実行している命令が、元のループで本来実行されない、脱出分岐命令以降の命令である」ことを示すフラグが設けられる。メモリにデータを書き込む前にフラグが参照され、条件付代入命令を用いて「現在メモリ上にあるデータ」と「更新されたデータ」とのどちらを書き込むか決定することで、脱出と等価な処理が実現される。
分岐予測ミスの発生を抑止するため、プレディケイトレジスタを使用する技術の場合、例えば図29に示すような命令列が出力される。図29においては、分岐条件が成立したか否かを示すフラグが命令アドレス0x0018の命令によって設定されており、プレディケイトレジスタを備えるプロセッサは、プレディケイトレジスタに値が設定されている場合に一部の命令の実行をスキップすることができる。図29においては、太線枠291によって囲まれた部分の命令列がスキップされる。太線枠291に含まれる、命令アドレス0x002cの命令によって、プレディケイトレジスタに値が設定される。
但し、脱出分岐命令が無くなることでループの回転数が最大値で固定され、無駄な処理を実行することになる。特に、ループの回転数が多く、比較的早期にループから脱出する場合、最適化前と比べると実行時間が長くなる。例えば、前者の技術の場合、最適化前のループ回転数をN、分岐条件がX回転目で成立するとして、Xが1からNの一様乱数をとる場合、ループの平均回転数はN/2からNに増加する。ループ1回転あたりの処理時間をTbodyとし、分岐予測ミスによる時間損失をTbntとすると、(Tbody*N/2≧Tbnt)の場合に実行時間が長くなる。
また、背景技術の欄で述べたように、ループ回転を跨いだRAWのデータ依存があり、そのために、SIMD化や並列化等の技術を適用することができないので、先に述べた、ループ回転数が多くなるという問題を解決できない。
また、フラグを使用する方式については、フラグを保持するためのレジスタが必要であり、必要なレジスタ数が増加する。また、レジスタを定義するための命令及び参照するための命令を追加することになるため、命令数が増加する。必要なレジスタ数がプロセッサに搭載されている実レジスタ数を超えると、一時的にレジスタ上のデータをメモリ上に退避する処理(すなわちスピル)及びメモリ上に退避されたデータをレジスタ上に復元する処理(すなわちフィル)が行われる。スピル及びフィルに要する時間はアーキテクチャによって異なるが、一般的に、数サイクルから数百サイクルを要するため、性能を大きく低下させる原因になりうる。
また、後者の技術の場合、プロセッサに大規模な回路を搭載することを前提としており、汎用的な技術ではない。前者の方法で使用される条件付代入命令やノンフォルティングロード命令は、既存の回路に数個の論理ゲートを付け加えれば実現できる単純な命令であり、多くのアーキテクチャで採用されている(例えば、SPARC、x86_64、IA−64など)。これに対し、後者の方法の命令制御を実現するためにはパイプライン制御部に複雑な回路を組み込まなければならず、後者の方法を採用するアーキテクチャは稀である。
以上の4つの問題点のうち最後の問題点以外の問題点の具体例を、図30を用いて説明する。図30に示したコードは、図28に示したコードと同じである。図30の例において、ループの回転数はnであり、ループの回転数は最大値で固定されている。また、命令アドレス0x001cの命令及び命令アドレス0x0030の命令は、ループ回転を跨いだRAWのデータ依存に該当する。さらに、命令アドレス0x0018の命令、命令アドレス0x001cの命令及び命令アドレス0x0030の命令は、新たに導入されたフラグを定義するための命令及び参照するための命令である。
なお、分岐予測については、例えば"Hisa Ando, "コンピュータアーキテクチャ技術入門 高速化の追求×消費電力の壁 (WEB+DB PRESS plus)", 技術評論社, 2014年05月01日"を参照されたい。
以上で本付録を終了する。
以上述べた本発明の実施の形態をまとめると、以下のようになる。
本実施の形態の第1の態様に係るコード生成装置は、(A)最適化の対象である最適化対象コードから、分岐条件(例えば、実施の形態における脱出分岐条件)が成立した場合に最適化対象コードに含まれるループから脱出することを規定する条件分岐命令を含む第1のループコードを特定する特定部(例えば、実施の形態におけるプログラム解析部122)と、(B)特定部により特定された第1のループコードに対して、ループインデックスの開始値と終了値とを交換し、ループインデックスの変化値について符号の正負を反転し、第1のループコードの外部のコードから参照される第1の変数への代入命令を分岐条件が成立した場合に第1の変数に代入する命令に変換し、且つ条件分岐命令を削除する処理を実行する最適化部(例えば、実施の形態におけるプログラム最適化部123)とを有する。
このような処理によって生成されるコードであれば、ループからの脱出が発生しないような形で、元のコードに基づく処理と等価な処理を実現することができるようになる。これにより、分岐予測ミスの発生を抑止可能なオブジェクトコードを生成することができるようになる。また、上記処理によって生成されるコードに対してはSIMD化や並列化といった技術を適用することができるので、実行時間を短縮することができるようになる。さらに、レジスタ数が増えることがなく、特殊なハードウエアを導入することもない。
また、第1のループコードは、第1のループコードに含まれる条件分岐命令の数が1であるという第1の条件と、異なるループインデックス間でのデータ依存が無いという第2の条件と、第1のループコードの種別が所定の種別であるという第3の条件と、第1の変数への値の代入についての第4の条件とを満たしてもよい。最適化部による最適化が有効なループコードを特定できるようになる。
また、第4の条件は、代入先のアドレスが不変であるという第5の条件と、第1の変数への代入が条件分岐命令より前に行われるという第6の条件と、ループからの脱出が発生しない場合に第1の変数に代入される値を計算できるという第7の条件とを含んでもよい。最適化部による最適化が有効なループコードを特定できるようになる。
また、最適化部は、(b1)第1のループコードによるループからの脱出が発生しない場合に第1の変数に代入される値を第1の変数に代入する命令を、第1のループコードの直前に追加する処理をさらに実行してもよい。場合によってはループからの脱出が発生しないこともあるので、このような処理を実行することで、ループからの脱出が発生しない場合にエラーとなることを防ぐことができるようになる。
また、代入命令の変換処理において、(b2)第1の変数への代入命令を一時変数への代入命令に変換し、分岐条件が成立した場合に第1の変数に一時変数の値を代入する命令を追加してもよい。
また、最適化部は、(b3)特定部により特定された第1のループコードに対して、コピー伝播と不要なコードの削除とを実行してもよい。
また、本コード生成装置は、(C)最適化部の処理によって生成されたコードからオブジェクトコードを生成する生成部(例えば、実施の形態におけるオブジェクト生成部132)をさらに有してもよい。
本実施の形態の第2の態様に係るコード生成方法は、(D)最適化の対象である最適化対象コードから、分岐条件が成立した場合に最適化対象コードに含まれるループから脱出することを規定する条件分岐命令を含む第1のループコードを特定し、(E)特定された第1のループコードに対して、ループインデックスの開始値と終了値とを交換し、ループインデックスの変化値について符号の正負を反転し、第1のループコードの外部のコードから参照される第1の変数への代入命令を分岐条件が成立した場合に第1の変数に代入する命令に変換し、且つ、条件分岐命令を削除する処理を実行する処理を含む。
なお、上記方法による処理をプロセッサに行わせるためのプログラムを作成することができ、当該プログラムは、例えばフレキシブルディスク、CD−ROM、光磁気ディスク、半導体メモリ、ハードディスク等のコンピュータ読み取り可能な記憶媒体又は記憶装置に格納される。尚、中間的な処理結果はメインメモリ等の記憶装置に一時保管される。
以上の実施例を含む実施形態に関し、さらに以下の付記を開示する。
(付記1)
最適化の対象である最適化対象コードから、分岐条件が成立した場合に前記最適化対象コードに含まれるループから脱出することを規定する条件分岐命令を含む第1のループコードを特定する特定部と、
前記特定部により特定された前記第1のループコードに対して、ループインデックスの開始値と終了値とを交換し、前記ループインデックスの変化値について符号の正負を反転し、前記第1のループのコードの外部のコードから参照される第1の変数への代入命令を前記分岐条件が成立した場合に前記第1の変数に代入する命令に変換し、且つ前記条件分岐命令を削除する処理を実行する最適化部と、
を有するコード生成装置。
(付記2)
前記第1のループコードは、前記第1のループコードに含まれる条件分岐命令の数が1であるという第1の条件と、異なるループインデックス間でのデータ依存が無いという第2の条件と、前記第1のループコードの種別が所定の種別であるという第3の条件と、前記第1の変数への値の代入についての第4の条件とを満たす、
付記1記載のコード生成装置。
(付記3)
前記第4の条件は、代入先のアドレスが不変であるという第5の条件と、前記第1の変数への代入が前記条件分岐命令より前に行われるという第6の条件と、ループからの脱出が発生しない場合に前記第1の変数に代入される値を計算できるという第7の条件とを含む、
付記2記載のコード生成装置。
(付記4)
前記最適化部は、
前記第1のループコードによるループからの脱出が発生しない場合に前記第1の変数に代入される値を前記第1の変数に代入する命令を、前記第1のループコードの直前に追加する、
処理をさらに実行する付記1乃至3のいずれか1つ記載のコード生成装置。
(付記5)
前記代入命令を変換する処理において、
前記第1の変数への代入命令を一時変数への代入命令に変換し、前記分岐条件が成立した場合に前記第1の変数に前記一時変数の値を代入する命令を追加する、
付記1乃至4のいずれか1つ記載のコード生成装置。
(付記6)
前記最適化部は、
前記特定部により特定された前記第1のループコードに対して、コピー伝播と不要なコードの削除とを実行する、
処理をさらに実行する付記1乃至5のいずれか1つ記載のコード生成装置。
(付記7)
前記最適化部の処理によって生成されたコードからオブジェクトコードを生成する生成部
をさらに有する付記1乃至6のいずれか1つ記載のコード生成装置。
(付記8)
コンピュータが、
最適化の対象である最適化対象コードから、分岐条件が成立した場合に前記最適化対象コードに含まれるループから脱出することを規定する条件分岐命令を含む第1のループコードを特定し、
特定された前記第1のループコードに対して、ループインデックスの開始値と終了値とを交換し、前記ループインデックスの変化値について符号の正負を反転し、前記第1のループコードの外部のコードから参照される第1の変数への代入命令を前記分岐条件が成立した場合に前記第1の変数に代入する命令に変換し、且つ前記条件分岐命令を削除する処理を実行する、
ことを特徴とするコード生成方法。
(付記9)
コンピュータに、
最適化の対象である最適化対象コードから、分岐条件が成立した場合に前記最適化対象コードに含まれるループから脱出することを規定する条件分岐命令を含む第1のループコードを特定させ、
特定された前記第1のループコードに対して、ループインデックスの開始値と終了値とを交換し、前記ループインデックスの変化値について符号の正負を反転し、前記第1のループコードの外部のコードから参照される第1の変数への代入命令を前記分岐条件が成立した場合に前記第1の変数に代入する命令に変換し、且つ前記条件分岐命令を削除する処理を実行させる、
ことを特徴とするコード生成プログラム。