A reduction-identifier is either an identifier or one of the following operators: +, -, *, &, |, ^, && and ||.
The reduction clauses are data-sharing attribute clauses that can be used to perform some forms of recurrence calculations in parallel. Reduction clauses include reduction scoping clauses and reduction participating clauses. Reduction scoping clauses define the region in which a reduction is computed. Reduction participating clauses define the participants in the reduction. Reduction clauses specify a reduction-identifier and one or more list items.
Syntax
The syntax of a reduction-identifier is defined as follows:
A reduction-identifier is either an identifier or one of the following operators: +, -, *, &, |, ^, && and ||.
A reduction-identifier is either an id-expression or one of the following operators: +, -, *, &, |, ^, && and ||.
A reduction-identifier is either a base language identifier, or a user-defined operator, or one of the following operators: +, -, *, .and., .or., .eqv., .neqv., or one of the following intrinsic procedure names: max, min, iand, ior, ieor.
Table 2.11 lists each reduction-identifier that is implicitly declared at every scope for arithmetic types and its semantic initializer value. The actual initializer value is that value as expressed in the data type of the reduction list item.
Table 2.11: | Implicitly Declared C/C++ reduction-identifiers |
Identifier | Initializer | Combiner |
+ | omp_priv = 0 | omp_out += omp_in |
- | omp_priv = 0 | omp_out += omp_in |
* | omp_priv = 1 | omp_out *= omp_in |
& | omp_priv = ~ 0 | omp_out &= omp_in |
| | omp_priv = 0 | omp_out |= omp_in |
^ | omp_priv = 0 | omp_out ^= omp_in |
&& | omp_priv = 1 | omp_out = omp_in && omp_out |
|| | omp_priv = 0 | omp_out = omp_in || omp_out |
max | omp_priv = Least representable number in the reduction list item type | omp_out = omp_in > omp_out ? omp_in : omp_out |
min | omp_priv = Largest representable number in the reduction list item type | omp_out = omp_in < omp_out ? omp_in : omp_out |
Table 2.12 lists each reduction-identifier that is implicitly declared for numeric and logical types and its semantic initializer value. The actual initializer value is that value as expressed in the data type of the reduction list item.
Table 2.12: | Implicitly Declared Fortran reduction-identifiers |
Identifier | Initializer | Combiner |
+ | omp_priv = 0 | omp_out = omp_in + omp_out |
- | omp_priv = 0 | omp_out = omp_in + omp_out |
* | omp_priv = 1 | omp_out = omp_in * omp_out |
.and. | omp_priv = .true. | omp_out = omp_in .and. omp_out |
.or. | omp_priv = .false. | omp_out = omp_in .or. omp_out |
.eqv. | omp_priv = .true. | omp_out = omp_in .eqv. omp_out |
.neqv. | omp_priv = .false. | omp_out = omp_in .neqv. omp_out |
max | omp_priv = Least representable number in the reduction list item type | omp_out = max(omp_in, omp_out) |
min | omp_priv = Largest representable number in the reduction list item type | omp_out = min(omp_in, omp_out) |
iand | omp_priv = All bits on | omp_out = iand(omp_in, omp_out) |
ior | omp_priv = 0 | omp_out = ior(omp_in, omp_out) |
ieor | omp_priv = 0 | omp_out = ieor(omp_in, omp_out) |
In the above tables, omp_in and omp_out correspond to two identifiers that refer to storage of the type of the list item. omp_out holds the final value of the combiner operation.
Any reduction-identifier that is defined with the declare reduction directive is also valid. In that case, the initializer and combiner of the reduction-identifier are specified by the initializer-clause and the combiner in the declare reduction directive.
DescriptionA reduction clause specifies a reduction-identifier and one or more list items. The reduction-identifier specified in a reduction clause must match a previously declared reduction-identifier of the same name and type for each of the list items. This match is done by means of a name lookup in the base language.
The list items that appear in a reduction clause may include array sections.
If the type is a derived class, then any reduction-identifier that matches its base classes is also a match, if there is no specific match for the type.
If the reduction-identifier is not an id-expression, then it is implicitly converted to one by prepending the keyword operator (for example, + becomes operator+).
If the reduction-identifier is qualified then a qualified name lookup is used to find the declaration.
If the reduction-identifier is unqualified then an argument-dependent name lookup must be performed using the type of each list item.
If the list item is an array or array section, it will be treated as if a reduction clause would be applied to each separate element of the array section.
If the list item is an array section, the elements of any copy of the array section will be allocated contiguously.
If the original list item has the POINTER attribute, any copies of the list item are associated with private targets.
Any copies associated with the reduction are initialized with the initializer value of the reduction-identifier.
Any copies are combined using the combiner associated with the reduction-identifier.
Execution Model Events The reduction-begin event occurs before a task begins to perform loads and stores that belong to the implementation of a reduction and the reduction-end event occurs after the task has completed loads and stores associated with the reduction. If a task participates in multiple reductions, each reduction may be bracketed by its own pair of reduction-begin/reduction-end events or multiple reductions may be bracketed by a single pair of events. The interval defined by a pair of reduction-begin/reduction-end events may not contain a task scheduling point.
Tool Callbacks A thread dispatches a registered ompt_callback_reduction with ompt_sync_region_reduction in its kind argument and ompt_scope_begin as its endpoint argument for each occurrence of a reduction-begin event in that thread. Similarly, a thread dispatches a registered ompt_callback_reduction with ompt_sync_region_reduction in its kind argument and ompt_scope_end as its endpoint argument for each occurrence of a reduction-end event in that thread. These callbacks occur in the context of the task that performs the reduction and has the type signature ompt_callback_sync_region_t.
RestrictionsThe restrictions common to reduction clauses are as follows:
∙ A variable that is part of another variable, with the exception of array elements, cannot appear in a reduction clause.
∙ A variable that is part of another variable, with the exception of array elements, cannot appear in a reduction clause except if the reduction clause is associated with a construct within a class non-static member function and the variable is an accessible data member of the object for which the non-static member function is invoked.
∙ The type of a list item that appears in a reduction clause must be valid for the reduction-identifier. For a max or min reduction in C, the type of the list item must be an allowed arithmetic data type: char, int, float, double, or _Bool, possibly modified with long, short, signed, or unsigned. For a max or min reduction in C++, the type of the list item must be an allowed arithmetic data type: char, wchar_t, int, float, double, or bool, possibly modified with long, short, signed, or unsigned. ∙ A list item that appears in a reduction clause must not be const-qualified. ∙ The reduction-identifier for any list item must be unambiguous and accessible.
∙ A variable that is part of another variable, with the exception of array elements, cannot appear in a reduction clause. ∙ A type parameter inquiry cannot appear in a reduction clause. ∙ The type, type parameters and rank of a list item that appears in a reduction clause must be valid for the combiner and initializer. ∙ A list item that appears in a reduction clause must be definable. ∙ A procedure pointer may not appear in a reduction clause. ∙ A pointer with the INTENT(IN) attribute may not appear in the reduction clause. ∙ An original list item with the POINTER attribute or any pointer component of an original list item that is referenced in the combiner must be associated at entry to the construct that contains the reduction clause. Additionally, the list item or the pointer component of the list item must not be deallocated, allocated, or pointer assigned within the region. ∙ An original list item with the ALLOCATABLE attribute or any allocatable component of an original list item that corresponds to the special variable identifier in the combiner or the initializer must be in the allocated state at entry to the construct that contains the reduction clause. Additionally, the list item or the allocatable component of the list item must be neither deallocated nor allocated, explicitly or implicitly, within the region. ∙ If the reduction-identifier is defined in a declare reduction directive, the declare reduction directive must be in the same subprogram, or accessible by host or use association. ∙ If the reduction-identifier is a user-defined operator, the same explicit interface for that operator must be accessible as at the declare reduction directive. ∙ If the reduction-identifier is defined in a declare reduction directive, any subroutine or function referenced in the initializer clause or combiner expression must be an intrinsic function, or must have an explicit interface where the same explicit interface is accessible as at the declare reduction directive.
Reduction scoping clauses define the region in which a reduction is computed by tasks or SIMD lanes. All properties common to all reduction clauses, which are defined in Section 2.19.5.1 on page 873, apply to reduction scoping clauses.
The number of copies created for each list item and the time at which those copies are initialized are determined by the particular reduction scoping clause that appears on the construct.
The time at which the original list item contains the result of the reduction is determined by the particular reduction scoping clause.
The location in the OpenMP program at which values are combined and the order in which values are combined are unspecified. Therefore, when comparing sequential and parallel runs, or when comparing one parallel run to another (even if the number of threads used is the same), there is no guarantee that bitwise-identical results will be obtained or that side effects (such as floating-point exceptions) will be identical or take place at the same location in the OpenMP program.
To avoid data races, concurrent reads or updates of the original list item must be synchronized with the update of the original list item that occurs as a result of the reduction computation.
A reduction participating clause specifies a task or a SIMD lane as a participant in a reduction defined by a reduction scoping clause. All properties common to all reduction clauses, which are defined in Section 2.19.5.1 on page 873, apply to reduction participating clauses.
Accesses to the original list item may be replaced by accesses to copies of the original list item created by a region that corresponds to a construct with a reduction scoping clause.
In any case, the final value of the reduction must be determined as if all tasks or SIMD lanes that participate in the reduction are executed sequentially in some arbitrary order.
SummaryThe reduction clause specifies a reduction-identifier and one or more list items. For each list item, a private copy is created in each implicit task or SIMD lane and is initialized with the initializer value of the reduction-identifier. After the end of the region, the original list item is updated with the values of the private copies using the combiner associated with the reduction-identifier.
reduction([ reduction-modifier,]reduction-identifier : list)
Where reduction-identifier is defined in Section 2.19.5.1 on page 873, and reduction-modifier is one of the
following:
inscan
task
default
DescriptionThe reduction clause is a reduction scoping clause and a reduction participating clause, as described in Section 2.19.5.2 on page 884 and Section 2.19.5.3 on page 884. If reduction-modifier is not present or the defaultreduction-modifier is present, the behavior is as follows. For parallel and worksharing constructs, one or more private copies of each list item are created for each implicit task, as if the private clause had been used. For the simd construct, one or more private copies of each list item are created for each SIMD lane, as if the private clause had been used. For the taskloop construct, private copies are created according to the rules of the reduction scoping clauses. For the teams construct, one or more private copies of each list item are created for the initial task of each team in the league, as if the private clause had been used. For the loop construct, private copies are created and used in the construct according to the description and restrictions in Section 2.19.3 on page 827. At the end of a region that corresponds to a construct for which the reduction clause was specified, the original list item is updated by combining its original value with the final value of each of the private copies, using the combiner of the specified reduction-identifier.
If the inscanreduction-modifier is present, a scan computation is performed over updates to the list item performed in each logical iteration of the loop associated with the worksharing-loop, worksharing-loop SIMD, or simd construct (see Section 2.9.6 on page 376). The list items are privatized in the construct according to the description and restrictions in Section 2.19.3 on page 827. At the end of the region, each original list item is assigned the value of the private copy from the last logical iteration of the loops associated with the construct.
If the taskreduction-modifier is present for a parallel or worksharing construct, then each list item is privatized according to the description and restrictions in Section 2.19.3 on page 827, and an unspecified number of additional private copies are created to support task reductions. Any copies associated with the reduction are initialized before they are accessed by the tasks that participate in the reduction, which include all implicit tasks in the corresponding region and all participating explicit tasks that specify an in_reduction clause (see Section 2.19.5.6 on page 897). After the end of the region, the original list item contains the result of the reduction.
If nowait is not specified for the construct, the reduction computation will be complete at the end of the construct; however, if the reduction clause is used on a construct to which nowait is also applied, accesses to the original list item will create a race and, thus, have unspecified effect unless synchronization ensures that they occur after all threads have executed all of their iterations or section constructs, and the reduction computation has completed and stored the computed value of that list item. This can most simply be ensured through a barrier synchronization.
RestrictionsThe restrictions to the reduction clause are as follows:
∙ If a list item in a reduction clause on a worksharing construct or loop construct for which the corresponding region binds to a parallel region has a reference type then it must bind to the same object for all threads of the team. ∙ If a list item in a reduction clause on a worksharing construct or loop construct for which the corresponding region binds to a parallel region is an array section or an array element then the base pointer must point to the same variable for all threads of the team. ∙ A variable of class type (or array thereof) that appears in a reduction clause with the inscan reduction-modifier requires an accessible, unambiguous default constructor for the class type. The number of calls to the default constructor while performing the scan computation is unspecified. ∙ A variable of class type (or array thereof) that appears in a reduction clause with the inscan reduction-modifier requires an accessible, unambiguous copy assignment operator for the class type. The number of calls to the copy assignment operator while performing the scan computation is unspecified.
SummaryThe task_reduction clause specifies a reduction among tasks.
task_reduction(reduction-identifier : list)
Where reduction-identifier is defined in Section 2.19.5.1.
DescriptionThe task_reduction clause is a reduction scoping clause, as described in 2.19.5.2. For each list item, the number of copies is unspecified. Any copies associated with the reduction are initialized before they are accessed by the tasks participating in the reduction. After the end of the region, the original list item contains the result of the reduction.
RestrictionsThe restrictions to the task_reduction clause are as follows:
SummaryThe in_reduction clause specifies that a task participates in a reduction.
in_reduction(reduction-identifier : list)
where reduction-identifier is defined in Section 2.19.5.1 on page 873.
DescriptionThe in_reduction clause is a reduction participating clause, as described in Section 2.19.5.3 on page 884. For a given a list item, the in_reduction clause defines a task to be a participant in a task reduction that is defined by an enclosing region for a matching list item that appears in a task_reduction clause or a reduction clause with the task modifier, where either:
For the task construct, the generated task becomes the participating task. For each list item, a private copy may be created as if the private clause had been used.
For the target construct, the target task becomes the participating task. For each list item, a private copy will be created in the data environment of the target task as if the private clause had been used, and this private copy will be implicitly mapped into the device data environment of the target device.
At the end of the task region, if a private copy was created its value is combined with a copy created by a reduction scoping clause or with the original list item.
RestrictionsThe restrictions to the in_reduction clause are as follows:
SummaryThe following section describes the directive for declaring user-defined reductions. The declare reduction directive declares a reduction-identifier that can be used in a reduction clause. The declare reduction directive is a declarative directive.
Syntax
#pragma omp declare reduction(reduction-identifier : typename-list :
combiner )[initializer-clause] new-line
where:
#pragma omp declare reduction(reduction-identifier : typename-list :
combiner) [initializer-clause] new-line
where:
!$omp declare reduction(reduction-identifier : type-list : combiner)
[initializer-clause]
where:
DescriptionCustom reductions can be defined using the declare reduction directive; the reduction-identifier and the type identify the declare reduction directive. The reduction-identifier can later be used in a reduction clause that uses variables of the type or types specified in the declare reduction directive. If the directive applies to several types then it is considered as if there were multiple declare reduction directives, one for each type.
If a type with deferred or assumed length type parameter is specified in a declare reduction directive, the reduction-identifier of that directive can be used in a reduction clause with any variable of the same type and the same kind parameter, regardless of the length type Fortran parameters with which the variable is declared.
The visibility and accessibility of this declaration are the same as those of a variable declared at the same point in the program. The enclosing context of the combiner and of the initializer-expr is that of the declare reduction directive. The combiner and the initializer-expr must be correct in the base language as if they were the body of a function defined at the same point in the program.
If the reduction-identifier is the same as the name of a user-defined operator or an extended operator, or the same as a generic name that is one of the allowed intrinsic procedures, and if the operator or procedure name appears in an accessibility statement in the same module, the accessibility of the corresponding declare reduction directive is determined by the accessibility attribute of the statement.
If the reduction-identifier is the same as a generic name that is one of the allowed intrinsic procedures and is accessible, and if it has the same name as a derived type in the same module, the accessibility of the corresponding declare reduction directive is determined by the accessibility of the generic name according to the base language.
The declare reduction directive can also appear at points in the program at which a static data member could be declared. In this case, the visibility and accessibility of the declaration are the same as those of a static data member declared at the same point in the program.
The combiner specifies how partial results can be combined into a single value. The combiner can use the special variable identifiers omp_in and omp_out that are of the type of the variables that this reduction-identifier reduces. Each of them will denote one of the values to be combined before executing the combiner. The special omp_out identifier refers to the storage that holds the resulting combined value after executing the combiner.
The number of times that the combiner is executed, and the order of these executions, for any reduction clause is unspecified.
If the combiner is a subroutine name with an argument list, the combiner is evaluated by calling the subroutine with the specified argument list.
If the combiner is an assignment statement, the combiner is evaluated by executing the assignment statement.
As the initializer-expr value of a user-defined reduction is not known a priori the initializer-clause can be used to specify one. Then the contents of the initializer-clause will be used as the initializer for private copies of reduction list items where the omp_priv identifier will refer to the storage to be initialized. The special identifier omp_orig can also appear in the initializer-clause and it will refer to the storage of the original variable to be reduced.
The number of times that the initializer-expr is evaluated, and the order of these evaluations, is unspecified.
If the initializer-expr is a function name with an argument list, the initializer-expr is evaluated by calling the function with the specified argument list. Otherwise, the initializer-expr specifies how omp_priv is declared and initialized.
If no initializer-clause is specified, the private variables will be initialized following the rules for initialization of objects with static storage duration.
If no initializer-expr is specified, the private variables will be initialized following the rules for default-initialization.
If the initializer-expr is a subroutine name with an argument list, the initializer-expr is evaluated by calling the subroutine with the specified argument list.
If the initializer-expr is an assignment statement, the initializer-expr is evaluated by executing the assignment statement.
If no initializer-clause is specified, the private variables will be initialized as follows:
If reduction-identifier is used in a target region then a declare target construct must be specified for any function that can be accessed through the combiner and initializer-expr.
If reduction-identifier is used in a target region then a declare target construct must be specified for any function or subroutine that can be accessed through the combiner and initializer-expr.
∙ A type name in a declare reduction directive cannot be a function type, an array type, a reference type, or a type qualified with const, volatile or restrict.
∙ If the initializer-expr is a function name with an argument list, then one of the arguments must be the address of omp_priv.
∙ If the initializer-expr is a function name with an argument list, then one of the arguments must be omp_priv or the address of omp_priv.
∙ If the initializer-expr is a subroutine name with an argument list, then one of the arguments must be omp_priv. ∙ If the declare reduction directive appears in the specification part of a module and the corresponding reduction clause does not appear in the same module, the reduction-identifier must be the same as the name of a user-defined operator, one of the allowed operators that is extended or a generic name that is the same as the name of one of the allowed intrinsic procedures. ∙ If the declare reduction directive appears in the specification of a module, if the corresponding reduction clause does not appear in the same module, and if the reduction-identifier is the same as the name of a user-defined operator or an extended operator, or the same as a generic name that is the same as one of the allowed intrinsic procedures then the interface for that operator or the generic name must be defined in the specification of the same module, or must be accessible by use association. ∙ Any subroutine or function used in the initializer clause or combiner expression must be an intrinsic function, or must have an accessible interface. ∙ Any user-defined operator, defined assignment or extended operator used in the initializer clause or combiner expression must have an accessible interface. ∙ If any subroutine, function, user-defined operator, defined assignment or extended operator is used in the initializer clause or combiner expression, it must be accessible to the subprogram in which the corresponding reduction clause is specified. ∙ If the length type parameter is specified for a type, it must be a constant, a colon or an *. ∙ If a type with deferred or assumed length parameter is specified in a declare reduction directive, no other declare reduction directive with the same type, the same kind parameters and the same reduction-identifier is allowed in the same scope. ∙ Any subroutine used in the initializer clause or combiner expression must not have any alternate returns appear in the argument list.