Skip to main content

PWR025: Consider annotating pure function with OpenMP declare simd

Issue

A SIMD version of the function can most likely be generated by the compiler.

Actions

Annotate the pure function with #pragma omp declare simd.

Relevance

A loop invoking functions tends to make it difficult for the compiler to vectorize. However, calls to some functions can be vectorized. Calls to a pure function (function whose return value depends only on function parameters) can be vectorized if the compiler is instructed to do so with a compiler pragma.

note

If the compiler manages to inline the function, then vectorization pragma is not needed. To see the performance benefit of this approach, the caller loop and called functions must reside in different compilation units.

Also, make sure OpenMP support in your compiler is enabled using compiler switches (typically -fopenmp-simd or -fopenmp).

Code example

C

The following loop invokes a pure function foo:

int foo(int a) {
return 2 * a;
}

void example(int *A, int n) {
for (int i = 0; i < n; i++) {
A[i] = foo(i);
}
}

By adding the #pragma omp declare simd clause, the compiler will create a vectorizable version of foo:

#pragma omp declare simd
int foo(int a) {
return 2 * a;
}

void example(int *A, int n) {
for (int i = 0; i < n; i++) {
A[i] = foo(i);
}
}

Fortran

The following loop invokes a pure function foo:

integer function foo(a)
integer, intent(in) :: a
foo = 2 * a
end function foo

subroutine example(A)
integer, external :: foo
integer, intent(out) :: A(:)
integer :: i

do i = 1, size(A, 1)
A(i) = foo(i)
end do
end subroutine example

By adding the !$omp declare simd clause, the compiler will create a vectorizable version of foo:

integer function foo(a)
!$omp declare simd
integer, intent(in) :: a
foo = 2 * a
end function foo

subroutine example(A)
integer, external :: foo
integer, intent(out) :: A(:)
integer :: i

do i = 1, size(A, 1)
A(i) = foo(i)
end do
end subroutine example

References