Chapter 6. CF90 Directives

The MIPSpro 7 Fortran 90 compiler, running on IRIX systems, recognizes some of the directives that are supported by the CF90 compiler on UNICOS and UNICOS/mk systems. The directives themselves and the sections in which they are discussed are as follows:

Using Directives

The following sections describe how to use the CF90 directives and the effects they have on IRIX platforms.

For additional general information on using directives, see “Using Directives” in Chapter 3.

Directive Continuation

In the following example, an asterisk (*) appears in column 6 to indicate that the second line is a continuation of the preceding line:

!DIR$ NA
!DIR$*ME

The FIXED and FREE directives must appear alone on a directive line and cannot be continued.

If you want to specify more than one directive on a line, separate each directive with a comma. Some directives require that you specify one or more arguments; when specifying a directive of this type, no other directive can appear on the line.

Spaces can precede, follow, or be embedded within a directive, regardless of source form.

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

Directive Range and Placement

The range and placement of directives is as follows:

  • The FIXED and FREE directives can appear anywhere in your source code. All other directives must appear within a program unit.

  • The BOUNDS/NOBOUNDS and TASK/NOTASK directives take effect at the point at which they appear in the source code.

  • The ID and NOSIDEEFFECTS directives do not apply to any particular range of code. They add information to the file.o generated from the input program.

  • The following directives apply only to the next loop encountered lexically:

    • IVDEP

    • NOINTERCHANGE

    • PREFERTASK

    • UNROLL/NOUNROLL

  • The NAME and IGNORE_TKR directives do not apply to particular ranges of code. They are declarative directives that alter the status of entities in ways that affect compilation.

Interaction of Directives with the -x Command Line Option

The -x option on the f90(1) command line accepts one or more directives as arguments. When your input is compiled, the compiler ignores directives named as arguments to the -x option. For example, if you specify -x mipspro, all directives are ignored. If you specify -x dirname, the particular directive named in dirname is ignored. For more information on this command line option, see “-xdirlist” in Chapter 2.

Check Array Bounds: BOUNDS and NOBOUNDS

Array bounds checking provides a check of most array references at both compile time and run time to ensure that each subscript is within the array's declared size.

The -C option on the f90(1) command line controls bounds checking for a whole compilation. The BOUNDS and NOBOUNDS directives toggle the feature on and off within a program unit. Either directive can specify particular arrays or can apply to all arrays. The formats of these directives are as follows:

!DIR$ BOUNDS [array[, array] ... ]
!DIR$ NOBOUNDS [array[, array] ... ]
array

The name of an array. The name cannot be a subobject of a derived type. When no array name is specified, the directive applies to all arrays.

BOUNDS remains in effect for a given array until the appearance of a NOBOUNDS directive that applies to that array, or until the end of the program unit. Bounds checking can be enabled and disabled many times in a single program unit.


Note: To be effective, these directives must follow the declarations for all affected arrays. It is suggested that they be placed at the end of a program unit's specification statements unless they are meant to control particular ranges of code.

The bounds checking feature detects any reference to an array element whose subscript exceeds the array's declared size. For example:

      REAL A(10)
!  DETECTED AT COMPILE TIME:
      A(11) = X
!  DETECTED AT RUN TIME IF IFUN(M) EXCEEDS 10:
      A(IFUN(M)) = W

The compiler generates a message when it detects an out-of-bounds subscript. If the compiler cannot detect the out-of-bounds subscript (for example, if the subscript includes a function reference), a message is issued for out-of-bound subscripts when your program runs.

Bounds checking increases program run time. If an array's last dimension declarator is *, checking is not performed on the last dimension's upper bound. Arrays in formatted WRITE and READ statements are not checked.

If bounds checking detects an out-of-bounds array reference, a message is issued and the program halts.

Specify Source Form: FREE and FIXED

The FREE and FIXED directives specify whether the source code in the program unit is written in free source form or fixed source form. The FREE and FIXED directives override the -fixedform and -freeform options, if specified, on the f90(1) command line. For more information on the -fixedform and -freeform options, see “-fixedform” in Chapter 2, and “-freeform” in Chapter 2.

The formats of these directives are as follows:

!DIR$ FREE
!DIR$ FIXED

These directives apply to the source file in which they appear, and they allow you to switch source forms within a source file.

You can change source form within an INCLUDE file. After the INCLUDE file has been processed, the source form reverts back to the source form that was being used prior to processing of the INCLUDE file.


Note: The source preprocessor does not recognize the FREE and FIXED directives. These directives must not be specified in a file that is submitted to the source preprocessor.


Create Identification String: ID

The ID directive inserts a character string into the file.o produced for a Fortran source file. The format of this directive is as follows:

!DIR$ ID "character_string"
character_ string 

The character string to be inserted into file.o. The syntax box shows quotation marks as the character_string delimiter, but you can use either apostrophes (' ') or quotation marks (" ").

The character_string can be obtained from file.o in one of the following ways:

  • Method 1. Using the what(1) command. To use the what(1) command to retrieve the character string, begin the character string with the sentinel characters @(#). For example, assume that id.f contains the following source code:

    !DIR$ ID  "@(#)file.f 01 July 1997"
          PRINT *, 'hello'
          END

    The next step is to use file id.o as the argument to the what(1) command, as follows:

    % what id.o
    % id.o:
    %   file.f 01 July 1997

    Note that what(1) does not include the special sentinel characters in the output.

    In the following example, character_string does not begin with the characters @(#). The output shows that what(1) does not recognize the string.

    Input file id2.o contains the following:

    !DIR$ ID  'file.f 01 July 1997'
          PRINT *, 'Hello, world'
          END

    The what(1) command generates the following output:

    % what id2.o
    % id2.o:

  • Method 2. Using the strings(1) or od(1) command. The following example shows how to obtain output using the strings(1) command.

    Input file id.f contains the following:

    !DIR$ ID  "File: id.f   Date: 1 July 1997"
    
             PRINT *, 'hello'
             END

    The strings(1) command generates the following output:

    % f90 -c id.o
    % strings id.o
    File: id.f  Date: 1 July 1997
    % od -c id.o
    ... portion of dump deleted0002300  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
    0002320   F   i   l   e   :       i   d   .   f               D   a   t
    0002340   e   :       1       J   u   l   y       1   9   9   7 001  \0
    0002360  \0  \0  \0  \0 024 003 240 031  \0  \0 203 031  \0  \0 205 005... portion of dump deleted

Disregard Dummy Argument Type, Kind, and Rank: IGNORE_TKR

The IGNORE_TKR directive directs the compiler to ignore the type, kind, and rank (TKR) of specified dummy arguments in a procedure interface. For information on Fortran TKR rules, see chapters 4 and 6 of the Fortran Language Reference Manual, Volume 2.

The format for this directive is as follows:

!DIR$ IGNORE_TKR [darg_name[ , darg_name] ... ]
darg_name

If specified, indicates the dummy arguments for which TKR rules should be ignored. Dummy arguments for assumed-shape arrays or Fortran pointers cannot be specified.

If not specified, TKR rules are ignored for all dummy arguments in the procedure that contains the directive.

The directive causes the compiler to ignore type and kind and rank of the specified dummy arguments when resolving a generic to a specific call. The compiler also ignores type and kind and rank on the specified dummy arguments when checking all the specifics in a generic call for ambiguities.

Example. The following directive instructs the compiler to ignore type, kind, and rank rules for the dummy arguments supplied for the SHMEM_PUT64(3) function call:

      INTERFACE SHMEM_PUT64
         SUBROUTINE SHMEM_PUT64(targ, src, len, pe)
!DIR$    IGNORE_TYPE targ, src
         INTEGER(KIND=4) len
         INTEGER(KIND=4) pe
         END SUBROUTINE SHMEM_PUT64
      END INTERFACE

The preceding code specifies that targ and src can be any data type, but len and pe must be INTEGER(KIND=4) data.

Ignore Vector Dependencies: IVDEP

The IVDEP directive directs the compiler to perform a more liberal dependency analysis for the purpose of software pipelining and other optimizations. The format of this directive is as follows:

!DIR$ IVDEP

This directive's effects depend on command line settings. When this directive is in effect, certain dependencies are ignored depending on the state of the following f90(1) command line options:

Option
 

Effect

-OPT:cray_ivdep=OFF
 

Default command line setting. IRIX semantics are used when performing dependency analysis. Loop-carried dependencies in the subsequent loop are ignored between any two array references whenever the location referred to by at least one of the array references varies inside the loop. For more information on this command line option, see “-OPT:cray_ivdep=setting” in Chapter 2.

-OPT:cray_ivdep=ON
 

UNICOS semantics are used when performing dependency analysis. The compiler disregards backward dependencies only. For more information on this command line option, see “-OPT:cray_ivdep=setting” in Chapter 2.

-OPT:liberal_ivdep=ON
 

All dependencies are disregarded. For more information on this command line option, see “-OPT:liberal_ivdep=setting” in Chapter 2.

The IVDEP directive applies only to inner loops, and it applies to the first DO loop that follows the directive within the same program unit.

Example 1. There are two basic types of dependencies in the loop below: loop-carried and non-loop-carried. A loop-carried dependency occurs across iterations of the loop. A non-loop-carried dependency occurs within an iteration of the loop.

!DIR$ IVDEP
      DO I = 1,N
         A(INDEX(1,I)) = B(I)
         A(INDEX(2,I)) = C(I)
      END DO

A loop-carried dependency would occur if INDEX(1,I) in some iteration of I was equal to INDEX(1,I+K) in some other iteration of I. A non-loop-carried dependency would occur if INDEX(1,I) was equal to INDEX(2,I) in any iteration of I.

Example 2. The following loop is executed with default command line options:

!DIR$ IVDEP
      DO I = 1,N
         A(B(K)) = A(C(K)) + D(I)
      END DO

Neither the reference to A(B(K)) nor to A(C(K)) vary inside the loop, so the IVDEP directive does not break the dependence.

Example 3. The following loop is executed with default command line options:

!DIR$ IVDEP
      DO I = 1,N
         A(I) = A(I-1) + 3.0
      END DO

The IVDEP directive breaks the dependence, but the compiler issues a message indicating that an obvious dependence is being broken.

Example 4. The following loop is executed with default command line options, and the IVDEP directive breaks the dependence:

!DIR$ IVDEP
      DO I = 1,N
         A(B(I)) = A(B(I)) + 3.0
      END DO

Example 5. The following loop is executed with default command line options, and the IVDEP directive does not break the dependence on A(I) because the dependence is non-loop-carried:

!DIR$ IVDEP
      DO I = 1,N
         A(I) = B(I)
         C(I) = A(I) + 3.0
      END DO

Example 6. The following loop is executed with -OPT:cray_ivdep=ON in effect:

!DIR$ IVDEP
      DO I = 1,N
         A(I) = A(I-1) + 3.0
      END DO

UNICOS semantics are used, and the IVDEP directive breaks all lexically backward dependencies. When the loop is executed, however, the compiler issues a message indicating that it is breaking an obvious dependence.

Example 7. When the following loop is executed, the IVDEP directive does not break the dependence. This is because the dependence is from the load to the store, and the load comes lexically before the store. Assume that the code fragment in this example was compiled with -OPT:cray_ivdep=ON.

!DIR$ IVDEP
      DO I = 1,N
         A(I) = A(I+1) + 3.0
      END DO

To break all dependencies, specify -OPT:liberal_ivdep=ON. Both -OPT:cray_ivdep and -OPT:liberal_ivdep are disabled by default.

For UNICOS vector codes being transitioned to IRIX, it is recommended that -OPT:cray_ivdep=ON be used.

External Name Mapping Directive: NAME

The NAME directive allows you to specify a case-sensitive external name, or a name that contains characters outside of the Fortran character set, in a Fortran program. This directive must appear inside a program unit. The case-sensitive external name is specified on the NAME directive, in the following format:

!DIR$ NAME (fortran_name="external_name"
[, fortran_name="external_name" ] ... )
fortran_name

The name used for the object throughout the Fortran program.

external_name

The external form of the name.

Rules for Fortran naming do not apply to the external_name string; any character sequence is valid. You can use this directive, for example, when writing calls to C routines.

Example:

      PROGRAM MAIN
!DIR$ NAME (FOO="XyZ")
      CALL FOO           ! XyZ IS REALLY BEING CALLED
      END PROGRAM

Inhibit Loop Interchange: NOINTERCHANGE

The NOINTERCHANGE directive inhibits the compiler's ability to interchange the loop that follows the directive with another inner or outer loop. The format of this directive is as follows:

!DIR$ NOINTERCHANGE

Determine Register Storage: NOSIDEEFFECTS

The NOSIDEEFFECTS directive allows the compiler to keep information in registers across a single call to a subprogram without reloading the information from memory after returning from the subprogram. The directive is not needed for intrinsic functions.

NOSIDEEFFECTS declares that a called subprogram does not redefine any variables that meet the following conditions:

  • Local to the calling program

  • Passed as arguments to the subprogram

  • Accessible to the calling subprogram through host association

  • Declared in a common block or module

  • Accessible through USE association

The format of this directive is as follows:

!DIR$ NOSIDEEFFECTS f[, f] ...
f

Symbolic name of a subprogram that the user ensures to have no side effects. f must not be the name of a dummy procedure, module procedure, or internal procedure.

A procedure declared NOSIDEEFFECTS should not define variables in a common block or module shared by a program unit in the calling chain. All arguments should be intent IN; that is, the procedure must not modify its arguments. If these conditions are not met, results are unpredictable.

The NOSIDEEFFECTS directive must appear in the specification part of a program unit and must appear before the first executable statement.

The compiler may move invocations of a NOSIDEEFFECTS subprogram from the body of a DO loop to the loop preamble if the arguments to that function are invariant in the loop. This may affect the results of the program, particularly if the NOSIDEEFFECTS subprogram calls functions such as the random number generator or the real-time clock.

The effects of the NOSIDEEFFECTS directive are similar to those that can be obtained by specifying the PURE prefix on a function or a subroutine declaration. For more information on the PURE prefix, see Fortran Language Reference Manual, Volume 2.

Designate a Nest to Task: PREFERTASK

The PREFERTASK directive allows loops with large iteration counts to be considered as candidates for tasking.

The compiler analyzes loops that follow a PREFERTASK directive to determine whether the loop is suitable for Autotasking. The PREFERTASK directive disables the compiler's threshold checking.


Note: The Autotasking directives are outmoded. Silicon Graphics encourages you to write new codes using the OpenMP Fortran API directives.

This directive can be used if there is more than one loop in the nest that can be autotasked. Autotasking must be enabled for this directive to take effect. The format of this directive is as follows:

!DIR$ PREFERTASK

In the following example, both loops can be autotasked, but the PREFERTASK directive directs the compiler to autotask the inner DO J loop. Without the directive and without any knowledge of N and M, the compiler would task the outer DO I loop. With the directive, the loops are interchanged, to increase parallel granularity, and the resulting outer DO J loop is autotasked.

      DO I = 1, N
!DIR$ PREFERTASK
        DO J = 1, M
          E(J,I) = F(J,I) + G(J,I)
        END DO
      END DO

Tasking Directives: TASK and NOTASK

The NOTASK directive suppresses compiler attempts to task loops and disables recognition of Autotasking directives. NOTASK takes effect at the next statement and applies to the rest of the program unit unless it is superseded by a TASK directive. These directives are disabled if tasking is disabled.


Note: The Autotasking directives are outmoded. Silicon Graphics encourages you to write new codes using the OpenMP Fortran API directives.

The formats of these directives are as follows:

!DIR$ TASK
!DIR$ NOTASK

When !DIR$ NOTASK has been used within the same program unit, !DIR$ TASK causes the compiler to resume its attempts to task loops. After a TASK directive is specified, the compiler again attempts to autotask loops and array syntax statements and !MIC$ directives are again recognized.

The TASK directive affects subsequent loops. The NOTASK directive also affects subsequent loops, but if it is specified within the body of a loop, it affects the loop in which it is contained and all subsequent loops.

Unroll Loops: UNROLL and NOUNROLL

Loop unrolling can improve program performance by revealing cross-iteration memory optimization opportunities such as read-after-write and read-after-read. The effects of loop unrolling also include:

  • Improved loop scheduling by increasing basic block size

  • Reduced loop overhead

  • Improved chances for cache hits

The formats of these directives are as follows:

!DIR$ UNROLL [n]
!DIR$ NOUNROLL
n

Specifies the total number of loop body copies to be generated. n must be a positive integer.

If you specify a value for n, the compiler does not attempt to determine the number of copies to generate based on the number of inner loops in the loop nest.

The UNROLL directive should be placed immediately before the DO statement of the loop that should be unrolled.


Warning: If placed prior to a noninnermost loop, the UNROLL directive asserts that the following loop has no dependencies across iterations of that loop. If dependencies exist, incorrect code could be generated.

The UNROLL directive can be used only on loops whose iteration counts can be calculated before entering the loop. If UNROLL is specified on a loop that is not the innermost loop in a loop nest, the inner loops must be nested perfectly. That is, all loops in the nest can contain only 1 loop, and only the innermost loop can contain work.

The NOUNROLL directive inhibits loop unrolling.