Skip to content

Reduction variables: members, composites, and array elements

What is a reduction variable allowed to be? Most code reduces into a plain scalar, but the OpenACC 3.3 specification permits more than that — and explicitly forbids one form that looks natural. The restrictions in section 2.5.15 are:

OpenACC 3.3 section 2.5.15, Restrictions
• A var in a reduction clause must be a scalar variable name, an aggregate variable name,
  an array element, or a subarray (refer to Section 2.7.1).
• If the reduction var is an array element or a subarray, accessing the elements of the array
  outside the specified index range results in unspecified behavior.
• The reduction var may not be a member of a composite variable.
• If the reduction var is a composite variable, each member of the composite variable must be
  a supported datatype for the reduction operation.

So a whole derived-type variable and an array element are valid reduction vars, while a member of a derived-type variable is not. For aggregates the semantics are member-wise/element-wise (section 2.9.11):

OpenACC 3.3 section 2.9.11
If the reduction var is an array or subarray, the reduction operation is logically equivalent to
applying that reduction operation to each array element of the array or subarray individually. If the
reduction var is a composite variable, the reduction operation is logically equivalent to applying that
reduction operation to each member of the composite variable individually.

We tested all three forms. In the tables below, the Correctness column states whether each compiler's observed behaviour conforms to the OpenACC specification.

Reduction on a member of a composite variable

reduction(+:s%total) is invalid per the specification ("The reduction var may not be a member of a composite variable"), so a compile-time diagnostic is the expected outcome:

Code
program main
  implicit none
  type :: stats
    integer :: total
  end type
  type(stats) :: s
  integer :: i

  s%total = 0
  !$acc parallel loop reduction(+:s%total)
  do i = 1, 100
    s%total = s%total + i
  end do

  if (s%total == 5050) then
    write(*,*) "OK (member reduction accepted and correct)"
  else
    write(*,*) "Wrong result: ", s%total
    error stop
  end if
end program
Compiler Result Correctness Notes
Cray Fortran 19.0.0 ❌ Compile error Per spec — member reductions are invalid ftn-802: "Variable subobjects are not allowed as arguments for this clause or directive."
nvfortran 25.3-0 ❌ Compile error Per spec — member reductions are invalid NVFORTRAN-S-0155-Reduction variable must be a scalar or array variable - total

Reduction on a whole composite variable

reduction(+:s), where s is a derived-type variable with two integer members, is valid per the specification: the reduction applies to each member individually, so the program should compile and print OK:

Code
program main
  implicit none
  type :: stats
    integer :: a
    integer :: b
  end type
  type(stats) :: s
  integer :: i

  s%a = 0
  s%b = 0
  !$acc parallel loop reduction(+:s)
  do i = 1, 100
    s%a = s%a + i
    s%b = s%b + 1
  end do

  if (s%a == 5050 .and. s%b == 100) then
    write(*,*) "OK"
  else
    write(*,*) "Wrong result: ", s%a, s%b
    error stop
  end if
end program
Compiler Result Correctness Notes
Cray Fortran 19.0.0 ❌ Compile error Not per spec — rejects a valid aggregate reduction var ftn-689: "The operator "+" has not been declared as a user defined reduction." The message suggests Cray only supports derived-type reductions through a user-declared reduction, not the implicit member-wise semantics the specification requires.
nvfortran 25.3-0 ❌ Compile error Not per spec — rejects a valid aggregate reduction var NVFORTRAN-S-0155-Reduction variable must be of intrinsic type - s

This is a rare case where both compilers agree with each other against the specification: neither implements member-wise reductions on derived-type variables.

Reduction on an array element

reduction(+:a(1)) is also valid per the specification (an "array element"), with the restriction that the loop must not touch elements outside the specified index range — which the program below respects. It should compile and print OK:

Code
program main
  implicit none
  integer :: a(2), i

  a = 0
  !$acc parallel loop reduction(+:a(1))
  do i = 1, 100
    a(1) = a(1) + i
  end do

  if (a(1) == 5050) then
    write(*,*) "OK"
  else
    write(*,*) "Wrong result: ", a(1)
    error stop
  end if
end program
Compiler Result Correctness Notes
Cray Fortran 19.0.0 ❌ Compile error Not per spec — rejects a valid array-element reduction var ftn-802: "Variable subobjects are not allowed as arguments for this clause or directive." — the same blanket subobject ban that (correctly) rejects the member case above, here over-restricting a valid form.
nvfortran 25.3-0 ✅ OK Per spec The compile log shows the element being handled as the subarray a(:1) (Generating reduction(+:a(:1))); the program runs and prints OK.