Sun Studio 12 Update 1:Fortran 用户指南

2.3 指令

可使用源代码指令(一种 Fortran 注释格式)将有关专门的优化或并行化选择的特定信息传递给编译器。编译器指令有时也称为 pragma。编译器可以识别一组通用指令和并行化指令。f95 还可处理 OpenMP 共享内存多处理指令。

特定于 f95 的指令在4.8 指令中进行说明。表 C–1 提供了 f95 可识别的所有指令的完整摘要。


注 –

指令并不是 Fortran 标准的一部分。


2.3.1 通用指令

Fortran 通用指令的各种形式包括:

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

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

C$PRAGMA SPARC keyword ( a [ , a ] … ) [ , keyword ( a [ , a ] … ) ] ,…

变量 keyword 标识特定的指令。此外也可以使用额外的参数或子选项。(某些指令要求使用额外的关键字 SUNSPARC,如上所示。)

通用指令使用以下语法:

请遵循以下约束:

Fortran 编译器可识别以下通用指令:

表 2–2 通用 Fortran 指令摘要

C 指令

C$PRAGMA C(list)

将一系列外部函数的名称声明为 C 语言例程。 

IGNORE_TKR 指令

C$PRAGMA IGNORE_TKR {name {, name} ...}

在解析特定调用时,编译器会忽略在通用过程接口中出现的指定哑元参数名称的类型、种类和等级。 

UNROLL 指令

C$PRAGMA SUN UNROLL=n

建议编译器将下面的循环解开为指定的长度 n

WEAK 指令

C$PRAGMA WEAK(name[=name2])

name 声明为弱符号,或者声明为 name2 的别名。

OPT 指令

C$PRAGMA SUN OPT=n

将子程序的优化级别设置为 n

PIPELOOP 指令

C$PRAGMA SUN PIPELOOP=n

断言下面的循环中在间隔为 n 的迭代之间存在依赖性。

PREFETCH 指令

C$PRAGMA SUN_PREFETCH_READ_ONCE(name)C$PRAGMA SUN_PREFETCH_READ_MANY(name)C$PRAGMA SUN_PREFETCH_WRITE_ONCE(name)C$PRAGMA SUN_PREFETCH_WRITE_MANY(name)

请求编译器为名称引用生成预取指令。(需要使用 -xprefetch 选项,缺省情况下启用该选项。编译时使用 —xprefetch=no 可以禁用预取指令。目标体系结构也必须支持预取指令,而且编译器优化级别必须大于 —xO2。)

ASSUME 指令

C$PRAGMA [BEGIN} ASSUME (expression [,probability])

C$PRAGMA END ASSUME

断言编译器可假定程序中某些点处的条件为真。 

2.3.1.1 C 指令

C() 指令指定其参数为外部函数。它与 EXTERNAL 声明等效,但有一点例外,与普通外部名称不同,Fortran 编译器在这些参数名称的后面不附加下划线。有关详细信息,请参见《Fortran 编程指南》中的“C-Fortran 接口”一章。

在每个包含特定函数引用的子程序中,用于该函数的 C() 指令应该出现在对该函数的第一次引用之前。

示例-为 C 编译 ABCXYZ


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

2.3.1.2 IGNORE_TKR 指令

此指令导致编译器在解析特定调用时,忽略在通用过程接口中出现的指定哑元参数名称的类型、种类和等级。

例如,在下面的过程接口中,指令指定 SRC 可以是任何数据类型,但 LEN 可以为 KIND=4KIND=8。接口块为通用过程名称定义了两个特定过程。此示例以 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_64S 的实际类型并不能确定要调用哪个例程。对于基于参数类型、种类或等级来调用特定库例程的包装器来说,这可大大简化为其编写通用接口的工作。

请注意,无法在该指令中指定假定形状数组、Fortran 指针或可分配数组的哑元参数。如果未指定名称,则该指令将应用于过程的所有哑元参数,但假定形状数组、Fortran 指针或可分配数组的哑元参数除外。

2.3.1.3 UNROLL 指令

UNROLL 指令要求您在 C$PRAGMA 后面指定 SUN

C$PRAGMA SUN UNROLL=n 指令指示编译器在其优化过程中将下面的循环解开 n 次。(只有当编译器分析认为此类解开有必要时,它才会解开循环。)

n 是正整数。选项有:

如果实际解开了任何循环,那么可执行文件会变大。有关详细信息,请参见《Fortran 编程指南》中有关性能与优化的章节。

示例—解开循环两次:


C$PRAGMA SUN UNROLL=2

2.3.1.4 WEAK 指令

WEAK 指令定义一个符号,其优先级比以前定义的相同符号要低。此 pragma 主要用于源文件中以创建库。如果链接程序无法解析弱符号,它并不生成错误消息。


C$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 指令要求您在 C$PRAGMA 后面指定 SUN

OPT 指令设置子程序的优化级别,这将覆盖编译命令行中指定的级别。该指令必须紧挨在目标子程序前面出现,并且仅应用于该子程序。例如:


C$PRAGMA SUN OPT=2
        SUBROUTINE smart(a,b,c,d,e)
        ...etc

在使用指定 -O4f95 命令编译以上内容时,该指令将覆盖此级别,并以 -O2 级别编译子例程。 除非该例程后面另有一个指令,否则下一个子程序将以 -O4 级别编译。

还必须使用 -xmaxopt[=n] 选项编译例程以便识别该指令。此编译器选项为 PRAGMA OPT 指令指定最大的优化值:如果 PRAGMA OPT 指定的优化级别大于 -xmaxopt 级别,则使用 -xmaxopt 级别。

2.3.1.6 PIPELOOP[= n] 指令

PIPELOOP=n 指令要求您在 C$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)
C$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.157 –xprefetch[= a[,a]])可启用一组 PREFETCH 指令,这些指令建议编译器在支持预取的处理器上为指定的数据元素生成预取指令。


C$PRAGMA SUN_PREFETCH_READ_ONCE(name)
C$PRAGMA SUN_PREFETCH_READ_MANY(name)
C$PRAGMA SUN_PREFETCH_WRITE_ONCE(name)
C$PRAGMA SUN_PREFETCH_WRITE_MANY(name)

有关预取指令的详细信息,另请参见《C 用户指南》或《SPARC Architecture Manual, Version 9》。

2.3.1.8 ASSUME 指令

ASSUME 指令向编译器提供有关程序中某些点的条件的提示。这些断言可以帮助编译器设定其优化策略。程序员也可以在执行过程中使用这些指令检查程序的有效性。ASSUME 有两种格式。

“点断言”ASSUME 的语法是:


C$PRAGMA ASSUME (expression [,probability])

另外,“范围断言”ASSUME 的语法是:


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

请使用点断言格式来声明编译器可在程序中的该点采用的条件。而使用范围断言格式来声明在语句封闭范围内有效的条件。范围断言中的 BEGINEND 对必须正确嵌套。

必需的 expression 是一个布尔表达式,该表达式可在程序中的该点求值,并且其中不包含用户定义的运算符或函数调用(下面列出的除外)。

可选的 probability 值是一个介于 0.0 和 1.0 之间的实数或者是整数 0 或 1,它给出表达式为真的可能性。probability 的值为 0.0(或 0)意味着永远不会为真;值为 1.0(或 1)则意味着始终为真。如果没有指定,则认为表达式很有可能为真,但并不一定为真。probability 为 0 或 1 以外其他值的断言是非必然断言。类似地,probability 正好为 0 或 1 的断言是必然断言

例如,如果程序员知道 DO 循环的长度始终大于 10,000,则为编译器提供该提示可使之生成更好的代码。通常,以下循环在使用 ASSUME pragma 时比不使用时运行得要快。


C$PRAGMA BEGIN ASSUME(__tripcount().GE.10000,1) !! a big loop
        do i = j, n
           a(i) = a(j) + 1
        end do
C$PRAGMA END ASSUME

有两个内部函数专用于 ASSUME 指令的表达式子句。(请注意,它们的名称前面有两个下划线。)

__branchexp()

用于紧挨在分支转移语句(带有布尔控制表达式)前面的点断言。它与控制分支转移语句的布尔表达式生成相同的结果。 

__tripcount()

生成紧跟在指令后面的或指令所包含的循环的行程计数。在用于点断言时,指令后面的语句必须位于 DO 的第一行。在用于范围断言时,它应用于最外层的封闭循环。

在将来的版本中,特殊内部函数的列表可能会扩展。

可与 -xassume_control 编译器选项结合使用。(请参见3.4.111 –xassume_control[ =keywords])例如,在使用 -xassume_control=check 进行编译时,如果行程计数变为小于 10,000,则上述示例将生成一条警告。

如果使用 -xassume_control=retrospective 进行编译,则在程序终止时会生成一个摘要报告,指出所有断言是真还是假。有关 -xassume_control 的详细信息,请参见 f95 手册页。

另一个示例:


C$PRAGMA ASSUME(__tripcount.GT.0,1)
       do i=n0, nx

如果使用 -xassume_control=check 编译上述示例,则在由于行程计数为零或负数而没有执行循环时,将会发出一条运行时警告。

2.3.2 并行化指令

并行化指令显式地请求编译器尝试并行处理该指令后面的 DO 循环或代码区域。其语法与一般指令不同。只有在使用 -openmp 选项进行编译时才能识别并行化指令。有关 Fortran 并行化的详细信息,请参见《OpenMP API 用户指南》和《Fortran 编程指南》。

Fortran 编译器支持 OpenMP 3.0 共享内存并行化模型。传统的 Sun 和 Cray 并行化指令现已过时,不应再使用它们。

2.3.2.1 OpenMP 并行化指令

Fortran 编译器将 OpenMP Fortran 共享内存多处理 API 识别为首选的并行编程模型。该 API 是由 OpenMP 体系结构审查委员会 (http://www.openmp.org) 指定的。

要启用 OpenMP 指令,您必须使用命令行选项 -xopenmp 进行编译。(请参见3.4.149 –xopenmp[={ parallel|noopt|none}]。)

有关 f95 接受的 OpenMP 指令的更多信息,请参见《OpenMP API 用户指南》。

2.3.2.2 传统的 Sun/Cray 并行化指令


注 –

传统的 Sun 和 Cray 风格的并行化指令现已过时。首选使用 OpenMP 并行化 API。有关如何从传统的 Sun/Cray 指令迁移到 OpenMP 模型的信息,请参见《OpenMP API 用户指南》。