Chapter 3. General Directives

A directive is a line inserted into Fortran source code that specifies actions to be performed by the compiler. Directive lines are not Fortran statements.

Many compiler features are implemented as either command line options or directives. The features implemented as command line options are set at compile time and applied to all files in the compilation. The features implemented through directives are set within your Fortran source code, and they apply to portions of your source code.

This chapter introduces the compiler directive set and describes the general directives. The sections in this chapter are as follows:

Using Directives

All directives are of the following form:

prefix directive
prefix

Each directive begins with a prefix. The prefix needed for each directive is shown in the directive's description. The following directive prefixes are used:

The prefix used also depends on which Fortran source form you are using, as follows:

  • If you are using fixed source form, begin a directive line with the characters Cprefix or !prefix. The ! or C character must appear in column 1. Beginning the directive with a ! or C character ensures that other compilers will treat directive lines as comment lines.

  • If you are using free source form, begin a directive line with the characters !prefix, followed by a space, and then one or more directives. The !prefix need not start in column 1, but it must be the first text on a line.

Because both fixed source form and free source form accept directives that start with the exclamation point (!), that is the initial character used in all directive syntax descriptions in this manual.

directive

This is the specific directive's syntax. The syntax usually consists of the directive name. Some directives accept arguments. A directive's arguments, if any, are shown in the description for the directive itself.

The following sections describe the general format for directives and explain how directives are continued across source code lines.


Note: The multiprocessing directives supported in previous MIPSpro Fortran 90 releases are outmoded, and so are the !$PAR, C$PAR, !$, and C$ directive prefixes. This technology is outmoded, but it is still supported for older codes that require this functionality. You are encouraged to modify your code using the OpenMP directives described in Chapter 4, “OpenMP Fortran API Multiprocessing Directives”.


Directives and Command Line Options

Some compiler features can be activated on the command line and through compiler directives. The difference is that a command line setting applies to all files in the compilation, but a directive applies to only a program unit or to another specific part of a source file.

Generally, and by default, directives override command line options. There are exceptions to this rule, however. The exceptions, if any, are noted in the introductory text to each directive group.

Directive Range

The range of a particular directive depends on the directive itself, as follows:

  • If a directive appears within a program unit, it applies only to that program unit. Within a program unit, many directives apply only to the loops that they immediately precede.

  • If a directive appears outside a program unit (for example, prior to program code in a file) it applies to the entire file.

The descriptions for the individual directives indicate the range of the directive.

Directive Continuation and Other Considerations

It is sometimes necessary to continue a directive across one or more source code lines. The continuation character used and its placement within the directive line depends on the type of directive you are using. The introductory text for each directive group indicates the continuation character that is appropriate for that group.

For all directives in this chapter, the prefix for a directive line that is a continuation line is !*$*&.

Do not use source preprocessor (#) directives within multiline compiler directives.

LNO Directives

The loop nest optimization (LNO) directives control loop nest optimizations. By default, directives override command line options. To reverse this, and have command line options override the LNO directives, specify -LNO:ignore_pragmas . To continue a directive, the continuation line must begin with !*$*&.

The LNO directives are described in detail on the lno(5) man page. The following list summarizes the available directives:

  • The AGGRESSIVEINNERLOOPFISSION directive specifies that the following loop should be split into as many loops as possible. In a loop nest, this directive must precede an inner loop.

  • The BLOCKABLE directive specifies that it is legal to cache block the subsequent loops.

  • The BLOCKINGSIZE and NOBLOCKING directives assert that the loop following the directive either is (or is not) involved in a cache blocking for the primary or secondary cache.

  • The fission control directives specify whether the compiler should perform loop fission on the loops that immediately follow these directives.

  • The fusion control directives specify whether the compiler should perform loop fusion on the loops that immediately follow these directives. Loop iterations may be peeled as needed during loop fusion. The limit of this peeling is 5, or the number specified by the -LNO:fusion_peeling_limit command line option.

  • The loop interchange control directives specify whether or not the order of the following two or more loops should be interchanged. These directives apply to the loops that they immediately precede.

  • The PREFETCH directive controls the MIPS IV prefetch instruction. Using this directive can increase performance in program units that are likely to encounter cache misses during execution. This directive applies only to the program unit in which it appears.

    When the directive is specified, the compiler estimates the memory references that will be cache misses, inserts prefetches for the misses, and schedules the prefetches ahead of their corresponding references. You can specify different levels of prefetching aggressiveness for the primary and secondary cache.

  • The PREFETCH_MANUAL directive specifies whether the PREFETCH_REF and the PREFETCH_REF_DISABLE directives, which perform manual prefetches, should be respected or ignored within a subprogram.

  • The PREFETCH_REF directive requests prefetching for a specific memory reference. This directive applies only to the loop nest that includes references to array, and the directive must immediately precede the loop nest.

    When this directive is specified, all references to array in the subsequent loop nest are ignored by the automatic prefetcher (if enabled).

  • The PREFETCH_REF_DISABLE directive disables prefetching for all references to an array. This directive applies to all array references within the program unit.

  • The UNROLL directive specifies loop unrolling. This directive applies to the loop that immediately follows the directive.

    Inner loop unrolling occurs automatically when -O2 or -O3 are in effect. Non-inner loop unrolling (and jam) occurs when -O3 is in effect.

Symbol Storage Directives

The following directives control symbol storage:

  • ALIGN_SYMBOL

  • FILL_SYMBOL

  • FLUSH

  • SECTION_GP

  • SECTION_NON_GP

Control Symbol Alignment and Padding

The ALIGN_SYMBOL and FILL_SYMBOL directives control the way symbols are stored.

The ALIGN_SYMBOL directive aligns the start of symbol at a specified alignment boundary.

The FILL_SYMBOL directive pads symbol with additional storage so that the symbol is assured not to overlap (even partially) with any other data item within the storage of the specified size. The additional padding required is divided between each end of the specified variable. For example, a FILL_SYMBOL(X,L1CACHELINE) directive guarantees that X does not suffer from false sharing for the primary cache line.

The formats for these directives are as follows:

!*$* ALIGN_SYMBOL (symbol [, storage])

!*$* FILL_SYMBOL (symbol [, storage])
symbol

Specify the name of a symbol. symbol can be a common block variable or a module name. symbol cannot be a component of a derived type, an array element, a common block, or blank common.

storage

Specify the storage size. Specify one of the following values for storage:

storage 

Action

L1CACHELINE 

Specifies the machine-specific first-level cache line size, typically 32 bytes.

L2CACHELINE 

Specifies the machine-specific secondary cache line size, typically 128 bytes.

PAGE 

Specifies a machine-specific page. Typically 16 KB.

power-of-two 

An integer value that is a power of 2. This is measured in bytes.

For common block variables, these directives are required at each declaration of the common block. Because the directives modify the allocated storage and its alignment for the named symbol, inconsistent directives can lead to undefined results.

The ALIGN_SYMBOL directive has no effect on fixed-size local symbols, such as simple scalars or arrays of known size (for example symbols declared as REAL(N) or REAL(A(3))). The directive continues to be effective for automatic arrays (stack-allocated arrays of dynamically determined size).

You cannot specify an ALIGN_SYMBOL directive and a FILL_SYMBOL directive for the same symbol .

Example 3-1. Controlling symbol alignment and padding

! X IS A COMMON BLOCK VARIABLE
      COMMON X!
      INTEGER(KIND=4) X
!*$* ALIGN_SYMBOL (X, 32)

!   X WILL START AT A 32-BYTE BOUNDARY.
!   WARNING: THE LAYOUT OF THE COMMON BLOCK WILL BE AFFECTED

!*$* ALIGN_SYMBOL (X, 2)
!   ERROR: CANNOT REQUEST AN ALIGNMENT LOWER THAN THE NATURAL
!   ALIGNMENT OF THE SYMBOL.

      REAL(KIND=8) Y
!   Y IS A COMMON BLOCK OR LOCAL VARIABLE
!*$* FILL_SYMBOL (Y, L2CACHELINE)


!   ALLOCATE EXTRA STORAGE BOTH BEFORE AND AFTER Y SO THAT
!   Y IS WITHIN AN L2CACHELINE (128 BYTES) ALL BY ITSELF.
!   THIS CAN BE USEFUL TO AVOID FALSE-SHARING BETWEEN MULTIPLE
!   PROCESSORS FOR THE CACHE LINE CONTAINING Y.


Declare a Synchronization Point

The FLUSH directive identifies synchronization points at which thread-visible variables are written back to memory. This directive must appear at the precise point in the code at which the synchronization is required.


Note: This directive has the same effect as the FLUSH directive described in the OpenMP Fortran API.

Thread-visible variables include the following data items:

  • Globally visible variables (common blocks and modules).

  • Local variables that do not have the SAVE attribute but have had their address taken and saved or have had their address passed to another subprogram.

  • Local variables that do not have the SAVE attribute that are declared shared in a parallel region within the subprogram.

  • Dummy arguments.

  • All pointer dereferences.

This directive has the following format:

!*$* FLUSH [(var[, var] ...)]
var

Variables to be flushed.

Specify Global Pointer Use

The compiler can reference global data by using the global pointer and an offset value. Using the global pointer (gp) is more efficient than constructing the address at each occurence, but because the offset size is limited to 16 bits, only a limited set of elements can be referenced using the global pointer.

The compiler places global data in gp-relative or non-gp-relative sections, but you can use the SECTION_GP and SECTION_NON_GP directives to specify the variables to go within the gp-relative section and the variables that need to be addressed explicitly.

The formats for these directives are as follows:

!*$* SECTION_GP (symbol [, symbol] ...)

!*$* SECTION_NON_GP (symbol [, symbol] ...)
symbol

Enter one or more symbols. Separate multiple symbols with commas. Valid symbols are common block names, variables specified on SAVE statements, and module names. If a module name is specified, all storage in the module is affected. If a common block name is specified, it must be of the following form: /name/ .

Inlining and IPA Directives

The following are the inlining and interprocedural analysis (IPA) directives:

  • INLINE, NOINLINE

  • IPA, NOIPA


Note: Neither inlining nor IPA are enabled by default. By default, the directives in this section, if present in your source code, are ignored. To enable the directives and turn on inlining and IPA, specify the -INLINE: option or the -IPA: option on your f90(1) command line. For more information on the command line interaction with these features, see the f90 (1) or ipa(5) man page.

Inlining is the process of replacing a procedure reference with a copy of the procedure's code. This eliminates procedure call overhead and exposes the relationships between the procedure code, the return value, and the surrounding code. The INLINE and NOINLINE directives allow you to specify procedures that should be inlined.

Interprocedural analysis (IPA) is a compiler feature that includes inlining, common block array padding, constant propagation, dead procedure elimination, dead variable elimination, and global name optimizations. For detailed information on the IPA feature, see the ipa(5) man page. The IPA and NOIPA directives allow you to control IPA.

The formats of these directives are as follows:

!*$* INLINE location [(name [,name] ...)]

!*$* NOINLINE location [(name [,name] ...)]

!*$* IPA location [(name [,name] ...)]

!*$* NOIPA location [(name [,name] ...)]
location

Specify one of the following for location:

location

Action

HERE

Specifies that routines named on the subsequent source code line should be inlined or should undergo IPA. Default.

ROUTINE

Specifies that the named function should be inlined or should undergo IPA everywhere it appears within the current routine.

GLOBAL

Specifies that the named function should be inlined or should undergo IPA throughout the source file.

name

For the inlining directives, each name specification represents one or more routines to be inlined. If no routines are named, all routines in the program are inlined.

For the IPA directives, each name specification represents one or more routines to undergo IPA. If no routines are named, all routines in the program undergo IPA.

Example 3-2. Inlining

Consider the following code fragment:

      DO I = 1,N
!*$* INLINE HERE (BETA)
         CALL BETA(I,1)
      ENDDO
      CALL BETA(N,2)

Using the specifier ROUTINE rather than HERE in this example would inline both calls to BETA. Note that -INLINE:=ON must be specified on the f90(1) command line when this code is compiled in order for the inlining directive to be recognized.