JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
Oracle Solaris Studio 12.3: Fortran ユーザーズガイド     Oracle Solaris Studio 12.3 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

1.  概要

2.  Solaris Studio Fortran の使用

2.1 クイックスタート

2.2 コンパイラの起動

2.2.1 コンパイルとリンクの流れ

2.2.2 ファイル名の拡張子

2.2.3 ソースファイル

2.2.4 ソースファイルプリプロセッサ

2.2.5 コンパイルとリンクの分離

2.2.6 コンパイルとリンクの整合性

2.2.7 認識されないコマンド行引数

2.2.8 モジュール

2.3 指令

2.3.1 一般的な指令

2.3.1.1 C 指令

2.3.1.2 IGNORE_TKR 指令

2.3.1.3 UNROLL 指令

2.3.1.4 WEAK 指令

2.3.1.5 OPT 指令

2.3.1.6 PIPELOOP[= n] 指令

2.3.1.7 PREFETCH 指令

2.3.1.8 ASSUME 指令

2.3.2 並列化の指令

2.3.2.1 OpenMP 並列化指令

2.3.2.2 従来の Sun および Cray 並列指令

2.3.3 IVDEP 指令

2.4 ライブラリインタフェースと system.inc

2.5 コンパイラの利用方法

2.5.1 ハードウェアプラットフォームの特定

2.5.2 環境変数の使用

2.5.3 メモリーサイズ

2.5.3.1 スワップ領域の制限

2.5.3.2 スワップ領域の増加

2.5.3.3 仮想メモリーの制御

2.6 ユーザー指定のデフォルトオプションファイル

3.  Fortran コンパイラオプション

4.  Solaris Studio Fortran の機能および拡張機能

5.  FORTRAN 77 の互換性: Solaris Studio Fortran への移行

A.  実行時のエラーメッセージ

B.  各リリースにおける機能変更

C.  Fortran 指令の要約

索引

2.3 指令

Fortran の注釈の書式であるソースコード「指令」を使用して、特殊な最適化または並列化の選択に関する情報をコンパイラに渡すことができます。コンパイラ指令はプラグマと呼ばれることもあります。コンパイラは一般的な指令と並列化指令のセットを認識します。f95 は、OpenMP 共有メモリーマルチプロセッシング指令も処理します。

f95 に固有の指令については、「4.8 指令」で説明します。f95 によって認識されるすべての指令については、付録 C Fortran 指令の要約を参照してください。


注 - 指令は Fortran 規格には含まれていません。


2.3.1 一般的な指令

一般的な Fortran 指令は次のような書式で使用します。

!$PRAGMA keyword ( a [ , a ] ) [ , keyword ( a [ , a ] ) ] ,

!$PRAGMA SUN keyword ( a [ , a ] … ) [ , keyword ( a [ , a ] … ) ] ,…

変数 keyword は特定の指令を表します。追加の引数やサブオプションも指定できます。指令によっては、前述に示す追加のキーワード SUN を指定する必要があります。

一般的な指令の構文は、次のとおりです。

制限事項は、次のとおりです。

Fortran のコンパイラは、次の一般的な指令を認識します。

表 2-2 一般的な Fortran 指令の要約

C 指令
!$PRAGMA C(list )

外部関数の名前リストを C 言語のルーチンとして宣言します。

IGNORE_TKR Directive
!$PRAGMA IGNORE_TKR {name {, name} ...}

コンパイラは、特定の呼び出しを解釈するとき、一般的な手続きのインタフェースで表示される仮引数名の型、種類、ランクを無視します。

UNROLL Directive
!$PRAGMA SUN UNROLL=n

コンパイラに、次のループは長さ n に展開できることを伝えます。

WEAK Directive
!$PRAGMA WEAK(name[ =name2])

name を弱いシンボル (weak symbol) または name2 の別名として宣言します。

OPT 指令
!$PRAGMA SUN OPT=n

副プログラムの最適化レベルを n に設定します。

PIPELOOP Directive
!$PRAGMA SUN PIPELOOP=n

次のループでは n 離れた反復間に依存関係があることを宣言します。

PREFETCH Directives
!$PRAGMA SUN_PREFETCH_READ_ONCE(name)
!$PRAGMA SUN_PREFETCH_READ_MANY(name)
!$PRAGMA SUN_PREFETCH_WRITE_ONCE(name)
!$PRAGMA SUN_PREFETCH_WRITE_MANY(name)
名前の参照のために、先読み命令を生成するようにコンパイラに要求します。(-xprefetch オプションを指定する必要があります。このオプションはデフォルトで有効になっています。PREFETCH 指令は、—xprefetch=no でコンパイルし無効にします。ターゲットアーキテクチャーも PREFETCH 指令をサポートしている必要があり、コンパイラ最適化レベルは -xO2 より上である必要があります)。
ASSUME Directives
!$PRAGMA [BEGIN} ASSUME (expression [ ,probability])

!$PRAGMA END ASSUME

プログラム内の特定の個所において、コンパイラが真であると想定できる条件について表明を行います。

2.3.1.1 C 指令

C() 指令は、その引数が外部関数であることを指定します。EXTERNAL 宣言と同義です。ただし、通常の外部名とは違って、Fortran コンパイラでは、これらの引数名に下線が付けられません。詳細は、『Fortranプログラミングガイド』の「C と Fortran のインタフェース」の章を参照してください。

特殊な関数の C() 指令は、各副プログラム中にある、その関数への最初の引用よりも前に現れなければなりません。

例: CABCXYZ をコンパイルします。

       EXTERNAL ABC, XYZ
!$PRAGMA C(ABC, XYZ)

2.3.1.2 IGNORE_TKR 指令

この指令では、コンパイラは、特定の呼び出しを解釈するとき、総称手続きのインタフェースで表示される仮引数名の型、種別、次元数を無視します。

たとえば、次の手続きのインタフェースでは、SRC はどのようなデータ型でもよく、LENKIND=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 ポインタ、割り当て可能な配列の仮引数を除いて、手続きのすべての仮引数に指令が適用されます。

2.3.1.3 UNROLL 指令

UNROLL 指令では、!$PRAGMA のあとに SUN と指定する必要があります。

!$PRAGMA SUN UNROLL=n 指令は、最適化パス中に、次のループを n 回展開するようにコンパイラに指示します。コンパイラは、解析の結果、ループの展開が適切であると判断した場合のみ展開します。

n は正の整数です。次の選択が可能です。

実際に展開されたループがあると、実行可能ファイルのサイズが大きくなります。詳細については、『Fortran プログラミングガイド 』のパフォーマンスと最適化に関する章を参照してください。

例: ループを 2 回展開するときは、次のように指定します。

!$PRAGMA SUN UNROLL=2

2.3.1.4 WEAK 指令

WEAK 指令は、以前に定義されているよりも低い優先順位で同じシンボルを定義します。この指令は主に、ライブラリを作成する場合にソースファイル中で使用されます。リンカーは弱いシンボルを解決できなくてもエラーメッセージを表示しません。

!$PRAGMA WEAK (name1 [=name2])

WEAK (name1) によって、name1 が優先順位の低いシンボルとして定義されます。この場合リンカーは、name1 の定義が見つけられなくてもエラーメッセージを出力しません。

WEAK (name1=name2) によって、name1 が優先順位の低いシンボルとして、また、name2 の別名として定義されます。

プログラムから呼び出された name1 が定義されていない場合、リンカーはライブラリの定義を使用します。ただし、プログラムで name1 の定義が行われている場合は、そのプログラムの定義が使用され、ライブラリ中にある name1 の優先順位が低い大域的な定義は使用されません。プログラムから name2 が直接呼び出されると、ライブラリの定義が使用されます。name2 の定義が重複すると、エラーが発生します。詳細は、Solaris の『リンカーとライブラリ』を参照してください。

2.3.1.5 OPT 指令

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 レベルが使用されます。

2.3.1.6 PIPELOOP[= n] 指令

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 プログラミングガイド』を参照してください。

2.3.1.7 PREFETCH 指令

-xprefetchオプションフラグを使用すると (「3.4.153 -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』も参照してください。

2.3.1.8 ASSUME 指令

ASSUME 指令は、プログラムの特定地点の条件についてコンパイラにヒントを与えます。これらの表明は、コンパイラへの最適化指示のガイドラインとして役立ちます。また、プログラマは、それらの指令を使用して、実行時にプログラムの妥当性をチェックできます。ASSUME のフォーマットは 2 種類あります。

「単一表明」ASSUME の構文は、次のようになります。

!$PRAGMA ASSUME (expression [,probability])

また、「範囲表明」ASSUME は、次のようになります。

!$PRAGMA BEGIN ASSUME [expression [, probability)
     block of statements
!$PRAGMA END ASSUME

単一表明形式を使用すると、プログラムのその地点でコンパイラが想定できる条件を示すことができます。範囲表明形式を使用すると、ステートメントの範囲内を通して成立する条件を示すことができます。範囲表明の BEGINEND のペアは正しくネストされる必要があります。

必要なは、上にリストされている以外でユーザー定義の演算子や関数呼び出しを含まないプログラムの特定地点で評価可能なブール式です。

オプションの 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.105 -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 かマイナスになるため、そのループを使用しないよう実行時の警告が発せられます。

2.3.2 並列化の指令

並列化 指令は、コンパイラに対して、指令のあとに続く DO ループまたはコードの範囲を並列化するように明示的に指示します。一般的な指令とは、構文が異なります。並列化指令は、-openmp を使用してコンパイルされる場合にのみ認識されます。Fortran の並列化についての詳細は、『OpenMP API ユーザーズガイド』および『Fortran プログラミングガイド』を参照してください。

Fortran コンパイラは、OpenMP 3.1 共有メモリー並列化モデルをサポートします。従来の Sun および Cray の並列化指令は現在推奨されていないため、使用すべきではありません。

2.3.2.1 OpenMP 並列化指令

Fortran コンパイラでは、並列プログラミングモデルとして OpenMP Fortran 共有メモリーマルチプロセッシング API を使用することをお勧めします。API は、OpenMP Architecture Review Board (http://www.openmp.org) によって仕様が定められています。

OpenMP 指令を使用可能にするには、コマンド行オプション -openmp を指定してコンパイルする必要があります (「3.4.145 -xopenmp[={ parallel|noopt|none}]」を参照)。

f95 で使用可能な OpenMP 指令についての詳細は、『OpenMP API ユーザーズガイド』を参照してください。

2.3.2.2 従来の Sun および Cray 並列指令


注 - 従来の Sun および Cray 形式の並列化指令は非推奨になりました。Open MP 並列化 API が推奨されます。従来の Sun/Cray 指令から OpenMP モデルへの移行方法については、『OpenMP API ユーザーズガイド』を参照してください。


2.3.3 IVDEP 指令

!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.126 -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 構文にも適用できます。特定のループに対して複数の指令が存在する場合 (IVDEPUNROLL など)、コンパイラは可能な限りそれらすべての指令に従います。