以下、本実施の形態を図面を参照して説明する。
[第1の実施の形態]
図1は、第1の実施の形態のコンパイル装置の例を示す図である。
コンパイル装置10は、C言語などの高級言語を用いて記述されたソースコードを、プロセッサが実行可能なオブジェクトコードに変換(コンパイル)する。コンパイル装置10は、コンパイルを行うソフトウェアを実行するコンピュータであってもよい。コンパイル装置10またはコンパイルを行うソフトウェアを「コンパイラ」と呼んでもよい。また、コンパイル装置10は、ユーザが操作する端末装置としてのクライアント装置であってもよいし、クライアント装置からアクセスされるサーバ装置であってもよい。また、生成されたオブジェクトコードを実行するプロセッサは、コンパイル装置10が備えるプロセッサでもよいし、他のコンピュータが備えるプロセッサでもよい。
コンパイル装置10は、記憶部11および演算部12を有する。記憶部11は、RAM(Random Access Memory)などの揮発性の記憶装置でもよいし、HDD(Hard Disk Drive)などの不揮発性の記憶装置でもよい。演算部12は、例えば、プロセッサである。プロセッサは、CPUやDSP(Digital Signal Processor)であってもよく、ASIC(Application Specific Integrated Circuit)やFPGA(Field Programmable Gate Array)などの特定用途の集積回路を含んでもよい。プロセッサは、RAMなどの記憶装置(例えば、記憶部11)に記憶されたプログラムを実行するものであってもよい。また、2以上のプロセッサの集合(マルチプロセッサ)を「プロセッサ」と呼んでもよい。
記憶部11は、コード13(第1のコード)およびコード14(第2のコード)を記憶する。コード13は、例えば、ソースコード、または、ソースコードから字句解析・構文解析などのフロンドエンド処理を通じて生成される中間コードである。コード14は、例えば、コード13に対応するアセンブリコードまたはオブジェクトコードである。
演算部12は、記憶部11からコード13を取得し、コード13に対して最適化処理を含むバックエンド処理を行い、コード13に対応するコード14を生成して記憶部11に格納する。最適化処理において、演算部12は、コード13に含まれる複数の命令の間の依存関係を示す依存ツリー15を生成する。依存ツリー15に含まれる命令は、例えば、加算・減算・乗算・除算・ロード・ストアなどの基本的命令である。
依存ツリー15が生成されると、演算部12は、依存ツリー15の中から所定条件を満たす部分ツリーを検出する。所定条件を満たす部分ツリーは、命令#1(第1の命令)と命令#2(第2の命令)と命令#1,#2の演算結果に依存する命令#3(第3の命令)とを含む。命令#1,#2は、例えば、それぞれ2以上の参照オペランドを有し、加算・減算・乗算・除算などの四則演算を行う命令である。命令#3は、例えば、命令#1,#2の演算結果を参照する参照オペランドを有し、加算・減算・乗算・除算などの四則演算を行う命令である。検出する部分ツリーは、三角形状の部分ツリーと言うこともできる。
部分ツリーが検出されると、演算部12は、検出した部分ツリーを複合命令を用いて書き換えることで、依存ツリー15を依存ツリー15aに変換する。複合命令は、1命令によって複数の演算(例えば、異なる種類の演算)を含む複合演算をプロセッサに実行させるものである。複合命令の一例として、参照オペランドA,B,Cに対して乗算と加算を組み合わせたA×B+Cを算出するFMA命令が挙げられる。なお、FMA命令に類する命令群に、乗算と減算を組み合わせたA×B−Cを算出する命令なども含まれ得る。
部分ツリーは、1つの複合命令または2以上の複合命令の組み合わせへと書き換えられる。好ましくは、書き換え後の複合命令の数は、書き換え前の部分ツリーに含まれる命令の数以下になる。また、好ましくは、ルートノードからの深さが同じ命令が少なくなるように部分ツリーが書き換えられる。また、好ましくは、書き換え前の部分ツリーに種類の異なる演算の命令が混在していても、書き換え後は1種類の複合命令によって部分ツリーの演算が表現される。部分ツリーを書き換えるにあたり、演算部12は、命令#1,#2,#3の演算の種類に応じた変換規則を用いてもよい。
例えば、命令#1,#2が乗算であり命令#3が加算である、すなわち、データA,B,C,Dに対して(A×B)+(C×D)を算出する部分ツリーを検出したとする。すると、演算部12は、例えば、A×B+(C×D+0)=FMA(A,B,FMA(C,D,0))のように2つのFMA命令を用いて部分ツリーを書き換える。この変換規則によれば、命令数が書き換え前よりも減少し、同じ深さに配置される命令の数も減少し(2つの命令が異なる深さに属し)、命令の種類がFMA命令のみに統一される。
依存ツリー15が依存ツリー15aに変換されると、演算部12は、複合命令を含む依存ツリー15aに基づいてコード14を生成する。演算部12は、命令#1,#2,#3に代えて複合命令を含むコード14を生成してもよい。また、演算部12は、依存ツリー15aを、依存ツリー15aと依存関係がなく複合命令を含む他の依存ツリーと比較し、依存ツリー15aに含まれる複合命令と他の依存ツリーに含まれる複合命令とを並列化命令に変換してもよい。この並列化命令は、1命令によって2以上の複合演算をプロセッサに並列実行させるものである。並列化命令は、例えば、SIMD−FMA命令である。
例えば、依存ツリー15の部分ツリーがFMA(A0,B0,FMA(C0,D0,0))と変換され、他の依存ツリーの部分ツリーがFMA(A1,B1,FMA(C1,D1,0))と変換されたとする。すると、演算部12は、FMA(C0,D0,0)=X0とFMA(C1,D1,0)=X1とをSIMD−FMA命令に変換し、FMA(A0,B0,X0)とFMA(A1,B1,X1)とをSIMD−FMA命令に変換する。
第1の実施の形態のコンパイル装置10によれば、依存ツリー15から三角形状の命令#1,#2,#3を含む部分ツリーが検出され、この部分ツリーが複合命令を用いて書き換えられる。そして、複合命令を含む依存ツリー15aを用いてFMA化やSIMD化などの最適化処理が行われる。これにより、依存ツリー15aの同じ深さに配置された命令の数が依存ツリー15よりも少なくなることが期待でき、命令の組み合わせのパターンが減少し得る。また、依存ツリー15aに含まれる命令の多くが同じ種類の複合命令になると期待でき、命令の種類に応じて実行サイクル数が異なる場合であっても命令スケジューリングが容易になる。よって、依存ツリー15aを探索することで、依存ツリー15を探索する場合と比べて最適化処理の計算量を抑制でき処理時間を短縮できる。
また、コード13に含まれる多くの命令を複合命令に変換することで、コード14の命令数を削減することができる。また、多くの命令を同じ種類の複合命令に変換することで、それらの同じ種類の複合命令を空き時間が少なくなるように高密度にスケジューリングできる。よって、コード14の実行効率を向上させることができる。
[第2の実施の形態]
図2は、端末装置が備えるハードウェア例を示すブロック図である。
第2の実施の形態の端末装置100は、高級言語で記述されたソースコードをコンパイルして、機械可読なオブジェクトコードを生成する。また、端末装置100は、複数のオブジェクトコードをリンクして、端末装置100または他のコンピュータに実行させる実行コードを生成する。ただし、第2の実施の形態で説明するコンパイルおよびリンクは、端末装置100からアクセスされるサーバコンピュータで実行することもできる。
端末装置100は、CPU101、RAM102、HDD103、画像信号処理部104、入力信号処理部105、ディスクドライブ106および通信インタフェース107を有する。CPU101は、第1の実施の形態の演算部12の一例であり、RAM102またはHDD103は、第1の実施の形態の記憶部11の一例である。
CPU101は、プログラムの命令を実行する演算器を含むプロセッサである。CPU101は、HDD103に記憶されているプログラムやデータの少なくとも一部をRAM102にロードし、プログラムを実行する。なお、CPU101は複数のプロセッサコアを備えてもよく、端末装置100は複数のプロセッサを備えてもよく、以下で説明する処理を複数のプロセッサまたはプロセッサコアを用いて並列実行してもよい。
RAM102は、CPU101が実行するプログラムや計算に用いられるデータを一時的に記憶する揮発性メモリである。なお、端末装置100は、RAM以外の種類のメモリを備えてもよく、複数のメモリを備えてもよい。
HDD103は、OS(Operating System)やファームウェアやアプリケーションソフトウェアなどのソフトウェアのプログラム、および、データを記憶する不揮発性記憶装置である。なお、端末装置100は、フラッシュメモリやSSD(Solid State Drive)などの他の種類の記憶装置を備えてもよく、複数の記憶装置を備えてもよい。
画像信号処理部104は、CPU101からの命令に従って、端末装置100に接続されたディスプレイ21に画像を出力する。ディスプレイ21としては、CRT(Cathode Ray Tube)ディスプレイや液晶ディスプレイなどを用いることができる。
入力信号処理部105は、端末装置100に接続された入力デバイス22から入力信号を取得し、CPU101に通知する。入力デバイス22としては、マウスやタッチパネルなどのポインティングデバイス、キーボードなどを用いることができる。
ディスクドライブ106は、記録媒体23に記録されたプログラムやデータを読み取る駆動装置である。記録媒体23として、例えば、フレキシブルディスク(FD:Flexible Disk)やHDDなどの磁気ディスク、CD(Compact Disc)やDVD(Digital Versatile Disc)などの光ディスク、光磁気ディスク(MO:Magneto-Optical disk)を使用できる。ディスクドライブ106は、例えば、CPU101からの命令に従って、記録媒体23から読み取ったプログラムやデータをRAM102またはHDD103に格納する。
通信インタフェース107は、ネットワーク24を介して他のコンピュータと通信を行えるインタフェースである。通信インタフェース107は、有線網に接続する有線インタフェースでもよいし、無線網に接続する無線インタフェースでもよい。
図3は、端末装置で実行されるソフトウェア例を示すブロック図である。
端末装置100は、ファイル記憶部110、コンパイラ120およびリンカ130を有する。ファイル記憶部110は、例えば、RAM102またはHDD103に確保した記憶領域として実現することができる。コンパイラ120およびリンカ130は、例えば、CPU101が実行するプログラムのモジュールとして実現することができる。
ファイル記憶部110は、ソースファイル111、オブジェクトファイル112および実行ファイル113を記憶する。ソースファイル111は、高級言語で記述されたソースコードを記憶する。オブジェクトファイル112は、SIMD命令やFMA命令やSIMD−FMA命令を含み得る機械可読なオブジェクトコードを記憶する。実行ファイル113は、SIMD命令やFMA命令やSIMD−FMA命令を解釈できるアーキテクチャのプロセッサが実行する実行形式のファイルである。なお、CPU101は、実行ファイル113を実行可能であってもよいし実行可能でなくてもよい。
コンパイラ120は、ファイル記憶部110からソースファイル111を読み出し、ソースコードをオブジェクトコードに変換して、オブジェクトファイル112をファイル記憶部110に格納する。コンパイラ120は、入出力制御部121、ファイル入力部122、中間コード生成部123、中間コード記憶部124、最適化部125、アセンブリコード生成部128およびファイル出力部129を有する。
入出力制御部121は、ファイルの種類に応じた入出力方法を選択し、ファイル入力部122およびファイル出力部129を制御する。ファイル入力部122は、入出力制御部121からの指示に応じて、ソースファイル111をオープンし、ソースファイル111からソースコードを読み出す。中間コード生成部123は、ファイル入力部122が読み出したソースコードを解析して、コンパイラ120の内部で利用される中間言語で記述された中間コードに変換し、中間コードを中間コード記憶部124に格納する。ソースコードの解析には、字句解析、構文解析、意味解析などが含まれる。中間コード記憶部124は、例えば、RAM102に確保された記憶領域であり、中間コードを記憶する。
最適化部125は、中間コード記憶部124に記憶された中間コードを、実行効率が上がる(例えば、実行速度が上がる)ように最適化する。最適化部125は、解析部126および最適化実行部127を有する。解析部126は、中間コードを解析して最適化方法を決定する。解析部126が行う最適化方法の決定には、中間コードに含まれる命令の中でSIMD命令、FMA命令またはSIMD−FMAに変換する命令の組み合わせを決定することを含む。最適化実行部127は、解析部126が決定した最適化方法に従って中間コードを最適化する。最適化実行部127が行う最適化には、中間コードに含まれる命令をSIMD命令、FMA命令またはSIMD−FMA命令に変換することを含む。
中間コードに含まれる非SIMD命令をSIMD命令に変換することは「SIMD化」と言うことができる。中間コードに含まれる非FMA命令をFMA命令に変換することは「FMA化」と言うことができる。SIMD−FMA命令に変換することは、SIMD化かつFMA化を実行することであり、「SIMD−FMA化」と言うこともできる。
アセンブリコード生成部128は、最適化された中間コードを、低級言語であるアセンブリ言語で記述されたアセンブリコードに変換する。ファイル出力部129は、入出力制御部121からの指示に応じて、オブジェクトファイル112を生成する。そして、ファイル出力部129は、アセンブリコード生成部128が生成したアセンブリコードをオブジェクトコードに変換し、オブジェクトファイル112に書き込む。
リンカ130は、ファイル記憶部110からオブジェクトファイル112を読み出し、オブジェクトコードを解析して、参照されている他のオブジェクトファイルやライブラリを検出する。そして、リンカ130は、オブジェクトファイル112と、検出した他のオブジェクトファイルやライブラリとをリンクし、実行ファイル113を生成する。なお、コンパイラ120にリンカ130の機能が統合されていてもよい。
次に、SIMD命令やSIMD−FMA命令の実行方法について説明する。
図4は、SIMD命令とSIMDレジスタの関係例を示す図である。
SIMD命令を解釈できるプロセッサは、並列に処理するデータを組み合わせて格納するSIMDレジスタを備える。各SIMDレジスタは、プロセッサのアーキテクチャによって決まる並列度(並列に実行できる同じ種類の演算の数)に相当する数のサブレジスタを含む。図4の例は、並列度が2の場合を示している。
例えば、図4に示すように、A=B+C,E=F+Gという2つの命令を1つのSIMD命令s1=s2+s3に変換した場合を考える。この場合、SIMDレジスタs2のサブレジスタ1にデータB、SIMDレジスタs2のサブレジスタ2にデータF、SIMDレジスタs3のサブレジスタ1にデータC、SIMDレジスタs3のサブレジスタ2にデータGを格納しておく。すると、SIMD命令によって、2つの加算が並列に実行されてデータA,Eが算出され、SIMDレジスタs1のサブレジスタ1にデータA、SIMDレジスタs1のサブレジスタ2にデータEが格納されることになる。
なお、同じ位置にあるサブレジスタの集合をスロットと呼ぶ。すなわち、SIMDレジスタs1,s2,s3の各サブレジスタ1はスロット1に属し、SIMDレジスタs1,s2,s3の各サブレジスタ2はスロット2に属する。SIMD命令では、同じスロットに属する複数のサブレジスタを用いて1つの演算が行われることになる。
図5は、SIMDレジスタの実装例を示す図である。
プロセッサ内にSIMDレジスタを実装する方式としては、例えば、図5に示すような(A)分割方式または(B)結合方式を用いることができる。
分割方式では、1つの大きな物理レジスタを論理的に均等な大きさに分割して、複数のサブレジスタを形成する。並列度2の場合は物理レジスタの記憶領域を2等分し、並列度4の場合は物理レジスタの記憶領域を4等分する。物理レジスタの大きさを一定とすると、並列度が高いほど、各サブレジスタのビット数は小さくなる。分割方式では、SIMDレジスタは物理的なレジスタを指し、サブレジスタは論理的なレジスタを指す。
一方、結合方式では、ビット数が等しい複数の物理レジスタをグルーピングし、各物理レジスタをサブレジスタとして用いてSIMDレジスタを形成する。並列度2の場合は2個の物理レジスタの集合をSIMDレジスタとして扱い、並列度4の場合は4個の物理レジスタの集合をSIMDレジスタとして扱う。物理レジスタの大きさを一定とすると、並列度が高いほど、SIMDレジスタのビット数は大きくなる。結合方式では、SIMDレジスタは論理的なレジスタを指し、サブレジスタは物理的なレジスタを指す。
図6は、SIMD化とFMA化の組み合わせ例を示す図である。
FMA命令を解釈できるプロセッサは、1つのFMA命令に基づいて積和演算、すなわち、乗算とその乗算結果を用いた加算とを実行する。例えば、X=B×C,A=X+Dという2つの命令を1つのFMA命令に変換すると、プロセッサは1命令としてA=B×C+Dを算出する。また、Y=F×G,E=Y+Hという2つの命令を1つのFMA命令に変換すると、プロセッサは1命令としてE=F×G+Hを算出する。
また、SIMD−FMA命令を解釈できるプロセッサは、2以上の積和演算を並列に実行することができる。すなわち、2以上のFMA命令がSIMD化される。例えば、SIMD−FMA命令を解釈できるプロセッサは、アーキテクチャによって決まる並列度に相当する数の算術演算器を備える。図6の例は、並列度が2の場合を示している。
例えば、図6に示すように、A=B×C+D,E=F×G+Hという2つのFMA命令を1つのSIMD−FMA命令s1=s2×s3+s4に変換した場合を考える。この場合、SIMDレジスタs2のサブレジスタ1にデータB、SIMDレジスタs2のサブレジスタ2にデータFを格納しておく。また、SIMDレジスタs3のサブレジスタ1にデータC、SIMDレジスタs3のサブレジスタ2にデータG、SIMDレジスタs4のサブレジスタ1にデータD、SIMDレジスタs4のサブレジスタ2にデータHを格納しておく。すると、SIMD−FMA命令によって、2つの積和演算が並列に実行されてデータA,Eが算出され、SIMDレジスタs1のサブレジスタ1にデータA、SIMDレジスタs1のサブレジスタ2にデータEが格納されることになる。
次に、SIMD命令でもFMA命令でもない基本的命令を組み合わせてSIMD−FMA命令に変換する(SIMD−FMA化する)最適化処理について説明する。
図7は、加算と乗算を含む命令列の例を示す図である。
ここでは理解を容易にするため、ソースコード形式で記述された命令と最適化処理との関係について説明する。コード141は、ソースファイル111に含まれている。コード141の1つの翻訳単位に、図7に示すような命令1〜14が含まれているとする。翻訳単位は、コンパイラ120が一度に処理するコード範囲を示す。コンパイラ120による最適化処理は、同じ翻訳単位に属する命令の間で行われる。
命令1〜8,13,14では2つのオペランドに対して乗算(×)が行われ、命令9〜12では2つのオペランドに対して加算(+)が行われる。命令1〜8は依存関係がなく並列に実行可能であり、命令9〜12は依存関係がなく並列に実行可能であり、命令13,14は依存関係がなく並列に実行可能である。一方、命令9は命令1,5の乗算結果を参照し、命令10は命令2,6の乗算結果を参照し、命令11は命令3,7の乗算結果を参照し、命令12は命令4,8の乗算結果を参照する。命令13は命令9,11の加算結果を参照し、命令14は命令10,12の加算結果を参照する。
図8は、命令列に対応する依存ツリーの例を示す図である。
コンパイラ120は、図7に示した命令1〜14から、命令1〜14の間の依存関係を示す依存ツリー31,32を生成する。依存ツリー31は、命令1,3,5,7,9,11,13を含む。上記のように、命令1,3,5,7,13は乗算(MULT)の命令であり、命令9,11は加算(ADD)の命令である。命令9は命令1,5に依存し、命令11は命令3,7に依存し、命令13は命令9,11に依存する。
依存ツリー32は、命令2,4,6,8,10,12,14を含む。上記のように、命令2,4,6,8,14は乗算(MULT)の命令であり、命令10,12は加算(ADD)の命令である。命令10は命令2,6に依存し、命令12は命令4,8に依存し、命令14は命令10,12に依存する。依存ツリー31に属する命令と依存ツリー32に属する命令とは、互いに依存関係がなく並列に実行することが可能である。
図9は、SIMD−FMA化した命令列の例を示す図である。
コンパイラ120は、依存ツリー31,32を直接探索して命令1〜14を最適化する場合、例えば、次のような手順でSIMD−FMA命令を生成することが考えられる。
まず、コンパイラ120は、依存ツリー31と依存ツリー32とを比較して、SIMD命令に変換可能な依存ツリー31の命令と依存ツリー32の命令との組み合わせのパターンを探索する。SIMD命令に変換可能な命令の組は、演算の種類が同じであり、各依存ツリーのルートからの深さが同じ命令の組である。なお、命令13,14の深さは1、命令9〜12の深さは2、命令1〜8の深さは3である。
ここでは、コンパイラ120は、命令1,2を組み合わせて乗算のSIMD命令A0|A1=B0|B1×C0|C1を生成する。A0|A1は、同じSIMDレジスタにデータA0とデータA1が格納されることを示す。同様に、コンパイラ120は、命令3,4を組み合わせて乗算のSIMD命令、命令5,6を組み合わせて乗算のSIMD命令、命令7,8を組み合わせて乗算のSIMD命令を生成する。また、コンパイラ120は、命令9,10を組み合わせて加算のSIMD命令、命令11,12を組み合わせて加算のSIMD命令、命令13,14を組み合わせて乗算のSIMD命令を生成する。これにより、7個のSIMD命令を含むコード142が生成される。
次に、コンパイラ120は、SIMD−FMA命令に変換可能な乗算のSIMD命令と加算のSIMD命令との組み合わせのパターンを、コード142から探索する。SIMD−FMA命令に変換可能なSIMD命令の組は、一方のSIMD命令の乗算結果(乗算のSIMD命令が定義したデータ)を他方のSIMD命令が参照しているものである。
ここでは、コンパイラ120は、コード142の1,5番目のSIMD命令を組み合わせてSIMD−FMA命令X0|X1=B0|B1×C0|C1+A4|A5を生成する。また、コンパイラ120は、コード142の2,6番目のSIMD命令を組み合わせてSIMD−FMA命令X2|X3=B2|B3×C2|C3+A6|A7を生成する。コード142の3,4,7番目のSIMD命令はそのまま維持される。これにより、2個のSIMD−FMA命令と3個のSIMD命令を含むコード143が生成される。
しかし、このようなSIMD−FMA化には次のような課題がある。
2つの依存ツリーの同じ深さに同じ種類の演算の命令がn個ずつ存在するとき、その深さにおける命令の組み合わせパターンはnPn通りになる。依存ツリー全体の組み合わせパターン数は、各深さの組み合わせパターン数の合計となる。図8に示した依存ツリー31,32の場合、深さ3に4個の乗算命令があり、深さ2に2個の加算命令があり、深さ1に1個の乗算命令があるため、4P4+2P2+1P1=24+2+1=27通りの組み合わせパターンが存在する。この探索方法は、依存ツリーの規模が大きくなると計算量や使用するメモリ領域が急激に増大し、長時間を要する可能性がある。
また、最適化によって生成されたコード143には、FMA化された2個の命令(SIMD−FMA命令)とFMA化されていない3個の命令(SIMD命令)とが混在している。コード143に含まれる命令のうちFMA化されている命令の割合(FMA化率)は40%である。これに対し、命令は演算の種類に応じて実行サイクル数(その命令の実行に要するプロセッサのクロック数)が異なる可能性がある。演算の種類のばらつきが大きい、すなわち、命令の実行サイクル数のばらつきが大きいと、空き時間が少なくなるように高密度に命令をスケジューリングすることが容易でなくなる。また、パイプライン処理化などに際して適切なスケジュールを探索するのに時間を要することになる。
そこで、第2の実施の形態では、変形した依存ツリーを用いて最適化処理を行う。
図10は、FMA正規化した依存ツリーの例を示す図である。
コンパイラ120は、前述の依存ツリー31を変形して依存ツリー33を生成し、前述の依存ツリー32を変形して依存ツリー34を生成する。依存ツリー31,32に含まれていた命令は、全て1種類の命令(FMA命令)に変換されている。
依存ツリー33は、積和演算(FMADD)を示す5個のFMA命令を含む。命令5はFMA命令A4=B4×C4+0に変換され、命令7はFMA命令A6=B6×C6+0に変換されている。命令1,9はFMA命令X0=B0×C0+A4に変換され、命令3,11はFMA命令X2=B2×C2+A6に変換されている。命令13はFMA命令Z0=X0×X2+0に変換されている。依存ツリー34は、5個のFMA命令を含む。命令6はFMA命令A5=B5×C5+0に変換され、命令8はFMA命令A7=B7×C7+0に変換されている。命令2,10はFMA命令X1=B1×C1+A5に変換され、命令4,12はFMA命令X3=B3×C3+A7に変換されている。命令14はFMA命令Z1=X1×X3+0に変換されている。
すなわち、乗算の命令1とその乗算結果を参照する加算の命令9の組は、そのまま1つのFMA命令に変換することができる。命令2,10の組、命令3,11の組、命令4,12の組も、そのまま1つのFMA命令に変換することができる。一方、余った乗算の命令5については、ダミーの加算として乗算結果に0を加えることで、演算結果を変えないようにFMA命令に変換できる。命令6〜8,13,14も、ダミーの加算を追加することでFMA命令に変換することができる。なお、余った加算の命令については、ダミーの乗算として一方のオペランドに1をかけることでFMA命令に変換することができる。
図11は、SIMD−FMA化した命令列の他の例を示す図である。
依存ツリー31,32から依存ツリー33,34に変換することは、コード141から図11に示すようなコード144に変換することを実質的に意味する。コード144は、依存ツリー33,34に表したように10個のFMA命令を含む。コンパイラ120は、依存ツリー33と依存ツリー34とを比較して、SIMD化可能な依存ツリー33の命令と依存ツリー34の命令との組み合わせのパターンを探索する。SIMD化可能な命令の組は、演算の種類および深さが同じ命令の組である。ただし、依存ツリー33,34の命令では、演算の種類が積和演算(FMADD)に統一されている。
ここでは、コンパイラ120は、深さ3のFMA命令を組み合わせて、SIMD−FMA命令A4|A5=B4|B5×C4|C5+0|0およびSIMD−FMA命令A6|A7=B6|B7×C6|C7+0|0を生成する。また、コンパイラ120は、深さ2のFMA命令を組み合わせて、SIMD−FMA命令X0|X1=B0|B1×C0|C1+A4|A5およびSIMD−FMA命令X2|X3=B2|B3×C2|C3+A6|A7を生成する。また、コンパイラ120は、深さ1のFMA命令を組み合わせて、SIMD−FMA命令Z0|Z1=X0|X1×X2|X3+0|0を生成する。これにより、5個のSIMD−FMA命令を含むコード145が生成される。
変形した依存ツリー33,34を用いて最適化処理を行う場合、深さ3に2個のFMA命令があり、深さ2に2個のFMA命令があり、深さ1に1個のFMA命令があるため、2P2+2P2+1P1=2+2+1=5通りの組み合わせパターンが存在する。よって、変形前の依存ツリー31,32を用いる場合と比べて計算量や使用するメモリ領域が低減され、コンパイラ120が高速に最適化処理を行うことができる。
また、最適化によって生成されたコード145には、5個のSIMD−FMA命令が含まれ、他の種類の演算を行う命令は含まれない。コード145のFMA化率は100%である。よって、演算の種類に応じて実行サイクル数が異なる場合であっても、命令間の実行サイクル数のばらつきは小さくなり、空き時間が少なくなるように高密度に命令をスケジューリングすることが容易となる。また、命令のスケジューリングが簡潔になり、適切なスケジュールを探索するのに要する時間を短縮できる。
次に、コンパイラ120によるSIMD最適化の手順の一例を説明する。
図12は、SIMD最適化の手順例を示すフローチャートである。
(S1)解析部126は、中間コード記憶部124から1つの翻訳単位の中間コードを読み出し、読み出した中間コードに含まれる命令の間の依存関係を解析する。そして、解析部126は、命令間の依存関係を示す複数の依存ツリーを生成する。
(S2)解析部126は、ステップS1で生成した依存ツリーの少なくとも1つを、命令の組み合わせパターンの探索が容易になるように変形する。ステップS2は、以下のステップS2a,S2b,S2c,S2dを含む。
(S2a)解析部126は、依存ツリーそれぞれに対して、後述するステップS3で行うFMA正規化の前調整を行う。FMA正規化の前調整では、解析部126は、ステップS3においてFMA命令を用いて書き換え可能な部分ツリーを多く検出できるように、演算の意味を変えない範囲で依存ツリーを変形する。(S2b)解析部126は、少なくとも1つの依存ツリーに疑似命令を挿入することで、複数の依存ツリーの高さが同じになるように調整する。(S2c)解析部126は、依存ツリー毎に、演算の種類に応じて同じ深さにある命令をソートする。(S2d)解析部126は、依存ツリー毎に、読み込むデータの変数名に応じて同じ深さにあるロード命令をソートする。
(S3)解析部126は、各依存ツリーに対してFMA正規化を行う。FMA正規化では、解析部126は、FMAの形状になっている2つの命令(乗算の命令とその乗算結果を参照する加算の命令)を依存ツリーから検出し、検出した2つの命令を1つのFMA命令に書き換える。また、解析部126は、2以上のFMA命令の組み合わせとして表現できる部分ツリー(後述する三角の部分ツリー)を依存ツリーから検出し、変換規則を適用して、検出した部分ツリーを2以上のFMA命令を用いて書き換える。
(S4)解析部126は、依存ツリー同士の比較を容易にするため、依存ツリーの中から1またはそれ以上の基点となる命令を選択し、選択した基点がルートノードになるように依存ツリーを分割する(レベル管理)。第2の実施の形態では、解析部126は、RAMにデータを書き込むストア命令を基点の命令として用いる。
(S5)解析部126は、依存ツリー間での命令の比較を効率的に行えるように、各依存ツリーを符号化する。すなわち、解析部126は、依存ツリー毎に、演算の種類を示す符号を当該依存ツリーの構造に従って並べた符号データを生成する。
(S6)解析部126は、依存ツリーの組の候補を全通り算出する。1つの組に属する依存ツリーの数は、SIMDの並列度に一致させる。例えば、並列度が2である場合、解析部126は、所定の条件(例えば、基点のレベルが同じである、互いに依存関係がないなどの条件)を満たす2つの依存ツリーの組を全通り算出する。なお、ステップS5の処理とステップS6の処理は、逆順で行ってもよいし並列に行ってもよい。
(S7)解析部126は、ステップS6で算出した依存ツリーの組の候補について、ステップS5で生成した符号データ同士を比較して、命令の一致度を示すスコアを算出する(スコアリング)。スコアリングでは、複数の依存ツリーの間の対応するノードに、同じ種類の演算を行う命令が存在するか評価される。解析部126は、算出したスコアに基づいて依存ツリーの組を決定し、組み合わせた複数の依存ツリーの対応するノードにある命令同士を組み合わせてSIMD化することを決定する。
以下では、図12に示した処理手順の実装例について説明する。まず、中間コードから命令間の依存関係を解析して依存ツリーを生成する手順について説明する。
図13は、加算と乗算を含む中間コードの例を示す図である。
中間コード146は、中間コード記憶部124に記憶される。中間コード146の1つの翻訳単位に、命令1〜13が含まれている。命令1,2,4,6,7,9はロード命令(LOAD)であり、命令12,13はストア命令(STORE)である。命令3,8は乗算命令(MULT)であり、命令5,10,11は加算命令(ADD)である。
命令3は命令1,2でロードされたデータを参照し、命令5は命令3で算出されたデータと命令4でロードされたデータを参照し、命令8は命令6,7でロードされたデータを参照している。命令10は命令8で算出されたデータと命令9でロードされたデータを参照し、命令11は命令5,10で算出されたデータを参照している。命令12は命令11で算出されたデータを参照している。命令13は命令1〜12でロードまたは算出されたデータの何れも参照していない。なお、図13に記載したR01〜R12は、論理的なレジスタを示す。mem01〜mem08は、RAM上の論理的な記憶領域を示す。
図14は、中間コードに対応する依存ツリーの例を示す図である。
依存ツリー41は、図13に示した命令1〜12から生成される。命令1〜12と依存関係がない命令13は、依存ツリー41に属さない。依存ツリー41では、一方の命令が他方の命令に依存しているとき、一方の命令が親ノードに対応付けられ、他方の命令が子ノードに対応付けられる。依存ツリー41のリーフノードからルートノードに向かって演算が進行することになる。図14に示すように、命令3は命令1,2に依存し、命令5は命令3,4に依存し、命令8は命令6,7に依存し、命令10は命令8,9に依存し、命令11は命令5,10に依存し、命令12は命令11に依存している。
図15は、命令データと依存データの例を示す図である。
依存関係の解析を通じて、命令データ151および依存データ152が生成される。
命令データ151は、命令毎に、命令番号、解析済フラグ、命令名、定義オペランドおよび参照オペランドの項目を含む。命令番号は、各命令を識別するための番号である。解析済フラグは、依存関係の解析などの処理の際に、その命令が解析済か否かを識別するために利用されるフラグである。解析済フラグの初期値はOFFに設定される。命令名は、演算の種類を示す名称(ADD,SUB,MULT,DIV,LOAD,STORE、FMADDなど)である。定義オペランドの項目には、中間コード146で使用されている論理的なレジスタまたはRAMの記憶領域を示す識別子であって、データの格納先を示す識別子が設定される。参照オペランドの項目には、参照するデータが格納されている1または2以上の論理的なレジスタまたはRAMの記憶領域を示す識別子が設定される。
依存データ152は、定義命令の命令番号と参照命令の命令番号の組を1つ以上含む。定義命令は、定義オペランドであるレジスタまたはRAM領域が、他の命令によって参照される命令である。参照命令は、他の命令が定義オペランドとして定義したレジスタまたはRAMの記憶領域を、参照オペランドとして参照している命令である。
図16は、依存解析の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS1において実行される。
(S111)解析部126は、翻訳単位に含まれる命令を、先頭から優先的に1つ選択する。(S112)解析部126は、選択した命令から命令名、定義オペランドおよび参照オペランドを抽出し、命令番号を付与して命令データ151にその命令を登録する。(S113)解析部126は、ステップS111で翻訳単位の末尾まで全ての命令を選択したか判断する。全て選択した場合は処理をステップS114に進め、未選択の命令がある場合は処理をステップS111に進める。
(S114)解析部126は、翻訳単位に含まれる命令を、末尾から優先的に1つ選択する。(S115)解析部126は、選択した命令が依存ツリーに含めるべき命令か判断する。条件を満たす場合は処理をステップS116に進め、条件を満たさない場合は処理をステップS123に進める。(S116)解析部126は、選択した命令の解析済フラグがONであるか(解析済であるか)判断する。ONの場合は処理をステップS123に進め、OFFの場合は処理をステップS117に進める。
(S117)解析部126は、ステップS114で選択した命令の参照オペランドを1つ選択する。(S118)解析部126は、翻訳単位から、選択した参照オペランドに対応する定義オペランドをもつ命令(定義命令)を検索する。(S119)解析部126は、検索した定義命令が、現在の翻訳単位の依存ツリーに属するべきものか(例えば、他の翻訳単位の命令でないか)判断する。条件を満たす場合は処理をステップS120に進め、条件を満たさない場合は処理をステップS121に進める。(S120)解析部126は、ステップS118で検索した定義命令からステップS114で選択した命令(参照命令)への依存関係を、依存データ152に登録する。
(S121)解析部126は、ステップS117で、選択した命令に含まれる全ての参照オペランドを選択したか判断する。全て選択した場合は処理をステップS122に進め、未選択の参照オペランドがある場合は処理をステップS117に進める。(S122)解析部126は、ステップS114で選択した命令の解析済フラグをONに設定する。(S123)解析部126は、ステップS114で翻訳単位の先頭まで全ての命令を選択したか判断する。全て選択した場合は処理を終了し、未選択の命令がある場合は処理をステップS114に進める。
次に、FMA正規化の前調整による依存ツリーの変形について説明する。
図17は、依存ツリーに対するFMA正規化の前調整の例を示す図である。
解析部126は、三角の部分ツリーが多く検出されるように前調整を行う。
ここでは、図17に示す命令1〜7を含む依存ツリー42を考える。命令1〜4はロード命令であり、命令5は加算命令であり、命令6,7は乗算命令である。命令5は命令1,2に依存し、命令6は命令3,5に依存し、命令7は命令4,6に依存する。依存ツリー42は、演算の実質的な意味を変えず依存ツリー43のように変形することができる。依存ツリー43は、命令1〜5,6a,7aを含む。命令6a,7aは乗算命令である。命令7aは命令3,4に依存し、命令6aは命令5,7aに依存する。
依存ツリー42は、命令7を命令6と命令3の間に移動し、命令7を命令3,4に依存させ、命令6を命令5,7に依存させることで、依存ツリー43に変形することができる。依存ツリー42は、命令5の加算結果に命令3でロードされた値をかけ、その乗算結果に対して更に命令4でロードされた値をかけることを示すものである。これに対し、依存ツリー43は、命令3でロードされた値と命令4でロードされた値をかけ、その乗算結果に対して命令5の加算結果をかけることを示すものである。乗算には結合則が成立するため、依存ツリー42と依存ツリー43の最終的な演算結果は一致する。
依存ツリーを変形するにあたり、解析部126は、次の条件を満たす第1・第2・第3の命令を依存ツリーから検出する。第1の命令は、乗算命令または加算命令であり、2つの子命令(第1の命令から見た定義命令)のうちの一方の子命令としてロード命令などの非演算命令に依存し、他方の子命令として第2の命令に依存する。第2の命令は、第1の命令と演算の種類が同じ(乗算または加算)であり、2つの子命令(第2の命令から見た定義命令)のうちの一方の子命令として非演算命令に依存し、他方の子命令として第3の命令に依存する。第3の命令は、乗算命令または加算命令である。
上記の条件を満たす第1・第2・第3の命令が検出されると、解析部126は、第1の命令を、第2の命令と第2の命令の子命令である非演算命令との間に移動する。第1の命令は、第2の命令の子命令である非演算命令に依存させる。これにより、第1・第2・第3の命令を含む三角形状の部分ツリーを形成することができる。なお、変形後の第2の命令は部分ツリーの「頂点」、第1・第3の命令は「依存点」と言うこともできる。
図18は、FMA前調整の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS2aにおいて実行される。
(S131)解析部126は、依存ツリーのルートノードに近い命令から優先的に、乗算命令または加算命令である命令M(第1の命令)を1つ選択する。(S132)解析部126は、第1の命令から見て子ノードに相当する2つの子命令のうち、一方(第2の命令)のみが乗算命令や加算命令などの演算命令であり、他方がロード命令などの非演算命令であるか判断する。一方の子命令のみ演算命令である場合は処理をステップS133に進め、それ以外の場合は処理をステップS136に進める。
(S133)解析部126は、第2の命令の演算が第1の命令と同じ種類であるか判断する。第1・第2の命令の演算の種類が同じ場合は処理をステップS134に進め、演算の種類が異なる場合は処理をステップS136に進める。(S134)解析部126は、第2の命令から見て子ノードに相当する2つの子命令(第1の命令から見たときの孫命令)のうち、一方がロード命令などの非演算命令であり、他方(第3の命令)が乗算命令または加算命令であるか判断する。この条件を満たす場合は処理をステップS135に進め、それ以外の場合は処理をステップS136に進める。
(S135)解析部126は、第2の命令とその子命令である非演算命令との間に、ステップS131で選択した第1の命令を移動する。(S136)解析部126は、ステップS131で依存ツリーに含まれる全ての命令を選択したか判断する。全ての命令を選択した場合は処理を終了し、未選択の命令がある場合は処理をステップS131に進める。
次に、他の依存ツリーの変形について説明する。
図19は、変形前の依存ツリーの例を示す図である。
依存ツリー44,45は、中間コードに含まれる命令間の依存関係を示す。ここでは、コンパイラ120が1度に処理するコード範囲(翻訳単位)に、命令1〜16が含まれているとする。命令1,2,4,5,8,10,11,13,14はロード命令であり、命令3,7,15は乗算命令であり、命令6,9,12,16は加算命令である。命令1はデータA(I)、命令2はデータC(I)、命令4はデータB(I)、命令5はデータD(I)をロードする。命令10はデータD(I+1)、命令11はデータB(I+1)、命令13はデータC(I+1)、命令14はデータA(I+1)をロードする。データA(I)とA(I+1)、データB(I)とB(I+1)、データC(I)とC(I+1)、データD(I)とD(I+1)は、RAM上に隣接して配置される可能性が高い。
命令3は命令1,2に依存し、命令6は命令4,5に依存し、命令7は命令3,6に依存し、命令9は命令7,8に依存する。命令12は命令10,11に依存し、命令15は命令13,14に依存し、命令16は命令12,15に依存する。依存ツリー44は命令1〜9を含み、依存ツリー45は命令10〜16を含む。すなわち、命令1〜9の集合と命令10〜16の集合とは、互いに依存関係がなく並列に実行できる。
解析部126は、依存ツリー44の命令と依存ツリー45の命令を組み合わせてSIMD化することが考えられる。しかし、依存ツリー44,45は形状が異なるため、そのままではSIMD化できる命令組を探索することが容易でない。例えば、深さが同じ命令の間で演算の種類が同じ命令を探すだけでは、深さ2にある命令7,15の組と深さ1にある命令9,16の組しか検出されない。そこで、解析部126は、依存ツリー44,45の形状が互いに近くなるように依存ツリー44,45を変形する。
図20は、依存ツリーの第1の変形例を示す図である。
依存ツリー44の高さ(ルートノードから最も深いリーフノードまでに並んだノードの数)は4である一方、依存ツリー45の高さは3である。そこで、解析部126は、高さの小さい依存ツリー45を、疑似命令を挿入することで依存ツリー46に変形する。
疑似命令は、挿入前のデータと挿入後のデータが同じになる命令である。疑似加算命令(疑似ADD)は入力値に0を加えるものであり、疑似減算命令(疑似SUB)は入力値から0を引くものであり、疑似乗算命令(疑似MULT)は入力値に1をかけるものであり、疑似除算命令(疑似DIV)は入力値を1で割るものである。疑似ロード命令はレジスタのデータが変化しないように同じデータを再度読み込むものであり、疑似ストア命令はRAMのデータが変化しないように同じデータをRAMに上書きするものである。
依存ツリー46は、命令10〜16を含む依存ツリー45に対して、命令17,18を挿入したものである。命令17は、依存ツリー44の命令9に対応するように挿入された疑似加算命令である。命令18は、依存ツリー44の命令8に対応するように挿入された疑似ロード命令である。命令17は命令16,18に依存する。命令17,18が挿入されることで、依存ツリー46の高さは依存ツリー44と同じになっている。解析部126は、依存ツリー44と高さが同じになり、かつ、できる限り同じ深さに同じ種類の演算を行う命令がくるように、依存ツリー45に疑似命令を挿入する。
図21は、依存ツリーの第2の変形例を示す図である。
解析部126は、依存ツリー44,46の対応する位置に、同じ種類の演算を行う命令が存在する確率を高くするため、順序を入れ替え可能な命令を演算の種類に応じてソートする。演算順序の入れ替えは、依存ツリー44,46それぞれに対して行う。図21は、依存ツリー46を、演算順序を入れ替えて依存ツリー47に変形する例を示している。
命令をソートするにあたり、解析部126は、演算の優先順位を予め定めておく。例えば、四則演算については、乗算(MULT)>除算(DIV)>加算(ADD)>減算(SUB)のように優先順位を定める。この場合、命令16と依存関係のある命令12,15が入れ替え可能な命令の組として検出され、演算の優先順位に従って、乗算命令である命令15が加算命令である命令12よりも依存ツリー上で左側に移動する。一方、上記の演算の優先順位を採用した場合、依存ツリー44は変形しなくてよい。
図22は、依存ツリーの第3の変形例を示す図である。
解析部126は、ロード命令の組をSIMD化するとき、複数のロード命令ができる限りRAMの近い記憶領域にアクセスするよう、変数名に応じてロード命令をソートする。変数名の入れ替えは、依存ツリー44,47それぞれに対して行う。図22は、依存ツリー47を、変数名を入れ替えて依存ツリー48に変形する例を示している。
例えば、変数名の優先順位をA>B>C>Dのように定める。この場合、命令12と依存関係のある命令10,11が入れ替え可能なロード命令の組として検出され、変数名に従って、命令11が命令10よりも依存ツリー上で左側に移動する。また、命令15と依存関係のある命令13,14が入れ替え可能なロード命令の組として検出され、変数名に従って、命令14が命令13よりも依存ツリー上で左側に移動する。変数名の情報は、中間コード記憶部124に記憶された中間コードに含まれている。
なお、図21では命令の内容と共に命令番号も移動しているが、後述するように、解析部126の内部処理では命令の内容のみを入れ替えて命令番号は入れ替えない。このため、例えば、命令番号12の命令が、ADD命令からMULT命令に変換されることになる。同様に、図22ではロードするデータの変数名と共に命令番号も移動しているが、解析部126の内部処理では変数名のみを入れ替えて命令番号は入れ替えない。このため、例えば、命令番号13の命令でロードされるデータの変数名が、C(I+1)からA(I+1)に変換されることになる。また、図21で説明した演算順序の入れ替えと図22で説明した変数名の入れ替えは、何れを先に実行してもよい。
図23は、高さ調整の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS2bにおいて実行される。この処理は、複数の依存ツリーのうち最も高いもの以外の各依存ツリーに対して行われる。
(S141)解析部126は、依存ツリーの中で疑似命令を挿入できる位置を列挙する。例えば、依存ツリー45の場合、7つの位置、すなわち、命令10〜16に対応する各ノードから1つ上位の(深さが小さくなる方向の)位置が選択される。(S142)解析部126は、ステップS141で列挙された位置のべき集合(位置の組み合わせのパターン全て)を算出する。例えば、7つの位置が列挙された場合、Φ(空集合),{位置1},{位置1,2},{位置1,2,3},・・・,{位置6},{位置6,7},{位置7}のように、位置の組み合わせを全パターン算出する。
(S143)解析部126は、ステップS142で算出された位置の組み合わせのうち1つを選択する。(S144)解析部126は、選択した組み合わせの各位置に疑似命令を挿入することで、依存ツリーの高さが、対比する他の依存ツリーと同じになるか判断する。高さが同じになる場合は処理をステップS145に進める。高さが同じにならない場合は処理をステップS147に進める。
(S145)解析部126は、ステップS143で選択した組み合わせの各位置に疑似命令を挿入する。このとき、解析部126は、疑似命令を挿入する依存ツリーと、対比する他の依存ツリーとの間で、同じ深さにできる限り同じ種類の演算を指定した命令がくるように、疑似命令の演算の種類を選択する。(S146)解析部126は、疑似命令を挿入した依存ツリーと他の依存ツリーとの間で、同じ深さにある命令を比較してSIMD化可能な命令組を検出し、疑似命令を挿入した依存ツリーのSIMD化率(または、SIMD化される命令の数(SIMD化数))を算出する。
(S147)解析部126は、ステップS143で全ての組み合わせを選択したか判断する。全て選択した場合は処理をステップS148に進める。未選択の組み合わせがある場合は、疑似命令の挿入を取り消して依存ツリーを元に戻し、処理をステップS143に進める。(S148)解析部126は、ステップS146で算出されたSIMD化率(またはSIMD化数)が最大になる位置の組み合わせを判定し、判定された組み合わせに従って依存ツリーに疑似命令を挿入する。
図24は、ノード入替の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS2c,S2dにおいて実行される。この処理は、図23の処理の後に各依存ツリーに対して行われる。
(S151)解析部126は、依存ツリーのうちルートノードに近い命令から優先的に、命令を1つ選択する。(S152)解析部126は、選択した命令から見て子ノードに相当する命令が2つ以上存在するか判断する。存在する場合は処理をステップS153に進め、存在しない場合は処理をステップS158に進める。
(S153)解析部126は、依存ツリーの左側から順に、子ノードに相当する命令の命令番号を、RAM102に確保した記憶領域であるスタックAに格納する。(S154)解析部126は、命令番号に対応する順序で、子ノードに相当する命令のデータを、RAM102に確保した他の記憶領域であるスタックBに格納する。例えば、ステップS151で依存ツリー46の命令16を選択した場合、命令番号12,15がスタックAに格納され、命令12,15のデータがスタックBに格納される。
(S155)解析部126は、各命令の命令名に基づいて、スタックBの中で命令のデータをソートする。例えば、命令12,15の順にデータがスタックBに格納されている場合、命令15,12の順にデータが入れ替えられる。(S156)解析部126は、スタックBに2以上のロード命令のデータが格納されているとき、各ロード命令に対応する変数名を、中間コード146を参照して確認する。そして、解析部126は、変数名に基づいて、スタックBの中でロード命令のデータをソートする。
(S157)解析部126は、命令データ151におけるスタックAの命令番号が示す位置に、スタックBに格納された命令のデータを上書きする。スタックAの命令番号はソート前の順序で並んでいるため、命令番号と命令の内容との対応関係が更新されることになる。例えば、命令15のデータが命令番号12の位置に上書きされ、命令12のデータが命令番号15の位置に上書きされる。(S158)解析部126は、ステップS151で全ての命令を選択したか判断する。全て選択した場合は処理を終了し、未選択の命令がある場合は処理をステップS151に進める。
次に、依存ツリーのFMA正規化について説明する。
図25は、変換規則テーブルの例を示す図である。
変換規則テーブル153は、RAM102またはHDD103に格納されている。解析部126は、依存ツリーに含まれる三角の部分ツリーをFMA命令を用いて書き換える(FMA正規化を行う)とき、変換規則テーブル153を参照する。変換規則テーブル153は、ルール番号、変換前の式および変換後の式の項目を含む。ルール番号の項目には、各変換規則に付与された番号が登録される。変換前の式の項目には、部分ツリーに含まれる3つの命令の演算の種類を示す式が登録される。変換後の式の項目には、変換前の部分ツリーを2以上のFMA命令の組み合わせとして表現した式が登録される。変換前の式は変換規則の適用条件に相当し、変換後の式は適用される変換規則に相当する。
変換前の式および変換後の式において、Aは左側依存点が参照する1番目のデータを示し、Bは左側依存点が参照する2番目のデータを示し、Cは右側依存点が参照する1番目のデータを示し、Dは右側依存点が参照する2番目のデータを示す。
変換規則1は、頂点と2つの依存点の何れも加算命令である部分ツリーに対して適用される。この部分ツリーは、((A×1+B)×1+C)×1+D=FMA(FMA(FMA(A,1,B),1,C),1,D)のように3つのFMA命令を用いて書き換えられる。変換規則2は、頂点と左側依存点が加算命令であり右側依存点が乗算命令である部分ツリーに対して適用される。この部分ツリーは、(C×D+A)×1+B=FMA(FMA(C,D,A),1,B)のように2つのFMA命令を用いて書き換えられる。ただし、前述のステップS2cの演算入れ替えによって、変換規則2が適用されるべき部分ツリーは変換規則5が適用される部分ツリーへと変形されている。
変換規則3は、頂点が乗算命令であり2つの依存点が加算命令である部分ツリーに対して適用される。この部分ツリーは、(A×1+B)×(C×1+D)+0=FMA(FMA(A,1,B),FMA(C,1,D),0)のように3つのFMA命令を用いて書き換えられる。変換規則4は、頂点と右側依存点が乗算命令であり左側依存点が加算命令である部分ツリーに対して適用される。この部分ツリーは、((A×1+B)×C+0)×D+0=FMA(FMA(FMA(A,1,B),C,0),D,0)のように3つのFMA命令を用いて書き換えられる。ただし、ステップS2cによって、変換規則4が適用されるべき部分ツリーは変換規則7が適用される部分ツリーへと変形されている。
変換規則5は、頂点と右側依存点が加算命令であり左側依存点が乗算命令である部分ツリーに対して適用される。この部分ツリーは、(A×B+C)×1+D=FMA(FMA(A,B,C),1,D)のように2つのFMA命令を用いて書き換えられる。変換規則6は、頂点が加算命令であり2つの依存点が乗算命令である部分ツリーに対して適用される。この部分ツリーは、A×B+(C×D+0)=FMA(A,B,FMA(C,D,0))のように2つのFMA命令を用いて書き換えられる。
変換規則7は、頂点と左側依存点が乗算命令であり右側依存点が加算命令である部分ツリーに対して適用される。この部分ツリーは、((C×1+D)×A+0)×B+0=FMA(FMA(FMA(C,1,D),A,0),B,0)のように3つのFMA命令を用いて書き換えられる。変換規則8は、頂点および2つの依存点の何れも乗算命令である部分ツリーに対して適用される。この部分ツリーは、((A×B+0)×C+0)×D+0=FMA(FMA(FMA(A,B,0),C,0),D,0)のように3つのFMA命令を用いて書き換えられる。
なお、中間コードに含まれる減算命令(SUB)は、参照オペランドの符号を反転することで加算命令(ADD)に置き換えることができる。また、除算命令(DIV)は、関数に置き換えることができ、また、除算命令以外の複数の命令を用いて書き換えることもできる。よって、第2の実施の形態のFMA正規化においては、依存ツリーに減算命令や除算命令が含まれていないものとして取り扱っている。
図26は、FMA正規化パターンの例を示す図である。
変換規則を定義するにあたり、同じ部分ツリーに対して複数の変換パターンが考えられる場合もある。例えば、頂点と左側依存点が乗算命令であり右側依存点が加算命令である部分ツリー(変換規則7)に対しては、図26のようにパターン1,2が考えられる。
パターン1によれば、依存ツリーが、(A×B+0)×(C×1+D)+0=FMA(FMA(A,B,0),FMA(C,1,D),0)を含む依存ツリー51に書き換えられる。パターン2は、図25の変換規則7に示したものと同じである。パターン2によれば、依存ツリーが、((C×1+D)×A+0)×B+0=FMA(FMA(FMA(C,1,D),A,0),B,0)を含む依存ツリー52に書き換えられる。
ただし、依存ツリー51では深さ2に2つのFMA命令が存在するのに対し、依存ツリー52では各深さに1つずつFMA命令が存在する。同じ深さに存在する命令の数が多くなるほど、SIMD化可能な命令の組み合わせパターンが多くなってしまう。このため、依存ツリー51への変形よりも依存ツリー52への変形の方が好ましい。
図27は、FMA正規化の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS3において実行される。
(S161)解析部126は、依存ツリーから積和形式の部分ツリー、すなわち、乗算命令とその乗算結果を参照する加算命令との組を抽出する。そして、解析部126は、抽出した部分ツリーを1つのFMA命令に書き換える。(S162)解析部126は、依存ツリーから三角の部分ツリー、すなわち、変換規則テーブル153に登録された変換規則1〜8の何れかの適用条件に該当する部分ツリーを抽出する。この部分ツリーは、乗算命令または加算命令である1つの頂点Pと、それぞれが乗算命令または加算命令である2つの依存点C1,C2とを含むものである。(S163)解析部126は、ステップS162で抽出した三角の部分ツリーのうちの1つを選択する。
(S164)解析部126は、3つの命令のうち依存点C1,C2の一方のみが乗算命令(MULT)であるか判断する。すなわち、解析部126は、三角の部分ツリーが変換規則5を適用すべきものであるか判断する。条件を満たす場合は処理をステップS165に進め、条件を満たさない場合は処理をステップS166に進める。(S165)解析部126は、三角の部分ツリーを、2つのFMA命令を用いて(A×B+C)×1+D=FMA(FMA(A,B,C),1,D)に変換する。
(S166)解析部126は、3つの命令のうち依存点C1,C2の一方のみが加算命令(ADD)であるか判断する。すなわち、解析部126は、三角の部分ツリーが変換規則7を適用すべきものであるか判断する。条件を満たす場合は処理をステップS167に進め、条件を満たさない場合は処理をステップS168に進める。(S167)解析部126は、三角の部分ツリーを、3つのFMA命令を用いて((C×1+D)×A+0)×B+0=FMA(FMA(FMA(C,1,D),A,0),B,0)に変換する。
(S168)解析部126は、3つの命令の全てが加算命令(ADD)であるか判断する。すなわち、解析部126は、三角の部分ツリーが変換規則1を適用すべきものであるか判断する。条件を満たす場合は処理をステップS169に進め、条件を満たさない場合は処理をステップS170に進める。(S169)解析部126は、三角の部分ツリーを、3つのFMA命令を用いて((A×1+B)×1+C)×1+D=FMA(FMA(FMA(A,1,B),1,C),1,D)に変換する。
(S170)解析部126は、3つの命令の全てが積算命令(MULT)であるか判断する。すなわち、解析部126は、三角の部分ツリーが変換規則8を適用すべきものであるか判断する。条件を満たす場合は処理をステップS171に進め、条件を満たさない場合は処理をステップS172に進める。(S171)解析部126は、三角の部分ツリーを、3つのFMA命令を用いて((A×B+0)×C+0)×D+0)=FMA(FMA(FMA(A,B,0),C,0),D,0)に変換する。
(S172)解析部126は、3つの命令のうち頂点Pのみ加算命令(ADD)であるか判断する。すなわち、解析部126は、三角の部分ツリーが変換規則6を適用すべきものであるか判断する。条件を満たす場合は処理をステップS173に進め、条件を満たさない場合は処理をステップS174に進める。(S173)解析部126は、三角の部分ツリーを、2つのFMA命令を用いてA×B+(C×D+0)=FMA(A,B,FMA(C,D,0))に変換する。
(S174)解析部126は、3つの命令のうち頂点Pのみ乗算命令(MULT)であるか判断する。すなわち、解析部126は、三角の部分ツリーが変換規則3を適用すべきものであるか判断する。条件を満たす場合は処理をステップS175に進め、条件を満たさない場合は処理をステップS176に進める。(S175)解析部126は、三角の部分ツリーを、3つのFMA命令を用いて(A×1+B)×(C×1+D)+0=FMA(FMA(A,1,B),FMA(C,1,D),0)に変換する。
(S176)解析部126は、ステップS163において全ての三角の部分ツリーを選択したか判断する。全ての三角の部分ツリーを選択した場合は処理を終了し、未選択の三角の部分ツリーがある場合は処理をステップS163に進める。
なお、ステップS165,S167,S169,S171,S173,S175の変換は、次の4つの関数を用いて纏めることができる。f1(x1,x2,x3,x4,x5)=(x1×x2+x3)×x4+x5。f2(x1,x2,x3,x4,x5,x6,x7)=((x1×x2+x3)×x4+x5)×x6+x7。f3(x1,x2,x3,x4,x5)=x1×x2+(x3×x4+x5)。f4(x1,x2,x3,x4,x5,x6,x7)=(x1×x2+x3)×(x4×x5+x6)+x7。
ステップS165はf1(A,B,C,1,D)として実装できる。ステップS167はf2(C,1,D,A,0,B,0)、ステップS169はf2(A,1,B,1,C,1,D)、ステップS171はf2(A,B,0,C,0,D,0)として実装できる。ステップS173はf3(A,B,C,D,0)として実装できる。ステップS174はf4(A,1,B,C,1,D,0)として実装できる。
次に、基点命令の選択および依存ツリーの分割(レベル管理)について説明する。
図28は、依存ツリーの分割例を示す図である。
ここでは、図28に示す命令1〜14を含む依存ツリー53が生成された場合を考える。命令3,9は乗算命令であり、命令5,11,13は加算命令である。命令1,2,4,7,8,10はロード命令であり、命令6,12,14はストア命令である。命令3は命令1,2に依存し、命令5は命令3,4に依存し、命令6は命令5に依存している。命令9は命令7,8に依存し、命令11は命令9,10に依存し、命令12は命令11に依存している。命令13は命令6,12に依存し、命令14は命令13に依存している。
第2の実施の形態では、依存ツリー間の比較を容易にするため、ストア命令である命令6,12,14を基点にして、依存ツリー53を3つの小さな依存ツリーに分割する。すなわち、解析部126は、依存ツリー53を、命令6が基点命令(ルートの命令)であり命令1〜6を含む依存ツリーと、命令12が基点命令であり命令7〜12を含む依存ツリーと、命令14が基点命令であり命令13,14を含む依存ツリーとに分割する。
このとき、解析部126は、各基点命令についてレベルを算出しておく。基点命令のレベルは、分割前の依存ツリー53において、基点命令のノードとそのノードの配下にある各リーフノードとの間のパスのうち、最長のパス上に並ぶノードの数である。例えば、命令6のレベルは、命令6と命令1(または命令2)とを結ぶパス上に4個のノードが並ぶことから、4である。命令12のレベルは、命令12と命令7(または命令8)とを結ぶパス上に4個のノードが並ぶことから、4である。命令14のレベルは、命令14と命令1(または命令2,7,8)とを結ぶパス上に6個のノードが並ぶことから、6である。
図29は、基点データの例を示す図である。
解析部126は、基点命令を選択して依存ツリー53を分割すると、基点データ154を生成する。基点データ154は、分割後の依存ツリー毎に、ツリーID(Identifier)、基点番号、レベルおよび命令番号の項目を含む。ツリーIDは、分割後の各依存ツリーを識別するための識別子である。基点番号は、基点命令の命令番号である。レベルは、上記のように算出された基点命令のレベルである。命令番号の項目には、分割後の依存ツリーに含まれる命令の命令番号が列挙される。
図30は、基点選択の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS4において実行される。
(S181)解析部126は、ルートノードに近い命令から優先的に、依存ツリーに含まれる命令を1つ選択する。(S182)解析部126は、選択した命令がストア命令(STORE)であるか判断する。選択した命令がストア命令である場合、その命令を基点命令に採用し、処理をステップS183に進める。選択した命令がストア命令でない場合は、その命令を基点命令に採用せず、処理をステップS186に進める。
(S183)解析部126は、カウンタC=0,レベルL=0に初期化する。(S184)解析部126は、後述するサブルーチンを用いて、基点命令のレベルを算出する。(S185)解析部126は、採用した基点命令をルートノードとする依存ツリーの情報を基点データ154に登録する。(S186)解析部126は、ステップS181で全ての命令を選択したか判断する。全ての命令を選択した場合は処理を終了し、未選択の命令がある場合は処理をステップS181に進める。
図31は、レベル算出のサブルーチンの手順例を示すフローチャートである。
このサブルーチンは、パラメータとしてカウンタCとレベルLを受け取る。このサブルーチンは、上記のステップS184において呼び出される。
(S191)解析部126は、カウンタCをインクリメント(値を1だけ加算)する。(S192)解析部126は、現在のレベルLの値がカウンタCの値よりも小さいか判断する。レベルLの値がカウンタCの値より小さい場合は処理をステップS193に進め、それ以外の場合は処理をステップS194に進める。(S193)解析部126は、レベルLにカウンタCの値を代入する。
(S194)解析部126は、現在着目している命令の子ノードに相当する命令が、次のステップS195で全て選択されたか判断する。全て選択された場合は処理をステップS197に進め、未選択の命令がある場合は処理をステップS195に進める。(S195)解析部126は、子ノードに相当する命令を1つ選択する。(S196)解析部126は、ステップS195で選択した子ノードに相当する命令について、この時点のレベルLとカウンタCをパラメータとして渡して、図31のサブルーチンを再帰的に呼び出す。その後、処理をステップS194に進める。(S197)解析部126は、カウンタCをデクリメント(値を1だけ減算)する。
次に、依存ツリーの符号化について説明する。
図32は、符号テーブルの例を示す図である。
符号テーブル155は、演算の種類と符号との対応関係を示す。符号テーブル155は、RAM102またはHDD103に格納されている。解析部126は、依存ツリーを符号化するとき(ステップS5)、符号テーブル155を参照する。
図32の例によれば、乗算命令(MULT)は「1」に変換され、除算命令(DIV)は「2」に変換され、加算命令(ADD)は「3」に変換され、減算命令(SUB)は「4」に変換される。ロード(LOAD)命令は「5」に変換され、ストア(STORE)命令は「6」に変換される。
また、積和演算の命令(FMADD)は「7」に変換され、負の積和演算の命令(FNMADD)は「8」に変換され、積差演算の命令(FMSUB)は「9」に変換され、負の積差演算の命令(FNMSUB)は「10」に変換される。FNMADDは、データA,B,Cに対して−(A×B+C)を算出する演算である。FMSUBは、データA,B,Cに対してA×B−Cを算出する演算である。FNMSUBは、データA,B,Cに対して−(A×B−C)を算出する演算である。FNMADD,FMSUB,FNMSUBの命令は、FMA命令に類する命令群に属すると言うこともできる。
図33は、符号化の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS5において実行される。
(S211)解析部126は、基点データ154を参照して、ステップS4で分割された依存ツリーを1つ選択する。(S212)解析部126は、選択した依存ツリーに含まれる命令の数に相当する大きさの配列を、符号データとして生成する。
(S213)解析部126は、ステップS211で選択した依存ツリーから、木構造に応じた順序で、命令を1つ選択する。例えば、解析部126は、帰り掛け深さ優先探索により、依存ツリーを探索して命令を選択する。図28に示した命令6を基点とする依存ツリーの場合、命令1,2,3,4,5,6の順に選択していく。(S214)解析部126は、符号テーブル155から、選択した命令で行われる演算の種類に対応する符号を検索し、検索した符号を配列に格納する。ステップS213でi個目の命令を選択すると、その命令に対応する符号は配列のi番目に格納される。例えば、図28に示した命令6を基点とする依存ツリーの場合、この依存ツリーに対応する符号データとして、5,5,1,5,3,6という符号列の符号データが生成される。
(S215)解析部126は、ステップS213で全ての命令を選択したか判断する。全て選択した場合は処理をステップS216に進め、未選択の命令がある場合は処理をステップS213に進める。(S216)解析部126は、ステップS211で全ての依存ツリーを選択したか判断する。全て選択した場合は処理を終了し、未選択の依存ツリーがある場合は処理をステップS211に進める。
次に、依存ツリーの組の候補の算出および依存ツリーの組の決定について説明する。
図34は、エッジデータとパックデータの例を示す図である。
解析部126は、依存ツリーの組の候補を算出してエッジデータ156を生成する。また、解析部126は、依存ツリーの組を決定してパックデータ157を生成する。
エッジデータ156は、依存ツリーの組毎に、エッジ番号および2以上の基点番号の項目を含む。エッジ番号は、エッジ(依存ツリーの組)を識別するための番号である。基点番号[S](S=1,2,・・・)の項目には、依存ツリーの基点命令の命令番号が設定される。基点番号の個数は、SIMDの並列度に一致する。SIMD化の際は、基点番号[S]に対応する依存ツリーの命令に、S番目のスロットが割り当てられることになる。すなわち、基点番号[1]に対応する依存ツリーの命令にスロット1が割り当てられ、基点番号[2]に対応する依存ツリーの命令にスロット2が割り当てられる。
パックデータ157は、エッジデータ156に登録された依存ツリーの組のうち、SIMD命令を生成するために採用する1またはそれ以上の依存ツリーの組の集合(パック)を示す。パックデータ157は、1またはそれ以上のエッジ番号の項目を含む。エッジデータ156とパックデータ157とは、エッジ番号によって関連付けられる。
図35は、候補算出の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS6において実行される。
(S221)解析部126は、1つのエッジ分のデータを格納するための空のフレームE0を生成する。フレームE0に含まれる基点番号の項目の数は、SIMDの並列度に一致させる。(S222)解析部126は、変数として基点K,スロットSを定義し、基点K=1,スロットS=1に初期化する。
(S223)解析部126は、後述するサブルーチンを用いて、フレームE0およびフレームE0からコピーされたフレームに、基点番号を設定していく。このとき、解析部126は、フレームE0,基点K,スロットSを、パラメータとしてサブルーチンに渡す。(S224)解析部126は、基点Kをインクリメント(値を1だけ加算)する。(S225)解析部126は、基点Kの値が、基点命令の総数(生成された依存ツリーの総数)以下であるか判断する。条件を満たす場合は処理をステップS223に進め、条件を満たさない場合は処理を終了する。
図36は、エッジデータ設定のサブルーチンの手順例を示すフローチャートである。
このサブルーチンは、パラメータとしてフレームE,基点K,スロットSを受け取る。このサブルーチンは、上記のステップS223において呼び出される。
(S231)解析部126は、スロットSの値がSIMDの並列度以下であるか、すなわち、フレームEの基点番号の項目にまだ空の項目が存在するか判断する。空の基点番号の項目がある場合は処理をステップS232に進め、基点番号の項目が全て埋まった場合は処理をステップS238に進める。(S232)解析部126は、フレームEの基点番号[S]の項目に、K番目の基点命令の命令番号を設定する。(S233)解析部126は、スロットSの値をインクリメント(値を1だけ加算)する。また、解析部126は、変数として基点Cを定義し、C=1に初期化する。
(S234)解析部126は、フレームEのデータをコピーしてフレームEcを生成する。フレームEからフレームEcへは、設定済の基点番号が引き継がれる。(S235)解析部126は、現在のフレームEc,基点C,スロットSをパラメータとして渡して、図36のサブルーチンを再帰的に呼び出す。(S236)解析部126は、基点Cをインクリメントする。(S237)解析部126は、基点Cの値が、基点命令の総数以下であるか判断する。条件を満たす場合は処理をステップS234に進め、条件を満たさない場合はサブルーチンを終了する。
(S238)解析部126は、フレームEに、重複する命令番号が基点番号として含まれているか判断する。同じ命令番号が含まれる場合は処理をステップS243に進め、それ以外の場合は処理をステップS239に進める。(S239)解析部126は、フレームEに含まれる基点番号が示す基点命令の「レベル」が全て同じであるか判断する。レベルが同じ場合は処理をステップS240に進め、レベルが異なる場合は処理をステップS243に進める。(S240)解析部126は、フレームEが示す複数の依存ツリーの間に、依存関係があるか判断する。依存関係がある場合は処理をステップS243に進め、依存関係がない場合は処理をステップS241に進める。
(S241)解析部126は、フレームEが示す複数の依存ツリーに属する命令を組み合わせることが、プロセッサのアーキテクチャに反するか判断する。アーキテクチャ違反の例としては、メモリ割り当ての制約を満たさない、データの型(整数型や浮動小数点型など)がSIMD命令で扱うことができない型である、などが挙げられる。アーキテクチャに反する場合は処理をステップS243に進め、それ以外の場合は処理をステップS242に進める。(S242)解析部126は、フレームEのデータをエッジデータ156に登録し、サブルーチンを終了する。(S243)解析部126は、フレームEのデータを破棄し、サブルーチンを終了する。
図37は、エッジデータ生成の流れの例を示す図である。
図36のサブルーチンを再帰的に実行していくことで、基点番号[1],基点番号[2],…の順に、基点命令の命令番号がフレームEに1つずつ設定されていく。そして、全ての基点番号の項目が埋まると、フレームEが示す複数の依存ツリーを組み合わせ可能か判定され、組み合わせ不可な複数の依存ツリーを示すデータは破棄される。例えば、基点番号[1]=6,基点番号[2]=6というデータは破棄される。また、複数の基点命令のレベルが全て同じか判定され、レベルが異なる基点命令の組を示すデータは破棄される。例えば、基点番号=6の基点命令のレベルと基点番号=14の基点命令のレベルとが異なるとき、基点番号[1]=6,基点番号[2]=14というデータは破棄される。
図38は、パックデータの候補の例を示す図である。
解析部126は、複数のエッジのべき集合をパックの集合として算出し、各パックをSIMD化できる命令の数の観点から評価することで、パックを1つ選択する。例えば、互いに独立なエッジ1,2が存在するとき、エッジ1のみを採用したパック1と、エッジ2のみを採用したパック2と、エッジ1,2の両方を採用したパック3とが評価される。
図39は、符号データからスコアを算出する例を示す図である。
パックを評価するために、解析部126は、各パックのスコアを算出する。スコアの高いパックほど、SIMD化できる命令が多いパックであることを示している。解析部126は、エッジ毎に、複数の依存ツリーの間で符号データを比較して、対応する位置にある命令の組であって演算の種類が同じ命令の組の数を、エッジのスコアとして算出する。そして、解析部126は、エッジ毎のスコアを合算してパックのスコアとする。
図40は、SIMD化判定の手順例を示すフローチャートである。
このフローチャートが示す処理は、前述のステップS7において実行される。
(S251)解析部126は、変数としてエッジeとパックPを定義し、エッジe=0,パックP=Φ(空集合)に初期化する。(S252)解析部126は、変数として最大スコアZを定義し、最大スコアZ=−1に初期化する。(S253)解析部126は、後述するサブルーチンを用いて、スコアが最大となるパックを探索する。
(S254)解析部126は、最大スコアZの値が初期値=−1のままであるか、すなわち、パックを1つも発見できなかったか判断する。最大スコアZ=−1の場合は処理をステップS256に進め、それ以外の場合は処理をステップS255に進める。(S255)解析部126は、パックデータ157からSIMD化する命令組を決定する。組み合わせる命令は、同じエッジに含まれる複数の依存ツリーの間の対応する位置にある命令同士である。(S256)解析部126は、中間コード146における現在の翻訳単位に含まれる命令をSIMD化することを中止する。
図41は、パックデータ設定のサブルーチンの手順例を示すフローチャートである。
このサブルーチンは、パラメータとしてエッジe,パックPを受け取る。このサブルーチンは、上記のステップS253において呼び出される。
(S261)解析部126は、後述する方法によって、符号データを用いてパックPのスコアを算出する。(S262)解析部126は、エッジeをインクリメント(値を1だけ加算)する。(S263)解析部126は、エッジeの値が、最大のエッジ番号以下であるか判断する。条件を満たす場合は処理をステップS264に進め、条件を満たさない場合はサブルーチンを終了する。
(S264)解析部126は、e番目のエッジ(エッジ番号eのエッジ)を含むパックを評価するか判断する。次の3つの条件の少なくとも1つに該当するとき、e番目のエッジを含むパックを評価しなくてよいと判断する。(1)e番目のエッジの依存ツリーが、パックPに既に含まれている。(2)e番目のエッジの依存ツリーが、パックPに既に含まれている何れかの依存ツリーと依存関係にある。(3)現時点のパックPのスコアが、計算済の他のパックのスコアの最大値よりも所定差以上下回っており、パックPにe番目のエッジを追加しても最良のパックになる見込みがない。e番目のエッジを含むパックを評価する場合、処理をステップS265に進め、そのようなパックを評価しなくてよい場合、処理をステップS268に進める。
(S265)解析部126は、e番目のエッジをパックPに追加する。(S266)解析部126は、e番目のエッジを含むパックPとエッジeをパラメータとして渡し、図41に示すサブルーチンを再帰的に呼び出す。(S267)解析部126は、ステップS265で追加したe番目のエッジをパックPから削除する。(S268)解析部126は、e番目のエッジを含まないパックPとエッジeをパラメータとして渡し、図41に示すサブルーチンを再帰的に呼び出す。
図42は、スコア算出の手順例を示すフローチャートである。
このフローチャートが示す処理は、上記のステップS261において実行される。
(S271)解析部126は、パックに含まれるエッジを1つ選択する。(S272)解析部126は、配列に含まれる符号を特定するためのインデックスpの値を1つ選択する。インデックスpの値は、1から、エッジに属する複数の依存ツリーに対応する複数の配列の中で最も長い配列の配列長まで変化する。(S273)解析部126は、変数としてスロットSを定義し、スロットS=1に初期化する。
(S274)解析部126は、ステップS271で選択したエッジの基点番号[S]に対応する依存ツリーを選択し、その依存ツリーに対応する符号データである配列を取得する。そして、解析部126は、RAM102に確保した記憶領域であるスタックXに、取得した配列に含まれるp番目の符号を格納する。なお、取得した配列の配列長がpより小さいときは、命令が無いことを示す所定の符号(例えば「0」)をスタックXに格納する。(S275)解析部126は、スロットSをインクリメント(値を1だけ加算)する。(S276)解析部126は、スロットSの値がSIMDの並列度以下であるか判断する。スロットSの値が並列度以下の場合は処理をステップS274に進め、並列度より大きい場合は処理をステップS277に進める。
(S277)解析部126は、スタックXに格納された符号が全て同じであるか、すなわち、対応する位置にある命令間で演算の種類が全て同じか判断する。全て同じ場合は処理をステップS278に進め、同じでない場合は処理をステップS279に進める。(S278)解析部126は、パックのスコアをインクリメントする。
(S279)解析部126は、ステップS272で全てのインデックスpの値を選択したか判断する。全て選択した場合は処理をステップS280に進め、未選択のインデックスpの値がある場合は処理をステップS272に進める。(S280)解析部126は、ステップS271で全てのエッジを選択したか判断する。全て選択した場合は処理をステップS281に進め、未選択のエッジがある場合は処理をステップS271に進める。(S281)解析部126は、ステップS278の処理を通じて算出されたパックのスコアが、現在の最大スコアZより大きいか判断し、現在の最大スコアZより大きい場合は、最大スコアZを算出されたスコアに置き換える。
図43は、パックデータ生成の流れの例を示す図である。
図41のサブルーチンが再帰的に呼び出されることで、スコア評価の処理が、e番目のエッジをパックPに含めるときの処理と含めないときの処理とに分岐する。まず、1番目のエッジをパックPに含めるか否かによって、処理が2つに分岐する。次に、2番目のエッジをパックPに含めるか否かによって、処理が更に2つずつに分岐し、合計で処理が4つに分岐することになる。以下、エッジの数に応じて処理の分岐が発生する。
第2の実施の形態の端末装置100によれば、依存ツリーからFMA命令を用いて書き換え可能な部分ツリーが検出され、FMA命令を含む依存ツリーに変換される。そして、FMA命令を含む依存ツリーに基づいて、中間コードのFMA化やSIMD化などの最適化処理が行われる。これにより、依存ツリーの同じ深さに配置された命令の数が減少し、SIMD化において探索される命令の組み合わせパターンが減少する。また、依存ツリーに含まれる命令の多くがFMA命令に変換されるため、命令の種類に応じて実行サイクル数が異なる場合であっても命令スケジューリングが容易になる。よって、変形した依存ツリーを探索することで、最適化処理の計算量を抑制でき処理時間を短縮できる。
また、FMA正規化の前に変換規則に合致するような部分ツリーが多く現れるように、依存ツリーを整形することで、依存ツリーに含まれる多くの命令をFMA命令に書き換えることができる。また、FMA正規化にあたって、同じ深さにあるFMA命令が少なくなるように変換規則が作成される。これにより、SIMD化の負荷が軽減される。
また、中間コードに含まれる多くの命令をFMA命令やSIMD−FMA命令に変換することで、オブジェクトコードの命令数を削減することができる。また、多くの命令をFMA命令やSIMD−FMA命令に変換することで、それら少数の種類の命令を空き時間が少なくなるように高密度にスケジューリングできる。よって、コンパイラ120が生成するオブジェクトコードの実行効率を向上させることができる。
なお、前述のように、第1の実施の形態の情報処理は、コンパイル装置10にプログラムを実行させることで実現でき、第2の実施の形態の情報処理は、端末装置100にプログラムを実行させることで実現できる。プログラムは、コンピュータ読み取り可能な記録媒体(例えば、記録媒体23)に記録しておくことができる。記録媒体としては、例えば、磁気ディスク、光ディスク、光磁気ディスク、半導体メモリなどを使用できる。磁気ディスクには、FDおよびHDDが含まれる。光ディスクには、CD、CD−R(Recordable)/RW(Rewritable)、DVDおよびDVD−R/RWが含まれる。
プログラムを流通させる場合、例えば、当該プログラムを記録した可搬記録媒体が提供される。コンピュータは、例えば、可搬記録媒体に記録されたプログラムを記憶装置(例えば、HDD103)にコピーし、当該記憶装置からプログラムを読み込んで実行する。ただし、可搬記録媒体から読み込んだプログラムを直接実行してもよい。