(57)【要約】      （修正有）【課題】ストライドアクセスを繰り返すループにプリフェッチ命令を追加し、ベクトル化を行う。【解決手段】ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データをキャッシュメモリに格納するプリフェッチ命令を、ループ内に追加し、キャッシュメモリのキャッシュラインサイズ（Ｃ）、ストライドアクセス間要素長（ｍ）、配列の一要素のサイズ（Type_Size）、プリフェッチ命令のプリフェッチアドレス（ｘ）の場合、プリフェッチアドレス（ｘ）をキャッシュラインサイズ（Ｃ）で除算したときの余り（ｘ％Ｃ）が、ストライドアクセス間要素長（ｍ）に一要素サイズ（Type_Size）を乗算したストライドアクセス間アドレス長（S）より小さい場合（（ｘ％Ｃ）＜Ｓ）、プリフェッチ命令を実行する条件文を、ループ内に追加し、ループ内のストライドアクセス命令と条件文及びプリフェッチ命令をベクトル命令に変換する。【選択図】図１１
2019128760.tif 000002
【特許請求の範囲】
【請求項１】
ソースプログラム内のメモリ内の配列の複数の要素をストライドアクセス間要素長の間隔でアクセスするストライドアクセス命令を複数回繰り返すループを検出し、
前記ストライドアクセス命令から前記ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データを前記メモリにアクセスしてキャッシュメモリに格納するプリフェッチ命令を、前記ループ内に追加し、
前記キャッシュメモリのキャッシュラインサイズ（Ｃ）、前記ストライドアクセス間要素長（ｍ）、前記配列の一要素のサイズ（Type_Size）、前記プリフェッチ命令のプリフェッチアドレス（ｘ）の場合、前記プリフェッチアドレス（ｘ）を前記キャッシュラインサイズ（Ｃ）で除算したときの余り（ｘ％Ｃ）が、前記ストライドアクセス間要素長（ｍ）に一要素サイズ（Type_Size）を乗算したストライドアクセス間アドレス長（S）より小さい場合（（ｘ％Ｃ）＜Ｓ）、前記プリフェッチ命令を実行する条件文を、前記ループ内に追加し、
前記ループ内の前記ストライドアクセス命令と前記条件文及び前記プリフェッチ命令を、複数、並列に実行するベクトル命令に変換するベクトル化、
する処理をコンピュータに実行させるコンパイラプログラム。
【請求項２】
前記ベクトル命令は、前記ストライドアクセス命令を複数並列に実行する第１のベクトル命令と、前記第１のベクトル命令に対応して前記条件文が真の場合に前記プリフェッチ命令を実行することを複数並列に実行する第２のベクトル命令とを有する、請求項１に記載のコンパイラプログラム。
【請求項３】
前記第２のベクトル命令は、
前記第１のベクトル命令に対応して前記条件文が真か否かをマスク配列の各要素に格納する第３のベクトル命令と、前記第１のベクトル命令に対応して前記マスク配列の要素が真の場合に前記プリフェッチ命令を実行する第４のベクトル命令とを有する、請求項２に記載のコンパイラプログラム。
【請求項４】
さらに、
前記条件文を前記ループ内に追加する処理は、
前記プリフェッチアドレス（ｘ）を前記キャッシュラインサイズ（Ｃ）で除算したときの余りを、前記キャッシュラインサイズ（C）から１を減じた２進数と、前記プリフェッチアドレス（ｘ）の２進数の各ビット間の論理積を演算して求める演算命令を生成することを含む、請求項１に記載のコンパイラプログラム。
【請求項５】
ソースプログラム内のメモリ内の配列の複数の要素をストライドアクセス間要素長の間隔でアクセスするストライドアクセス命令を複数回繰り返すループを検出し、
前記ストライドアクセス命令から前記ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データを前記メモリにアクセスしてキャッシュメモリに格納するプリフェッチ命令を、前記ループ内に追加し、
前記キャッシュメモリのキャッシュラインサイズ（Ｃ）、前記ストライドアクセス間要素長（ｍ）、前記配列の一要素のサイズ（Type_Size）、前記プリフェッチ命令のプリフェッチアドレス（ｘ）の場合、前記プリフェッチアドレス（ｘ）を前記キャッシュラインサイズ（Ｃ）で除算したときの余り（ｘ％Ｃ）が、前記ストライドアクセス間要素長（ｍ）に一要素サイズ（Type_Size）を乗算したストライドアクセス間アドレス長（S）より小さい場合（（ｘ％Ｃ）＜Ｓ）、前記プリフェッチ命令を実行する条件文を、前記ループ内に追加し、
前記ループ内の前記ストライドアクセス命令と前記条件文及び前記プリフェッチ命令を、複数、並列に実行するベクトル命令に変換するベクトル化、
する処理をコンピュータに実行させるコンパイル方法。
【請求項６】
メモリと、
前記メモリにアクセス可能なプロセッサとを有し、
前記プロセッサは、
ソースプログラム内のメモリ内の配列の複数の要素をストライドアクセス間要素長の間隔でアクセスするストライドアクセス命令を複数回繰り返すループを検出し、
前記ストライドアクセス命令から前記ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データを前記メモリにアクセスしてキャッシュメモリに格納するプリフェッチ命令を、前記ループ内に追加し、
前記キャッシュメモリのキャッシュラインサイズ（Ｃ）、前記ストライドアクセス間要素長（ｍ）、前記配列の一要素のサイズ（Type_Size）、前記プリフェッチ命令のプリフェッチアドレス（ｘ）の場合、前記プリフェッチアドレス（ｘ）を前記キャッシュラインサイズ（Ｃ）で除算したときの余り（ｘ％Ｃ）が、前記ストライドアクセス間要素長（ｍ）に一要素サイズ（Type_Size）を乗算したストライドアクセス間アドレス長（S）より小さい場合（（ｘ％Ｃ）＜Ｓ）、前記プリフェッチ命令を実行する条件文を、前記ループ内に追加し、
前記ループ内の前記ストライドアクセス命令と前記条件文及び前記プリフェッチ命令を、複数、並列に実行するベクトル命令に変換するベクトル化、
する処理を実行するコンパイルする情報処理装置。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は，コンパイラプログラム、コンパイル方法及びコンパイルする情報処理装置に関する。
【背景技術】
【０００２】
情報処理装置において、メインメモリの処理性能はプロセッサの処理性能に比較して著しく低い。そのため、プロセッサは、メインメモリ内のデータにアクセスすると、そのアクセスが終了するまで処理が待ち状態になり、稼働低下を招く。このような稼働低下を回避するために、プロセッサは、高速なアクセスを可能にするキャッシュメモリを内蔵し、メインメモリ内のデータの一部をキャッシュメモリに格納し、メインメモリへのアクセス時間を短縮する。
【０００３】
一方、データのアクセスの一形態として、ソースプログラムのループ内において、配列の要素のデータを順番にアクセスする以外に、所定の要素数ずつ飛びとびにアクセスするストライドアクセスがある。このようにループ内で配列の要素へのメモリアクセスを繰り返す場合、将来のメモリアクセスを予測して所定のアクセス反復回数前にメインメモリにアクセスしてデータをキャッシュメモリに登録するプリフェッチを行うと、プロセッサの処理効率を高めることができる。
【０００４】
そこで、ソースプログラムをアセンブリコードまたはオブジェクトコードに変換するコンパイラは、最適化処理の一つとして、ソースプログラムの配列の要素のデータへのアクセスを繰り返すループ内にプリフェッチ命令を追加する。
【０００５】
また、コンパイラの別の最適化処理として、所定の命令が繰り返されるループのソースコードをベクトル化する処理も知られている。ベクトル化処理は、ループ内の所定の命令の繰り返し実行を、同じ一つの命令を複数のデータについて並列に実行するベクトル命令、またはSIMD（Single Instruction Multiple Data）命令に変換する処理である。このようにコンパイラがソースプログラム内のループ内で繰り返される所定の命令をSIMD命令に変換することで、SIMD演算器を有するプロセッサの効率的処理を利用することができる。
【０００６】
以下の特許文献は、ストライドアクセスのプリフェッチに関するもの、及びプリフェッチ追加による最適化処理に関するものである。
【先行技術文献】
【特許文献】
【０００７】
【特許文献１】特開平６−２７４５２５号公報
【特許文献２】特開平１−１３４６７０号公報
【特許文献３】特表２０１４−５１３３４０号公報
【特許文献４】特表平４−５０５２２５号公報
【特許文献５】特開２００８−７１１２８号公報
【特許文献６】特開２０１５−１５３１２２号公報
【発明の概要】
【発明が解決しようとする課題】
【０００８】
しかしながら、キャッシュメモリのキャッシュラインのサイズＣよりストライドアクセスのストライド長Ｓ（隣接するアクセス間のアドレス間隔）が小さい場合、連続するプリフェッチ命令が同じキャッシュライン内のデータに対してメインメモリに重複してアクセスする場合がある。このような重複する複数のアクセスは冗長なアクセスである。そのため、コンパイラの最適化処理によるプリフェッチ命令は、冗長アクセスの場合は行わないことが望ましい。その場合、コンパイラが冗長アクセスか否かの判定処理を追加する必要がある。しかし、かかる判定処理を追加するとベクトル化を行うことができない場合がある。
【０００９】
そこで，本発明の目的は，プリフェッチ命令の追加とベクトル化処理を両立できるコンパイラプログラム、コンパイル方法、コンパイルする情報処理装置を提供することにある。
【課題を解決するための手段】
【００１０】
実施の形態の一つの側面は，ソースプログラム内のメモリ内の配列の複数の要素をストライドアクセス間要素長の間隔でアクセスするストライドアクセス命令を複数回繰り返すループを検出し、
前記ストライドアクセス命令から前記ループの所定繰り返し回数後のストライドアクセス命令のアクセス先データを前記メモリにアクセスしてキャッシュメモリに格納するプリフェッチ命令を、前記ループ内に追加し、
前記キャッシュメモリのキャッシュラインサイズ（Ｃ）、前記ストライドアクセス間要素長（ｍ）、前記配列の一要素のサイズ（Type_Size）、前記プリフェッチ命令のプリフェッチアドレス（ｘ）の場合、前記プリフェッチアドレス（ｘ）を前記キャッシュラインサイズ（Ｃ）で除算したときの余り（ｘ％Ｃ）が、前記ストライドアクセス間要素長（ｍ）に一要素サイズ（Type_Size）を乗算したストライドアクセス間アドレス長（S）より小さい場合（（ｘ％Ｃ）＜Ｓ）、前記プリフェッチ命令を実行する条件文を、前記ループ内に追加し、
前記ループ内の前記ストライドアクセス命令と前記条件文及び前記プリフェッチ命令を、複数、並列に実行するベクトル命令に変換するベクトル化、
する処理をコンピュータに実行させるコンパイラプログラムである。
【発明の効果】
【００１１】
第１の側面によれば，プリフェッチ命令の追加とベクトル化処理を両立できる。
【図面の簡単な説明】
【００１２】
【図１】本実施の形態におけるコンパイルする情報処理装置（コンピュータ）の構成例を示す図である。
【図２】本実施の形態のコンパイラの処理の一例を示すフローチャート図である。
【図３】プリフェッチ命令追加処理の第１の例を示す図である。
【図４】配列ａに対するストライドアクセスのアドレスとキャッシュラインとの関係を示す図である。
【図５】プリフェッチ命令追加処理の第２の例を示す図である。
【図６】ソースコードSC_1に対するベクトル化の例を示す図である。
【図７】ベクトル化ができない一例を示す図である。
【図８】図５でプリフェッチ命令を追加されたソースコードSC_3をベクトル長２でベクトル化した例を示す図である。
【図９】本実施の形態におけるプリフェッチ命令追加処理で追加されるプリフェッチ命令の一例を説明する図である。
【図１０】図１のソースコードSC_1にプリフェッチ命令追加処理S3を行って生成されたソースコードSC_8の例を示す図である。
【図１１】本実施の形態におけるプリフェッチ追加処理のフローチャート図である。
【図１２】本実施の形態におけるベクトル処理の一例を示す図である。
【発明を実施するための形態】
【００１３】
図１は、本実施の形態におけるコンパイルする情報処理装置（コンピュータ）の構成例を示す図である。情報処理装置は、複数の演算コア回路ＣＯＲＥとＬ２キャッシュＬ２＿ＣＡＣＨＥとメモリコントローラＭＡＣとを有するＣＰＵ（Central Processing Unit、以下プロセッサ回路またはプロセッサと称する）１０と、ＣＰＵのメモリコントローラＭＡＣによりアクセス制御されるメインメモリ１２と、補助記憶装置であるストレージ２０〜２７とを有する。さらに、情報処理装置は、ネットワークNETに接続されるネットワークインターフェース１４とバス１８とを有する。また、演算コア回路ＣＯＲＥ内には、図示しないＬ１キャッシュが設けられる。
【００１４】
ストレージ２０〜２７は、ＯＳ（Operating System）２０と、コンパイラ（プログラム）２２、アセンブラ（アセンブリコードをオブジェクトコードに変換するプログラム）２３、コンパイラによるコンパイル対象のソースプログラム２４、ソースプログラムから変換されたアセンブリコード２６、アセンブリコードから変換されたオブジェクトコード２７とを格納する。プロセッサ１０がコンパイラ２２を実行して、ソースプログラム２４の最適化、アセンブリコードへの変換、さらにオブジェクトコードへの変換を含むコンパイル処理を行う。プロセッサ１０は、コンパイルされたオブジェクトコードを実行してもよい。
【００１５】
図２は、本実施の形態のコンパイラの処理の一例を示すフローチャート図である。プロセッサは、コンパイラプログラムを実行し、ソースプログラムの字句解析を行い、さらに、構文解析を行う（S1）。さらに、プロセッサは、種々の最適化処理S2-S6を実行し、ソースコードから変換された最適化済みのアセンブリコードを出力する（S7）。プロセッサは、さらに、アセンブリコードをオブジェクトコードに変換してもよい。
【００１６】
最適化処理S2-S6には、配列へのアクセス命令を繰り返すループにプリフェッチ命令を追加する処理S3と、ソースプログラムのループ内の反復実行されるアクセス命令を、ベクトル命令に変換するベクトル化処理S5とが含まれる。プロセッサは、ベクトル化処理では、ループ内で繰り返し実行される配列へのアクセス命令を、アクセス命令を複数、並列実行するベクトル命令に変換する。プロセッサは、ベクトル化処理S5で、ループ内の配列へのアクセス命令にプリフェッチ命令が追加されている場合、アクセス命令に加えてプリフェッチ命令も複数、並列実行するベクトル命令に変換する。
【００１７】
上記以外の最適化処理は、コンパイラの一般的な処理であるので、ここでの説明は省略する。
【００１８】
［プリフェッチ命令追加処理］
以下、ループ内のメモリアクセスにプリフェッチ命令を追加する処理について、ソースコード例を示して説明する。
【００１９】
図３は、プリフェッチ命令追加処理の第１の例を示す図である。ソースコードSC_1のプログラムは、行１１〜１３に変数i=0からi=N-1まで変数iをi=i＋1して行１２の命令を繰り返し実行するループ命令が含まれる。行１２には、配列ａの要素a[i*m]に０を書き込む命令（アクセス命令）が含まれる。行１２のa[i*m]=0は、配列aのｍ要素間隔のストライドアクセスである。mは定数でも変数でもよい。
【００２０】
ソースコードSC_2は、ソースコードSC_1のループ内に、P回の反復先のアクセスa[i*m]=0に対するプリフェッチ命令、行２３のprefetch(&a[(P+i)*m]）、を有する。ソースコードSC_1にプリフェッチ命令追加処理S3を実行すると、単純に行２３のプリフェッチ命令が追加された例である。ここで、prefetch(&x)は、ｘのアドレス（&x）をプリフェッチすることを意味する。また、プリフェッチとは、メインメモリ内のアドレスｘのデータにアクセスし、そのデータをキャッシュメモリに格納する処理である。したがって、プリフェッチ命令prefetch(&a[(P+i)*m])は、配列aの要素a[(P+i)*m]のデータをメインメモリから読み出しキャッシュメモリに格納する命令である。
【００２１】
ソースコードSC_2のプリフェッチ命令では、ループの全ての反復（繰り返し）で行２３のプリフェッチ命令が実行される。キャッシュメモリは、ラインと呼ばれる一定サイズの連続領域の単位でデータを取り扱う（アクセス、格納、置換）ので、同じキャッシュラインを複数回プリフェッチすることは冗長なアクセスであり、１つのキャッシュラインに対して１回プリフェッチすることが性能上最善である。
【００２２】
そのため、ソースコードSC_2のようなｍ間隔のストライドアクセスを反復実行する場合、ｍの絶対値abs(m)がキャッシュラインのサイズCより小さい場合、冗長なプリフェッチが発生する。
【００２３】
図４は、配列ａに対するストライドアクセスのアドレスとキャッシュラインとの関係を示す図である。図中、キャッシュラインサイズが４バイト、ｍ間隔がｍ＝３、配列ａのタイプサイズ（type_size:要素サイズ）が１バイト、要素a[P*m]が先頭キャッシュラインの先頭とする。配列aに対するキャッシュラインは、実線で示す４バイトの領域（４つの要素の領域）である。また、横軸に示されるとおり、左から右に向かってアドレスが増加する。
【００２４】
図４には、配列ａの上側にｍ間隔の複数のストライドアクセスが示される。ｍ間隔の複数のストライドアクセスそれぞれに対して、要素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]のプリフェッチと同じキャッシュラインをプリフェッチするので、冗長なプリフェッチである。そこで、このような冗長なプリフェッチが実行されないような条件文とプリフェッチ命令を追加することが考えられる。
【００２５】
図５は、プリフェッチ命令追加処理の第２の例を示す図である。ソースコードSC_1は、図３と同じである。それに対して、プリフェッチ命令追加処理S3により生成されるソースコードSC_3は、行３４−３５の条件文（if文）と、行３１，行３６のプリフェッチアドレスを算出する命令と、行３７のプリフェッチ命令を有する。
【００２６】
図３から理解されるとおり、冗長なプリフェッチを回避するためには、前回プリフェッチしたキャッシュラインの先頭アドレスlast_prefetch（図４参照）と、各ループ内でのプリフェッチ命令のアドレス&a[(P+i)*m]とを比較し、各ループ内でのプリフェッチ命令のアドレス&a[(P+i)*m]が、前回のプリフェッチアドレスlast_prefetchより小さい場合と、前回のプリフェッチアドレスlast_prefetchよりキャッシュラインサイズC以上大きい場合に、プリフェッチ命令を実行すればよい。つまり、以下の条件１が真の場合、プリフェッチ命令を実行する。
&a[(P+i)*m]＜last_prefetch, またはlast_prefetch+C＜＝&a[(P+i)*m]    条件１
ここで、C=4である。
【００２７】
図５の行３４，３５のif文の括弧内の条件文は、上記の条件１に対応する。ここで、||は論理和を意味する。また、行３１は、前回のプリフェッチアドレスlast_prefetchに初期値「０」を設定する。そして、行３６は、アドレス&a[(P+i)*m]をキャッシュラインサイズCで除算し、小数点を切り捨てた整数に、キャッシュラインサイズCを乗算したアドレスを、前回のプリフェッチアドレス（キャッシュラインの先頭アドレス）last_prefetchとする演算命令である。そして、行３７はアドレスlast_prefetchへのプリフェッチ命令である。この時のプリフェッチアドレスlast_prefetchは、ループ内の次回の繰り返しでは前回プリフェッチアドレスとなる。
【００２８】
ソースコードSC_3によれば、ループ内において、ループ初回のi=0では、プロセッサは、行３６によりlast_prefetched=&a[P*m]と更新し、要素a[P*m]のキャッシュラインに対するプリフェッチを実行する。図４に示したとおりである。
【００２９】
次に、i=1では、プリフェッチ対象の要素a[(P+1)*m]は、前回プリフェッチした要素a[P*m]と同じキャッシュラインに属するため、要素a[(P+1)*m]へのプリフェッチを実行すると同じキャッシュラインを冗長にプリフェッチすることになる。図５のソースコードSC_3では、行３４−３５のif文の条件文（上記の条件１）が偽となり、プロセッサは、行３６のlast_prefetchの更新命令と行３７のプリフェッチ命令を実行せず、冗長なプリフェッチを抑止する。
【００３０】
さらに、i=2では、プリフェッチ対象要素a[(P+2)*m]は、前回プリフェッチしたキャッシュラインとは異なるキャッシュライン内であり、条件１のlast_prefetched+4＜＝&a[(P+2)*m]が真となり、プロセッサは、行３６の更新命令と行３７のプリフェッチ命令を実行する。以下、i=5ではプリフェッチ命令は実行されず、それ以外のi=3,4,6ではプリフェッチ命令が実行される。以上の通り、ソースコードSC_3によれば、図４に示した冗長なプリフェッチ命令の実行が防止される。
【００３１】
［ベクトル化］
次に、コンパイラの別の最適化処理であるベクトル化についてソースコードを例にして説明する。ベクトル化とは、前述のとおり、ソースプログラムを、SIMD命令またはベクトル命令を含むプログラムに変換する処理である。また、ベクトル化では、配列へのアクセス命令を繰り返すループについて、アクセス命令を複数、並列実行するベクトル命令に変換する。コンパイルされたプログラムが、SIMD演算器を有する情報処理装置により実行されると、１命令で複数のデータを演算するベクトル命令が、SIMD演算器内の複数の演算器で並列に実行される。そのため、プログラムの実行効率が向上する。
【００３２】
図６は、ソースコードSC_1に対するベクトル化の例を示す図である。ソースコードSC_1は、ベクトル化されない場合、ループ内ではアドレス&a[i*m]に「０」を書き込む命令を実行するだけである。一方、ベクトル化されたソースコードSC_4は、ベクトル長が２の例であり、行４２のベクトル命令が、アドレス&a[i*m], &a[(i+1)*m]の要素に「０」を並列に書込む命令である。そのため、行４１内のループの変数iのインクリメントの間隔は２に設定される。また、ベクトル長が２の場合、繰り返し数（イタレーション数）Ｎをベクトル長２で除算した余りのループは、ベクトル命令の対象外となる。その場合、ソースコードSC_1の行１２のストア命令a[i*m]=0が一回実行される。
【００３３】
ベクトル長をＶに一般化すると、ベクトル命令は、&a[i*m],&a[(i+1)*m], ..., &a[(i+V-1)*m]のＶ個のアドレスの要素それぞれに「0」をストアする命令となる。ベクトル長Vは、ベクトル命令に設定される設定値であり、コンパイルされたプログラムを実行するSIMD演算器のSIMD長に対応するまたは等しい長さに設定される。そして、N/Vの余りのループはベクトル命令の対象外となり、ベクトル化前のソースコードのストア命令a[i*m]=0を実行するコードに変換される。
【００３４】
ほとんどのベクトル命令は、ベクトル命令の対象データについて、あるデータを先に計算し、その結果に基づいて他のデータを計算するということは、できない。したがって、通常、ループのイタレーション間で依存がない場合にベクトル化が行われ、依存がある場合はベクトル化は行われない。例えば、図６のソースコードSC_1のループは、他のイタレーションの計算結果を参照しないので、ソースコードSC_4の行４２のベクトル命令のように、ベクトル化が可能である。
【００３５】
図７は、ベクトル化ができない一例を示す図である。ソースコードSC_5の行５２は、前のイタレーションで演算した要素a[i-1]を、要素a[i]に乗算して、要素a[i]に書込む命令であり、前のイタレーション結果a[i-1]を参照する演算命令である。ソースコードSC_5の行５２の命令を、ベクトル長２でベクトル化すると、例えばソースコードSC_6の行６２のベクトル命令に変換される。このソースコードSC_6の行６２のベクトル命令は、以下の２つの演算命令がベクトル化されている。
a[i] = a[i] * a[i-1]
a[i+1] = a[i+1] * a[i]
【００３６】
ここで、上記の２つの演算命令を実行すると、初期値が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
【００３７】
一方、ソースコードSC_6の行６２のベクトル命令では、２つの演算が並列に実行されるため、以下のとおりとなる。
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」と一致しない。このように、イタレーション間で依存のある命令をベクトル化することは不適切である。
【００３８】
図８は、図５でプリフェッチ命令を追加されたソースコードSC_3をベクトル長２でベクトル化した例を示す図である。ソースコードSC_3では、行３６で次回のループのif文の条件文で参照する前回のプリフェッチアドレスlast_prefetchが演算される。
【００３９】
かかるソースコードSC_3をベクトル化すると、SC_3内の行３３の命令a[i*m] = 0は、ベクトル化されたソースコードSC_7内の行７３のように並列化される。即ち、以下のとおりである。
a[i*m:(i+1)*m] = 0
【００４０】
しかし、ソースコードSC_3内の行３４，３５のif文の条件文が前のイタレーションで求めた前回プリフェッチアドレスlast_prefetchの参照を含むので、行３４−３７をベクトル化できない。その結果、コードSC_7では、並列処理ではなく、行７４−７８と行７９−７Ｄのように順次処理するコードのままとなる。これでは、ベクトル化が十分ではない。
【００４１】
［本実施の形態］
次に、本実施の形態におけるストライドアクセスを繰り返すループでのプリフェッチ命令追加処理と、ベクトル化処理について説明する。前述のとおり、コンパイラでの最適化処理において、ストライドアクセスを繰り返す（反復、イタレート）するループに、プリフェッチ命令を追加するとともにベクトル化することが望ましい。
【００４２】
図９は、本実施の形態におけるプリフェッチ命令追加処理で追加されるプリフェッチ命令の一例を説明する図である。図９には、配列ａについて、キャッシュラインサイズＣ＝８バイト、ストライドアクセスのアドレス間隔Ｓ＝３バイト（要素間隔ｍ＝３、要素サイズ（type_size）１バイト）、プリフェッチアドレスｘの例が示されている。プリフェッチアドレスｘの括弧内には、各キャッシュラインの先頭要素（０）からの相対的な要素位置を示す。破線が要素、１バイトの区切りで、実線がキャッシュラインの区切りである。
【００４３】
配列ａの先頭アドレスX1がキャッシュラインの先頭とする。この場合、プリフェッチアドレスｘのキャッシュラインサイズＣに対する剰余（モジュロ）x%Cがストライドアクセスのアドレス間隔abs(Ｓ)より小さいという条件を満たす場合に、プリフェッチ命令prefetch(x)を実行し、満たさない場合は実行しないようにする。こうすれば、冗長なプリフェッチの実行を防止できる。つまり、図9に示すとおり、コンパイラは、プリフェッチアドレスX1−X8が各キャッシュラインサイズＣ（＝８バイト）の先頭から３バイト以内であれば、プリフェッチ命令を実行するようなソースコードに変換する。その場合、キャッシュライン当たり１回のプリフェッチが実行されるようになる。ここで、abs()とは、カッコ内の絶対値の意味である。
【００４４】
図９の例では、アドレスX1、X4、X7だけがプリフェッチ実行の条件、(x%C) ＜ abs(S)、を満たすので、プリフェッチ命令が実行される。そして、if文の条件文、(x%C) ＜ abs(S)、は、他のイタレーションの計算結果を利用しないので、ベクトル化が可能である。
【００４５】
以上の通り、プリフェッチを実行する条件は、Sバイト間隔のストライドアクセスに対して、プリフェッチアドレスｘについて(x%C) ＜ abs(S)を満たす時、アドレスｘが、アドレスｘに対応するキャッシュラインにアクセスするストライドアクセスの中で最も小さなアクセスアドレスとなる。
【００４６】
図１０は、図１のソースコードSC_1にプリフェッチ命令追加処理S3を行って生成されたソースコードSC_8の例を示す図である。ソースコードSC_8は、行８３−８５に以下のif文とプリフェッチ命令が追加される。
if(abs(m*type_size) > &a[(P+i)*m]%C) {
prefetch(&a[(P+i)*m])
}
【００４７】
すなわち、プロセッサは、プリフェッチ命令追加処理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])を実行するコードを追加する。
【００４８】
図１１は、本実施の形態におけるプリフェッチ追加処理のフローチャート図である。図２で説明したとおり、プロセッサは、コンパイラを実行して、事前にソースプログラムの字句解析及び構文解析S1を実行し、ソースプログラム内のループの位置と数、各ループ内のメモリアクセス命令の位置と数を抽出済みである。図１０のソースプログラムSC_1は、ループ数は１つ、ループ内のメモリアクセスは１つである。
【００４９】
プロセッサは、コンパイラのプリフェッチ追加処理を実行して、以下の処理を行う。まず、プロセッサは、ループ番号ｎ１を初期値０に設定し（S11）、ループ番号ｎ１がソースプログラム内のループ数より小さい間(S12のTRUE)、処理S13-S22を繰り返す。プロセッサは、ループ番号ｎ１がループ数と等しくなると（S12のFALSE）、プリフェッチ追加処理を終了する。
【００５０】
次に、プロセッサは、ループ番号ｎ１のループをプリフェッチ追加対象ループLに設定し（S13）、ループLのプリフェッチ距離を変数Pに設定する（S14）。ループ内のプリフェッチ距離Pは、前述したとおり、コンパイルされたプログラムを実行するコンピュータのプロセッサがメインメモリ内のデータをプリフェッチするのに要する時間（メインメモリの読み出しと、キャッシュメモリへのリードデータの格納に要する時間）に対応して設定される、ループのイタレーション回数である。つまり、プリフェッチ距離がPということは、Pイタレーション先でアクセスするデータをメインメモリからプリフェッチすることを意味する。
【００５１】
さらに、プロセッサは、ループL内のメモリアクセス番号ｎ２を初期値０に設定し（S15）、メモリアクセス番号ｎ２がループLのメモリアクセス数未満の間（S16のTRUE）、処理S17-S21を繰り返す。メモリアクセス番号ｎ２がループLのメモリアクセス数と等しくなると（S16のFALSE）、ループ番号ｎ１を＋１だけインクリメントし（S22）、次のループに対する処理に戻る（S12）。
【００５２】
プロセッサは、処理対象のメモリアクセス番号ｎ２について、ループL内のｎ２番目のメモリアクセスを対象メモリアクセスＡに設定し（S17）、さらに、ループ内のアクセスＡのイタレーション間のアドレス間隔をＳに設定する(S18)。つまり、ループLが１イタレーション進んだ時のアクセスのアドレスの差分をSに設定する。プロセッサは、字句解析と構文解析により、ループの開始と終了を例えば分岐命令とその分岐先から認識することができ、さらに、ループ内でメモリアクセスのアドレスの増加量または減少量から、ループ内のアクセスＡのイタレーション間のアドレス間隔をその増加量または減少量と認識することができる。
【００５３】
アドレス間隔Ｓがイタレーションにより変化せず一定の場合(S19のTRUE)、対象メモリアクセスAのPイタレーション先のプリフェッチアドレスをｘとすると、プロセッサは、以下に示す、プリフェッチ実行の条件文を含むif文と、プリフェッチ命令とを追加する（S20）。この追加されるif文とプリフェッチ命令は、前述したものと同じであり、以下のとおりである。
if(abs(S) > &a[(P+i)*m]%C) {
prefetch(&a[(P+i)*m])
}
ここで、S=m*type_size（S：イタレーション間のアドレス間隔、ｍ：イタレーション間の要素間隔、type_size：要素のサイズ）である。つまり、図１０のソースコードSC_8の行８３−８５の追加コードに対応する。
【００５４】
アドレス間隔Ｓがイタレーションにより変化する場合は（S19のFALSE）、本実施の形態による最適化処理の対象外であるので、処理S20を実行せず、次のメモリアクセスを処理対象メモリアクセスAとする（S17）。
【００５５】
そして、プロセッサは、メモリアクセス番号ｎ２をインクリメント（ｎ２＝ｎ２＋１）し（S21）、対象ループL内の次のメモリアクセスについて処理S16-S21を繰り返す。
【００５６】
図１０のソースコードSC_1は、ループ数が１、ループ内のメモリアクセスが１（a[i*m]=0）である。したがって、ソースコードSC_1の場合、図１１のフローチャートでは、プロセッサは、処理S13-S22を一回、処理S16-S21も一回実行する。
【００５７】
ここで、プロセッサは、コンパイラを実行して、上記のif文の条件文のアクセスアドレス&a[(P+i)*m]とキャッシュラインサイズCとの剰余演算&a[(P+i)*m]%Cを、アドレス&a[(P+i)*m]=xと、C-1の各2進数のビットの論理積で演算する演算命令に変形してもよい。
【００５８】
すなわち、キャッシュラインサイズCは通常２冪（べき）、2y=10000000、であるので、C-1は次のとおりとなる。
C-1 = 10000000-1 = 01111111
【００５９】
したがって、アドレスｘ＝10101000の場合、C-1=011111111各ビットの論理積は以下のとおりとなる。
C-1      = 01111111
x        = 10101000
x・(C-1) = 00101000
【００６０】
つまり、論理積x・（C-1）は、アドレスｘの最上位ビット以外の値00101000となり、これは剰余演算x%Cで求めた余りと一致する。
【００６１】
図１２は、本実施の形態におけるベクトル処理の一例を示す図である。図１２には、図１１でプリフェッチ命令が追加されたソースコードSC_8をベクトル化した疑似コードPSC_9が示される。ベクトル化されたコードはソースコードである必要はなく、コンパイラ内部のプログラムコードやアセンブリコードでも良い。図１２には、人間が理解しやすいようにソースコード風の疑似コードPSC_9で示す。
【００６２】
プロセッサは、ベクトル化処理S5を実行して以下の処理を行っている。すなわち、プロセッサは、ベクトル化後の疑似コードPSC_9では、コードSC_8内の行８１のfor文について、行９１のfor文のように、変数ｉのイタレーション毎の増分をベクトル長Ｖに変更する。そして、プロセッサは、コードPSC_9において、行９２に示すとおり、ベクトル長Ｖに対応する変数iの最大値i+V-1を変数ｋに設定する。
【００６３】
さらに、プロセッサは、コードSC_8の行８２のメモリアクセスa[i*m]=0を、図示されるとおり、コードPSC_9の行９３の要素番号i*m〜k*mの要素a[i*m:k*m]に「０」を並列に書き込むベクトル命令に変更する。つまり、行９３のベクトル命令は、以下の通りである。
a[i*m:k*m]=0
このベクトル命令は、配列ａの要素番号i*m〜k*mのＶ個の要素に「０」を並列に書き込む命令である。
【００６４】
そして、プロセッサは、コードPSC_9の行９４のとおり、各プリフェッチアドレス&a[(P+i)*m]〜&a[(P+k)*m]のキャッシュラインサイズＣに対する剰余（フェッチアドレスをキャッシュラインサイズＣで除算した余り）が、ストライドアクセス間のアドレス差分の絶対値abs(m*type_size)より小さいか否かの比較を行い、その比較結果（真：１、偽：０）をマスクの配列mask[0:V-1]のＶ個の要素それぞれ代入するベクトル命令を生成する。
【００６５】
また、プロセッサは、コードPSC_9の行９５のとおり、マスク配列mask[0:V-1]の真の比較結果が代入された要素に対応するアドレスにプリフェッチ命令prefetchを実行するベクトル命令を生成する。但し、マスク配列にプリフェッチ命令の実行の有無を示す値を代入すること以外の方法で、各プリフェッチ命令の実行か否かを判別するようにしてもよい。
【００６６】
図１２において、コードPSC_9には、N/Vの余りのループのコードは省略している。コードPSC_9には、N/Vの余りのループであるINT(N/V)*V+1〜N番目の各ループのif文とそのメモリアクセスa[i*m]=0（コードSC_8の行８３−８４のコード）が追加される。
【００６７】
図１２において、ベクトル化により生成されるベクトル命令は、行９３のストライドアクセスを並列に行う第１のベクトル命令と、行９４のプリフェッチ命令を実行する条件を並列に判定して判定結果をマスク配列の各要素に格納する第２のベクトル命令と、行９５のマスク配列の各要素が真の場合にプリフェッチ命令を実行する第３のベクトル命令とを有する。
【００６８】
以上の通り、本実施の形態によれば、プロセッサが、コンパイラを実行して、ソースプログラム内のメモリ内の配列の複数の要素に対してストライドアクセス命令を反復実行するループのストライドアクセス命令に、プリフェッチ命令のプリフェッチアドレスｘのキャッシュラインサイズCに対する剰余（余り）（ｘ％C）が、ストライドアクセス間アドレス長Sより小さい場合に、実行されるプリフェッチ命令を追加する。これにより、プロセッサは、ストライドアクセス命令とプリフェッチ命令とをベクトル化することができる。その結果、コンパイラの最適化処理により、配列の複数の要素にストライドアクセスを反復実行するループに、プリフェッチ命令を追加しさらにベクトル命令に変換し、コンパイルされたコードの情報処理装置による処理効率を高めることができる。
【符号の説明】
【００６９】
１０：CPU, プロセッサ
L2 CACHE：キャッシュメモリ
MAC：メモリアクセスコントローラ
M_MEM：メインメモリ
２２：コンパイラ
２３：アセンブラ
２４：ソースプログラム
２６：アセンブリコード
２７：オブジェクトコード
a[i*m]：配置aに対するストライドアクセス命令
for()：ループ
ａ：配列
Ｓ：ストライドアクセス間アドレス長（隣接するストライドアクセス間のアドレス間隔）
ｍ：ストライドアクセス間要素長（隣接するストライドアクセス間の要素間隔）
Type_Size：配列の一要素サイズ（S＝ｍ * Type_Size）
ｘ：プリフェッチアドレス
C：キャッシュラインのサイズ
Prefetch：プリフェッチ命令
Last_prefetched：直前のプリフェッチアドレス
【図１】
2019128760.tif 000003
【図２】
2019128760.tif 000004
【図３】
2019128760.tif 000005
【図４】
2019128760.tif 000006
【図５】
2019128760.tif 000007
【図６】
2019128760.tif 000008
【図７】
2019128760.tif 000009
【図８】
2019128760.tif 000010
【図９】
2019128760.tif 000011
【図１０】
2019128760.tif 000012
【図１１】
2019128760.tif 000013
【図１２】
2019128760.tif 000014