特許第6974722号(P6974722)IP Force 特許公報掲載プロジェクト 2022.1.31 β版

知財求人 - 知財ポータルサイト「IP Force」

▶ 富士通株式会社の特許一覧

特許6974722コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置
<>
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000002
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000003
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000004
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000005
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000006
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000007
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000008
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000009
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000010
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000011
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000012
  • 特許6974722-コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置 図000013
< >
(19)【発行国】日本国特許庁(JP)
(12)【公報種別】特許公報(B2)
(11)【特許番号】6974722
(24)【登録日】2021年11月9日
(45)【発行日】2021年12月1日
(54)【発明の名称】コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置
(51)【国際特許分類】
   G06F 8/41 20180101AFI20211118BHJP
【FI】
   G06F8/41 130
【請求項の数】6
【全頁数】16
(21)【出願番号】特願2018-9576(P2018-9576)
(22)【出願日】2018年1月24日
(65)【公開番号】特開2019-128760(P2019-128760A)
(43)【公開日】2019年8月1日
【審査請求日】2020年10月8日
(73)【特許権者】
【識別番号】000005223
【氏名又は名称】富士通株式会社
(74)【代理人】
【識別番号】100094525
【弁理士】
【氏名又は名称】土井 健二
(74)【代理人】
【識別番号】100094514
【弁理士】
【氏名又は名称】林 恒徳
(72)【発明者】
【氏名】向井 優太
【審査官】 石川 亮
(56)【参考文献】
【文献】 特開2008−071128(JP,A)
【文献】 特開平09−022361(JP,A)
【文献】 特開2014−130580(JP,A)
【文献】 特開2001−166989(JP,A)
【文献】 特開2015−219652(JP,A)
【文献】 米国特許第06567975(US,B1)
【文献】 米国特許第05950007(US,A)
(58)【調査した分野】(Int.Cl.,DB名)
G06F 8/41
(57)【特許請求の範囲】
【請求項1】
ソースプログラム内のメモリ内の配列の複数の要素をストライドアクセス間要素長の間隔でアクセスするストライドアクセス命令を複数回繰り返すループを検出し、
前記ストライドアクセス命令から前記ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データを前記メモリにアクセスしてキャッシュメモリに格納するプリフェッチ命令を、前記ループ内に追加し、
前記キャッシュメモリのキャッシュラインサイズ(C)、前記ストライドアクセス間要素長(m)、前記配列の一要素のサイズ(Type_Size)、前記プリフェッチ命令のプリフェッチアドレス(x)の場合、前記プリフェッチアドレス(x)を前記キャッシュラインサイズ(C)で除算したときの余り(x%C)が、前記ストライドアクセス間要素長(m)に一要素サイズ(Type_Size)を乗算したストライドアクセス間アドレス長(S)より小さい場合((x%C)<S)、前記プリフェッチ命令を実行する条件文を、前記ループ内に追加し、
前記ループ内の前記ストライドアクセス命令と前記条件文及び前記プリフェッチ命令を、複数、並列に実行するベクトル命令に変換するベクトル化、
する処理をコンピュータに実行させるコンパイラプログラム。
【請求項2】
前記ベクトル命令は、前記ストライドアクセス命令を複数並列に実行する第1のベクトル命令と、前記第1のベクトル命令に対応して前記条件文が真の場合に前記プリフェッチ命令を実行することを複数並列に実行する第2のベクトル命令とを有する、請求項1に記載のコンパイラプログラム。
【請求項3】
前記第2のベクトル命令は、
前記第1のベクトル命令に対応して前記条件文が真か否かをマスク配列の各要素に格納する第3のベクトル命令と、前記第1のベクトル命令に対応して前記マスク配列の要素が真の場合に前記プリフェッチ命令を実行する第4のベクトル命令とを有する、請求項2に記載のコンパイラプログラム。
【請求項4】
さらに、
前記条件文を前記ループ内に追加する処理は、
前記プリフェッチアドレス(x)を前記キャッシュラインサイズ(C)で除算したときの余りを、前記キャッシュラインサイズ(C)から1を減じた2進数と、前記プリフェッチアドレス(x)の2進数の各ビット間の論理積を演算して求める演算命令を生成することを含む、請求項1に記載のコンパイラプログラム。
【請求項5】
ソースプログラム内のメモリ内の配列の複数の要素をストライドアクセス間要素長の間隔でアクセスするストライドアクセス命令を複数回繰り返すループを検出し、
前記ストライドアクセス命令から前記ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データを前記メモリにアクセスしてキャッシュメモリに格納するプリフェッチ命令を、前記ループ内に追加し、
前記キャッシュメモリのキャッシュラインサイズ(C)、前記ストライドアクセス間要素長(m)、前記配列の一要素のサイズ(Type_Size)、前記プリフェッチ命令のプリフェッチアドレス(x)の場合、前記プリフェッチアドレス(x)を前記キャッシュラインサイズ(C)で除算したときの余り(x%C)が、前記ストライドアクセス間要素長(m)に一要素サイズ(Type_Size)を乗算したストライドアクセス間アドレス長(S)より小さい場合((x%C)<S)、前記プリフェッチ命令を実行する条件文を、前記ループ内に追加し、
前記ループ内の前記ストライドアクセス命令と前記条件文及び前記プリフェッチ命令を、複数、並列に実行するベクトル命令に変換するベクトル化、
する処理をコンピュータに実行させるコンパイル方法。
【請求項6】
メモリと、
前記メモリにアクセス可能なプロセッサとを有し、
前記プロセッサは、
ソースプログラム内のメモリ内の配列の複数の要素をストライドアクセス間要素長の間隔でアクセスするストライドアクセス命令を複数回繰り返すループを検出し、
前記ストライドアクセス命令から前記ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データを前記メモリにアクセスしてキャッシュメモリに格納するプリフェッチ命令を、前記ループ内に追加し、
前記キャッシュメモリのキャッシュラインサイズ(C)、前記ストライドアクセス間要素長(m)、前記配列の一要素のサイズ(Type_Size)、前記プリフェッチ命令のプリフェッチアドレス(x)の場合、前記プリフェッチアドレス(x)を前記キャッシュラインサイズ(C)で除算したときの余り(x%C)が、前記ストライドアクセス間要素長(m)に一要素サイズ(Type_Size)を乗算したストライドアクセス間アドレス長(S)より小さい場合((x%C)<S)、前記プリフェッチ命令を実行する条件文を、前記ループ内に追加し、
前記ループ内の前記ストライドアクセス命令と前記条件文及び前記プリフェッチ命令を、複数、並列に実行するベクトル命令に変換するベクトル化、
する処理を実行するコンパイルする情報処理装置。
【発明の詳細な説明】
【技術分野】
【0001】
本発明は,コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置に関する。
【背景技術】
【0002】
情報処理装置において、メインメモリの処理性能はプロセッサの処理性能に比較して著しく低い。そのため、プロセッサは、メインメモリ内のデータにアクセスすると、そのアクセスが終了するまで処理が待ち状態になり、稼働低下を招く。このような稼働低下を回避するために、プロセッサは、高速なアクセスを可能にするキャッシュメモリを内蔵し、メインメモリ内のデータの一部をキャッシュメモリに格納し、メインメモリへのアクセス時間を短縮する。
【0003】
一方、データのアクセスの一形態として、ソースプログラムのループ内において、配列の要素のデータを順番にアクセスする以外に、所定の要素数ずつ飛びとびにアクセスするストライドアクセスがある。このようにループ内で配列の要素へのメモリアクセスを繰り返す場合、将来のメモリアクセスを予測して所定のアクセス反復回数前にメインメモリにアクセスしてデータをキャッシュメモリに登録するプリフェッチを行うと、プロセッサの処理効率を高めることができる。
【0004】
そこで、ソースプログラムをアセンブリコードまたはオブジェクトコードに変換するコンパイラは、最適化処理の一つとして、ソースプログラムの配列の要素のデータへのアクセスを繰り返すループ内にプリフェッチ命令を追加する。
【0005】
また、コンパイラの別の最適化処理として、所定の命令が繰り返されるループのソースコードをベクトル化する処理も知られている。ベクトル化処理は、ループ内の所定の命令の繰り返し実行を、同じ一つの命令を複数のデータについて並列に実行するベクトル命令、またはSIMD(Single Instruction Multiple Data)命令に変換する処理である。このようにコンパイラがソースプログラム内のループ内で繰り返される所定の命令をSIMD命令に変換することで、SIMD演算器を有するプロセッサの効率的処理を利用することができる。
【0006】
以下の特許文献は、ストライドアクセスのプリフェッチに関するもの、及びプリフェッチ追加による最適化処理に関するものである。
【先行技術文献】
【特許文献】
【0007】
【特許文献1】特開平6−274525号公報
【特許文献2】特開平1−134670号公報
【特許文献3】特表2014−513340号公報
【特許文献4】特表平4−505225号公報
【特許文献5】特開2008−71128号公報
【特許文献6】特開2015−153122号公報
【発明の概要】
【発明が解決しようとする課題】
【0008】
しかしながら、キャッシュメモリのキャッシュラインのサイズCよりストライドアクセスのストライド長S(隣接するアクセス間のアドレス間隔)が小さい場合、連続するプリフェッチ命令が同じキャッシュライン内のデータに対してメインメモリに重複してアクセスする場合がある。このような重複する複数のアクセスは冗長なアクセスである。そのため、コンパイラの最適化処理によるプリフェッチ命令は、冗長アクセスの場合は行わないことが望ましい。その場合、コンパイラが冗長アクセスか否かの判定処理を追加する必要がある。しかし、かかる判定処理を追加するとベクトル化を行うことができない場合がある。
【0009】
そこで,本発明の目的は,プリフェッチ命令の追加とベクトル化処理を両立できるコンパイラプログラム、コンパイル方法、コンパイルする情報処理装置を提供することにある。
【課題を解決するための手段】
【0010】
実施の形態の一つの側面は,ソースプログラム内のメモリ内の配列の複数の要素をストライドアクセス間要素長の間隔でアクセスするストライドアクセス命令を複数回繰り返すループを検出し、
前記ストライドアクセス命令から前記ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データを前記メモリにアクセスしてキャッシュメモリに格納するプリフェッチ命令を、前記ループ内に追加し、
前記キャッシュメモリのキャッシュラインサイズ(C)、前記ストライドアクセス間要素長(m)、前記配列の一要素のサイズ(Type_Size)、前記プリフェッチ命令のプリフェッチアドレス(x)の場合、前記プリフェッチアドレス(x)を前記キャッシュラインサイズ(C)で除算したときの余り(x%C)が、前記ストライドアクセス間要素長(m)に一要素サイズ(Type_Size)を乗算したストライドアクセス間アドレス長(S)より小さい場合((x%C)<S)、前記プリフェッチ命令を実行する条件文を、前記ループ内に追加し、
前記ループ内の前記ストライドアクセス命令と前記条件文及び前記プリフェッチ命令を、複数、並列に実行するベクトル命令に変換するベクトル化、
する処理をコンピュータに実行させるコンパイラプログラムである。
【発明の効果】
【0011】
第1の側面によれば,プリフェッチ命令の追加とベクトル化処理を両立できる。
【図面の簡単な説明】
【0012】
図1】本実施の形態におけるコンパイルする情報処理装置(コンピュータ)の構成例を示す図である。
図2】本実施の形態のコンパイラの処理の一例を示すフローチャート図である。
図3】プリフェッチ命令追加処理の第1の例を示す図である。
図4】配列aに対するストライドアクセスのアドレスとキャッシュラインとの関係を示す図である。
図5】プリフェッチ命令追加処理の第2の例を示す図である。
図6】ソースコードSC_1に対するベクトル化の例を示す図である。
図7】ベクトル化ができない一例を示す図である。
図8図5でプリフェッチ命令を追加されたソースコードSC_3をベクトル長2でベクトル化した例を示す図である。
図9】本実施の形態におけるプリフェッチ命令追加処理で追加されるプリフェッチ命令の一例を説明する図である。
図10図1のソースコードSC_1にプリフェッチ命令追加処理S3を行って生成されたソースコードSC_8の例を示す図である。
図11】本実施の形態におけるプリフェッチ追加処理のフローチャート図である。
図12】本実施の形態におけるベクトル処理の一例を示す図である。
【発明を実施するための形態】
【0013】
図1は、本実施の形態におけるコンパイルする情報処理装置(コンピュータ)の構成例を示す図である。情報処理装置は、複数の演算コア回路COREとL2キャッシュL2_CACHEとメモリコントローラMACとを有するCPU(Central Processing Unit、以下プロセッサ回路またはプロセッサと称する)10と、CPUのメモリコントローラMACによりアクセス制御されるメインメモリ12と、補助記憶装置であるストレージ20〜27とを有する。さらに、情報処理装置は、ネットワークNETに接続されるネットワークインターフェース14とバス18とを有する。また、演算コア回路CORE内には、図示しないL1キャッシュが設けられる。
【0014】
ストレージ20〜27は、OS(Operating System)20と、コンパイラ(プログラム)22、アセンブラ(アセンブリコードをオブジェクトコードに変換するプログラム)23、コンパイラによるコンパイル対象のソースプログラム24、ソースプログラムから変換されたアセンブリコード26、アセンブリコードから変換されたオブジェクトコード27とを格納する。プロセッサ10がコンパイラ22を実行して、ソースプログラム24の最適化、アセンブリコードへの変換、さらにオブジェクトコードへの変換を含むコンパイル処理を行う。プロセッサ10は、コンパイルされたオブジェクトコードを実行してもよい。
【0015】
図2は、本実施の形態のコンパイラの処理の一例を示すフローチャート図である。プロセッサは、コンパイラプログラムを実行し、ソースプログラムの字句解析を行い、さらに、構文解析を行う(S1)。さらに、プロセッサは、種々の最適化処理S2-S6を実行し、ソースコードから変換された最適化済みのアセンブリコードを出力する(S7)。プロセッサは、さらに、アセンブリコードをオブジェクトコードに変換してもよい。
【0016】
最適化処理S2-S6には、配列へのアクセス命令を繰り返すループにプリフェッチ命令を追加する処理S3と、ソースプログラムのループ内の反復実行されるアクセス命令を、ベクトル命令に変換するベクトル化処理S5とが含まれる。プロセッサは、ベクトル化処理では、ループ内で繰り返し実行される配列へのアクセス命令を、アクセス命令を複数、並列実行するベクトル命令に変換する。プロセッサは、ベクトル化処理S5で、ループ内の配列へのアクセス命令にプリフェッチ命令が追加されている場合、アクセス命令に加えてプリフェッチ命令も複数、並列実行するベクトル命令に変換する。
【0017】
上記以外の最適化処理は、コンパイラの一般的な処理であるので、ここでの説明は省略する。
【0018】
[プリフェッチ命令追加処理]
以下、ループ内のメモリアクセスにプリフェッチ命令を追加する処理について、ソースコード例を示して説明する。
【0019】
図3は、プリフェッチ命令追加処理の第1の例を示す図である。ソースコードSC_1のプログラムは、行11〜13に変数i=0からi=N-1まで変数iをi=i+1して行12の命令を繰り返し実行するループ命令が含まれる。行12には、配列aの要素a[i*m]に0を書き込む命令(アクセス命令)が含まれる。行12のa[i*m]=0は、配列aのm要素間隔のストライドアクセスである。mは定数でも変数でもよい。
【0020】
ソースコードSC_2は、ソースコードSC_1のループ内に、P回の反復先のアクセスa[i*m]=0に対するプリフェッチ命令、行23のprefetch(&a[(P+i)*m])、を有する。ソースコードSC_1にプリフェッチ命令追加処理S3を実行すると、単純に行23のプリフェッチ命令が追加された例である。ここで、prefetch(&x)は、xのアドレス(&x)をプリフェッチすることを意味する。また、プリフェッチとは、メインメモリ内のアドレスxのデータにアクセスし、そのデータをキャッシュメモリに格納する処理である。したがって、プリフェッチ命令prefetch(&a[(P+i)*m])は、配列aの要素a[(P+i)*m]のデータをメインメモリから読み出しキャッシュメモリに格納する命令である。
【0021】
ソースコードSC_2のプリフェッチ命令では、ループの全ての反復(繰り返し)で行23のプリフェッチ命令が実行される。キャッシュメモリは、ラインと呼ばれる一定サイズの連続領域の単位でデータを取り扱う(アクセス、格納、置換)ので、同じキャッシュラインを複数回プリフェッチすることは冗長なアクセスであり、1つのキャッシュラインに対して1回プリフェッチすることが性能上最善である。
【0022】
そのため、ソースコードSC_2のようなm間隔のストライドアクセスを反復実行する場合、mの絶対値abs(m)がキャッシュラインのサイズCより小さい場合、冗長なプリフェッチが発生する。
【0023】
図4は、配列aに対するストライドアクセスのアドレスとキャッシュラインとの関係を示す図である。図中、キャッシュラインサイズが4バイト、m間隔がm=3、配列aのタイプサイズ(type_size:要素サイズ)が1バイト、要素a[P*m]が先頭キャッシュラインの先頭とする。配列aに対するキャッシュラインは、実線で示す4バイトの領域(4つの要素の領域)である。また、横軸に示されるとおり、左から右に向かってアドレスが増加する。
【0024】
図4には、配列aの上側にm間隔の複数のストライドアクセスが示される。m間隔の複数のストライドアクセスそれぞれに対して、要素a[P*m]、a[(P+1)*m]、a[(P+2)*m]、a[(P+3)*m]…a[(P+6)*m]のアドレスがプリフェッチされる。これらのプリフェッチのうち、要素a[(P+1)*m]、a[(P+5)*m]のプリフェッチは、それぞれ直前の要素a[(P)*m]、a[(P+4)*m]のプリフェッチと同じキャッシュラインをプリフェッチするので、冗長なプリフェッチである。そこで、このような冗長なプリフェッチが実行されないような条件文とプリフェッチ命令を追加することが考えられる。
【0025】
図5は、プリフェッチ命令追加処理の第2の例を示す図である。ソースコードSC_1は、図3と同じである。それに対して、プリフェッチ命令追加処理S3により生成されるソースコードSC_3は、行34−35の条件文(if文)と、行31,行36のプリフェッチアドレスを算出する命令と、行37のプリフェッチ命令を有する。
【0026】
図3から理解されるとおり、冗長なプリフェッチを回避するためには、前回プリフェッチしたキャッシュラインの先頭アドレスlast_prefetch(図4参照)と、各ループ内でのプリフェッチ命令のアドレス&a[(P+i)*m]とを比較し、各ループ内でのプリフェッチ命令のアドレス&a[(P+i)*m]が、前回のプリフェッチアドレスlast_prefetchより小さい場合と、前回のプリフェッチアドレスlast_prefetchよりキャッシュラインサイズC以上大きい場合に、プリフェッチ命令を実行すればよい。つまり、以下の条件1が真の場合、プリフェッチ命令を実行する。
&a[(P+i)*m]<last_prefetch, またはlast_prefetch+C<=&a[(P+i)*m] 条件1
ここで、C=4である。
【0027】
図5の行34,35のif文の括弧内の条件文は、上記の条件1に対応する。ここで、||は論理和を意味する。また、行31は、前回のプリフェッチアドレスlast_prefetchに初期値「0」を設定する。そして、行36は、アドレス&a[(P+i)*m]をキャッシュラインサイズCで除算し、小数点を切り捨てた整数に、キャッシュラインサイズCを乗算したアドレスを、前回のプリフェッチアドレス(キャッシュラインの先頭アドレス)last_prefetchとする演算命令である。そして、行37はアドレスlast_prefetchへのプリフェッチ命令である。この時のプリフェッチアドレスlast_prefetchは、ループ内の次回の繰り返しでは前回プリフェッチアドレスとなる。
【0028】
ソースコードSC_3によれば、ループ内において、ループ初回のi=0では、プロセッサは、行36によりlast_prefetched=&a[P*m]と更新し、要素a[P*m]のキャッシュラインに対するプリフェッチを実行する。図4に示したとおりである。
【0029】
次に、i=1では、プリフェッチ対象の要素a[(P+1)*m]は、前回プリフェッチした要素a[P*m]と同じキャッシュラインに属するため、要素a[(P+1)*m]へのプリフェッチを実行すると同じキャッシュラインを冗長にプリフェッチすることになる。図5のソースコードSC_3では、行34−35のif文の条件文(上記の条件1)が偽となり、プロセッサは、行36のlast_prefetchの更新命令と行37のプリフェッチ命令を実行せず、冗長なプリフェッチを抑止する。
【0030】
さらに、i=2では、プリフェッチ対象要素a[(P+2)*m]は、前回プリフェッチしたキャッシュラインとは異なるキャッシュライン内であり、条件1のlast_prefetched+4<=&a[(P+2)*m]が真となり、プロセッサは、行36の更新命令と行37のプリフェッチ命令を実行する。以下、i=5ではプリフェッチ命令は実行されず、それ以外のi=3,4,6ではプリフェッチ命令が実行される。以上の通り、ソースコードSC_3によれば、図4に示した冗長なプリフェッチ命令の実行が防止される。
【0031】
[ベクトル化]
次に、コンパイラの別の最適化処理であるベクトル化についてソースコードを例にして説明する。ベクトル化とは、前述のとおり、ソースプログラムを、SIMD命令またはベクトル命令を含むプログラムに変換する処理である。また、ベクトル化では、配列へのアクセス命令を繰り返すループについて、アクセス命令を複数、並列実行するベクトル命令に変換する。コンパイルされたプログラムが、SIMD演算器を有する情報処理装置により実行されると、1命令で複数のデータを演算するベクトル命令が、SIMD演算器内の複数の演算器で並列に実行される。そのため、プログラムの実行効率が向上する。
【0032】
図6は、ソースコードSC_1に対するベクトル化の例を示す図である。ソースコードSC_1は、ベクトル化されない場合、ループ内ではアドレス&a[i*m]に「0」を書き込む命令を実行するだけである。一方、ベクトル化されたソースコードSC_4は、ベクトル長が2の例であり、行42のベクトル命令が、アドレス&a[i*m], &a[(i+1)*m]の要素に「0」を並列に書込む命令である。そのため、行41内のループの変数iのインクリメントの間隔は2に設定される。また、ベクトル長が2の場合、繰り返し数(イタレーション数)Nをベクトル長2で除算した余りのループは、ベクトル命令の対象外となる。その場合、ソースコードSC_1の行12のストア命令a[i*m]=0が一回実行される。
【0033】
ベクトル長をVに一般化すると、ベクトル命令は、&a[i*m],&a[(i+1)*m], ..., &a[(i+V-1)*m]のV個のアドレスの要素それぞれに「0」をストアする命令となる。ベクトル長Vは、ベクトル命令に設定される設定値であり、コンパイルされたプログラムを実行するSIMD演算器のSIMD長に対応するまたは等しい長さに設定される。そして、N/Vの余りのループはベクトル命令の対象外となり、ベクトル化前のソースコードのストア命令a[i*m]=0を実行するコードに変換される。
【0034】
ほとんどのベクトル命令は、ベクトル命令の対象データについて、あるデータを先に計算し、その結果に基づいて他のデータを計算するということは、できない。したがって、通常、ループのイタレーション間で依存がない場合にベクトル化が行われ、依存がある場合はベクトル化は行われない。例えば、図6のソースコードSC_1のループは、他のイタレーションの計算結果を参照しないので、ソースコードSC_4の行42のベクトル命令のように、ベクトル化が可能である。
【0035】
図7は、ベクトル化ができない一例を示す図である。ソースコードSC_5の行52は、前のイタレーションで演算した要素a[i-1]を、要素a[i]に乗算して、要素a[i]に書込む命令であり、前のイタレーション結果a[i-1]を参照する演算命令である。ソースコードSC_5の行52の命令を、ベクトル長2でベクトル化すると、例えばソースコードSC_6の行62のベクトル命令に変換される。このソースコードSC_6の行62のベクトル命令は、以下の2つの演算命令がベクトル化されている。
a[i] = a[i] * a[i-1]
a[i+1] = a[i+1] * a[i]
【0036】
ここで、上記の2つの演算命令を実行すると、初期値がa[0]=2, a[1]=3, a[2]=4の場合、以下の通りとなる。
a[1] = a[1] * a[0] = 3 * 2 = 6
a[2] = a[2] * a[1] = 4 * 6 = 24
【0037】
一方、ソースコードSC_6の行62のベクトル命令では、2つの演算が並列に実行されるため、以下のとおりとなる。
a[1] = a[1] * a[0] = 3 * 2 = 6, a[2] = a[2] * a[1] = 4 * 3 = 12
この演算結果a[2] = 12は、a[1]が更新される前の初期値a[1] = 3に基づいて算出されるので正しい値「24」と一致しない。このように、イタレーション間で依存のある命令をベクトル化することは不適切である。
【0038】
図8は、図5でプリフェッチ命令を追加されたソースコードSC_3をベクトル長2でベクトル化した例を示す図である。ソースコードSC_3では、行36で次回のループのif文の条件文で参照する前回のプリフェッチアドレスlast_prefetchが演算される。
【0039】
かかるソースコードSC_3をベクトル化すると、SC_3内の行33の命令a[i*m] = 0は、ベクトル化されたソースコードSC_7内の行73のように並列化される。即ち、以下のとおりである。
a[i*m:(i+1)*m] = 0
【0040】
しかし、ソースコードSC_3内の行34,35のif文の条件文が前のイタレーションで求めた前回プリフェッチアドレスlast_prefetchの参照を含むので、行34−37をベクトル化できない。その結果、コードSC_7では、並列処理ではなく、行74−78と行79−7Dのように順次処理するコードのままとなる。これでは、ベクトル化が十分ではない。
【0041】
[本実施の形態]
次に、本実施の形態におけるストライドアクセスを繰り返すループでのプリフェッチ命令追加処理と、ベクトル化処理について説明する。前述のとおり、コンパイラでの最適化処理において、ストライドアクセスを繰り返す(反復、イタレート)するループに、プリフェッチ命令を追加するとともにベクトル化することが望ましい。
【0042】
図9は、本実施の形態におけるプリフェッチ命令追加処理で追加されるプリフェッチ命令の一例を説明する図である。図9には、配列aについて、キャッシュラインサイズC=8バイト、ストライドアクセスのアドレス間隔S=3バイト(要素間隔m=3、要素サイズ(type_size)1バイト)、プリフェッチアドレスxの例が示されている。プリフェッチアドレスxの括弧内には、各キャッシュラインの先頭要素(0)からの相対的な要素位置を示す。破線が要素、1バイトの区切りで、実線がキャッシュラインの区切りである。
【0043】
配列aの先頭アドレスX1がキャッシュラインの先頭とする。この場合、プリフェッチアドレスxのキャッシュラインサイズCに対する剰余(モジュロ)x%Cがストライドアクセスのアドレス間隔abs(S)より小さいという条件を満たす場合に、プリフェッチ命令prefetch(x)を実行し、満たさない場合は実行しないようにする。こうすれば、冗長なプリフェッチの実行を防止できる。つまり、図9に示すとおり、コンパイラは、プリフェッチアドレスX1−X8が各キャッシュラインサイズC(=8バイト)の先頭から3バイト以内であれば、プリフェッチ命令を実行するようなソースコードに変換する。その場合、キャッシュライン当たり1回のプリフェッチが実行されるようになる。ここで、abs()とは、カッコ内の絶対値の意味である。
【0044】
図9の例では、アドレスX1、X4、X7だけがプリフェッチ実行の条件、(x%C) < abs(S)、を満たすので、プリフェッチ命令が実行される。そして、if文の条件文、(x%C) < abs(S)、は、他のイタレーションの計算結果を利用しないので、ベクトル化が可能である。
【0045】
以上の通り、プリフェッチを実行する条件は、Sバイト間隔のストライドアクセスに対して、プリフェッチアドレスxについて(x%C) < abs(S)を満たす時、アドレスxが、アドレスxに対応するキャッシュラインにアクセスするストライドアクセスの中で最も小さなアクセスアドレスとなる。
【0046】
図10は、図1のソースコードSC_1にプリフェッチ命令追加処理S3を行って生成されたソースコードSC_8の例を示す図である。ソースコードSC_8は、行83−85に以下のif文とプリフェッチ命令が追加される。
if(abs(m*type_size) > &a[(P+i)*m]%C) {
prefetch(&a[(P+i)*m])
}
【0047】
すなわち、プロセッサは、プリフェッチ命令追加処理S3を実行して、ストライドアクセスのストライド間隔S=m*type_sizeの絶対値abs(m*type_size)よりも、プリフェッチ対象要素a[(P+i)*m]のアドレス、&a[(P+i)*m]、のキャッシュラインサイズCに対する剰余&a[(P+i)*m]%Cが小さい場合、プリフェッチ命令prefetch(&a[(P+i)*m])を実行するコードを追加する。
【0048】
図11は、本実施の形態におけるプリフェッチ追加処理のフローチャート図である。図2で説明したとおり、プロセッサは、コンパイラを実行して、事前にソースプログラムの字句解析及び構文解析S1を実行し、ソースプログラム内のループの位置と数、各ループ内のメモリアクセス命令の位置と数を抽出済みである。図10のソースプログラムSC_1は、ループ数は1つ、ループ内のメモリアクセスは1つである。
【0049】
プロセッサは、コンパイラのプリフェッチ追加処理を実行して、以下の処理を行う。まず、プロセッサは、ループ番号n1を初期値0に設定し(S11)、ループ番号n1がソースプログラム内のループ数より小さい間(S12のTRUE)、処理S13-S22を繰り返す。プロセッサは、ループ番号n1がループ数と等しくなると(S12のFALSE)、プリフェッチ追加処理を終了する。
【0050】
次に、プロセッサは、ループ番号n1のループをプリフェッチ追加対象ループLに設定し(S13)、ループLのプリフェッチ距離を変数Pに設定する(S14)。ループ内のプリフェッチ距離Pは、前述したとおり、コンパイルされたプログラムを実行するコンピュータのプロセッサがメインメモリ内のデータをプリフェッチするのに要する時間(メインメモリの読み出しと、キャッシュメモリへのリードデータの格納に要する時間)に対応して設定される、ループのイタレーション回数である。つまり、プリフェッチ距離がPということは、Pイタレーション先でアクセスするデータをメインメモリからプリフェッチすることを意味する。
【0051】
さらに、プロセッサは、ループL内のメモリアクセス番号n2を初期値0に設定し(S15)、メモリアクセス番号n2がループLのメモリアクセス数未満の間(S16のTRUE)、処理S17-S21を繰り返す。メモリアクセス番号n2がループLのメモリアクセス数と等しくなると(S16のFALSE)、ループ番号n1を+1だけインクリメントし(S22)、次のループに対する処理に戻る(S12)。
【0052】
プロセッサは、処理対象のメモリアクセス番号n2について、ループL内のn2番目のメモリアクセスを対象メモリアクセスAに設定し(S17)、さらに、ループ内のアクセスAのイタレーション間のアドレス間隔をSに設定する(S18)。つまり、ループLが1イタレーション進んだ時のアクセスのアドレスの差分をSに設定する。プロセッサは、字句解析と構文解析により、ループの開始と終了を例えば分岐命令とその分岐先から認識することができ、さらに、ループ内でメモリアクセスのアドレスの増加量または減少量から、ループ内のアクセスAのイタレーション間のアドレス間隔をその増加量または減少量と認識することができる。
【0053】
アドレス間隔Sがイタレーションにより変化せず一定の場合(S19のTRUE)、対象メモリアクセスAのPイタレーション先のプリフェッチアドレスをxとすると、プロセッサは、以下に示す、プリフェッチ実行の条件文を含むif文と、プリフェッチ命令とを追加する(S20)。この追加されるif文とプリフェッチ命令は、前述したものと同じであり、以下のとおりである。
if(abs(S) > &a[(P+i)*m]%C) {
prefetch(&a[(P+i)*m])
}
ここで、S=m*type_size(S:イタレーション間のアドレス間隔、m:イタレーション間の要素間隔、type_size:要素のサイズ)である。つまり、図10のソースコードSC_8の行83−85の追加コードに対応する。
【0054】
アドレス間隔Sがイタレーションにより変化する場合は(S19のFALSE)、本実施の形態による最適化処理の対象外であるので、処理S20を実行せず、次のメモリアクセスを処理対象メモリアクセスAとする(S17)。
【0055】
そして、プロセッサは、メモリアクセス番号n2をインクリメント(n2=n2+1)し(S21)、対象ループL内の次のメモリアクセスについて処理S16-S21を繰り返す。
【0056】
図10のソースコードSC_1は、ループ数が1、ループ内のメモリアクセスが1(a[i*m]=0)である。したがって、ソースコードSC_1の場合、図11のフローチャートでは、プロセッサは、処理S13-S22を一回、処理S16-S21も一回実行する。
【0057】
ここで、プロセッサは、コンパイラを実行して、上記のif文の条件文のアクセスアドレス&a[(P+i)*m]とキャッシュラインサイズCとの剰余演算&a[(P+i)*m]%Cを、アドレス&a[(P+i)*m]=xと、C-1の各2進数のビットの論理積で演算する演算命令に変形してもよい。
【0058】
すなわち、キャッシュラインサイズCは通常2冪(べき)、2y=10000000、であるので、C-1は次のとおりとなる。
C-1 = 10000000-1 = 01111111
【0059】
したがって、アドレスx=10101000の場合、C-1=011111111各ビットの論理積は以下のとおりとなる。
C-1 = 01111111
x = 10101000
x・(C-1) = 00101000
【0060】
つまり、論理積x・(C-1)は、アドレスxの最上位ビット以外の値00101000となり、これは剰余演算x%Cで求めた余りと一致する。
【0061】
図12は、本実施の形態におけるベクトル処理の一例を示す図である。図12には、図11でプリフェッチ命令が追加されたソースコードSC_8をベクトル化した疑似コードPSC_9が示される。ベクトル化されたコードはソースコードである必要はなく、コンパイラ内部のプログラムコードやアセンブリコードでも良い。図12には、人間が理解しやすいようにソースコード風の疑似コードPSC_9で示す。
【0062】
プロセッサは、ベクトル化処理S5を実行して以下の処理を行っている。すなわち、プロセッサは、ベクトル化後の疑似コードPSC_9では、コードSC_8内の行81のfor文について、行91のfor文のように、変数iのイタレーション毎の増分をベクトル長Vに変更する。そして、プロセッサは、コードPSC_9において、行92に示すとおり、ベクトル長Vに対応する変数iの最大値i+V-1を変数kに設定する。
【0063】
さらに、プロセッサは、コードSC_8の行82のメモリアクセスa[i*m]=0を、図示されるとおり、コードPSC_9の行93の要素番号i*m〜k*mの要素a[i*m:k*m]に「0」を並列に書き込むベクトル命令に変更する。つまり、行93のベクトル命令は、以下の通りである。
a[i*m:k*m]=0
このベクトル命令は、配列aの要素番号i*m〜k*mのV個の要素に「0」を並列に書き込む命令である。
【0064】
そして、プロセッサは、コードPSC_9の行94のとおり、各プリフェッチアドレス&a[(P+i)*m]〜&a[(P+k)*m]のキャッシュラインサイズCに対する剰余(フェッチアドレスをキャッシュラインサイズCで除算した余り)が、ストライドアクセス間のアドレス差分の絶対値abs(m*type_size)より小さいか否かの比較を行い、その比較結果(真:1、偽:0)をマスクの配列mask[0:V-1]のV個の要素それぞれ代入するベクトル命令を生成する。
【0065】
また、プロセッサは、コードPSC_9の行95のとおり、マスク配列mask[0:V-1]の真の比較結果が代入された要素に対応するアドレスにプリフェッチ命令prefetchを実行するベクトル命令を生成する。但し、マスク配列にプリフェッチ命令の実行の有無を示す値を代入すること以外の方法で、各プリフェッチ命令の実行か否かを判別するようにしてもよい。
【0066】
図12において、コードPSC_9には、N/Vの余りのループのコードは省略している。コードPSC_9には、N/Vの余りのループであるINT(N/V)*V+1〜N番目の各ループのif文とそのメモリアクセスa[i*m]=0(コードSC_8の行83−84のコード)が追加される。
【0067】
図12において、ベクトル化により生成されるベクトル命令は、行93のストライドアクセスを並列に行う第1のベクトル命令と、行94のプリフェッチ命令を実行する条件を並列に判定して判定結果をマスク配列の各要素に格納する第2のベクトル命令と、行95のマスク配列の各要素が真の場合にプリフェッチ命令を実行する第3のベクトル命令とを有する。
【0068】
以上の通り、本実施の形態によれば、プロセッサが、コンパイラを実行して、ソースプログラム内のメモリ内の配列の複数の要素に対してストライドアクセス命令を反復実行するループのストライドアクセス命令に、プリフェッチ命令のプリフェッチアドレスxのキャッシュラインサイズCに対する剰余(余り)(x%C)が、ストライドアクセス間アドレス長Sより小さい場合に、実行されるプリフェッチ命令を追加する。これにより、プロセッサは、ストライドアクセス命令とプリフェッチ命令とをベクトル化することができる。その結果、コンパイラの最適化処理により、配列の複数の要素にストライドアクセスを反復実行するループに、プリフェッチ命令を追加しさらにベクトル命令に変換し、コンパイルされたコードの情報処理装置による処理効率を高めることができる。
【符号の説明】
【0069】
10:CPU, プロセッサ
L2 CACHE:キャッシュメモリ
MAC:メモリアクセスコントローラ
M_MEM:メインメモリ
22:コンパイラ
23:アセンブラ
24:ソースプログラム
26:アセンブリコード
27:オブジェクトコード
a[i*m]:配置aに対するストライドアクセス命令
for():ループ
a:配列
S:ストライドアクセス間アドレス長(隣接するストライドアクセス間のアドレス間隔)
m:ストライドアクセス間要素長(隣接するストライドアクセス間の要素間隔)
Type_Size:配列の一要素サイズ(S=m * Type_Size)
x:プリフェッチアドレス
C:キャッシュラインのサイズ
Prefetch:プリフェッチ命令
Last_prefetched:直前のプリフェッチアドレス
図1
図2
図3
図4
図5
図6
図7
図8
図9
図10
図11
図12