Chapter 7. Fine-Tuning Power Fortran

This chapter contains the following sections:

Overview of Directives and Assertions

After you run a Fortran source program through Power Fortran once, you can use directives and assertions to fine-tune program execution. The listing file shows where and why Power Fortran did not parallelize the code. You can also use WorkShop Pro MPF to review the Power Fortran analysis of your program.

You can use directives and assertions to force Power Fortran to execute portions of code in various ways. Command-line directives apply to the program as a whole. You can use the –pfa,–directives command-line option to selectively enable or disable certain directives and assertions. Refer to “Recognizing Directives” for information about the –directives option.

If you want finer control for parallelizing a critical loop or inlining a particular occurrence of a routine, specify directives and assertions directly in the code. You can also use directives and assertions to keep Power Fortran from converting code to run in parallel. In other cases you might want to explicitly force Power Fortran to run segments of code in parallel even though it normally would not.

Because Power Fortran does not check the correctness of assertions, they can be unsafe. If you specify an incorrect assertion, the code generated by Power Fortran might give different answers from the scalar program. If you suspect unsafe assertions are causing problems, use thenodirectives command-line option or the C*$* NO ASSERTIONS directive to tell Power Fortran to ignore all assertions.

Directives

Directives enable, disable, or modify a feature of the compiler. Essentially, directives are command-line options specified within the input file instead of on the command line. Unlike command-line options, directives have no default setting. To invoke a directive, you must either toggle it on or set a desired value for its level.

Directives allow you to enable, disable, or modify a feature of the compiler in addition to, or instead of, command-line options. Directives placed on the first line of the input file are called global directives. The compiler interprets them as if they appeared at the top of each program unit in the file. Use global directives to ensure that the program is compiled with the correct command-line options. Directives appearing anywhere else in the file apply only until the end of the current program unit. The compiler resets the value of the directive to the global value at the start of the next program unit. (Set the global value using a command-line option or a global directive.)

Some command-line options act like global directives. Others override directives. Many directives have corresponding command-line options. If you specify conflicting settings in the command line and a directive, the compiler chooses the most restrictive setting. For Boolean options, if either the directive or the command line has the option turned off, it is considered off. For options that require a numeric value, the compiler uses the minimum of the command-line setting and the directive setting.

Table 7-1 lists the directives supported by the compiler. In addition to the standard Silicon Graphics directives, the compiler supports the Cray and VAST directives listed in the table. The compiler maps these directives to corresponding Silicon Graphics assertions. Refer to “Assertions” for details.

Table 7-1. Directives Summary

Directive

Compatability

C*$* ARCLIMIT(n)

Silicon Graphics

C*$* [NO] ASSERTIONS

Silicon Graphics

C*$* EACH_INVARIANT_IF_GROWTH(n)

Silicon Graphics

C*$* [NO] INLINE

Silicon Graphics

C*$* [NO] IPA

Silicon Graphics

C*$* MAX_INVARIANT_IF_GROWTH(n)

Silicon Graphics

C*$* OPTIMIZE(n)

Silicon Graphics

C*$* ROUNDOFF(n)

Silicon Graphics

C*$* SCALAR OPTIMIZE(n)

Silicon Graphics

C*$* UNROLL(integer[,weight])

Silicon Graphics

CDIR$ NO RECURRENCE

Cray

CVD$ [NO] DEPCHK

VAST

CVD$ [NO] LSTVAL

VAST


Assertions

Assertions provide the compiler with additional information about a source program. Sometimes assertions can improve optimization results. Use them only when speed is essential. Assertions can be unsafe because the compiler cannot verify the accuracy of the information provided. If you specify an incorrect assertion, the compiler-generated code might produce results different from those of the original serial program. If you suspect unsafe assertions are causing problems, use the –pfa,–nodirectives command-line option or the C*$* NO ASSERTIONS directive to tell the compiler to ignore all assertions.

Table 7-2 lists the supported assertions and their duration.

Table 7-2. Assertions and Their Duration

Assertion

Duration

C*$* ASSERT [NO] ARGUMENT ALIASING

Until reset

C*$* ASSERT [NO] BOUNDS VIOLATIONS

Until reset

C*$* ASSERT [NO] EQUIVALENCE HAZARD

Until reset

C*$* ASSERT NO RECURRENCE

Next loop

C*$* ASSERT RELATION (name.xx.name)

Next loop

C*$* ASSERT [NO] TEMPORARIES FOR CONSTANT ARGUMENTS

Next loop

As with a directive, the compiler treats an assertion as a global assertion if it comes before all comments and statements in the file. That is, the compiler treats the assertion as if it were repeated at the top of each program unit in the file.

Some assertions (such as C*$* ASSERT RELATION) include variable names. If you specify them as global assertions, a program uses them only when those variable names appear in COMMON blocks or are dummy argument names to the subprogram. You cannot use global assertions to make relational assertions about variables that are local to a subprogram.

Many assertions, like directives, are active until the end of the program unit (or file) or until you reset them. Other assertions are active within a program unit, regardless of where they appear in that program unit.

Certain Cray and VAST directives function like Silicon Graphics assertions. The compiler maps these directives to the corresponding Silicon Graphics assertions. These directives are described along with the related assertions later in this chapter.

There is no guarantee that a specified assertion will have an effect. The compiler notes the information provided by the assertion and uses the information if it will help.

To understand how the compiler interprets assertions, you must understand the concept of assumed dependences. The following loop contains two types of dependences:

         DO 10 i=1,n
 10      X(i) = X(i-1) + X(m)

X is an array, n and m are scalars, and nothing is known about the relationship between n and m. Between X(i) and X(i-1) there is a forward dependence, with a distance of one. Between X(i) and X(m), the compiler tries to find a relation, but cannot, because it does not know the value of m in relation to n. The second dependence is called an assumed dependence, because it is assumed but cannot be proven to exist.

Circumventing Power Fortran

Sometimes you might need to hand-tune a DO loop so that it runs in parallel. Use the directives in this section to prevent Power Fortran from analyzing your modified code.

C$ DOACROSS

The C$ DOACROSS directive tells the Fortran 77 compiler to generate parallel code for the following loop. When Power Fortran encounters this directive on input, it does not modify the accompanying loop and therefore does not interfere with any hand-tuning.

C$ DOACROSS is the standard method for parallelism in Fortran. This directive is the same directive that Power Fortran generates as a result of its analysis. Refer to the MIPSpro Fortran 77 Programmer's Guide for more information about the C$ DOACROSS directive and its optional clauses.

Power Fortran runs the following code as it appears:

C$ DOACROSS
       DO 10 I=1, 100
          A(I) = B(I)
 10    CONTINUE

The C$& Directive

The C$& directive continues the C$ DOACROSS directive onto multiple lines; for example:

C$DOACROSS SHARE(ALPHA, BETA, GAMMA, DELTA,
C$&   EPSILON, OMEGA), LASTLOCAL (I, J, K, L, M, N),
C$&   LOCAL(XXX1, XXX2, XXX3, XXX4, XXX5, XXX6, XXX7,
C$&   XXX8, XXX9)

The C*$* NO SYNC Assertion

Sometimes when Power Fortran concurrentizes a loop, it adds unnecessary sychronization directives or other sychronization code. Use the C*$* ASSERT NO SYNC assertion to eliminate sychronization overhead.

Fine-Tuning Scalar Optimizations

The compiler supports several directives that allow you to fine-tune the scalar optimizations described in “Controlling Scalar Optimizations”.

Controlling Internal Table Size

The C*$* ARCLIMIT(integer) directive sets the minimum size of the internal table that the compiler uses for data dependence analysis. The greater the value for integer, the more information the compiler can keep on complex loop nests. The maximum value and default value for integer is 5000. When you specify this directive globally, it has the same effect as the –arclimit command-line option (refer to “Controlling Internal Table Size” for details).

Setting Invariant IF Floating Limits

The C*$* EACH_INVARIANT_IF_GROWTH and the C*$* MAX_INVARIANT_IF_GROWTH directives control limits on invariant IF floating. This process generally involves duplicating the body of the loop, which can increase the amount of code considerably. Refer to “Setting Invariant IF Floating Limits” for details about invariant IF floating.

The C*$* EACH_INVARIANT_IF_GROWTH(integer) directive limits the total number of additional lines of code generated through invariant IF floating in a loop. You can control this limit globally with the –each_invariant_if_growth command-line option (see “Setting Invariant IF Floating Limits”).

You can limit the maximum amount of additional code generated in a program unit through invariant IF floating with the C*$* MAX_INVARIANT_IF_GROWTH(integer) directive. Use the –max_invariant_if_growth command-line option to control this limit globally (see “Setting Invariant IF Floating Limits”).

These directives are in effect until the end of the routine or until reset by a succeeding directive of the same type.

Example

Consider the following code:

C*$*EACH_INVARIANT_IF_GROWTH(integer)
C*$*MAX_INVARIANT_IF_GROWTH(integer)
      DO I = ...
C*$*EACH_INVARIANT_IF_GROWTH(integer)
C*$*MAX_INVARIANT_IF_GROWTH(integer)
          DO J = ...
C*$*EACH_INVARIANT_IF_GROWTH(integer)
C*$*MAX_INVARIANT_IF_GROWTH(integer)
            DO K = ...
               section-1
               IF ( ) THEN
                 section-2
               ELSE
                 section-3
               ENDIF
               section-4
            ENDDO
          ENDDO
       ENDDO

In floating the invariant IF out of the loop nest, the compiler honors the constraints set by the innermost directives first. If those constraints are satisfied, the invariant IF is floated from the inner loop. The middle pair of directives is tested and the invariant IF is floated from the middle loop as long as restrictions established by these directives are not violated. The process of floating continues as long as directive constraints are satisfied.

Optimization Level

The C*$* OPTIMIZE(integer) directive sets the optimization level in the same way as the –optimize command-line option. As you increase integer, the compiler performs more optimizations, and therefore takes longer to compile. Valid integer values are:

0 

Disables optimization.

1 

Performs only simple optimizations. Enables induction variable recognition.

2 

Performs lifetime analysis to determine when last-value assignment of scalars is necessary.

3 

Recognizes triangular loops and attempts loop interchanging to improve memory referencing. Uses special case data dependence tests. Also, recognizes special index sets called wrap-around variables.

4 

Generates two versions of a loop, if necessary, to break a data dependence arc.

5 

Enables array expansion and loop fusion.

Refer to “Controlling Scalar Optimizations” for examples.

Variations in Round Off

The C*$* ROUNDOFF(integer) directive controls the amount of variation in round off error produced by optimization in the same way as the –roundoff command-line option. Valid values for integer are as follows:

0 

Suppresses any transformations that change round-off error.

1 

Performs expression simplification, which might generate various overflow or underflow errors, for expressions with operands between binary and unary operators, for expressions that are inside trigonometric intrinsic functions returning integer values, and after forward substitution. Enables strength reduction. Performs intrinsic function simplification for max and min. Enables code floating if –scalaropt is at least 1. Allows loop interchanging around serial arithmetic reductions, if –optimize is at least 4. Allows loop rerolling, if –scalaropt is at least 2.

2 

Allows loop interchanging around arithmetic reductions if –optimize is at least 4. For example, the floating point expression A/B/C is computed as A/(B*C).

3 

Recognizes REAL (float) induction variables if –scalaropt is greater than 2 or –optimize is at least 1. Enables sum reductions. Enables memory management optimizations if –scalaropt=3 (see “Performing Memory Management Transformations” for details).

Controlling Scalar Optimizations

The C*$* SCALAR OPTIMIZE(integer) directive controls the amount of standard scalar optimizations that the compiler performs. Unlike the –pfa,–scalaropt command-line option, the C*$* SCALAR OPTIMIZE directive sets the level of loop-based optimizations (such as loop fusion) only, and not straight-code optimizations (such as dead-code elimination). Valid values for integer are as follows:

0 

Disables all scalar optimizations.

1 

Enables simple, loop-based, scalar optimization—changing IF loops to DO loops, simple code floating out of loops, and forward substitution of variables.

2 

Enables the full range of loop-based scalar optimizations—induction variable recognition, loop rerolling, loop unrolling, loop fusion, and array expansion.

3 

Enables memory management transformations if –roundoff=3. Refer to “Performing Memory Management Transformations” for details.

Enabling Loop Unrolling

The C*$* UNROLL(integer[,weight]) directive controls how the compiler unrolls scalar loops. Loops that cannot be optimized for concurrent execution usually execute more efficiently when they are unrolled. This directive is recognized only when you specify –pfa,–scalaropt=2.

The compiler unrolls the loop proceeding the C*$* UNROLL directive until either the number of operations in the loop equals the weight parameter or the number of iterations reaches the integer parameter, whichever occurs first. The –unroll and –unroll2 command-line options act like a global C*$* UNROLL directive. See “Enabling Loop Unrolling” for detailed examples.

The C*$* UNROLL directive is in effect only for the loop immediately following it, unlike other directives.

Fine-Tuning Inlining and IPA

Chapter 6, “Inlining and Interprocedural Analysis,” explains how to use inlining and IPA on an entire program. You can fine-tune inlining and IPA using the C*$* [NO] INLINE and C*$* [NO] IPA directives.

The compiler ignores these directives by default. They are enabled when you specify any inlining or IPA command-line option, respectively, on the command line. The –inline_manual and –ipa_manual command-line options enable these directives without activating the automatic inlining algorithms.

The C*$* [NO] INLINE directive behaves like the –inline command-line option, but allows you to specify which occurrences of a routine are actually inlined. The format for this directive is

C*$*[NO]INLINE [(name[,name ... ])] [HERE|ROUTINE|GLOBAL]

where

name 

Specifies the routines to be inlined. If you do not specify a name, this directive will affect all routines in the program.

HERE 

Applies the INLINE directive only to the next line; occurrences of the named routines on that next line are inlined.

ROUTINE 

Inlines the named routines everywhere they appear in the current routine.

GLOBAL 

Inlines the named routines throughout the source file.

If you do not specify HERE, ROUTINE, or GLOBAL, the directive applies only to the next statement. The C*$* NO INLINE form overrides the –inline command-line option and so allows you to selectively disable inlining of the named routines at specific points.

Example 7-1. Inline Control

In the following code fragment, the C*$* INLINE directive inlines the first call to beta but not the second:

       do i =1,n
C*$*INLINE (beta) HERE
          call beta (i,1)
       enddo
       call beta (n, 2)

Using the specifier ROUTINE rather than HERE inlines both calls. This routine must be compiled with the –inline_man command-line option for the compiler to recognize the C*$* INLINE directive.

The C*$* [NO] IPA directive is the analogous directive for interprocedural analysis. The format for this directive is

C*$*[NO]IPA [(name [,name...])]  [HERE|ROUTINE|GLOBAL]

Running Code Serially

Use the following assertions and directives to keep Power Fortran from running specific code in parallel.

C*$* ASSERT DO (SERIAL)

The C*$* ASSERT DO (SERIAL) assertion tells Power Fortran to run the loop immediately following it serially. Power Fortran also does not try to run any enclosing loop in parallel. However, it can still convert any loops nested inside the serial loop to run in parallel. For example, consider the following code.

Example 7-2. Serial Execution


       DO 100 i = 1,n
         DO 100 j = 1, n
C*$*ASSERT DO (SERIAL)
         DO 200 k = 1, n
           X(i,j,k) = X(i,j,k) * Y(i,j)
 200     CONTINUE
         DO 300 k = 1, n
           X(i,j,k) = X(i,j,k) + Z(i,k)
 300     CONTINUE
 100    CONTINUE

The assertion forces the DO 100 I loop, the DO 100 J loop, and the DO 200 K loop to be serial. The compiler can still optimize the DO 300 K loop. In this case, the compiler does not distribute the I or J loops to try to obtain an optimizable loop.

See also “C*$* ASSERT DO PREFER (SERIAL)”.

CDIR$ NEXT SCALAR

MIPSpro Power Fortran 77 supports the corresponding Cray directive, CDIR$ NEXT SCALAR. Power Fortran interprets this directive as if it were a C*$* ASSERT DO (SERIAL) assertion and generates scalar code for the next DO loop.

C*$* ASSERT DO PREFER (SERIAL)

The C*$* ASSERT DO PREFER (SERIAL) assertion tells the compiler to prefer any ordering in which the loop following the assertion remains serial. Unlike C*$* ASSERT DO (SERIAL), this assertion does not inhibit optimization of outer loops. This assertion directs Power Fortran to leave the DO loop alone, regardless of the setting of the optimization level. You can use this assertion to control which loop (in a nest of loops) Power Fortran chooses to run in parallel.

The following code segment is an example of how to use the assertion:

          DO 100  I = 1,  N 
C*$*ASSERT DO PREFER (SERIAL)
          DO 100  J = 1,  M 
            A(I,J) = B(I,J)
100       CONTINUE

In the DO loop above, the assertion requests that the J loop be serial. In this construction, Power Fortran tries to run the I loop in parallel but not the J loop. This capability is useful when you know the value of M to be very small or less than N. This assertion applies only to the DO loop that appears directly after the assertion.

Running Code in Parallel

This section explains the directives and assertions that allow Power Fortran to determine that specific areas of code are safe to run in parallel.

C*$* [NO] CONCURRENTIZE

The C*$* [NO] CONCURRENTIZE directive converts eligible loops to run in parallel. The NO version prevents Power Fortran from converting loops to run in parallel. These directives override the –[no] concurrentize command-line option.

For example, if your program contains the C*$* NO CONCURRENTIZE directive, parallelization is disabled even if you compile with –concurrentize. When specified globally, these directives have the same effect as the –concurrentize and –noconcurrentize options (see “Running Code in Parallel” for details).

CVD$ CONCUR

Power Fortran supports the VAST directive CVD$CONCUR. This directive runs a loop in parallel to optimize performance. Power Fortran interprets this directive as if it were the C*$*CONCURRENTIZE directive.

C*$* ASSERT DO PREFER (CONCURRENT)

The C*$* ASSERT DO PREFER (CONCURRENT) assertion directs Power Fortran to run a particular nested loop in parallel if possible. Power Fortran runs another of the nested loops in parallel only if a condition prevents running the selected loop in parallel.

This assertion applies only to the DO loop immediately after it.

Consider the following code:

C*$* ASSERT DO PREFER (CONCURRENT)
          DO 100 I = 1, N
          DO 100 J = 1, M
             A (I, J) = B (I, J)
100       CONTINUE

This code directs Power Fortran to prefer to run the I loop in parallel. However, if a data dependence conflict prevents running the I loop in parallel, Power Fortran might run the J loop in parallel.

The –noconcurrentize command-line option and the C*$* NO CONCURRENTIZE directive prevent Power Fortran from generating concurrent code, even if you specify the C*$* ASSERT DO PREFER (CONCURRENT) assertion.

Using Equivalenced Variables

The C*$* ASSERT [NO] EQUIVALENCE HAZARD assertion tells the compiler that your code does not use equivalenced variables to refer to the same memory location inside one loop nest. Normally, EQUIVALENCE statements allow your code to use different variable names to refer to the same storage location.

The –pfa,-assume=e command-line option acts like the global C*$* ASSERT EQUIVALENCE HAZARD assertion (see “Controlling Global Assumptions”). The C*$* ASSERT EQUIVALENCE HAZARD assertion is active until you reset it or until the end of the program.

Using Assertions

The C*$* [NO] ASSERTIONS directive instructs the compiler to accept or ignore assertions. The C*$* NO ASSERTIONS version is in effect until the next C*$* ASSERTIONS directive or the end of the program unit.

If you specify the –directives command-line option without the assertions parameter (that is, a), the compiler will ignore assertions regardless of whether the file contains the C*$* ASSERTIONS directive. Refer to “Recognizing Directives” for details on the –directives command-line option.

Using Aliasing

The C*$* ASSERT RELATION(name.xx.name) assertion indicates the relationship between two variables or between a variable and a constant. name is the variable or constant, and xx is any of the following: GT, GE, EQ, NE, LT, or LE. This assertion applies only to the next DO statement.

The C*$* ASSERT RELATION assertion includes variable names (name and xx). When specified globally, this assertion is used only when the variable names appear in COMMON blocks or are dummy arguments to a subprogram. You cannot use global assertions to make relational assertions about variables that are local to a subprogram.

As an example of the use of the C*$* ASSERT RELATION assertion, consider the following code:

          DO 100 I = 1, N
             A (I) = A (I+M) + B (I)
100       CONTINUE

If you know that M is greater than N, use the following assertion to give this information to the compiler:

C*$* ASSERT RELATION (M .GT. N) 
          DO 100 I = 1, N
             A (I) = A (I +M) + B (I)
100       CONTINUE

Knowing that M is greater than N, the compiler can generate parallel code for this loop. If M is less than N at run time, the answers produced by the code run in parallel could differ from the answers produced by the original code run serially.


Note: Many relationships of this type can be cheaply tested for at run time. The compiler attempts to answer questions of this sort by generating an IF statement that explicitly tests the relationship at run time. Occasionally, the compiler needs assistance, or you might want to squeeze that last bit of performance out of some critical loop by asserting some relationship rather than repeatedly checking it at run time.


Fine-Tuning Global Assumptions

Use the assertions described in this section to fine-tune the global assumptions discussed in “Controlling Global Assumptions”.

C*$* ASSERT [NO] BOUNDS VIOLATIONS

The C*$* ASSERT [NO] BOUNDS VIOLATIONS assertion indicates that array subscript bounds may be violated during execution. If your program does not violate array subscript bounds, do not specify this assertion. When specified, this assertion is active until reset or until the end of the program. For formal parameters, the compiler treats a declared last dimension of (1) the same as (*).

The –pfa,–assert=b command-line option acts like a global C*$* ASSERT BOUNDS VIOLATIONS assertion.

In the example below, the compiler assumes the first loop nest is standard conformant, and therefore optimizes both loops. The loops can be interchanged to improve memory referencing because no A(I,J) overwrites an A(I',J+1). In the second nest, the assertion warns the compiler that the loop limit of the first array index (I) might violate declared array bounds. The compiler plays it safe and optimizes only the right array index.


Note: The compiler always assumes that array references are within the array itself, so the rightness index is concurrentizable.


Example 7-3. Bounds Violations


      DO 100 I = 1,M
        DO 100 J = 1,N
          A(I,J) = A(I,J) + B (I,J)
  100 CONTINUE
C*$*ASSERT BOUNDS VIOLATIONS
      DO 200 I = 1,M
         DO 200 J = 1,N
           A(I,J) = A(I,J) + B (I,J)
  200 CONTINUE

The example above becomes:

C$DOACROSS SHARE(N,M,A,B),LOCAL(J,I)
        DO 2 J=1,N
      DO 2 I=1,M
          A(I,J) = A(I,J) + B (I,J)
              2     CONTINUE
C
C*$*ASSERT BOUNDS VIOLATIONS
      DO 4 I=1,M
C$DOACROSS SHARE(N,I,A,B),LOCAL(J)
        DO 3 J=1,N
          A(I,J) = A(I,J) + B (I,J)
    3     CONTINUE
    4     CONTINUE

C*$* ASSERT NO EQUIVALENCE HAZARD

The C*$* ASSERT NO EQUIVALENCE HAZARD assertion tells the compiler that equivalenced variables will not be used to refer to the same memory location inside one DO loop nest. Normally, EQUIVALENCE statements allow different variable names to refer to the same storage location. The –pfa,–assume=e command-line option acts like a global C*$* ASSERT NO EQUIVALENCE HAZARD assertion. This assertion is active until reset or until the end of the program.

In the following example, if arrays E and F are equivalenced, but you know that the overlapping sections will not be referenced in this loop, then using C*$* ASSERT NO EQUIVALENCE HAZARD allows the compiler to concurrentize the loop.

Example 7-4. Equivalence Hazard


        EQUIVALENCE ( E(1), F(101) )
C*$* ASSERT NO EQUIVALENCE HAZARD
        DO 10 I = 1,N
          E(I+1) = B(I)
          C(I) = F(I)
  10    CONTINUE

The example above becomes:

EQUIVALENCE (E(1), F(101))
C*$* ASSERT NO EQUIVALENCE HAZARD
C$DOACROSS SHARE(N,E,B,C,F),LOCAL(I)
        DO 10 I=1,N
           E(I+1) = B(I)
           C(I) = F(I)
  10    CONTINUE

C*$* ASSERT [NO] TEMPORARIES FOR CONSTANT ARGUMENTS

Sometimes the compiler does not perform certain transformations when their effects on the rest of the program are unclear. For example, usually the IF-to-intrinsic transformation changes the following code

      SUBROUTINE X(I,N)
        IF (I .LT. N) I = N
      END

into the following:

      SUBROUTINE X(I,N)
        I = MAX(I,N)
      END

But if the actual parameter for I were a constant such as the following,

CALL X(1,N)

it would appear that the value of the constant 1 was being reassigned. Without additional information, the compiler does not perform transformations within the subroutine.

Most compilers automatically put constant actual arguments into temporary variables to protect against this case. The C*$*ASSERT TEMPORARIES FOR CONSTANT ARGUMENTS assertion or the –pfa,–assume=c command-line option (the default) informs the compiler that constant parameters are protected.

The NO version directs the compiler to avoid transformations that might change the values of constant parameters.

Ignoring Data Dependencies

Power Fortran avoids running code in parallel that it believes to be data-dependent. Use the assertions described in the following sections to override this behavior.

C*$* ASSERT DO (CONCURRENT)

Use the C*$* ASSERT DO (CONCURRENT) assertion to tell Power Fortran to ignore assumed data dependencies. Normally Power Fortran is conservative about converting loops to run in parallel.

When Power Fortran determines that it can run a loop in parallel, it categorizes the loop into one of three groups:

  1. yes, it is safe to run the loop parallel

  2. no, it is not safe to run the loop in parallel

  3. not sure (cannot be determined)

Normally, Power Fortran does not run the loops it is unsure about in parallel. It assumes there are data dependencies. C*$* ASSERT DO (CONCURRENT) tells Power Fortran to go ahead and run these “not sure” loops in parallel.


Note: If Power Fortran identifies a loop as containing definite data dependencies (as opposed to dependencies it assumes, but is not sure of), it does not run the loop in parallel even if you specify a C*$* ASSERT DO (CONCURRENT) assertion.


CDIR$ IVDEP

Power Fortran interprets the Cray directive CDIR$ IVDEP as if it were a C*$* ASSERT DO (CONCURRENT) assertion. Some dependencies that are safe to run on Cray hardware are not safe to run on Silicon Graphics hardware. Therefore, to avoid incorrect parallelization of loops, recognition of this assertion is turned off by default.

C*$* ASSERT CONCURRENT CALL

The C*$* ASSERT CONCURRENT CALL tells Power Fortran to ignore assumed dependencies that are caused by a subroutine call or a function reference. However, you must ensure that the subroutines and referenced functions are safe for parallel execution. This assertion applies to all subroutine and function references in the accompanying loop, which must appear on the next line.

CVD$ CNCALL

Power Fortran interprets the VAST directive CDIR$ CNCALL as if it were a C*$* ASSERT CONCURRENT CALL assertion. Some dependencies that are safe to run on Cray hardware are not safe to run on Silicon Graphics hardware. Therefore, recognition of this assertion is turned off by default.

C*$* ASSERT NO RECURRENCE

The C*$* ASSERT NO RECURRENCE(variable) assertion tells the compiler to ignore all data dependence conflicts caused by variable in the DO loop that follows it. For example, the following code tells the compiler to ignore all dependence arcs caused by the variable X in the loop:

C*$* ASSERT NO RECURRENCE (X)
        DO 10 i= 1,m,5
  10    X(k) = X(k) + X(i)

Not only does the compiler ignore the assumed dependence, it also ignores the real dependence caused by X(k) appearing on both sides of the assignment.

The C*$* ASSERT NO RECURRENCE assertion applies only to the next DO loop. It cannot be specified as a global assertion.

C*$* ASSERT PERMUTATION

The C*$* ASSERT PERMUTATION(array) assertion tells Power Fortran that array contains no repeated values. This assertion permits Power Fortran to run in parallel certain kinds of loops that use indirect addressing; for example:

       DO I = 1, N
          A(INDEX(I)) = A(INDEX(I)) + B(I)
       ENDDO

You can run this loop in parallel only if the array INDEX has no repeated values (so that each INDEX (I) is unique). Power Fortran cannot determine this, so it does not run such a loop in parallel. However, if you know that every element of INDEX() is unique, you can insert the following line before the loop to permit the loop to be run in parallel:

C*$* ASSERT PERMUTATION (INDEX)