この章では、Fortran コンパイラについて説明します。
コンパイラの主な使用目的は、Fortran などの手続き型言語で記述されたプログラムを、コンピュータで実行できるデータファイルに変換することです。コンパイル処理の一部として、コンパイラから自動的にリンカーを起動して、実行可能ファイルを生成することもできます。
コンパイラは、次の処理にも使用します。
マルチプロセッサ用の並列化実行ファイルを生成します (-openmp オプション)。
ソースファイルとサブルーチン間におけるプログラムの整合性を分析し、レポートを作成します (-Xlist)。
ソースファイルを次のファイルに変換します。
再配置可能なバイナリ (.o) ファイル。あとで実行可能ファイルまたは静的ライブラリ (.a) ファイルにリンクされます。
動的共有ライブラリ (.so) ファイル (-G オプション)。
実行可能ファイルにリンクします。
実行時デバッガを有効にして実行可能ファイルをコンパイルします (-g オプション)。
文単位または手続き単位の実行時のプロファイルを有効にして、実行可能ファイルをコンパイルします (-pg オプション)。
ソースコードを調べて ANSI 標準への準拠を確認します (-ansi オプション)。
ここでは Fortran コンパイラを使用して、Fortran プログラムをコンパイルし、実行する方法について、簡単に説明します。コマンド行オプションの参考情報は、次の章で紹介します。
Fortran アプリケーションの基本的な実行手順は次のとおりです。まず、エディタを使用して、.f、.for、.f90、.f95、.F、.F90、.F95、.f03、または .F03 という接尾辞の付いた Fortran のソースファイルを作成します (表 表 2–1 を参照)。次に、コンパイラを起動して実行可能ファイルを生成し、最後にそのファイル名を入力してそのプログラムを起動します。
例: このプログラムは画面上にメッセージを表示します。
demo% cat greetings.f PROGRAM GREETINGS PRINT *, ’Real programmers write Fortran!’ END demo% f95 greetings.f demo% a.out Real programmers write Fortran! demo% |
この例では、f95 がソースファイル greetings.f をコンパイルし、デフォルトで実行可能プログラムを a.out というファイルにリンクします。プログラムを起動するには、コマンドプロンプトで実行可能ファイルの名前 a.out を入力します。
一般的には、UNIX のコンパイラは実行可能ファイルとして a.out というデフォルトのファイルを生成します。しかし、すべてのコンパイルで同じファイルを使用するのは不都合な場合があります。さらには、そのようなファイルがすでに存在している場合、コンパイラの次の実行で上書きされてしまいます。代わりに、-o コンパイラオプションを使用すると、実行可能出力ファイルの名前を明示的に指定することができます。
demo% f95 -o greetings greetings.f demo% greetings Real programmers write Fortran! demo% |
前述の例で、-o オプションを使用することにより、コンパイラは実行可能なコードをファイル greetings に書き込みます。規則により、実行可能ファイルはメインソースファイルと同じ名前を与えられますが、拡張子は付きません。
また別の方法として、コンパイル処理が終わるごとに、mv コマンドを使用してデフォルトの a.out ファイルの名前を変更することもできます。どちらの方法でも、シェルプロンプトで実行可能ファイルの名前を入力してプログラムを実行します。
この章の次の項では、 f95 コマンドで使用する表記法、コンパイラのソース行指令、これらのコンパイラの使用上の注意事項などについて解説します。次の章では、コマンド行の構文とすべてのオプションについて詳しく説明します。
シェルプロンプトで起動される単純なコンパイラコマンドの構文は次のとおりです。
f95 [options] files...
ここで、files… には、拡張子として .f、.F、.f90、.f95、.F90、.F95、または .for が付いている 1 つ以上の Fortran のソースファイル名を指定します。options には、1 つ以上のコンパイラオプションフラグを指定します。.f90 または .f95 の拡張子が付いているファイルは、f95 コンパイラだけが認識する「自由形式」の Fortran 95 ソースファイルです。
次の例では、f95 は 2 つのソースファイルをコンパイルし、実行時デバッグを有効な状態にして growth という名前の実行可能ファイルを生成します。
demo% f95 -g -o growth growth.f fft.f95 |
f95 または f90 コマンドのいずれを使用しても、Fortran コンパイラを起動できます。
新規: コンパイラは、拡張子が .f03 または .F03 のソースファイルも受け入れます。これらは、.f95 および .F95 と同等とみなされ、ソースファイルに Fortran 2003 拡張機能が含まれていることを示す手段として利用できます。
コンパイラが受け付ける各種ソースファイルの拡張子については、「2.2.2 ファイル名の拡張子」を参照してください。
前述の例では、コンパイラは growth.o と fft.o のロードオブジェクトファイルを自動的に生成し、次にシステムリンカーを起動して growth という実行可能プログラムファイルを生成します。
コンパイルの終了後、オブジェクトファイル growth.o と fft.o が残ります。このため、ファイルの再リンクや再コンパイルを簡単に行うことができます。
コンパイルが失敗すると、エラーごとにメッセージが返されます。エラーがあるソースファイルについては、.o ファイルや実行可能プログラムファイルは作成されません。
コマンド行で入力するファイル名の接尾辞によって、コンパイラがそのファイルをどのように処理するかが決まります。次の表に示されていない接尾辞の付いたファイル名、および拡張子のないファイル名は、リンカーに渡されます。
表 2–1 Fortran コンパイラが認識可能なファイル名の接尾辞
接尾辞 |
言語 |
処理 |
---|---|---|
.f |
Fortran 77 または Fortran 95 固定形式 |
Fortran ソースファイルをコンパイルし、オブジェクトファイルを現在のディレクトリに出力する。オブジェクトファイルのデフォルト名は、ソースファイル名に接尾辞 .o を付けたもの |
.f95.f90 |
Fortran 95 自由形式 |
.f と同じ |
.f03 |
Fortran 2003 自由形式 |
.f と同じ |
.for |
Fortran 77 または Fortran 95 固定形式 |
.f と同じ |
.F |
Fortran 77 または Fortran 95 固定形式 |
コンパイルの前に、FORTRAN 77 のソースファイルを Fortran または C のプリプロセッサで処理する |
.F95.F90 |
Fortran 95 自由形式 |
Fortran がコンパイルする前に、Fortran 95 自由形式のソースファイルを Fortran または C のプリプロセッサで処理する |
.F03 |
Fortran 2003 自由形式 |
.F95 と同じ |
.s |
アセンブラ |
アセンブラでソースファイルをアセンブルする |
.S |
アセンブラ |
アセンブルする前にアセンブラのソースファイルを C プリプロセッサで処理する |
.il |
インライン展開 |
インライン展開コードのテンプレートファイルを処理する。コンパイラはテンプレートを使って、選択されたルーチンのインライン呼び出しを展開します(テンプレートファイルは特殊なアセンブラファイル。inline(1) マニュアルページを参照)。 |
.o |
オブジェクトファイル |
オブジェクトファイルをリンカーに渡す |
.a、.so、.so.n |
ライブラリ |
ライブラリの名前をリンカーに渡す。.a ファイルは静的ライブラリ、.so と .so.n ファイルは動的ライブラリ |
Fortran 95 自由形式については、「4.1 ソース言語の機能」を参照してください。
Fortran コンパイラでは、コマンド行に複数のソースファイルを指定することができます。「コンパイルユニット」とも呼ばれる 1 つのソースファイル中に、複数の手続き (主プログラム、サブルーチン、関数、ブロックデータ、モジュールなど) を記述することができます。アプリケーションは、1 つのファイルに 1 つのソースコード手続きを記述して構成することも、同時に処理される手続きを 1 つのファイルにまとめて構成することもできます。これらの構成方法の長所と欠点については、『Fortran プログラミングガイド』を参照してください。
f95 は、fpp と cpp の 2 つのソースファイルプリプロセッサをサポートしています。いずれのプリプロセッサもコンパイラから起動され、ソースコード「マクロ」とシンボリック定義を展開してから、コンパイルを開始します。コンパイラでは、デフォルトで fpp が使用されます。-xpp=cpp オプションを指定すると、fpp から cpp にデフォルトを変更できます。-Dname オプションの説明も参照してください。
fpp は Fortran 言語専用のソースプリプロセッサです。詳細は、fpp(1) のマニュアルページと fpp の README を参照してください。fpp は、デフォルトでは、.F、.F90、.F95、または .F03 という拡張子の付いたファイル上で起動します。
fpp のソースコードは、次の Netlib Web サイトにあります。
http://www.netlib.org/fortran/
標準的な Unix C 言語のプリプロセッサについては、cpp(1) を参照してください。Fortran のソースファイルでは、fpp よりも cpp を使用することをお勧めします。
コンパイルとリンクをそれぞれ個別に実行することができます。-c オプションを指定すると、ソースファイルをコンパイルして .o オブジェクトファイルが生成されますが、実行可能ファイルは生成されません。-c オプションを指定しない場合、コンパイラはリンカーを起動します。このようにコンパイルとリンクを別々に実行すると、次の例に示すように、1 つのファイルを修正するための目的で全体を再コンパイルする必要がなくなります。
1 つのファイルをコンパイルし、別の手順でほかのオブジェクトファイルとリンクします。
demo% f95 -c file1.f (Make new object file) demo% f95 -o prgrm file1.o file2.o file3.o (Make executable file) |
リンク時には (2 行目)、完全なプログラムを作成するのに必要なすべてのオブジェクトファイルを必ず 指定してください。オブジェクトファイルが不足していると、未定義の外部参照エラー (ルーチンの不足) によって、リンクが失敗します。
コンパイルとリンクを別のステップで行う場合は、整合性のあるコンパイルとリンクのオプションを選択することが重要です。オプションによっては、プログラムの一部をコンパイルするときに使用したら、リンクするときにも同じオプションを使用する必要があります。すべてのソースファイルを、リンクも含めて指定してコンパイルする必要のあるオプションが数多くあります。
第 3 章では、このようなオプションについて説明します。
例: -fast を使用して sbr.f をコンパイルし、C ルーチンをコンパイルしてから、別のステップでリンクします。
demo% f95 -c -fast sbr.f demo% cc -c -fast simm.c demo% f95 -fast sbr.o simm.o link step; passes -fast to the linker |
コンパイラで認識されないコマンド行の引数はすべて、リンカーオプション、オブジェクトプログラムファイル名、またはライブラリ名である可能性があるとみなされます。
基本的には次のように区別されます。
認識されないオプション (- が付いている) には、警告メッセージが出力されます。
認識されない非オプション (- が付いていない) には、警告メッセージが出力されません。ただし、これらのオプションがリンカーに渡されて、リンカーに認識されない場合には、リンカーエラーメッセージが出力されます。
次に例を示します。
demo% f95 -bit move.f <- -bit is not a recognized f95 option f95: Warning: Option -bit passed to ld, if ld is invoked, ignored otherwise demo% f95 fast move.f <- The user meant to type -fast ld: fatal: file fast: cannot open file; errno=2 ld: fatal: File processing errors. No output written to a.out |
最初の例では、-bit は f95 では認識されず、このオプションはこれを解釈しようとするリンカー (ld) に渡されます。ld では 1 文字のオプションを続けて並べることもできるため、-bit が -b -i -tと解釈されます。-b、-i、-t はいずれも ld の有効なオプションであるからです。これは、ユーザーが意図している場合と、意図していない場合とがあります。
2 つ目の例では、f95 の共通のオプションとして -fast を指定しようとしていますが、先頭のハイフンが抜けています。この場合も、コンパイラは引数をリンカーに渡し、リンカーはこれをファイル名と解釈します。
前述の例から、コンパイラコマンドを指定する場合には、十分な注意が必要であることがわかります。
f95 は、ソースファイル中にある各 MODULE 宣言に対して、それぞれモジュール情報ファイルを自動的に作成し、USE 文で引用されるモジュールを検索します。検出されたモジュール (MODULE module_name) ごとに、コンパイラは、対応するファイル module_name.mod を現在のディレクトリ内に生成します。たとえば、ファイル mysrc.f95 中にある MODULE list 単位のモジュール情報ファイル list.mod は f95 によって生成されます。
モジュール情報ファイルを記述および検索するためのデフォルトのパスの設定方法については、-Mpath および -moddir dirlist オプションフラグを参照してください。
すべてのコンパイルユニットで暗黙的に MODULE 宣言を行う方法については、-use コンパイラオプションを参照してください。
fdumpmod(1) コマンドを使用すると、.mod モジュール情報ファイルの内容を表示できます。
詳細は、「4.9 モジュールファイル」を参照してください。
Fortran の注釈の書式であるソースコード「指令」を使用して、特殊な最適化または並列化の選択に関する情報をコンパイラに渡すことができます。コンパイラ指令は、プラグマとも呼ばれます。コンパイラは、一連の一般指令および並列化指令を認識します。f95 も OpenMP 共有メモリーマルチプロセッシング指令を処理します。
f95 に固有の指令については、「4.8 指令」で説明します。f95 が認識可能なすべての指令については、付録 C Fortran 指令の要約を参照してください。
指令は Fortran 規格には含まれていません。
一般的な Fortran 指令は次のような書式で使用します。
!$PRAGMA keyword ( a [ , a ] … ) [ , keyword ( a [ , a ] … ) ] ,…
!$PRAGMA SUN keyword ( a [ , a ] … ) [ , keyword ( a [ , a ] … ) ] ,…
変数 keyword は特定の指令を表します。追加の引数やサブオプションも指定できます。指令によっては、前述に示す追加のキーワード SUN を指定する必要があります。
一般的な指令の構文は、次のとおりです。
1 カラム目は、注釈指示子の文字 c、C、!、* などです。
f95 の自由形式では、! は認識される唯一の注釈指示子 (!$PRAGMA) です。この章の例では、Fortran 95 自由形式を想定しています。
次の 7 文字は空白文字を入れず $PRAGMA とします。大文字でも小文字でもかまいません。
自由形式ソースプログラムでは、! という注釈指示子文字を使用する指令は、行のどの位置にも記述できます。
制限事項は、次のとおりです。
Fortran テキストの場合と同様、最初の 8 文字のあとでは、空白は無視され、大文字と小文字は区別されません。
これは注釈であるため、指令は継続できませんが、必要に応じて多くの !$PRAGMA 行を順番に使用できます。
注釈が前述の構文条件を満たしていると、コンパイラが認識できる指令が 1 つまたは複数含まれていることになります。前述の構文条件を満たしていない場合は、警告メッセージが出力されます。
C プリプロセッサの cpp は注釈行または指令行の中でマクロシンボル定義を展開します。Fortran プリプロセッサの fpp は注釈行の中でマクロの展開は行いませんが、fpp は正当な f95 の指令は認識し、指令キーワード外の制限付き置換は実行します。ただし、キーワード SUN が必要な指令には注意してください。cpp は、小文字の sun を事前定義した値で置き換えます。また、cpp マクロ SUN を定義すると、SUN 指令キーワードが干渉されます。一般的な規則では、次のようにソースが cpp または fpp で処理される場合、プラグマは大文字と小文字を混在させて指定します。
!$PRAGMA Sun UNROLL=3
Fortran のコンパイラは、次の一般的な指令を認識します。
表 2–2 一般的な Fortran 指令の要約
C 指令 |
!$PRAGMA C(list ) 外部関数の名前リストを C 言語のルーチンとして宣言します。 |
|
IGNORE_TKR 指令 |
!$PRAGMA IGNORE_TKR {name {, name} ...} コンパイラは、特定の呼び出しを解釈するとき、一般的な手続きのインタフェースで表示される仮引数名の型、種類、ランクを無視します。 |
|
UNROLL 指令 |
!$PRAGMA SUN UNROLL=n コンパイラに、次のループは長さ n に展開できることを伝えます。 |
|
WEAK 指令 |
!$PRAGMA WEAK(name[ =name2]) name を弱いシンボル (weak symbol) または name2 の別名として宣言します。 |
|
OPT 指令 |
!$PRAGMA SUN OPT=n 副プログラムの最適化レベルを n に設定します。 |
|
PIPELOOP 指令 |
!$PRAGMA SUN PIPELOOP=n 次のループでは n 離れた反復間に依存関係があることを宣言します。 |
|
PREFETCH 指令 |
名前の参照のために、先読み命令を生成するようにコンパイラに要求します。(-xprefetch オプションを指定する必要があります。このオプションはデフォルトで有効になっています。PREFETCH 指令は、—xprefetch=no でコンパイルし無効にします。ターゲットアーキテクチャーも PREFETCH 指令をサポートしている必要があり、コンパイラ最適化レベルは -xO2 より上である必要があります)。 |
|
ASSUME 指令 |
!$PRAGMA [BEGIN} ASSUME (expression [ ,probability]) !$PRAGMA END ASSUME プログラム内の特定の個所において、コンパイラが真であると想定できる条件について表明を行います。 |
C() 指令は、その引数が外部関数であることを指定します。EXTERNAL 宣言と同義です。ただし、通常の外部名とは違って、Fortran コンパイラでは、これらの引数名に下線が付けられません。詳細は、『Fortranプログラミングガイド』の「C と Fortran のインタフェース」の章を参照してください。
特殊な関数の C() 指令は、各副プログラム中にある、その関数への最初の引用よりも前に現れなければなりません。
例: C で ABC と XYZ をコンパイルします。
EXTERNAL ABC, XYZ !$PRAGMA C(ABC, XYZ) |
この指令では、コンパイラは、特定の呼び出しを解釈するとき、総称手続きのインタフェースで表示される仮引数名の型、種別、次元数を無視します。
たとえば、次の手続きのインタフェースでは、SRC はどのようなデータ型でもよく、LEN は KIND=4 または KIND=8 のいずれかであることが可能です。インタフェースブロックは、汎用的な手順名に対し 2 つの特定の手順を定義します。この例は、Fortran 95 自由形式で示されます。
INTERFACE BLCKX SUBROUTINE BLCK_32(LEN,SRC) REAL SRC(1) !$PRAGMA IGNORE_TKR SRC INTEGER (KIND=4) LEN END SUBROUTINE SUBROUTINE BLCK_64(LEN,SRC) REAL SRC(1) !$PRAGMA IGNORE_TKR SRC INTEGER (KIND=8) LEN END SUBROUTINE END INTERFACE The subroutine call: INTEGER L REAL S(100) CALL BLCKX(L,S) |
BLCKX の呼び出しによって、一般的なコンパイルでは BLCK_32 が呼び出され、-xtypemap=integer:64 を使用してコンパイルした場合は BLCK_64 が呼び出されます。S の実際の型は、どのルーチンを呼び出すかを定義しません。これによって、引数の型、種別、次元数に基づいてライブラリルーチンを呼び出すラッパーの一般的なインタフェースの記述を単純化できます。
形状引き継ぎの配列、Fortran ポインタ、割り当て可能な配列の仮引数は、指令では指定できません。名前が指定されていない場合は、形状引き継ぎの配列、Fortran ポインタ、割り当て可能な配列の仮引数を除いて、手続きのすべての仮引数に指令が適用されます。
UNROLL 指令では、!$PRAGMA のあとに SUN と指定する必要があります。
!$PRAGMA SUN UNROLL=n 指令は、最適化パス中に、次のループを n 回展開するようにコンパイラに指示します。コンパイラは、解析の結果、ループの展開が適切であると判断した場合のみ展開します。
n は正の整数です。次の選択が可能です。
n=1 の場合、オプティマイザは、どのループも展開しない可能性があります。
n>1 の場合、オプティマイザは、ループを n 回展開する可能性があります。
実際に展開されたループがあると、実行可能ファイルのサイズが大きくなります。詳細については、『Fortran プログラミングガイド 』のパフォーマンスと最適化に関する章を参照してください。
例: ループを 2 回展開するときは、次のように指定します。
!$PRAGMA SUN UNROLL=2 |
WEAK 指令は、以前に定義されているよりも低い優先順位で同じシンボルを定義します。この指令は主に、ライブラリを作成する場合にソースファイル中で使用されます。リンカーは弱いシンボルを解決できなくてもエラーメッセージを表示しません。
!$PRAGMA WEAK (name1 [=name2]) |
WEAK (name1) によって、name1 が優先順位の低いシンボルとして定義されます。この場合リンカーは、name1 の定義が見つけられなくてもエラーメッセージを出力しません。
WEAK (name1=name2) によって、name1 が優先順位の低いシンボルとして、また、name2 の別名として定義されます。
プログラムから呼び出された name1 が定義されていない場合、リンカーはライブラリの定義を使用します。ただし、プログラムで name1 の定義が行われている場合は、そのプログラムの定義が使用され、ライブラリ中にある name1 の優先順位が低い大域的な定義は使用されません。プログラムから name2 が直接呼び出されると、ライブラリの定義が使用されます。name2 の定義が重複すると、エラーが発生します。詳細は、Solaris の『リンカーとライブラリ』を参照してください。
OPT 指令では、!$PRAGMA のあとに SUN と指定する必要があります。
OPT 指令は副プログラムの最適化レベルを設定し、コンパイルコマンド行に指定されているレベルは上書きされます。指令は副プログラムの直前に指定する必要があり、その副プログラムだけに適用されます。次に例を示します。
!$PRAGMA SUN OPT=2 SUBROUTINE smart(a,b,c,d,e) ...etc |
上記の例を、-O4 を指定する f95 コマンドでコンパイルする場合、指令はこのレベルを上書きして -O2 でサブルーチンをコンパイルします。このルーチンのあとに別の指令がないかぎり、次の副プログラムは -O4 でコンパイルされます。
ルーチンを -xmaxopt[ =n] オプションでコンパイルして、指令が認識されるようにする必要があります。このコンパイラオプションは PRAGMA OPT 指令の最適化の最大値を指定します。PRAGMA OPT に指定した最適化レベルが -xmaxopt レベルよりも大きいと、-xmaxopt レベルが使用されます。
PIPELOOP=n 指令では、!$PRAGMA の後に SUN と指定する必要があります。
この指令は DO ループの直前に指定する必要があります。n には正の整定数かゼロを指定し、ループの反復間の依存関係をオプティマイザに指示します。ゼロの値は反復間の依存関係 (ループの伝達性) がないことを示し、オプティマイザで自由にパイプラインできます。正の値の n はループの I 番目の反復が (I-n) 番目の反復に依存していることを意味し、一度に n 反復だけパイプラインできます。(n が指定されない場合のデフォルトは 0 です)
C We know that the value of K is such that there can be no C cross-iteration dependencies (E.g. K>N) !$PRAGMA SUN PIPELOOP=0 DO I=1,N A(I)=A(I+K) + D(I) B(I)=B(I) + A(I) END DO |
最適化についての詳細は、『Fortran プログラミングガイド』を参照してください。
-xprefetchオプションフラグを使用すると (「3.4.161 –xprefetch[= a[,a]]」 を参照)、コンパイラに指示した一連の PREFETCH 指令は、先読みをサポートするプロセッサで指定のデータ要素について先読み命令を生成できます。
!$PRAGMA SUN_PREFETCH_READ_ONCE(name) !$PRAGMA SUN_PREFETCH_READ_MANY(name) !$PRAGMA SUN_PREFETCH_WRITE_ONCE(name) !$PRAGMA SUN_PREFETCH_WRITE_MANY(name) |
先読み命令についての詳細は、『C ユーザーズガイド』または『SPARC Architecture Manual, Version 9』も参照してください。
ASSUME 指令は、プログラムの特定地点の条件についてコンパイラにヒントを与えます。これらの表明は、コンパイラへの最適化指示のガイドラインとして役立ちます。また、プログラマは、それらの指令を使用して、実行時にプログラムの妥当性をチェックできます。ASSUME のフォーマットは 2 種類あります。
「単一表明」ASSUME の構文は、次のようになります。
!$PRAGMA ASSUME (expression [,probability]) |
また、「範囲表明」ASSUME は、次のようになります。
!$PRAGMA BEGIN ASSUME [expression [, probability) block of statements !$PRAGMA END ASSUME |
単一表明形式を使用すると、プログラムのその地点でコンパイラが想定できる条件を示すことができます。範囲表明形式を使用すると、ステートメントの範囲内を通して成立する条件を示すことができます。範囲表明の BEGIN と END のペアは正しくネストされる必要があります。
必要な式は、上にリストされている以外でユーザー定義の演算子や関数呼び出しを含まないプログラムの特定地点で評価可能なブール式です。
オプションの probability 値は、0.0 から 1.0 までの実数、つまり整数の 0 または 1 であり、式が真となる可能性を示します。0.0 (または 0) の可能性は絶対に真にならないことを意味し、1.0 (または 1) は常に真になることを意味します。数値の指定がない場合、式は高い可能性で真とみなされますが、絶対ではありません。0 または 1 以外の可能性を持つ表明は「非確定表明」です。同様に、0 または 1 の可能性を持つ表明は「確定表明」です。
たとえば、DO ループが常に 10,000 より長いことがわかっている場合は、コンパイラにこれを示しておくと、より良いコードを生成できます。通常、次のループは、ASSUME プラグマがある場合の方がすばやく実行されます。
!$PRAGMA BEGIN ASSUME(__tripcount().GE.10000,1) !! a big loop do i = j, n a(i) = a(j) + 1 end do !$PRAGMA END ASSUME |
特に ASSUME 指令の式クローズで使用するために、2 つの組み込み関数が用意されています。それらの名前の前には、2 つの下線が配置されます。
__branchexp() |
ブール制御式を持つ分岐ステートメントの直前に配置された単一表明で使用します。分岐ステートメントを制御するブール式と同じ結果を生成します。 |
__tripcount() |
指令の直後または指令に閉じ込められたループのトリップカウントを生成します。単一表明で使用する場合、指令直後のステートメントは DO の最初の行となる必要があります。範囲表明で使用する場合、もっとも外側の閉じたループに適用します。 |
この特殊な組み込み関数のリストは、将来的なリリースで拡大する可能性があります。
-xassume_control コンパイラオプションとともに使用します。(「3.4.111 –xassume_control[ =keywords]」を参照) 。たとえば、-xassume_control=check を使用してコンパイルした場合、トリップカウントが 10,000 を下回ると警告が発せられます。
-xassume_control=retrospective を使用してコンパイルを実行すると、プログラムの終了時点ですべての表明の真と偽を示す要約レポートが生成されます。-xassume_control の詳細については、f95 のマニュアルページを参照してください。
もう 1 つの例
!$PRAGMA ASSUME(__tripcount.GT.0,1) do i=n0, nx |
-xassume_control=check を使用して前述の例をコンパイルすると、トリップカウントが 0 かマイナスになるため、そのループを使用しないよう実行時の警告が発せられます。
並列化 指令は、コンパイラに対して、指令のあとに続く DO ループまたはコードの範囲を並列化するように明示的に指示します。一般的な指令とは、構文が異なります。並列化指令は、-openmp を使用してコンパイルされる場合にのみ認識されます。Fortran の並列化についての詳細は、『OpenMP API ユーザーズガイド』および『Fortran プログラミングガイド』を参照してください。
Fortran コンパイラは、OpenMP 3.0 共有メモリー並列化モデルをサポートします。従来の Sun および Cray の並列化指令は現在推奨されていないため、使用すべきではありません。
Fortran コンパイラでは、並列プログラミングモデルとして OpenMP Fortran 共有メモリーマルチプロセッシング API を使用することをお勧めします。API は、OpenMP Architecture Review Board (http://www.openmp.org) によって仕様が定められています。
OpenMP 指令を使用可能にするには、コマンド行オプション -openmp を指定してコンパイルする必要があります (「3.4.153 –xopenmp[={ parallel|noopt|none}]」を参照)。
f95 で使用可能な OpenMP 指令についての詳細は、『OpenMP API ユーザーズガイド』を参照してください。
従来の Sun および Cray 形式の並列化指令は非推奨になりました。Open MP 並列化 API が推奨されます。従来の Sun/Cray 指令から OpenMP モデルへの移行方法については、『OpenMP API ユーザーズガイド』を参照してください。
!DIR$ IVDEP 指令は、ループ内で検出された一部またはすべての配列参照のループがもたらす依存関係を無視し、特にほかの方法では実行できないマイクロベクトル化、配布、ソフトウェアパイプラインなどのさまざまなループの最適化を実行するように、コンパイラに指示します。これは、依存関係が重要ではない、または依存関係が実際に発生しないことをユーザーが把握している状況で使用されます。
次に例を示します。
DO I = 1, N A(V(I)) = A(V(I)) + C(I) END DO |
このループでは、A(V(I)) へのいくつかのループがもたらす依存関係があります。V(I) には、インデックス A への複製値が含まれている可能性があり、ループの順序を変更すると、異なる結果になる可能性があります。ただし、V に固有の値のみ含まれていることがわかっている場合は、ループの順序を安全に変更でき、IVDEP 指令を使用して最適化を実行できます。
-xivdep コンパイラオプション (「3.4.133 –xivdep[= p]」 を参照) を使用して、IVDEP 指令の解釈を無効にするか、指定することができます。
IVDEP 指令の従来の解釈の中には、後方へのループがもたらす依存関係がないことを表明するだけのものがあります。Fortran コンパイラのデフォルトは —xivdep=loop です。これは、IVDEP 指令で推測されるループがもたらす依存関係がないことを表明することを示します。
次に、後方および前方への依存関係の例を示します。
do i = 1, n ! BACKWARD LOOP-CARRIED DEPENDENCE ... = a(i-1) ! S1 a(i) = ... ! S2 end do |
do i = 1, n ! FORWARD LOOP-CARRIED DEPENDENCE a(i) = ... ! S3 ... = a(i-1) ! S4 end do |
最初のループは S2 から S1 への後方へのループがもたらす依存関係で、2 つ目のループには、S3 から S4 への前方へのループがもたらす依存関係があります。2 つ目のループには前方への依存関係しかないため、このループは安全に配布やマイクロベクトル化が行えますが、最初のループは行えません。
次に、デフォルト値 -xivdep=loop を指定した IVDEP の使用例を示します。
integer target a(n) integer, pointer :: p(:), q(:) !DIR$ IVDEP do i = 1, n p(i) = q(i) a(i) = a(i-1) end do |
p(i) と q(i) 間、および p(i) と a(*) 間の推測される依存関係は無視されますが、a(i) と a(i-1) 間の明確な依存関係は無視されません。ループは 2 つのループに分割でき、その結果の p(i) = q(i) ループはマイクロベクトル化できます。
IVDEP 指令は、DO ループの直後に適用されます。この指令とループとの間にほかのコードを使用することはできません。!DIR$ IVDEP は、配列代入、FORALL、または WHERE 構文にも適用できます。特定のループに対して複数の指令が存在する場合 (IVDEP や UNROLL など)、コンパイラは可能な限りそれらすべての指令に従います。
Fortran コンパイラは、 ほとんどの非組み込みライブラリルーチンのインタフェースを定義するインクルードファイル system.inc を提供します。特にデフォルトのデータ型が -xtypemap で変更される場合は、呼び出す関数とその引数が正しく入力されていることを確実にするため、このインクルードファイルを宣言します。
たとえば、次のプログラムでは、関数 getpid() が明示的に入力されていないため、算術的な例外が発生します。
integer(4) mypid mypid = getpid() print *, mypid |
getpid() ルーチンは整数値を返しますが、関数の明示的な型が宣言されていない場合、コンパイラは実数値が返されたものとみなします。この数値が整数に変換されると、浮動小数点エラーが生じる可能性が高まります。
このような場合、getuid() と自分が呼び出す関数を明示的に入力します。
integer(4) mypid, getpid mypid = getpid() print *, mypid |
このような問題は、-Xlist (大域的なプログラム検査) オプションで診断できます。Fortran インクルードファイル ”system.inc’ は、これらのルーチンの明示的なインタフェース定義を提供します。
include ’system.inc’ integer(4) mypid mypid = getpid() print *, mypid |
Fortran ライブラリのルーチンを呼び出すプログラムに system.inc を含めると、インタフェースが自動的に定義され、コンパイラによる型の不一致の診断がサポートされます (詳細は、『Fortran ライブラリリファレンス』を参照)。
Fortran コンパイラを効果的に利用するための方法をいくつか紹介します。すべてのコンパイラオプションのリファレンスは、次の章に示します。
コンパイラフラグの中には、特定のハードウェアプラットフォームのオプションセットに合わせてコードを生成できるものもあります。コンパイラの -dryrun オプションを使用して、ネイティブプロセッサを特定できます。
<sparc>%f95 -dryrun -xtarget=native ### command line files and options (expanded): ### -dryrun -xarch=sparcvis2 -xcache=64/32/4:1024/64/4 -xchip=ultra3i <x64>%f95 -dryrun -xtarget=native ### command line files and options (expanded): ### -dryrun -xarch=sse2a -xcache=64/64/2:1024/64/16 -xchip=opteron |
FFLAGS または OPTIONS 変数を設定して、オプションを指定することができます。
コマンド行で FFLAGS または OPTIONS のいずれかを明示的に指定できます。make の暗黙のコンパイル規則を使用している場合は、make プログラムによって FFLAGS が自動的に使用されます。
demo% setenv FFLAGS ’-fast -Xlist’ |
例: FFLAGS を明示的に使用します。
demo% f95 $FFLAGS any.f |
make を使用するときに、FFLAGS 変数が前述のように設定されており、メイクファイルの「暗黙」のコンパイル規則が適用される場合 (すなわち「明示的」なコンパイラコマンド行がない場合) に make を実行すると、次のコンパイルを実行した場合と同じ意味になります。
f95 -fast -Xlist files…
make は Sun のすべてのコンパイラで使用できる強力なプログラム開発ツールです。make(1) マニュアルページおよび『Fortran プログラミングガイド』の第 3 章「プログラム開発」の章を参照してください。
make が仮定するデフォルトの暗黙的規則では、.f95 および .mod (モジュールファイル) という拡張子付きのファイルを認識できません。詳細は、『Fortran プログラミングガイド』および Fortran の README ファイルを参照してください。
コンパイル処理は大量のメモリーを使用することがあります。必要なメモリーのサイズは、選択した最適化レベル、およびコンパイルするファイルのサイズや複雑さに依存します。最適化でメモリーが不足した場合、その時点の手続きを低いレベルで最適化し直し、後続のルーチンはコマンド行の -On オプションで指定されていた本来のレベルで最適化を再開します。
コンパイラを実行するプロセッサには最低 64M バイトのメモリーが実装されている必要があります。256M バイトが推奨メモリーです。また、十分なスワップ領域が割り当てられる必要もあります。最低 200M バイトで、300M バイトが推奨値です。
メモリーの使用量は、手続きのサイズ、最適化レベル、仮想メモリーの制限、ディスクのスワップファイルのサイズ、その他さまざまな要素によって異なります。
多数のルーチンを含む単一のソースファイルをコンパイルすると、メモリーやスワップ領域が不足することがあります。
コンパイラのメモリーが不足する場合は、最適化レベルを下げてください。または fsplit(1) を使用して、複数のルーチンが含まれているソースファイルを、1 ルーチンが 1 ファイルに対応するようにいくつかのファイルに分割してください。
Solaris オペレーティングシステムのコマンドである swap -s コマンドは、利用可能なスワップ領域を表示します。swap(1M) を参照してください。
例: swap コマンドを使用します。
demo% swap -s total: 40236k bytes allocated + 7280k reserved = 47516k used, 1058708k available To determine the actual real memory: |
demo% /usr/sbin/dmesg | grep mem mem = 655360K (0x28000000) avail mem = 602476544 |
ワークステーションのスワップ領域を増やすには、mkfile(1M) と swap(1M) コマンドを使用します。この操作は、スーパーユーザーだけが実行できます。mkfile によって特定サイズのファイルを作成し、swap -a によってそのファイルをシステムのスワップ領域に追加します。
demo# mkfile -v 90m /home/swapfile /home/swapfile 94317840 bytes demo# /usr/sbin/swap -a /home/swapfile |
最適化レベル -O3 以上のレベルで大規模なルーチン (1 つの手続きが数千行ものコードで構成されるルーチン) をコンパイルすると、メモリーがさらに必要になる場合があり、コンパイル時間のパフォーマンスが低下することもあります。これを制御するには、1 つのプロセスで使用できる仮想メモリーの量を制限します。
sh シェルでは、ulimit コマンドを使用します。sh(1) を参照してください。
demo$ ulimit -d 16000 |
csh シェルでは、limit コマンドを使用します。csh(1) を参照してください。
例: 仮想メモリーを 16M バイトに制限します。
demo% limit datasize 16M |
いずれの場合も、オプティマイザは 16M バイトのデータ領域で最適化を再実行します。
この制限はマシンで利用可能なスワップ領域の総量を超えることはできないので、実際は、大規模なコンパイルの進行中であってもマシンを普通に使用できる程度の小さい値を指定してください。コンパイル処理でスワップ領域の半分以上が使用されることのないように注意してください。
例: 32M バイトのスワップ領域のあるマシンでは、次のコマンドを使用します。
sh シェルの場合:
demo$ ulimit -d 1600 |
csh の場合
demo% limit datasize 16M |
最適な設定は、最適化のレベルや、利用可能な実メモリーと仮想メモリーの量によって異なります。
64 ビットの Solaris 環境では、アプリケーションデータセグメントのサイズに対する弱い制限値は 2G バイトです。データ領域の追加割り当てが必要な場合は、シェルの limit または ulimit コマンドを使用して制限を解除します。
csh の場合:
demo% limit datasize unlimited |
sh、ksh の場合:
demo$ ulimit -d unlimited |
詳細は、『Solaris 64 ビット開発ガイド』を参照してください。