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.
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 = Minimal representable number in the reduction list item type | omp_out = omp_in > omp_out ? omp_in : omp_out |
| min | omp_priv = Maximal 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 = Minimal representable number in the reduction list item type | omp_out = max(omp_in, omp_out) |
| min | omp_priv = Maximal 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) |
Description A 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 no specific match for the type has been specified.
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 a 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 a list item is an array section, the elements of any copy of the array section will be stored contiguously.
If the original list item has the POINTER attribute, any copies of the list item are associated with private targets.
Any copies of a list item 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.
Restrictions 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 a 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 at the location of the declare reduction directive that defines the reduction-identifier. ∙ If the reduction-identifier is defined in a declare reduction directive, any procedure 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.21.5.1, 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 executions, or when comparing one parallel execution to another (even if the number of threads used is the same), bitwise-identical results are not guaranteed to be obtained. Similarly, side effects (such as floating-point exceptions) may not be identical and may not 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.21.5.1, 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.
Summary The reduction clause specifies a reduction-identifier and one or more list items. For each list item, a private copy is created for 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.
Syntax
The syntax of the reduction clause is as follows:
reduction([ reduction-modifier,]reduction-identifier : list)
Where reduction-identifier is defined in Section 2.21.5.1, and reduction-modifier is one of the
following:
inscan
task
default
Description The reduction clause is a reduction scoping clause and a reduction participating clause, as described in Section 2.21.5.2 and Section 2.21.5.3.
If reduction-modifier is not present or the defaultreduction-modifier is present, the behavior is as follows. For parallel, scope 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.21.3. 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.11.8). The list items are privatized in the construct according to the description and restrictions in Section 2.21.3. At the end of the region, each original list item is assigned the value described in Section 2.11.8.
If the taskreduction-modifier is present for a parallel, scope, or worksharing construct, then each list item is privatized according to the description and restrictions in Section 2.21.3, and an unspecified number of additional private copies may be 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.21.5.6). 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 region that corresponds to 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 be ensured simply through a barrier synchronization in most cases.
Restrictions Restrictions to the reduction clause are as follows:
∙ If a list item in a reduction clause on a worksharing construct, scope 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, scope 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.
Summary The task_reduction clause specifies a reduction among tasks.
Syntax
The syntax of the task_reduction clause is as follows:
task_reduction(reduction-identifier : list)
where reduction-identifier is defined in Section 2.21.5.1.
Description The task_reduction clause is a reduction scoping clause, as described in 2.21.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 that participate in the reduction. After the end of the region, the original list item contains the result of the reduction.
Restrictions Restrictions to the task_reduction clause are as follows:
Summary The in_reduction clause specifies that a task participates in a reduction.
Syntax
The syntax of the in_reduction clause is as follows:
in_reduction(reduction-identifier : list)
where reduction-identifier is defined in Section 2.21.5.1.
Description The in_reduction clause is a reduction participating clause, as described in Section 2.21.5.3. For a given 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 task as the reduction-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 may be created in the data environment of the target task as if the private clause had been used. This private copy will be implicitly mapped into the device data environment of the target device, if the target device is not the parent 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.
Restrictions Restrictions to the in_reduction clause are as follows:
Summary The 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.
The syntax of the declare reduction directive is as follows:
#pragma omp declare reduction(reduction-identifier : typename-list :
combiner )[initializer-clause] new-line
where:
The syntax of the declare reduction directive is as follows:
#pragma omp declare reduction(reduction-identifier : typename-list :
combiner) [initializer-clause] new-line
where:
The syntax of the declare reduction directive is as follows:
!$omp declare reduction(reduction-identifier : type-list : combiner)
[initializer-clause]
where:
Description User-defined 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 specifies several types then the behavior is as if a declare reduction directive was specified 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 a user-defined reduction are the same as those of a variable declared at the same location 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 location 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 the locations in a program where 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 location in the program.
The combiner specifies how partial results are 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 the two special variable identifiers denotes 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 are 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.
If a generic name is used in the combiner expression and the list item in the corresponding reduction clause is an array or array section, it is resolved to the specific procedure that is elemental or only has scalar dummy arguments.
If the initializer-expr value of a user-defined reduction is not known a priori, the initializer-clause can be used to specify one. The content of the initializer-clause will be used as the initializer for the 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 are 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 directive 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 directive must be specified for any function or subroutine that can be accessed through the combiner and initializer-expr.
Restrictions Restrictions to the declare reduction directive are as follows:
∙ 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.
∙ Any selectors in the designator of omp_in and omp_out can only be component selectors. ∙ If the initializer-expr is a subroutine name with an argument list, then one of the arguments must be omp_priv. ∙ 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. ∙ If the list item in the corresponding reduction clause is an array or array section, then any procedure used in the initializer clause or combiner expression must either be elemental or have dummy arguments that are scalar. ∙ Any procedure called in the region of initializer-expr or combiner must be pure and may not reference any host-associated variables.