OpenMP 4.0 New features Supported in Intel® Compiler 16.0

Intel® Compiler 16.0 supports below new features in OpenMP 4.0: 

- User-defined reductions, only support for C/C++ program using POD(Plain old data) types.

- Array reductions, only support for Fortran program.

OpenMP User-defined Reductions

OpenMP 4.0 supports declare reduction directive for declaring user-defined reductions. This declare reduction directive declares User-Defined Reduction (UDR) functions (reduction identifiers) that can be used as reduction operators in a reduction clause. 

The syntax is as following:

#pragma omp declare reduction (reduction-identifier : typename-list : combiner) [initializer-clause] 

Type names in typename-list must be POD (Plain Old Data) types. This means the type is compatible with the types used in the C programming language, can be manipulated using C library functions: it can be created with std::malloc, it can be copied with std::memmove, etc, and can be exchanged with C libraries directly, in its binary form. In addition, the type name cannot be a function type, an array type, a reference type, or a type qualified with const, volatile or C/C++ restrict.

The combiner is an expression that specifies how partial results can be combined into a single value.

The following rules and restrictions apply to the combiner:

  • The combiner can use the special variable identifiers omp_in and omp_out that are of the type of the variables being reduced with this reduction-identifier. These are the only variables allowed in the combiner.

  • The omp_in identifier refers to the partial result local to each thread, while the omp_out identifier refers to the storage that holds the resulting combined value after executing the combiner.

  • The number of times the combiner is executed, and the order of these executions, for any reduction clause is unspecified.

The following rules and restrictions apply to the optional initializer-expr:

  • If initializer-clause is specified, the initializer-expr value is used as the initializer for private copies of reduction list items where the omp_priv identifier refers to the storage to be initialized.

  • Only the variables omp_priv and omp_orig are allowed in the initializer-clause.

  • The special identifier omp_orig refers to the storage of the original variable to be reduced. If omp_orig is modified in the initializer-clause, the behavior is unspecified.

  • 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:

    • One of the arguments must be omp_priv or the address of omp_priv.

    • The initializer-expr is evaluated by calling the function with the specified argument list.

      Otherwise, the C/C++ initializer-expr specifies how omp_priv is declared and initialized.

When defining custom reductions, the reduction-identifier and the type identify the declare reduction pragma. If the pragma applies to several types, it is treated as if there were multiple declare reduction pragmas, one for each type. 

An Example:

#define abs(x)   (x<0 ? -x : x)
#define LARGENUM 2147483647
#define N        1000000
int data[N];

// return the smallest magnitude among all the integers in data[N]
int find_min_abs()
{
  int i;
  int result = LARGENUM;

  #pragma omp declare reduction(minabs : int :              \
    omp_out = abs(omp_in) > omp_out ? omp_out : abs(omp_in)) \
    initializer (omp_priv=LARGENUM)

  #pragma omp parallel for reduction(minabs:result)
  for (i=0; i<N; i++) {
    if (abs(data[i]) < result) {
      result = abs(data[i]);
    }
  }

  return result;
}

Array Reduction

The reduction clause can be used to perform some forms of recurrence calculations (involving mathematically associative and commutative operators) in parallel. For C++, arrays may not appear in a reduction clause. The reason is array operations are not supported in C/C++, which is not the case for Fortran. Hence in Fortran you may put arrays in a reduction clause as long as they are valid for the reduction operator or intrinsic. This helps when the recurrence calculations apply to all array elements, that you can simply put an array to the reduction clause.

For example:

 !$OMP SIMD reduction(+:a)
    do I=1,25,4
      do J=1,8
          a(J) = a(J) + b(I,J)*b(I,J) 
      enddo
    enddo

Here the inner loop is a small trip count loop which is ineffcient for vectorization. To vectorize the outer loop with omp simd directive, you should include the reduction clause for all array elements of array "a", since they are shared and repeatedly calculated within the outer loop. With array reduction supported in Fortran, you can simply add array a in the reduction clause for this purpose. 

Known Issue

In the initial release of Intel Fortran 16.0, array reduction only works when loop unroll is disabled, either from command line: /Qunroll0 or -unroll0, or by adding an nounroll directive before the omp simd loop, see:

 !DIR$ NOUNROLL
 !$OMP SIMD reduction(+:a)
    do I=1,25,4
      do J=1,8
          a(J) = a(J) + b(I,J)*b(I,J) 
      enddo
    enddo

This issue was recorded in internal tracking id: DPD200574061 and going to be fixed in the next update.

Для получения подробной информации о возможностях оптимизации компилятора обратитесь к нашему Уведомлению об оптимизации.
Возможность комментирования русскоязычного контента была отключена. Узнать подробнее.