Intel® Fortran Compiler Classic and Intel® Fortran Compiler Developer Guide and Reference

ID 767251
Date 11/07/2023
Public

A newer version of this document is available. Customers should click here to go to the newest version.

Document Table of Contents

DECLARE REDUCTION

OpenMP* Fortran Compiler Directive: Declares user-defined reductions which are identified by a reduction-identifier that can be used in a reduction clause of other directives.

Syntax

!$OMP DECLARE REDUCTION (reduction-identifier : type-list : combiner) [initializer-clause]

reduction-identifier

Is a Fortran identifier, or a defined or extended operator.

type-list

Is a comma-separated list of one or more type identifiers. These may be intrinsic types or accessible derived types. You cannot specify polymorphic and parameterized derived types, and coarrays.

type-list cannot contain a type which has previously been specified in a DECLARE REDUCTION directive with the same reduction-identifier if the reduction-identifier/type pair is accessible by use or host association.

If more than one type is specified, it is as if there is a separate DECLARE REDUCTION directive for each type.

combiner

Is an assignment statement, or a subroutine name followed by an argument list. It indicates how partial results are combined into a single value.

There are two special identifiers that are allowed in the combiner:

  • omp_out

    This identifier refers to the storage that holds the resulting combined value following execution of the combiner.

  • omp_in

The above identifiers refer to variables that are the type of the reduction variables specified in type-list for the reduction-identifier. They denote values to be combined by executing the combiner.

No other identifiers are permitted in the combiner. Any number of literal or named constants can appear in the combiner.

If combiner is a subroutine name followed by an argument list, it is evaluated by calling the subroutine with the specified argument list. If combiner is an assignment statement, combiner is evaluated by executing the assignment statement.

The number of times the combiner is executed, and the order of these executions, is unspecified.

initializer-clause

Is initializer (initializer-expression).

At most one initializer-clause can be specified.

Only the identifiers omp_priv and omp_orig are allowed in the initializer-clause. omp_orig refers to the storage of the original reduction variable that appears in the list in the REDUCTION clause that specifies reduction-identifier. If omp_orig is modified in the initializer-clause, the behavior is unspecified.

No other identifiers are allowed in initializer-clause. Any number of literal or named constants are permitted.

initializer-expression

Is one of the following identifiers:

  • omp_priv = expression

    This identifier refers to the storage to be initialized.

  • subroutine-name (argument-list)

If initializer-expression is a subroutine name and an argument list, the initializer is evaluated by executing a call to the subroutine with the specified argument list. If initializer is an assignment statement, it is evaluated by executing the assignment.

If initializer-expression is a subroutine name and an argument list, one of the arguments must be omp_priv, and it must be associated with an INTENT(OUT) dummy argument of the subroutine.

The number of times initializer-expression is evaluated and the order of the evaluations is unspecified.

The DECLARE REDUCTION directive is a specification directive. It can appear in a specification part of a subroutine, function, main program, module, or block construct. It is a pure directive, so it can appear in a Fortran PURE procedure.

User-defined (custom) reductions can be defined using the DECLARE REDUCTION directive. The reduction is identified by the reduction-identifier and the associated type from type-list. The reduction-identifier can be used in a REDUCTION clause in another OpenMP* directive anywhere it is accessible by use or host association.

A DECLARE REDUCTION directive cannot redefine a predefined reduction-identifier (see the table of implicitly defined reduction identifiers in the REDUCTION clause section).

If a type in type-list has deferred or assumed-length type parameters, the reduction-identifier can be used in a REDUCTION clause with a variable of the same type and kind type parameter as type, regardless of the length parameter with which the variable is declared. The length parameter of a character type must be a constant, colon, or asterisk. An accessible reduction-identifier defined with a deferred or assumed-length character type cannot appear in another DECLARE REDUCTION directive with a type-list item of type character with the same kind type parameter.

The accessibility of a reduction-identifier is determined by the same rules as for other Fortran entities; it can be declared PUBLIC or PRIVATE, be made accessible or blocked by a USE or IMPORT statement, and it can be renamed. If the reduction-identifier is the same as a generic name that is also the name of a derived type, the accessibility of the reduction-identifier is the same as that of the generic name.

If a subroutine or function used in initializer-expression or combiner is not an intrinsic procedure, it must have an accessible interface. Defined operators and defined assignments used in initializer or combiner must have accessible interfaces. All subroutines, functions, defined operators and defined assignments used in initializer or combiner must have accessible interfaces in the subprogram in which the corresponding REDUCTION clause appears. Procedures referenced in combiner and initializer cannot be alternate return subprograms.

The initial value of a user-defined reduction is not known before it is specified. The initializer-clause can be used to specify an initial value for the reduction variable. The initializer-clause will be executed to establish initial values for the private copies of reduction list items indicated in a REDUCTION clause that specifies the reduction-identifier.

If initializer is not specified, private reduction variables are initialized as follows:

  • If the reduction variable is type COMPLEX, REAL, or INTEGER, the default initializer is the value zero.

  • If the reduction variable specified in list of the REDUCTION clause is LOGICAL, the default initializer is the value .FALSE..

  • If the reduction variable is of a default initialized derived type, the default initializer value is used.

  • Otherwise, the initial value is unspecified.

If initializer is used in a target region, then a DECLARE TARGET construct (Linux* only) must be specified for any procedures that are executed during the execution of combiner or initializer.

If the execution of combiner or initializer results in the execution of an OpenMP* construct or an OpenMP* API call, the behavior is undefined. If the variable omp_orig is defined during execution of initializer, the behavior is unspecified.

Example

Consider that a DECLARE REDUCTION directive is used to declare a sum reduction for an integer component of a type my_type that is identified by the reduction-identifier '+'. It is then used in a REDUCTION clause of a parallel region to produce the sum of the thread numbers (numbered 1 thru 4) of the region:

module types
  type my_type
    integer :: component
  end type 
  interface operator(+)
    module procedure :: my_add
  end interface
!$omp declare reduction (+ : my_type : omp_out = omp_out + omp_in) initializer (omp_priv = my_type (0))
 
  contains
    function my_add (a1, a2)
      type(my_type),intent(in) :: a1, a2
      type(my_type)            :: my_add
      my_add%component = a1%component + a2%component
      return
    end function my_add
end module types

program main
  use types
  use omp_lib
  type(my_type) :: my_var

! Initialize the reduction variable before entering the OpenMP region
  my_var%component = 0

!$omp parallel reduction (+ : my_var) num_threads(4)
  my_var%component = omp_get_thread_num() + 1
!$omp end parallel

  print *, "sum of thread numbers is ", my_var%component
end program

The output of the program follows:

sum of thread numbers is 10