10.10. scan Directive#

The following examples illustrate how to parallelize a loop that saves the prefix sum of a reduction. This is accomplished by using the inscan modifier in the reduction clause for the input variable of the scan, and specifying with a scan directive whether the storage statement includes or excludes the scan input of the present iteration ( k ).

Basically, the inscan modifier connects a loop and/or SIMD reduction to the scan operation, and a scan construct with an inclusive or exclusive clause specifies whether the “scan phase’’ (lexical block before and after the directive, respectively) is to use an inclusive or exclusive scan value for the list item ( x ).

The first example uses the inclusive scan operation on a composite loop-SIMD construct. The scan directive separates the reduction statement on variable x from the use of x (saving to array b ). The order of the statements in this example indicates that value a[k] ( a(k) in Fortran) is included in the computation of the prefix sum b[k] ( b(k) in Fortran) for iteration k .

//%compiler: clang
//%cflags: -fopenmp

/*
* name:       scan.1
* type:       C
* version: omp_5.0
*/
#include <stdio.h>
#define N 100

int main(void)
{
   int a[N], b[N];
   int x = 0;

   // initialization
   for (int k = 0; k < N; k++)
      a[k] = k + 1;

   // a[k] is included in the computation of producing results in b[k]
   #pragma omp parallel for simd reduction(inscan,+: x)
   for (int k = 0; k < N; k++) {
      x += a[k];
      #pragma omp scan inclusive(x)
      b[k] = x;
   }

   printf("x = %d, b[0:3] = %d %d %d\n", x, b[0], b[1], b[2]);
   //           5050,        1  3  6

   return 0;
}
!!%compiler: gfortran
!!%cflags: -fopenmp

! name:       scan.1
! type:       F-free
! version: omp_5.0
program inclusive_scan
   implicit none
   integer, parameter :: n = 100
   integer a(n), b(n)
   integer x, k

   ! initialization
   x = 0
   do k = 1, n
      a(k) = k
   end do

   ! a(k) is included in the computation of producing results in b(k)
   !$omp parallel do simd reduction(inscan,+: x)
   do k = 1, n
      x = x + a(k)
      !$omp scan inclusive(x)
      b(k) = x
   end do

   print *,'x =', x, ', b(1:3) =', b(1:3)
   !           5050,            1  3  6

end program

The second example uses the exclusive scan operation on a composite loop-SIMD construct. The scan directive separates the use of x (saving to array b ) from the reduction statement on variable x . The order of the statements in this example indicates that value a[k] ( a(k) in Fortran) is excluded from the computation of the prefix sum b[k] ( b(k) in Fortran) for iteration k .

//%compiler: clang
//%cflags: -fopenmp

/*
* name:       scan.2
* type:       C
* version: omp_5.0
*/
#include <stdio.h>
#define N 100

int main(void)
{
   int a[N], b[N];
   int x = 0;

   // initialization
   for (int k = 0; k < N; k++)
      a[k] = k + 1;

   // a[k] is not included in the computation of producing
   // results in b[k]
   #pragma omp parallel for simd reduction(inscan,+: x)
   for (int k = 0; k < N; k++) {
      b[k] = x;
      #pragma omp scan exclusive(x)
      x += a[k];
   }

   printf("x = %d, b[0:3] = %d %d %d\n", x, b[0], b[1], b[2]);
   //           5050,        0  1  3

   return 0;
}
!!%compiler: gfortran
!!%cflags: -fopenmp

! name:       scan.2
! type:       F-free
! version: omp_5.0
program exclusive_scan
   implicit none
   integer, parameter :: n = 100
   integer a(n), b(n)
   integer x, k

   ! initialization
   x = 0
   do k = 1, n
      a(k) = k
   end do

   ! a(k) is not included in the computation of producing results in b(k)
   !$omp parallel do simd reduction(inscan,+: x)
   do k = 1, n
      b(k) = x
      !$omp scan exclusive(x)
      x = x + a(k)
   end do

   print *,'x =', x, ', b(1:3) =', b(1:3)
   !           5050,            0  1  3

end program