(57)【要約】【課題】配列を使用する実行プログラムの実行効率を向上させる。【解決手段】記憶部１１は、可変長配列１５を使用する配列処理１３ａと、配列処理１３ａの開始後に可変長配列１５のサイズを変更するサイズ変更処理１３ｂとが記述されたソースコード１３を記憶する。処理部１２は、可変長配列１５に対応する固定長配列１６を使用する配列処理１３ｃと配列処理１３ａとを選択的に実行させるコード１４ａを生成し、また、コード１４ａの初期状態として配列処理１３ｃが選択されるよう制御するコード１４ｂを生成する。処理部１２は、サイズ変更処理１３ｂが記述された位置に対応させて、固定長配列１６に格納されているデータを可変長配列１５に移動させ、配列処理１３ｃから配列処理１３ａに切り替えられるよう制御するコード１４ｃを生成する。処理部１２は、コード１４ａ，１４ｂ，１４ｃを含む実行プログラム１４を生成する。【選択図】図１
2018092383.tif 000002
【特許請求の範囲】
【請求項１】
コンピュータに、
可変長配列を使用する第１の配列処理と、前記第１の配列処理の開始後に前記可変長配列のサイズを変更するサイズ変更処理とが記述されたソースコードを取得し、
前記第１の配列処理の記述に基づいて、前記可変長配列に対応する固定長配列を使用する第２の配列処理と前記第１の配列処理とを選択的に実行させる第１のコードを生成し、また、前記第１のコードの初期状態として前記第１および第２の配列処理のうち前記第２の配列処理が選択されるよう制御する第２のコードを生成し、
前記サイズ変更処理が記述された位置に対応させて、前記固定長配列に格納されているデータを前記可変長配列に移動させ、前記第１のコードにおいて前記第２の配列処理から前記第１の配列処理に切り替えられるよう制御する第３のコードを生成し、
前記第１、第２および第３のコードを含む実行プログラムを生成する、
処理を実行させるコンパイルプログラム。
【請求項２】
前記第１のコードは、所定のメモリ領域に記憶されたフラグが第１の値のとき前記第１の配列処理を実行させ、前記フラグが第２の値のとき前記第２の配列処理を実行させ、
前記第２のコードは、前記フラグを前記第２の値に設定し、
前記第３のコードは、前記フラグを前記第１の値に変更する、
請求項１記載のコンパイルプログラム。
【請求項３】
前記所定のメモリ領域は、前記可変長配列に割り当てられる他のメモリ領域を基準として所定の相対位置に存在するメモリ領域である、
請求項２記載のコンパイルプログラム。
【請求項４】
前記可変長配列は、少なくとも１つの次元の要素数が可変である可変長多次元配列であり、前記固定長配列は、各次元の要素数が不変である固定長多次元配列である、
請求項１記載のコンパイルプログラム。
【請求項５】
コンピュータが実行するコンパイル方法であって、
可変長配列を使用する第１の配列処理と、前記第１の配列処理の開始後に前記可変長配列のサイズを変更するサイズ変更処理とが記述されたソースコードを取得し、
前記第１の配列処理の記述に基づいて、前記可変長配列に対応する固定長配列を使用する第２の配列処理と前記第１の配列処理とを選択的に実行させる第１のコードを生成し、また、前記第１のコードの初期状態として前記第１および第２の配列処理のうち前記第２の配列処理が選択されるよう制御する第２のコードを生成し、
前記サイズ変更処理が記述された位置に対応させて、前記固定長配列に格納されているデータを前記可変長配列に移動させ、前記第１のコードにおいて前記第２の配列処理から前記第１の配列処理に切り替えられるよう制御する第３のコードを生成し、
前記第１、第２および第３のコードを含む実行プログラムを生成する、
コンパイル方法。
【請求項６】
可変長配列を使用する第１の配列処理と、前記第１の配列処理の開始後に前記可変長配列のサイズを変更するサイズ変更処理とが記述されたソースコードを記憶する記憶部と、
前記第１の配列処理の記述に基づいて、前記可変長配列に対応する固定長配列を使用する第２の配列処理と前記第１の配列処理とを選択的に実行させる第１のコードを生成し、また、前記第１のコードの初期状態として前記第１および第２の配列処理のうち前記第２の配列処理が選択されるよう制御する第２のコードを生成し、前記サイズ変更処理が記述された位置に対応させて、前記固定長配列に格納されているデータを前記可変長配列に移動させ、前記第１のコードにおいて前記第２の配列処理から前記第１の配列処理に切り替えられるよう制御する第３のコードを生成し、前記第１、第２および第３のコードを含む実行プログラムを生成する処理部と、
を有する情報処理装置。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明はコンパイルプログラム、コンパイル方法および情報処理装置に関する。
【背景技術】
【０００２】
ソフトウェア開発においては、人間が理解容易な高級言語を用いてソースコードを作成し、コンパイラを用いてソースコードを機械可読な実行プログラムに変換することが多い。ソースコードでは、複数のデータ要素を体系的に管理するためのデータ構造として配列を使用することがある。配列は頻繁に使用されるデータ構造であるため、プログラム実行環境に用意された標準ライブラリの中で実装されていることがある。
【０００３】
配列の種類として、固定長配列と可変長配列が存在する。固定長配列は、ソースコードの変数宣言において配列サイズを固定することが要求され、演算中に動的に配列サイズを変更することが想定されていない配列である。一方、可変長配列は、変数宣言において配列サイズを固定しなくてもよく、動的に配列サイズを変更可能な配列である。固定長配列と可変長配列では、実行時におけるメモリ領域の管理方法が異なるため、その両方がプログラム実行環境や標準ライブラリなどに実装されていることがある。
【０００４】
なお、ソースコードから分散メモリ型並列計算機用の実行プログラムを生成するコンパイラが提案されている。提案のコンパイラは、ソースコードに現れる一次元配列を、それぞれが連続した区間である複数の部分配列に分割することで多次元化する。コンパイラは、変換された多次元配列に対して自動並列化を行う。
【０００５】
また、配列の入れ子（上位の配列の各要素が下位の配列であるデータ構造）として実装された多次元配列を使用する配列処理方法が提案されている。提案の配列処理方法では、コンパイル時に、最下位の配列が連続したメモリ領域に割り当てられていることを前提として最適化された最適化コードと、そのような最適化を行っていない非最適化コードとを生成しておく。実行時に、更新されたことのある配列にアクセスする場合は非最適化コードを実行し、それ以外の配列にアクセスする場合は最適化コードを実行する。
【０００６】
また、オブジェクト指向プログラミング言語における演算子のオーバーロード機能を利用して、複数のベクトル変数の間の代数演算を簡潔に記述できるようにした代数演算装置が提案されている。提案の代数演算装置は、複数のベクトル変数の間の代数演算の途中で生成される中間ベクトルデータを削減し、オーバヘッドを抑制する。
【０００７】
また、データ構造の１つとして、複数の構造体領域を連結リスト形式でリンクしたリストベクトルを扱うコンパイル装置が提案されている。提案のコンパイル装置は、ループ内で最初に領域確保要求が発行されるタイミングで、所定数の構造体領域が一括してメモリ上の連続領域に確保されるような実行プログラムを生成する。
【先行技術文献】
【特許文献】
【０００８】
【特許文献１】特開２０００−１１２９０１号公報
【特許文献２】特開２０００−２２２２１９号公報
【特許文献３】特開２００７−３２８６９２号公報
【特許文献４】特開２００８−３８８２号公報
【発明の概要】
【発明が解決しようとする課題】
【０００９】
可変長配列は、変数宣言の後に動的に配列サイズを変更することが可能であるため、ソースコードを作成する上で固定長配列より使いやすいという利点がある。一方で、可変長配列を実装した実行プログラムは、実行効率の点で次のような問題がある。
【００１０】
固定長配列は配列サイズが固定であるため、そのデータ要素をメモリ上に密に並べることが容易であり、コンパイルされた実行プログラムは連続したメモリ領域を使用することが多い。これに対し、可変長配列は配列サイズが可変であるため、可変長配列の使い方によっては全てのデータ要素をメモリ上に密に並べることができず、コンパイルされた実行プログラムは不連続なメモリ領域を使用することがある。例えば、列数が可変である可変長二次元配列では、ある行に対応するメモリ領域と次の行に対応するメモリ領域とが不連続になることがある。メモリ領域に連続性がないと、メモリ領域に連続性がある場合よりもキャッシュ効率が低下するなど実行効率が低くなるおそれがある。
【００１１】
１つの側面では、本発明は、配列を使用する実行プログラムの実行効率を向上させるコンパイルプログラム、コンパイル方法および情報処理装置を提供することを目的とする。
【課題を解決するための手段】
【００１２】
１つの態様では、コンピュータに以下の処理を実行させるコンパイルプログラムが提供される。可変長配列を使用する第１の配列処理と、第１の配列処理の開始後に可変長配列のサイズを変更するサイズ変更処理とが記述されたソースコードを取得する。第１の配列処理の記述に基づいて、可変長配列に対応する固定長配列を使用する第２の配列処理と第１の配列処理とを選択的に実行させる第１のコードを生成し、また、第１のコードの初期状態として第１および第２の配列処理のうち第２の配列処理が選択されるよう制御する第２のコードを生成する。サイズ変更処理が記述された位置に対応させて、固定長配列に格納されているデータを可変長配列に移動させ、第１のコードにおいて第２の配列処理から第１の配列処理に切り替えられるよう制御する第３のコードを生成する。第１、第２および第３のコードを含む実行プログラムを生成する。
【００１３】
また、１つの態様では、コンピュータが実行するコンパイル方法が提供される。また、１つの態様では、記憶部と処理部とを有する情報処理装置が提供される。
【発明の効果】
【００１４】
１つの側面では、配列を使用する実行プログラムの実行効率が向上する。
【図面の簡単な説明】
【００１５】
【図１】第１の実施の形態の情報処理装置の例を示す図である。
【図２】コンパイル装置のハードウェア例を示すブロック図である。
【図３】コンパイル装置の機能例を示すブロック図である。
【図４】固定長二次元配列の論理構造とメモリ配置の例を示す図である。
【図５】可変長二次元配列の論理構造とメモリ配置の例を示す図である。
【図６】固定長二次元配列と可変長二次元配列の切り替え例を示す図である。
【図７】第１のオリジナルのソースコード例を示す図である。
【図８】第１の最適化例をソースコード形式で説明する図である。
【図９】第２のオリジナルのソースコード例を示す図である。
【図１０】第２の最適化例をソースコード形式で説明する図である。
【図１１】コンパイルの手順例を示すフローチャートである。
【図１２】二次元配列検索の手順例を示すフローチャートである。
【図１３】フラグ変更処理挿入の手順例を示すフローチャートである。
【発明を実施するための形態】
【００１６】
以下、本実施の形態を図面を参照して説明する。
［第１の実施の形態］
第１の実施の形態を説明する。
【００１７】
図１は、第１の実施の形態の情報処理装置の例を示す図である。
第１の実施の形態の情報処理装置１０は、Ｃ＋＋などの高級言語で記述されたソースコードをコンパイルし、プロセッサに実行させる実行プログラムを生成する。実行プログラムは、例えば、機械可読なオブジェクトコードで記述される。情報処理装置１０をコンパイル装置と言うこともできる。情報処理装置１０は、ソフトウェアとしてのコンパイラを実行するコンピュータであってもよい。また、情報処理装置１０は、ユーザが操作するクライアント装置でもよいし、クライアント装置からアクセスされるサーバ装置でもよい。
【００１８】
情報処理装置１０は、記憶部１１および処理部１２を有する。記憶部１１は、例えば、ＲＡＭ（Random Access Memory）などの揮発性の記憶装置、または、ＨＤＤ（Hard Disk Drive）やフラッシュメモリなどの不揮発性の記憶装置である。処理部１２は、例えば、ＣＰＵ（Central Processing Unit）やＤＳＰ（Digital Signal Processor）などのプロセッサである。ただし、処理部１２は、ＡＳＩＣ（Application Specific Integrated Circuit）やＦＰＧＡ（Field Programmable Gate Array）などの特定用途の電子回路を含んでもよい。プロセッサは、ＲＡＭなどのメモリに記憶されたプログラムを実行する。例えば、プロセッサは、ソースコードをコンパイルするコンパイルプログラムを実行する。複数のプロセッサの集合を「マルチプロセッサ」または「プロセッサ」と呼ぶこともある。
【００１９】
記憶部１１は、ソースコード１３を記憶する。ソースコード１３には、配列処理１３ａ（第１の配列処理）とサイズ変更処理１３ｂとが記述されている。配列処理１３ａでは可変長配列１５が使用される。可変長配列１５は、複数のデータ要素を格納する集合データのうち、格納可能なデータ要素の数（配列長）を変数宣言後に変更できるものである。可変長配列１５は、例えば、標準ライブラリで定義されたｖｅｃｔｏｒなどのデータ型をもつデータである。サイズ変更処理１３ｂは、配列処理１３ａの開始後に可変長配列１５のサイズ（配列長）を変更する処理である。可変長配列１５のサイズの変更は、明示的なサイズの指定や可変長配列１５へのデータ要素の追加などによって発生し得る。
【００２０】
処理部１２は、ソースコード１３を実行プログラム１４に変換する。このとき、処理部１２は、ソースコード１３における配列処理１３ａの記述に基づいてコード１４ａ（第１のコード）を生成する。コード１４ａは、可変長配列１５に対応する固定長配列１６を使用する配列処理１３ｃ（第２の配列処理）と、可変長配列１５を使用する配列処理１３ａとを選択的に実行させる。固定長配列１６は、複数のデータ要素を格納する集合データのうち、格納可能なデータ要素の数を変数宣言後に変更できないものである。固定長配列１６は、例えば、言語仕様で定義されたａｒｒａｙなどのデータ型をもつデータである。コード１４ａは、例えば、フラグがＯＮである（例えば、フラグの値が「１」である）ときは配列処理１３ｃを実行させ、フラグがＯＦＦである（例えば、フラグの値が「０」である）ときは配列処理１３ａを実行させるコードである。
【００２１】
また、処理部１２は、コード１４ａの初期状態として、配列処理１３ａ，１３ｃのうち配列処理１３ｃが選択されるよう制御するコード１４ｂ（第２のコード）を生成する。コード１４ｂは、例えば、コード１４ａの開始前に上記フラグをＯＮに設定するコードである。これにより、コード１４ａの開始直後は、配列処理１３ａ，１３ｃのうち配列処理１３ｃが実行されるようになる。すなわち、複数のデータ要素を格納するデータ構造として固定長配列１６が優先的に使用されることになる。
【００２２】
また、処理部１２は、サイズ変更処理１３ｂが記述された位置に対応させてコード１４ｃ（第３のコード）を生成する。コード１４ｃは、固定長配列１６に格納されているデータ要素を可変長配列１５に移動させると共に、コード１４ａにおいて配列処理１３ｃから配列処理１３ａに切り替えられるよう制御する。コード１４ｃは、例えば、上記フラグをＯＦＦに更新する。サイズ変更処理１３ｂは、例えば、固定長配列１６から可変長配列１５にデータ要素が移動した後に可変長配列１５に対して行われる。コード１４ｃが少なくとも１回実行されると、コード１４ａでは配列処理１３ａ，１３ｃのうち配列処理１３ａが実行されるようになる。すなわち、それ以降は、複数のデータ要素を格納するデータ構造として可変長配列１５が使用されることになる。
【００２３】
そして、処理部１２は、コード１４ａ，１４ｂ，１４ｃを含む実行プログラム１４を生成する。コード１４ａ，１４ｂ，１４ｃは、例えば、上記の処理に対応するオブジェクトコードであり、プロセッサに実行させる命令の集合である。
【００２４】
第１の実施の形態の情報処理装置１０によれば、コンパイル時に、可変長配列１５を使用する配列処理１３ａの記述に基づいて、固定長配列１６を使用する配列処理１３ｃと配列処理１３ａとを選択的に実行させるコード１４ａが生成される。また、初期状態として配列処理１３ｃが選択されるよう制御するコード１４ｂが生成される。また、サイズ変更処理１３ｂの際に、固定長配列１６から可変長配列１５にデータを移動させると共に、以降は配列処理１３ａが選択されるよう制御するコード１４ｃが生成される。
【００２５】
これにより、ソースコード１３において可変長配列１５を使用するよう指定されていても、サイズ変更処理１３ｂが実行される前までは可変長配列１５に代えて固定長配列１６が使用される。固定長配列１６が使用されている限り、メモリ上に複数のデータ要素を密に配置することができ、固定長配列１６に対して連続したメモリ領域が割り当てられる可能性が高い。よって、実行プログラム１４の実行効率が向上する。例えば、固定長配列１６に対して連続メモリ領域が割り当てられることで、キャッシュメモリに一度に格納できるデータ要素の数が多くなり、メモリアクセス効率が向上する。
【００２６】
また、コンパイル時に自動的に可変長配列１５から固定長配列１６に変換される。よって、変数宣言の際に配列サイズを固定しなくてよい可変長配列１５を使ってソースコード１３を作成することができ、ソースコード１３の作成が容易になる。また、サイズ変更処理１３ｂが実行されるときに固定長配列１６から可変長配列１５に戻され、それ以降は可変長配列１５が使用される。よって、ソースコード１３が意図した通りの情報処理を実現することができる。例えば、複数のデータ要素がメモリ上に密に配置された状態で新たなデータ要素を途中に挿入しようとすることによるデータ破壊を防止できる。このように、可能な範囲で可変長配列１５に代えて固定長配列１６を使用することで、安全に実行プログラム１４の実行効率を向上させることができる。
【００２７】
［第２の実施の形態］
次に、第２の実施の形態を説明する。
第２の実施の形態のコンパイル装置１００は、高級言語で記述されたソースコードをコンパイルし、機械可読なオブジェクトコードを生成する。コンパイル装置１００は、ユーザが操作するクライアント装置（端末装置と言うこともある）でもよいし、クライアント装置からアクセスされるサーバ装置でもよい。コンパイル装置１００はコンピュータであり、ソフトウェアとしてのコンパイラおよびリンカを実行する。
【００２８】
図２は、コンパイル装置のハードウェア例を示すブロック図である。
コンパイル装置１００は、ＣＰＵ１０１、ＲＡＭ１０２、ＨＤＤ１０３、画像信号処理部１０４、入力信号処理部１０５、媒体リーダ１０６および通信インタフェース１０７を有する。上記ユニットはバス１０８に接続される。
【００２９】
ＣＰＵ１０１は、プログラムの命令を実行する演算回路を含むプロセッサである。ＣＰＵ１０１は、ＨＤＤ１０３に記憶されたプログラムやデータの少なくとも一部をＲＡＭ１０２にロードし、プログラムを実行する。なお、ＣＰＵ１０１は複数のプロセッサコアを備えてもよく、コンパイル装置１００は複数のプロセッサを備えてもよく、以下で説明する処理を複数のプロセッサまたはプロセッサコアを用いて並列に実行してもよい。複数のプロセッサの集合を「マルチプロセッサ」または「プロセッサ」と言うことがある。
【００３０】
ＲＡＭ１０２は、ＣＰＵ１０１が実行するプログラムやＣＰＵ１０１が演算に用いるデータを一時的に記憶する揮発性の半導体メモリである。なお、コンパイル装置１００は、ＲＡＭ以外の種類のメモリを備えてもよく、複数個のメモリを備えてもよい。
【００３１】
ＨＤＤ１０３は、ＯＳ（Operating System）やミドルウェアやアプリケーションソフトウェアなどのソフトウェアのプログラム、および、データを記憶する不揮発性の記憶装置である。プログラムには、コンパイルプログラムやリンクプログラムが含まれる。なお、コンパイル装置１００は、フラッシュメモリやＳＳＤ（Solid State Drive）などの他の種類の記憶装置を備えてもよく、複数の不揮発性の記憶装置を備えてもよい。
【００３２】
画像信号処理部１０４は、ＣＰＵ１０１からの命令に従って、コンパイル装置１００に接続されたディスプレイ１１１に画像を出力する。ディスプレイ１１１としては、ＣＲＴ（Cathode Ray Tube）ディスプレイ、液晶ディスプレイ（ＬＣＤ：Liquid Crystal Display）、プラズマディスプレイ、有機ＥＬ（ＯＥＬ：Organic Electro-Luminescence）ディスプレイなどを用いることができる。
【００３３】
入力信号処理部１０５は、コンパイル装置１００に接続された入力デバイス１１２から入力信号を取得し、ＣＰＵ１０１に出力する。入力デバイス１１２としては、マウスやタッチパネルやタッチパッドやトラックボールなどのポインティングデバイス、キーボード、リモートコントローラ、ボタンスイッチなどを用いることができる。また、コンパイル装置１００に複数の種類の入力デバイスが接続されていてもよい。
【００３４】
媒体リーダ１０６は、記録媒体１１３に記録されたプログラムやデータを読み取る読み取り装置である。記録媒体１１３として、例えば、磁気ディスク、光ディスク、光磁気ディスク（ＭＯ：Magneto-Optical disk）、半導体メモリなどを使用できる。磁気ディスクには、フレキシブルディスク（ＦＤ：Flexible Disk）やＨＤＤが含まれる。光ディスクには、ＣＤ（Compact Disc）やＤＶＤ（Digital Versatile Disc）が含まれる。
【００３５】
媒体リーダ１０６は、例えば、記録媒体１１３から読み取ったプログラムやデータを、ＲＡＭ１０２やＨＤＤ１０３などの他の記録媒体にコピーする。読み取られたプログラムは、例えば、ＣＰＵ１０１によって実行される。なお、記録媒体１１３は可搬型記録媒体であってもよく、プログラムやデータの配布に用いられることがある。また、記録媒体１１３やＨＤＤ１０３を、コンピュータ読み取り可能な記録媒体と言うことがある。
【００３６】
通信インタフェース１０７は、ネットワーク１１４に接続され、ネットワーク１１４を介して他のコンピュータと通信を行うインタフェースである。通信インタフェース１０７は、スイッチなどの通信装置とケーブルで接続される有線通信インタフェースでもよいし、基地局と無線リンクで接続される無線通信インタフェースでもよい。
【００３７】
なお、コンパイル装置１００は、第１の実施の形態の情報処理装置１０に対応する。ＲＡＭ１０２またはＨＤＤ１０３は、第２の実施の形態の記憶部１１に対応する。ＣＰＵ１０１は、第１の実施の形態の処理部１２に対応する。
【００３８】
図３は、コンパイル装置の機能例を示すブロック図である。
コンパイル装置１００は、ファイル記憶部１２０、コンパイラ１３０およびリンカ１４０を有する。ファイル記憶部１２０は、例えば、ＲＡＭ１０２またはＨＤＤ１０３に確保した記憶領域を用いて実装される。コンパイラ１３０およびリンカ１４０は、例えば、ＣＰＵ１０１が実行するプログラムモジュール（コンパイルプログラムおよびリンクプログラム）を用いて実装される。ただし、コンパイラ１３０およびリンカ１４０の機能の一部または全部を、ソフトウェアでなく電子回路として実装することも可能である。
【００３９】
ファイル記憶部１２０は、ソースファイル１２１、オブジェクトファイル１２２および実行ファイル１２３を記憶する。ソースファイル１２１は、Ｃ＋＋などの高級言語で記述されたソースコードを含む。オブジェクトファイル１２２は、機械可読なオブジェクトコードを含む。実行ファイル１２３は、ターゲットのプロセッサが実行できる形式のファイルであり、生成されたオブジェクトコードとライブラリなどへのリンクを含む。なお、実行ファイル１２３は、ＣＰＵ１０１が実行してもよいし、コンパイル装置１００が備える他のＣＰＵまたはコンパイル装置１００以外のコンピュータのＣＰＵが実行してもよい。
【００４０】
コンパイラ１３０は、ファイル記憶部１２０からソースファイル１２１を読み出し、ソースコードをオブジェクトコードに変換し、オブジェクトファイル１２２をファイル記憶部１２０に格納する。コンパイラ１３０は、入出力制御部１３１、ファイル入力部１３２、中間コード生成部１３３、中間コード記憶部１３４、最適化部１３５、アセンブリコード生成部１３８およびファイル出力部１３９を有する。
【００４１】
入出力制御部１３１は、ファイルの種類に応じた入出力方法を選択し、ファイル入力部１３２およびファイル出力部１３９を制御する。ファイル入力部１３２は、入出力制御部１３１からの指示に応じて、ソースファイル１２１をオープンし、ソースファイル１２１からソースコードを読み出す。中間コード生成部１３３は、ファイル入力部１３２が読み出したソースコードを解析して、コンパイラ１３０の内部で利用される中間言語で記述された中間コードに変換し、中間コードを中間コード記憶部１３４に格納する。ソースコードの解析には、字句解析、構文解析、意味解析などが含まれる。中間コード記憶部１３４は、ＲＡＭ１０２に確保された記憶領域であり、中間コードを記憶する。
【００４２】
最適化部１３５は、中間コード記憶部１３４に記憶された中間コードを、実行速度が向上するように最適化する。最適化部１３５は、解析部１３６および最適化実行部１３７を有する。解析部１３６は、中間コードを解析して最適化方法を決定する。このとき、解析部１３６は、プログラムモジュール間の呼び出し関係を表す呼び出し関係グラフ（ｃａｌｌｅｒ−ｃａｌｌｅｅグラフ）を参照する。呼び出し関係グラフは、後述するリンク時最適化（ＬＴＯ：Link Time Optimization）によって生成される。最適化実行部１３７は、解析部１３６が決定した最適化方法に従って中間コードを最適化する。最適化部１３５で行われる最適化には、可変長配列を利用する配列処理の最適化が含まれる。
【００４３】
アセンブリコード生成部１３８は、最適化部１３５によって最適化された中間コードを、低級言語であるアセンブリ言語で記述されたアセンブリコードに変換する。ファイル出力部１３９は、入出力制御部１３１からの指示に応じて、オブジェクトファイル１２２を生成し、アセンブリコード生成部１３８が生成したアセンブリコードをオブジェクトコードに変換し、オブジェクトコードをオブジェクトファイル１２２に書き込む。
【００４４】
リンカ１４０は、ファイル記憶部１２０からオブジェクトファイル１２２を読み出し、オブジェクトコードを解析して、参照されている他のオブジェクトファイルやライブラリを検出する。そして、リンカ１４０は、オブジェクトファイル１２２と、検出した他のオブジェクトファイルやライブラリとをリンクし、実行ファイル１２３を生成する。なお、コンパイラ１３０にリンカ１４０の機能が統合されていてもよい。
【００４５】
ここで、リンカ１４０は、コンパイル単位（翻訳単位）であるプログラムモジュールを超えた呼び出し関係を検出することができる。そこで、リンク時最適化では、リンカ１４０は、複数のプログラムモジュールの間の呼び出し関係を表す呼び出し関係グラフを生成し、呼び出し関係グラフをコンパイラ１３０にフィードバックする。
【００４６】
リンク時最適化では、ソースコードをオブジェクトコードに変換するコンパイルとオブジェクトコードのリンクとが２回繰り返される（２パス処理）。１パス目では、コンパイラ１３０は、コンパイル単位を超えた呼び出し関係を考慮せずに最適化を行い、コンパイル単位毎のオブジェクトコードを生成する。リンカ１４０は、それらオブジェクトコードをリンクすると共に呼び出し関係グラフを生成する。２パス目では、コンパイラ１３０は、コンパイル単位を超えた呼び出し関係を考慮して最適化を行い、再度オブジェクトコードを生成する。リンカ１４０は、再生成されたオブジェクトコードをリンクして実行ファイル１２３を生成する。２パス目においてコンパイラ１３０は、呼び出し先モジュールの処理内容を参照して呼び出し先モジュールを最適化することができる。
【００４７】
次に、データ構造としての二次元配列について説明する。
ソースコードには二次元配列が記述されることがある。特に、科学技術計算に用いるソースコードでは、大規模な二次元配列が記述されることがある。二次元配列は、同一種類の複数の単位データ（例えば、整数や浮動小数点型実数など）を体系的に格納するデータ構造であって、行番号と列番号によって各単位データを指定できるものである。二次元配列には、行数および列数が変数宣言時に固定される固定長二次元配列と、行数および列数を変数宣言後に変えることができる可変長二次元配列とが存在する。固定長二次元配列の典型例は、プログラミング言語の仕様で定義されているａｒｒａｙ型二次元配列である。可変長二次元配列の典型例は、ｖｅｃｔｏｒライブラリを利用して作成するｖｅｃｔｏｒ型二次元配列である。固定長二次元配列と可変長二次元配列とでは、ソースコードの記述方法やオブジェクトコード実行時のメモリ領域の使用方法が異なる。
【００４８】
図４は、固定長二次元配列の論理構造とメモリ配置の例を示す図である。
ソースコード１５１は、３行３列の固定長二次元配列ａｒｒａｙ＿ｍａｔを宣言している。ａｒｒａｙ＿ｍａｔの要素のデータ型は整数型である。ソースコード１５１に記述された固定長二次元配列は、論理構造１６１に対応する。論理構造１６１は、行番号０〜２および列番号０〜２によって特定される３行３列の行列である。（０，０）には整数＃１が格納される。（０，１）には整数＃２が格納される。（０，２）には整数＃３が格納される。（１，０）には整数＃４が格納される。（１，１）には整数＃５が格納される。（１，２）には整数＃６が格納される。（２，０）には整数＃７が格納される。（２，１）には整数＃８が格納される。（２，２）には整数＃９が格納される。
【００４９】
ソースコード１５１をコンパイルして生成したオブジェクトコードを実行すると、多くの場合、メモリにａｒｒａｙ＿ｍａｔ領域１７１が確保される。ａｒｒａｙ＿ｍａｔ領域１７１は、固定長二次元配列の要素の個数に相当する長さをもつ連続領域である。ａｒｒａｙ＿ｍａｔ領域１７１には、整数＃１〜＃９が連続して密に格納される。すなわち、整数＃１の直後に整数＃２が格納される。整数＃２の直後に整数＃３が格納される。整数＃３の直後に整数＃４が格納される。整数＃４の直後に整数＃５が格納される。整数＃５の直後に整数＃６が格納される。整数＃６の直後に整数＃７が格納される。整数＃７の直後に整数＃８が格納される。整数＃８の直後に整数＃９が格納される。
【００５０】
このように、行番号＝０の行の末尾にある整数＃３の後に、間隔を空けずに行番号＝１の行の先頭にある整数＃４が格納される。また、行番号＝１の行の末尾にある整数＃６の後に、間隔を空けずに行番号＝２の行の先頭にある整数＃７が格納される。固定長二次元配列では行数や列数が固定であるため、要素を密に配置できる。
【００５１】
図５は、可変長二次元配列の論理構造とメモリ配置の例を示す図である。
ソースコード１５２は、可変長二次元配列ｖｅｃ＿ｍａｔを宣言している。ｖｅｃ＿ｍａｔは、プログラミング言語の仕様で用意された標準ライブラリの中のｖｅｃｔｏｒライブラリを利用して作成されたｖｅｃｔｏｒ型二次元配列である。ｖｅｃｔｏｒライブラリによって定義されたｖｅｃｔｏｒ型配列は一次元配列であるが、ｖｅｃｔｏｒ型配列の要素にｖｅｃｔｏｒ型配列を代入することで二次元配列を作成することができる。
【００５２】
ここでは、ソースコード１５２は、ｖｅｃｔｏｒ型配列ｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３を宣言している。ｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３の要素のデータ型は整数型である。ｖｅｃ＿ｘ１には整数＃１〜＃３が挿入される。ｖｅｃ＿ｘ２には整数＃４〜＃６が挿入される。ｖｅｃ＿ｘ３には整数＃７〜＃９が挿入される。ｖｅｃ＿ｍａｔの要素のデータ型はｖｅｃｔｏｒである。ｖｅｃ＿ｍａｔにはｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３が挿入される。これにより、３行３列の二次元配列を作成できる。また、変数宣言後に行数や列数を変更することができる。例えば、ｖｅｃ＿ｍａｔに別のｖｅｃｔｏｒ型配列を挿入することで行数を増やすことができ、ｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３に更に整数を挿入することで列数を増やすことができる。
【００５３】
ソースコード１５２に記述された可変長二次元配列は、論理構造１６２に対応する。論理構造１６２は、ｖｅｃ＿ｘ１である一次元配列と、ｖｅｃ＿ｘ２である一次元配列と、ｖｅｃ＿ｘ３である一次元配列と、ｖｅｃ＿ｍａｔである一次元配列とを含む。ｖｅｃ＿ｍａｔは、ｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３の先頭を指すインデックスに相当する。ｖｅｃ＿ｍａｔの第０要素はｖｅｃ＿ｘ１を指し、ｖｅｃ＿ｍａｔの第１要素はｖｅｃ＿ｘ２を指し、ｖｅｃ＿ｍａｔの第２要素はｖｅｃ＿ｘ３を指している。論理構造１６２は、実質的に論理構造１６１と同様の二次元配列として使用できる。ｖｅｃ＿ｍａｔの要素番号０〜２が二次元配列の行番号に相当し、ｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３それぞれの要素番号０〜２が二次元配列の列番号に相当する。
【００５４】
ソースコード１５２をコンパイルして生成したオブジェクトコードを実行すると、例えば、メモリに以下の８個の領域が確保される。ｖｅｃ＿ｍａｔに関して、ｖｅｃ＿ｍａｔ管理領域１７２ａおよびｖｅｃ＿ｍａｔ実体領域１７２ｂが確保される。ｖｅｃ＿ｘ１に関して、ｖｅｃ＿ｘ１管理領域１７２ｃおよびｖｅｃ＿ｘ１実体領域１７２ｆが確保される。ｖｅｃ＿ｘ２に関して、ｖｅｃ＿ｘ２管理領域１７２ｄおよびｖｅｃ＿ｘ２実体領域１７２ｇが確保される。ｖｅｃ＿ｘ３に関して、ｖｅｃ＿ｘ３管理領域１７２ｅおよびｖｅｃ＿ｘ３実体領域１７２ｈが確保される。これら８個の領域それぞれは連続したメモリ領域であるが、異なる領域の間では連続性は保証されない。例えば、ｖｅｃ＿ｘ１実体領域１７２ｆとｖｅｃ＿ｘ２実体領域１７２ｇとの間では連続性は保証されない。
【００５５】
ｖｅｃ＿ｍａｔ管理領域１７２ａは、ｖｅｃ＿ｍａｔ実体領域１７２ｂへのアクセスを容易にするための情報を格納する。ｖｅｃ＿ｍａｔ管理領域１７２ａは、少なくともｖｅｃ＿ｍａｔ実体領域１７２ｂの先頭要素を指すポインタとｖｅｃ＿ｍａｔ実体領域１７２ｂの末尾要素を指すポインタとを格納する。
【００５６】
ｖｅｃ＿ｍａｔ実体領域１７２ｂは、ｖｅｃ＿ｍａｔの要素である実体データを格納する。ただし、ここではｖｅｃ＿ｍａｔの要素がｖｅｃｔｏｒ型配列であるため、ｖｅｃ＿ｍａｔ実体領域１７２ｂはこれらｖｅｃｔｏｒ型配列へのポインタを格納する。具体的には、ｖｅｃ＿ｍａｔ実体領域１７２ｂは、ｖｅｃ＿ｘ１管理領域１７２ｃの先頭要素を指すポインタと、ｖｅｃ＿ｘ２管理領域１７２ｄの先頭要素を指すポインタと、ｖｅｃ＿ｘ３管理領域１７２ｅの先頭要素を指すポインタとを格納する。
【００５７】
ｖｅｃ＿ｘ１管理領域１７２ｃは、ｖｅｃ＿ｘ１実体領域１７２ｆへのアクセスを容易にするための情報を格納する。ｖｅｃ＿ｘ１管理領域１７２ｃは、少なくともｖｅｃ＿ｘ１実体領域１７２ｆの先頭要素を指すポインタとｖｅｃ＿ｘ１実体領域１７２ｆの末尾要素を指すポインタとを格納する。
【００５８】
同様に、ｖｅｃ＿ｘ２管理領域１７２ｄは、ｖｅｃ＿ｘ２実体領域１７２ｇへのアクセスを容易にするための情報を格納する。ｖｅｃ＿ｘ２管理領域１７２ｄは、少なくともｖｅｃ＿ｘ２実体領域１７２ｇの先頭要素を指すポインタとｖｅｃ＿ｘ２実体領域１７２ｇの末尾要素を指すポインタとを格納する。また、ｖｅｃ＿ｘ３管理領域１７２ｅは、ｖｅｃ＿ｘ３実体領域１７２ｈへのアクセスを容易にするための情報を格納する。ｖｅｃ＿ｘ３管理領域１７２ｅは、少なくともｖｅｃ＿ｘ３実体領域１７２ｈの先頭要素を指すポインタとｖｅｃ＿ｘ３実体領域１７２ｈの末尾要素を指すポインタとを格納する。
【００５９】
ｖｅｃ＿ｘ１実体領域１７２ｆは、ｖｅｃ＿ｘ１の要素である実体データを格納する。ｖｅｃ＿ｘ１実体領域１７２ｆはｖｅｃ＿ｘ１の要素の個数に相当する長さをもつ連続領域であり、複数の要素が間隔を空けずに密に配置される。ここでは、ｖｅｃ＿ｘ１実体領域１７２ｆは整数＃１〜＃３を格納する。整数＃１の直後に整数＃２が格納され、整数＃２の直後に整数＃３が格納されることになる。
【００６０】
同様に、ｖｅｃ＿ｘ２実体領域１７２ｇは、ｖｅｃ＿ｘ２の要素である実体データを格納する。ｖｅｃ＿ｘ２実体領域１７２ｇはｖｅｃ＿ｘ２の要素の個数に相当する長さをもつ連続領域であり、複数の要素が間隔を空けずに密に配置される。ここでは、ｖｅｃ＿ｘ２実体領域１７２ｇは整数＃４〜＃６を格納する。整数＃４の直後に整数＃５が格納され、整数＃５の直後に整数＃６が格納される。また、ｖｅｃ＿ｘ３実体領域１７２ｈは、ｖｅｃ＿ｘ３の要素である実体データを格納する。ｖｅｃ＿ｘ３実体領域１７２ｈはｖｅｃ＿ｘ３の要素の個数に相当する長さをもつ連続領域であり、複数の要素が間隔を空けずに密に配置される。ここでは、ｖｅｃ＿ｘ３実体領域１７２ｈは整数＃７〜＃９を格納する。整数＃７の直後に整数＃８が格納され、整数＃８の直後に整数＃９が格納される。
【００６１】
このように、ｖｅｃ＿ｍａｔ管理領域１７２ａから整数＃１〜＃９に到達するまでに何回もポインタを辿ることになる。また、行番号＝０の行の末尾にある整数＃３と行番号＝１の行の先頭にある整数＃４とが不連続に格納され、行番号＝１の行の末尾にある整数＃６と行番号＝２の行の先頭にある整数＃７とが不連続に格納される。可変長二次元配列では行数や列数が可変であるため、行数や列数が増える場合に備えて要素を密に配置することが難しい。その結果、メモリアクセス回数が増加し、また、ある行の要素と次の行の要素を纏めてキャッシュメモリに読み込むことが難しくなりキャッシュ効率が低下する。よって、固定長二次元配列と比べて実行効率が低くなるおそれがある。
【００６２】
ここで、固定長二次元配列を用いると変数宣言時に行数や列数を固定するのに対し、可変長配列を用いると変数宣言時には行数や列数を固定しなくてよく、ソースコード作成が容易になる。よって、コンパイル装置１００がコンパイルするソースコードに、ｖｅｃｔｏｒ型二次元配列などの可変長二次元配列が記述されていることがある。しかし、そのようなソースコードを単純にコンパイルすると、上記のように固定長二次元配列を用いた場合と比べて実行効率の低いオブジェクトコードが生成されてしまう。
【００６３】
そこで、コンパイル装置１００は、コンパイル中の最適化において、所定条件を満たす可変長二次元配列を固定長二次元配列に自動的に置換し、生成されるオブジェクトコードの実行効率を向上させる。ただし、可変長二次元配列のサイズを事後的に変更させる命令が存在する場合、その命令が実行されるとデータが破壊される可能性がある。
【００６４】
例えば、図５に示したメモリ配置では、列数を増やしてｖｅｃ＿ｘ１の末尾に整数を追加する場合、ｖｅｃ＿ｘ１実体領域１７２ｆの整数＃３の次に新たな整数を格納し、ｖｅｃ＿ｘ１管理領域１７２ｃのポインタを更新すればよい。ｖｅｃ＿ｘ１実体領域１７２ｆとｖｅｃ＿ｘ２実体領域１７２ｇとは不連続であるため、新たな整数の挿入によってｖｅｃ＿ｘ２実体領域１７２ｇの整数＃４は破壊されない。これに対し、図４に示したメモリ配置では、ａｒｒａｙ＿ｍａｔ領域１７１の整数＃３の直後に整数＃４が格納されている。よって、このまま列数を増やしてａｒｒａｙ＿ｍａｔ［０］［３］に整数を代入しようとすると、整数＃３の直後にある整数＃４が上書き消去されてしまう。
【００６５】
そこで、コンパイル装置１００は、最初は可変長二次元配列に代えて固定長二次元配列を使用し、サイズを変更させる命令が実行される直前で固定長二次元配列から可変長二次元配列に戻すようなオブジェクトコードを生成する。これにより、可変長二次元配列の特徴である事後的なサイズ変更を許容しつつ、サイズ変更の前まではできる限り固定長二次元配列を使用させてオブジェクトコードの実行効率を向上させることができる。
【００６６】
図６は、固定長二次元配列と可変長二次元配列の切り替え例を示す図である。
コンパイル装置１００は、次のような動作を行うオブジェクトコードを生成する。
ソースコード１５２に記述されたｖｅｃｔｏｒ型二次元配列に対して、最初はメモリに以下の６個の領域が確保される。図５と同様、ｖｅｃ＿ｍａｔ実体領域１７２ｂ、ｖｅｃ＿ｘ１管理領域１７２ｃ、ｖｅｃ＿ｘ２管理領域１７２ｄおよびｖｅｃ＿ｘ３管理領域１７２ｅが確保される。また、ｖｅｃ＿ｍａｔ管理領域１７３およびｍａｔｒｉｘ領域１７４が確保される。ｖｅｃ＿ｘ１実体領域１７２ｆ、ｖｅｃ＿ｘ２実体領域１７２ｇおよびｖｅｃ＿ｘ３実体領域１７２ｈは、最初は確保しなくてよい。
【００６７】
ｖｅｃ＿ｍａｔ管理領域１７３は、ｖｅｃ＿ｍａｔに関する基準位置からメモリアドレスが増加する方向（正方向）に、図５のｖｅｃ＿ｍａｔ管理領域１７２ａと同様のポインタを格納する。すなわち、ｖｅｃ＿ｍａｔ管理領域１７３は、ｖｅｃ＿ｍａｔ実体領域１７２ｂの先頭要素を指すポインタと末尾要素を指すポインタとを格納する。
【００６８】
また、ｖｅｃ＿ｍａｔ管理領域１７３は、ｖｅｃ＿ｍａｔに関する基準位置からメモリアドレスが減少する方向（負方向）に、ｍａｔｒｉｘフラグおよびｍａｔｒｉｘポインタを格納する。ｍａｔｒｉｘフラグは、ｍａｔｒｉｘ領域１７４が使用されているか否かを示すフラグである。ｍａｔｒｉｘフラグがＯＮである（値が「１」である）ことは、ｍａｔｒｉｘ領域１７４が使用されていることを示す。ｍａｔｒｉｘフラグがＯＦＦである（値が「０」である）ことは、ｍａｔｒｉｘ領域１７４が使用されていないことを示す。ｍａｔｒｉｘフラグの初期値はＯＮ（「１」）である。ｍａｔｒｉｘポインタは、ｍａｔｒｉｘ領域１７４の先頭要素を指すポインタである。
【００６９】
ｍａｔｒｉｘ領域１７４は、図４のａｒｒａｙ＿ｍａｔ領域１７１に相当する記憶領域である。ｍａｔｒｉｘ領域１７４は、複数の単位データをａｒｒａｙ型二次元配列（固定長二次元配列）の形式で格納する。よって、ｍａｔｒｉｘ領域１７４は、二次元配列の行数×列数に相当する長さをもち、それら単位データを密に格納する。ｖｅｃ＿ｍａｔ管理領域１７３のｍａｔｒｉｘフラグがＯＮである間、ｖｅｃ＿ｍａｔ管理領域１７３のｍａｔｒｉｘポインタおよびｍａｔｒｉｘ領域１７４が使用される。この間、ｖｅｃ＿ｍａｔ実体領域１７２ｂ、ｖｅｃ＿ｘ１管理領域１７２ｃ、ｖｅｃ＿ｘ２管理領域１７２ｄおよびｖｅｃ＿ｘ３管理領域１７２ｅは、確保されているものの使用されない。二次元配列の初期値はｍａｔｒｉｘ領域１７４に書き込まれる。また、サイズが変更されない限り、単位データの参照や更新はｍａｔｒｉｘ領域１７４に対して行われる。
【００７０】
その後、二次元配列のサイズが変わる命令（例えば、ｖｅｃ＿ｘ１の末尾に整数を挿入することで列数が増える命令）に到達すると、その命令の実行前にｖｅｃ＿ｍａｔ管理領域１７３のｍａｔｒｉｘフラグがＯＦＦに書き換えられる。また、メモリにｖｅｃ＿ｘ１実体領域１７２ｆ、ｖｅｃ＿ｘ２実体領域１７２ｇおよびｖｅｃ＿ｘ３実体領域１７２ｈが確保される。そして、ｍａｔｒｉｘ領域１７４からｖｅｃ＿ｘ１実体領域１７２ｆ、ｖｅｃ＿ｘ２実体領域１７２ｇおよびｖｅｃ＿ｘ３実体領域１７２ｈに単位データがコピーされ、メモリからｍａｔｒｉｘ領域１７４が削除される。
【００７１】
ｖｅｃ＿ｍａｔ管理領域１７３のｍａｔｒｉｘフラグがＯＦＦになると、それ以降はｖｅｃ＿ｍａｔ実体領域１７２ｂ、ｖｅｃ＿ｘ１管理領域１７２ｃ、ｖｅｃ＿ｘ２管理領域１７２ｄおよびｖｅｃ＿ｘ３管理領域１７２ｅが使用される。また、ｖｅｃ＿ｘ１実体領域１７２ｆ、ｖｅｃ＿ｘ２実体領域１７２ｇおよびｖｅｃ＿ｘ３実体領域１７２ｈが使用される。単位データの参照や更新、二次元配列のサイズ変更は、ｖｅｃ＿ｘ１実体領域１７２ｆ、ｖｅｃ＿ｘ２実体領域１７２ｇおよびｖｅｃ＿ｘ３実体領域１７２ｈに対して行われる。よって、サイズが変わる命令を実行してもデータは破壊されない。
【００７２】
次に、コンパイル装置１００による最適化の例を、ソースコードを用いて説明する。なお、以下では説明を簡単にするためにソースコード形式で変換例を説明するが、実際にはコンパイル装置１００は中間コードに対して最適化を行う。
【００７３】
図７は、第１のオリジナルのソースコード例を示す図である。
ソースコード１５３は、ユーザによって記述されたオリジナルのソースコードであり、最適化前の処理手順を示している。ソースコード１５３は、ｖｅｃｔｏｒライブラリをｉｎｃｌｕｄｅすることでｖｅｃｔｏｒライブラリを参照している。ソースコード１５３は、整数を格納可能なｖｅｃｔｏｒ型配列ｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３を宣言している。また、ソースコード１５３は、整数を格納可能なｖｅｃｔｏｒ型配列を要素とするｖｅｃｔｏｒ型配列ｖｅｃ＿ｍａｔを宣言している。
【００７４】
ソースコード１５３では、ｆｏｒ文によってｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３に初期値が格納される。「１」がｖｅｃ＿ｘ１に挿入され、「４」がｖｅｃ＿ｘ２に挿入され、「７」がｖｅｃ＿ｘ３に挿入される。また、「２」がｖｅｃ＿ｘ１に挿入され、「５」がｖｅｃ＿ｘ２に挿入され、「８」がｖｅｃ＿ｘ３に挿入される。また、「３」がｖｅｃ＿ｘ１に挿入され、「６」がｖｅｃ＿ｘ２に挿入され、「９」がｖｅｃ＿ｘ３に挿入される。そして、ｖｅｃ＿ｍａｔに、ｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３が順に挿入される。これにより、ｖｅｃｔｏｒ型二次元配列が初期化される。
【００７５】
その後、ソースコード１５３では、ｆｏｒ文によってｖｅｃ＿ｍａｔを使用した配列演算が行われる。ｖｅｃ＿ｍａｔに格納された９個の整数は、行番号ｉと列番号ｊを指定することで参照できる。ｉ＝０はｖｅｃ＿ｘ１を示し、ｉ＝１はｖｅｃ＿ｘ２を示し、ｉ＝２はｖｅｃ＿ｘ３を示している。また、ｊ＝０〜２はｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３それぞれの中での要素番号を示している。ここでは、上記の９個の初期値を足し合わせた結果を変数ａｎｓｗｅｒとして出力している。
【００７６】
図８は、第１の最適化例をソースコード形式で説明する図である。
ソースコード１５４は、前述のソースコード１５３を最適化した後の処理手順を示している。ソースコード１５４は、ｖｅｃ＿ｘ１，ｖｅｃ＿ｘ２，ｖｅｃ＿ｘ３，ｖｅｃ＿ｍａｔに加えて、ａｒｒａｙ型二次元配列ｍａｔｒｉｘを宣言している。ｍａｔｒｉｘの行数および列数は、ソースコード１５３の記載からｖｅｃｔｏｒ型二次元配列ｖｅｃ＿ｍａｔに初期値を格納する処理を静的に解析することで決定することができる。
【００７７】
ソースコード１５４では、ｖｅｃ＿ｍａｔに初期値を格納する代わりにｍａｔｒｉｘに初期値が格納される。最初はｖｅｃ＿ｍａｔは使用されないため、ｖｅｃ＿ｍａｔに初期値を格納しなくてよい。また、ｍａｔｒｉｘに初期値を格納するときに、ｍａｔｒｉｘフラグがＯＮに初期化される。また、ｍａｔｒｉｘに初期値を格納するときに、ｖｅｃ＿ｍａｔのメモリ領域が確保される。すなわち、ソースコード１５４では、ｍａｔｒｉｘの宣言が挿入され、ｖｅｃ＿ｍａｔに初期値を格納する処理がｍａｔｒｉｘに初期値を格納する処理に置換されている。また、ｍａｔｒｉｘフラグをＯＮに初期化する処理とｖｅｃ＿ｍａｔのメモリ領域を確保する処理とが挿入されている。
【００７８】
また、ソースコード１５４では、ｖｅｃ＿ｍａｔを使用した配列演算に加えてｍａｔｒｉｘを使用した配列演算が挿入されている。ｍａｔｒｉｘに格納された９個の整数は、行番号ｉと列番号ｊを指定することで参照できる。ｍａｔｒｉｘを使用した配列演算は、ｖｅｃ＿ｍａｔを使用した配列演算と同様に、９個の初期値を足し合わせた結果を変数ａｎｓｗｅｒとして出力するものである。そして、ソースコード１５４では、ｖｅｃ＿ｍａｔを使用した配列演算とｍａｔｒｉｘを使用した配列演算とを、ｍａｔｒｉｘフラグ（ｍａｔｒｉｘ＿ｆｌｇ）に応じて選択する制御構造が挿入されている。ｍａｔｒｉｘフラグがＯＮである場合はｍａｔｒｉｘを使用した配列演算が選択され、ｍａｔｒｉｘフラグがＯＦＦである場合はｖｅｃ＿ｍａｔを使用した配列演算が選択される。
【００７９】
図９は、第２のオリジナルのソースコード例を示す図である。
ソースコード１５５，１５６は、ユーザによって記述されたオリジナルのソースコードであり、最適化前の処理手順を示している。ソースコード１５５は、図７に示したソースコード１５３とは異なる関数に含まれるものであり、ソースコード１５３と同じソースファイルに記載されてもよいし異なるソースファイルに記載されてもよい。ソースコード１５６は、ソースコード１５５から呼び出されるものであり、ソースコード１５５と同じソースファイルに記載されてもよいし異なるソースファイルに記載されてもよい。
【００８０】
ソースコード１５５は、ｖｅｃｔｏｒライブラリをｉｎｃｌｕｄｅすることでｖｅｃｔｏｒライブラリを参照している。ソースコード１５５は、ソースコード１５３で宣言されたｖｅｃｔｏｒ型二次元配列ｖｅｃ＿ｍａｔを使用している。ソースコード１５５では、ある条件が満たされた場合にｖｅｃ＿ｍａｔの行数が変更される。行数の変更には、ｖｅｃｔｏｒライブラリで定義されたライブラリ関数である関数ｒｅｓｉｚｅ（）が使用される。また、別の分岐条件が満たされた場合に、ユーザ定義の関数ｃａｌｌ＿ｒｅｓｉｚｅ（）が呼び出される。このとき、ｖｅｃ＿ｍａｔが引数として渡される。
【００８１】
ソースコード１５６は、ｖｅｃｔｏｒライブラリをｉｎｃｌｕｄｅすることでｖｅｃｔｏｒライブラリを参照している。ソースコード１５６は、ユーザ定義の関数ｃａｌｌ＿ｒｅｓｉｚｅ（）を含む。ソースコード１５６では、ｃａｌｌ＿ｒｅｓｉｚｅ（）が呼び出されたときに参照渡しによって引数としてｖｅｃ＿ｍａｔが取得される。ｃａｌｌ＿ｒｅｓｉｚｅ（）の中では、ｖｅｃ＿ｍａｔの行数が変更される。行数の変更には、ｖｅｃｔｏｒライブラリで定義されたライブラリ関数である関数ｒｅｓｉｚｅ（）が使用される。
【００８２】
この場合、ソースコード１５５では、ｖｅｃ＿ｍａｔの行数を変更するライブラリ関数であるｒｅｓｉｚｅ（）が呼び出される可能性がある。ただし、ある条件が満たされない限りｒｅｓｉｚｅ（）は呼び出されず、ｒｅｓｉｚｅ（）が呼び出されるタイミングは静的には確定しない。また、ソースコード１５５では、ｖｅｃ＿ｍａｔの行数を変更するユーザ定義関数であるｃａｌｌ＿ｒｅｓｉｚｅ（）が呼び出される可能性がある。ただし、ある条件が満たされない限りｃａｌｌ＿ｒｅｓｉｚｅ（）は呼び出されず、ｃａｌｌ＿ｒｅｓｉｚｅ（）が呼び出されるタイミングは静的には確定しない。
【００８３】
図１０は、第２の最適化例をソースコード形式で説明する図である。
ソースコード１５７は、前述のソースコード１５５を最適化した後の処理手順を示している。ソースコード１５７では、ｒｅｓｉｚｅ（）が呼び出される直前に、ｍａｔｒｉｘフラグをＯＦＦに書き換える処理が挿入されている。また、ｒｅｓｉｚｅ（）が呼び出される直前に、ｍａｔｒｉｘからｖｅｃ＿ｍａｔに整数をコピーする処理が挿入されている。ｍａｔｒｉｘとｖｅｃ＿ｍａｔは共に３行３列の行列として扱うことができるため、ｍａｔｒｉｘのｉ行ｊ列の整数がｖｅｃ＿ｍａｔのｉ行ｊ列にコピーされる。
【００８４】
また、ソースコード１５７では、ｃａｌｌ＿ｒｅｓｉｚｅ（）が呼び出される直前に、ｍａｔｒｉｘフラグをＯＦＦに書き換える処理が挿入されている。また、ｃａｌｌ＿ｒｅｓｉｚｅ（）が呼び出される直前に、ｍａｔｒｉｘからｖｅｃ＿ｍａｔに整数をコピーする処理が挿入されている。なお、ソースコード１５７には、ｍａｔｒｉｘフラグをＯＦＦにする処理およびｍａｔｒｉｘからｖｅｃ＿ｍａｔにコピーする処理が、ｍａｔｒｉｘフラグがＯＮであるときのみ実行されるように制御構造が挿入されてもよい。
【００８５】
次に、コンパイル装置１００のコンパイル手順について説明する。
図１１は、コンパイルの手順例を示すフローチャートである。
（Ｓ１０）コンパイラ１３０は、ソースファイル１２１からソースコードを読み出し、ソースコードの１回目のコンパイルを行い、生成したオブジェクトコードをオブジェクトファイル１２２に書き込む。１回目のコンパイルでは、コンパイラ１３０は、可変長二次元配列を固定長二次元配列に変換する最適化を行わなくてよい。
【００８６】
（Ｓ１１）コンパイラ１３０は、複数のコンパイル単位（例えば、複数の関数）の間の呼び出し関係を示す呼び出し関係グラフを、リンカ１４０から取得する。呼び出し関係グラフは、リンカ１４０が複数のコンパイル単位をリンクするときに生成される。
【００８７】
コンパイラ１３０は、ソースファイル１２１から再びソースコードを読み出し、ソースコードの２回目のコンパイルを行い、生成したオブジェクトコードをオブジェクトファイル１２２に書き込む。２回目のコンパイルでは、コンパイラ１３０は、呼び出し関係グラフを参照して可変長二次元配列を固定長二次元配列に変換する最適化を行う。以下、可変長二次元配列を固定長二次元配列に変換する最適化について説明する。
【００８８】
（Ｓ１２）最適化部１３５は、ｖｅｃｔｏｒ管理領域１７３が拡張されるようにｖｅｃｔｏｒライブラリを書き換える。すなわち、最適化部１３５は、ｖｅｃｔｏｒ管理領域１７３の負方向の位置にｍａｔｒｉｘフラグおよびｍａｔｒｉｘポインタが格納されるようにｖｅｃｔｏｒライブラリを書き換える。また、最適化部１３５は、ｍａｔｒｉｘ領域１７４にアクセスするときは、ｖｅｃｔｏｒ管理領域１７３のｍａｔｒｉｘポインタからｍａｔｒｉｘ領域１７４を辿るようにｖｅｃｔｏｒライブラリを書き換える。
【００８９】
（Ｓ１３）最適化部１３５は、中間コード記憶部１３４に記憶された中間コードの中からｖｅｃｔｏｒ型二次元配列を検索する。二次元配列検索の詳細は後述する。
（Ｓ１４）最適化部１３５は、ステップＳ１３で検索されたｖｅｃｔｏｒ型二次元配列の中からｖｅｃｔｏｒ型二次元配列を１つ選択する。
【００９０】
（Ｓ１５）最適化部１３５は、ステップＳ１４で選択したｖｅｃｔｏｒ型二次元配列が所定の変換条件を満たすか判断する。所定の変換条件は、ａｒｒａｙ型二次元配列に変換可能な条件であり、例えば、以下の（１）〜（５）の全てを満たすことである。
【００９１】
（１）ｖｅｃｔｏｒ型二次元配列とその要素である複数のｖｅｃｔｏｒ型配列の全てが、同一関数内で宣言されていること。（２）複数のｖｅｃｔｏｒ型配列の長さ（列数）が同一であり、ソースコードから静的に算出できること。（３）ｖｅｃｔｏｒ型二次元配列の長さ（行数）がソースコードから静的に算出できること。（４）各ｖｅｃｔｏｒ型配列に初期値を格納する処理では、メモリ領域の連続姓が維持されるライブラリ関数のみが使用され、メモリ領域の連続姓が維持されない可能性がある関数を使用していないこと。前者の例としてはｐｕｓｈ＿ｂａｃｋ（）やｐｏｐ＿ｂａｃｋ（）などが挙げられ、後者の例としてはｉｎｓｅｒｔ（）などが挙げられる。（５）ｖｅｃｔｏｒ型二次元配列が宣言された関数内で、ｒｅｓｉｚｅ（）などサイズを変える関数を使用していないこと。なお、図７のソースコード１５３は、上記の変換条件を満たしている。
【００９２】
上記の所定の変換条件が満たされる場合はステップＳ１６に処理が進み、所定の変換条件が満たされない場合はステップＳ２０に処理が進む。
（Ｓ１６）最適化部１３５は、ｖｅｃｔｏｒ型二次元配列が宣言された位置に、メモリにｍａｔｒｉｘ領域１７４を確保するための命令およびｍａｔｒｉｘフラグをＯＮに設定する命令を挿入する。このとき、ｍａｔｒｉｘ領域１７４の先頭要素のアドレスが、ｖｅｃ＿ｍａｔ管理領域１７３にｍａｔｒｉｘポインタとして格納される。なお、ｍａｔｒｉｘフラグおよびｍａｔｒｉｘポインタは、ソースコードで宣言されたｖｅｃｔｏｒ型二次元配列１つにつき１つずつ用意される。複数の関数が１つのｖｅｃｔｏｒ型二次元配列を共有する場合、同じｍａｔｒｉｘフラグおよびｍａｔｒｉｘポインタが参照される。
【００９３】
（Ｓ１７）最適化部１３５は、ｖｅｃｔｏｒ型二次元配列に初期値を格納する命令を、ｍａｔｒｉｘ領域１７４に初期値を格納する命令に変換する。
（Ｓ１８）最適化部１３５は、ｖｅｃｔｏｒ型二次元配列に初期値が格納された後、サイズを変更せずにｖｅｃｔｏｒ型二次元配列を使用する配列演算の命令を検出する。最適化部１３５は、検出した配列演算の位置に、ｖｅｃｔｏｒ型二次元配列の代わりにｍａｔｒｉｘ領域１７４を使用する配列演算の命令を挿入する。また、最適化部１３５は、ｖｅｃ＿ｍａｔ管理領域１７３のｍａｔｒｉｘフラグを確認し、ｍａｔｒｉｘフラグに応じて上記２種類の配列演算を選択的に実行させる命令を挿入する。例えば、最適化部１３５は、ｍａｔｒｉｘフラグがＯＮの場合はｍａｔｒｉｘ領域１７４を使用し、ｍａｔｒｉｘフラグがＯＦＦの場合はｖｅｃｔｏｒ型二次元配列を使用する分岐命令を挿入する。
【００９４】
（Ｓ１９）最適化部１３５は、ｖｅｃｔｏｒ型二次元配列のサイズを変更する命令を検出し、直前にフラグ変更処理の命令を挿入する。フラグ変更処理挿入の詳細は後述する。
（Ｓ２０）最適化部１３５は、ステップＳ１４で全てのｖｅｃｔｏｒ型二次元配列を選択したか判断する。全てのｖｅｃｔｏｒ型二次元配列を選択した場合は処理が終了し、未選択のｖｅｃｔｏｒ型二次元配列がある場合はステップＳ１４に処理が進む。
【００９５】
図１２は、二次元配列検索の手順例を示すフローチャートである。
この二次元配列検索は、前述のステップＳ１３で実行される。
（Ｓ３０）最適化部１３５は、コンパイル対象の関数を１つ選択する。
【００９６】
（Ｓ３１）最適化部１３５は、ステップＳ３０で選択した関数がｖｅｃｔｏｒライブラリをｉｎｃｌｕｄｅしているか（参照しているか）判断する。ｖｅｃｔｏｒライブラリをｉｎｃｌｕｄｅしている場合はステップＳ３２に処理が進み、ｖｅｃｔｏｒライブラリをｉｎｃｌｕｄｅしていない場合はステップＳ３７に処理が進む。
【００９７】
（Ｓ３２）最適化部１３５は、ステップＳ３０で選択した関数内に含まれている変数宣言の中から変数宣言を１つ選択する。
（Ｓ３３）最適化部１３５は、ステップＳ３２で選択した変数宣言のデータ型がｖｅｃｔｏｒであるか判断する。データ型がｖｅｃｔｏｒである場合、ステップＳ３４に処理が進む。ｖｅｃｔｏｒでない場合、ステップＳ３２で選択した変数宣言によって特定される変数がｖｅｃｔｏｒ型二次元配列でないと判定され、ステップＳ３６に処理が進む。
【００９８】
（Ｓ３４）最適化部１３５は、ステップＳ３３のｖｅｃｔｏｒに格納される要素のデータ型がｖｅｃｔｏｒであるか判断する。要素のデータ型がｖｅｃｔｏｒである場合、ステップＳ３５に処理が進む。ｖｅｃｔｏｒでない場合、ステップＳ３２で選択した変数宣言によって特定される変数がｖｅｃｔｏｒ型二次元配列でないと判定され、ステップＳ３６に処理が進む。
【００９９】
（Ｓ３５）最適化部１３５は、ステップＳ３２で選択した変数宣言によって特定される変数が、ｖｅｃｔｏｒ型二次元配列であると判定する。
（Ｓ３６）最適化部１３５は、ステップＳ３２で関数内の全ての変数宣言を選択したか判断する。全ての変数宣言を選択した場合はステップＳ３７に処理が進み、未選択の変数宣言がある場合はステップＳ３２に処理が進む。
【０１００】
（Ｓ３７）最適化部１３５は、ステップＳ３０で全ての関数を選択したか判断する。全ての関数を選択した場合は二次元配列検索が終了し、未選択の関数がある場合はステップＳ３０に処理が進む。
【０１０１】
図１３は、フラグ変更処理挿入の手順例を示すフローチャートである。
このフラグ変更処理挿入は、前述のステップＳ１９で実行される。
（Ｓ４０）最適化部１３５は、コンパイル単位（例えば、着目している関数）の中から、ｖｅｃｔｏｒ型二次元配列のサイズが変わるようなｖｅｃｔｏｒライブラリ関数の呼び出しを検索する。ｖｅｃｔｏｒ型二次元配列のサイズが変わるとは、行数および列数の少なくとも一方が変わることであり、行数または列数が増加する場合と行数または列数が減少する場合とを含む。サイズが変わるようなｖｅｃｔｏｒライブラリ関数には、サイズを明示的に指定するｒｅｓｉｚｅ（）、末尾に要素を追加するｐｕｓｈ＿ｂａｃｋ（）、要素を削除するｃｌｅａｒ（）、途中に要素を追加するｉｎｓｅｒｔ（）などが含まれる。
【０１０２】
（Ｓ４１）最適化部１３５は、ステップＳ４０で検索されたｖｅｃｔｏｒライブラリ関数呼び出しの中からｖｅｃｔｏｒライブラリ関数呼び出しを１つ選択する。
（Ｓ４２）最適化部１３５は、ステップＳ４１で選択したｖｅｃｔｏｒライブラリ関数呼び出しの直前に、ｍａｔｒｉｘフラグをＯＦＦに設定する命令を挿入する。また、最適化部１３５は、ｖｅｃｔｏｒライブラリ関数呼び出しの直前に、ｍａｔｒｉｘ領域１７４からｖｅｃｔｏｒ型二次元配列の領域に要素をコピーし、ｍａｔｒｉｘ領域１７４を削除する命令を挿入する。ｍａｔｒｉｘフラグを書き換える命令と要素をコピーする命令は、何れを先に実行するようにしてもよい。ｍａｔｒｉｘフラグを書き換える命令と要素をコピーする命令は、ｍａｔｒｉｘフラグがＯＮであるときに高々１回実行されるようにする。このために、最適化部１３５は、現在のｍａｔｒｉｘフラグを確認しｍａｔｒｉｘフラグに応じて分岐する制御構造を挿入するようにしてもよい。
【０１０３】
（Ｓ４３）最適化部１３５は、ステップＳ４１で全てのｖｅｃｔｏｒライブラリ関数呼び出しを選択したか判断する。全てのｖｅｃｔｏｒライブラリ関数呼び出しを選択した場合はステップＳ４４に処理が進み、それ以外の場合はステップＳ４１に処理が進む。
【０１０４】
（Ｓ４４）最適化部１３５は、コンパイル単位の中から、標準ライブラリ関数以外のユーザ関数の呼び出しを検索する。ユーザ関数には、呼び出し元の関数と同じユーザによって作成された関数に加えて、呼び出し元の関数と異なるユーザによって作成されたライブラリ関数（標準ライブラリ関数を除く）が含まれる。ユーザ関数呼び出しは、例えば、ステップＳ１１で取得した呼び出し関係グラフを参照して検索される。
【０１０５】
（Ｓ４５）最適化部１３５は、ステップＳ４４で検索されたユーザ関数呼び出しの中からユーザ関数呼び出しを１つ選択する。
（Ｓ４６）最適化部１３５は、ステップＳ４５で選択したユーザ関数呼び出しの呼び出し先ユーザ関数を、ステップＳ１１で取得した呼び出し関係グラフを参照して特定する。最適化部１３５は、呼び出し先ユーザ関数内でのｖｅｃｔｏｒ型二次元配列の使用状況を示す情報を取得する。なお、呼び出し先ユーザ関数が更に別のユーザ関数を呼び出している場合、最適化部１３５は再帰的に呼び出し先ユーザ関数を追跡する。
【０１０６】
（Ｓ４７）最適化部１３５は、呼び出し先ユーザ関数内でｖｅｃｔｏｒ型二次元配列のサイズが変化する可能性があるか判断する。具体的には、最適化部１３５は、呼び出し先ユーザ関数の中からステップＳ４０と同様のｖｅｃｔｏｒライブラリ関数呼び出しを検索する。呼び出し先ユーザ関数にｒｅｓｉｚｅ（）、ｐｕｓｈ＿ｂａｃｋ（）、ｃｌｅａｒ（）、ｉｎｓｅｒｔ（）などのライブラリ関数呼び出しが含まれている場合、最適化部１３５は、ｖｅｃｔｏｒ型二次元配列のサイズが変化する可能性があると判断する。ｖｅｃｔｏｒ型二次元配列のサイズが変わる可能性がある場合はステップＳ４８に処理が進み、サイズが変わる可能性がない場合はステップＳ４９に処理が進む。
【０１０７】
（Ｓ４８）最適化部１３５は、ステップＳ４５で選択したユーザ関数呼び出しの直前に、ｍａｔｒｉｘフラグをＯＦＦに設定する命令を挿入する。最適化部１３５は、また、最適化部１３５は、ユーザ関数呼び出しの直前に、ｍａｔｒｉｘ領域１７４からｖｅｃｔｏｒ型二次元配列の領域に要素をコピーし、ｍａｔｒｉｘ領域１７４を削除する命令を挿入する。ｍａｔｒｉｘフラグを書き換える命令と要素をコピーする命令は、何れを先に実行するようにしてもよい。ｍａｔｒｉｘフラグを書き換える命令と要素をコピーする命令は、ｍａｔｒｉｘフラグがＯＮであるときに高々１回実行されるようにする。このために、最適化部１３５は、現在のｍａｔｒｉｘフラグを確認しｍａｔｒｉｘフラグに応じて分岐する制御構造を挿入するようにしてもよい。
【０１０８】
（Ｓ４９）最適化部１３５は、ステップＳ４５で全てのユーザ関数呼び出しを選択したか判断する。全てのユーザ関数呼び出しを選択した場合はフラグ変更処理挿入が終了し、それ以外の場合はステップＳ４５に処理が進む。
【０１０９】
なお、第２の実施の形態では最適化する可変長二次元配列を、行数と列数が共に可変であるｖｅｃｔｏｒ型二次元配列に限定した。しかし、行数が固定であっても列数が可変である場合には、ある行の要素を格納するメモリ領域と次の行の要素を格納するメモリ領域とが不連続になる可能性がある。そこで、コンパイル装置１００は、行数が固定で列数が可変である可変長二次元配列を最適化の対象としてもよい。すなわち、少なくとも列数が可変である可変長二次元配列を固定長二次元配列に変換することが考えられる。
【０１１０】
第２の実施の形態のコンパイル装置１００によれば、コンパイル時に可変長二次元配列を使用する命令が固定長二次元配列を使用する命令に自動的に変換される。よって、二次元配列の要素にアクセスするときポインタを辿る回数が減少し、メモリアクセス効率が向上する。また、二次元配列の全ての要素が連続メモリ領域に密に格納され、キャッシュメモリの使用効率が向上する。また、二次元配列のサイズを変更しようとする命令の直前で、固定長二次元配列から可変長二次元配列に戻される。よって、二次元配列のデータが破壊されることを抑止し、ソースコードが意図した処理を実現できる。
【０１１１】
また、ユーザはオブジェクトコードの実行効率を向上させるために固定長二次元配列を明示的に使用しなくてもよく、変数宣言時にサイズを指定しなくてよい可変長二次元配列を使用でき、ソースコードの作成が容易となる。また、可変長二次元配列の管理用情報に隣接させて、管理用領域の負方向にｍａｔｒｉｘフラグとｍａｔｒｉｘポインタが格納される。これにより、ｍａｔｒｉｘフラグやｍａｔｒｉｘポインタを失わないように、メモリ上に安全に保持できる。例えば、可変長二次元配列の管理用情報が移動したときに、ｍａｔｒｉｘフラグやｍａｔｒｉｘポインタも合わせて移動させることが容易となり、可変長二次元配列に紐付けてｍａｔｒｉｘフラグやｍａｔｒｉｘポインタを保持できる。
【符号の説明】
【０１１２】
１０  情報処理装置
１１  記憶部
１２  処理部
１３  ソースコード
１３ａ，１３ｃ  配列処理
１３ｂ  サイズ変更処理
１４  実行プログラム
１４ａ，１４ｂ，１４ｃ  コード
１５  可変長配列
１６  固定長配列
【図１】
2018092383.tif 000003
【図２】
2018092383.tif 000004
【図３】
2018092383.tif 000005
【図４】
2018092383.tif 000006
【図５】
2018092383.tif 000007
【図６】
2018092383.tif 000008
【図７】
2018092383.tif 000009
【図８】
2018092383.tif 000010
【図９】
2018092383.tif 000011
【図１０】
2018092383.tif 000012
【図１１】
2018092383.tif 000013
【図１２】
2018092383.tif 000014
【図１３】
2018092383.tif 000015