Vectorizable Data References

For any data reference, either as an array element or pointer reference (see definitions below), take care to ensure that there are no potential dependence or alias constraints preventing vectorization; intuitively, an expression in one iteration must not depend on the value computed in a previous iteration and pointer variables must provably point to distinct locations.

Arrays

Vectorizable data in a loop may be expressed as uses of array elements, provided that the array references are unit-stride or loop-invariant.

Pointers

Vectorizable data can also be expressed using pointers, subject to the same constraints as uses of array elements; you cannot vectorize references that are non-unit stride or loop invariant.

Invariants

Vectorizable data can also include loop invariant references on the right hand inside an expression, either as variables or numeric constants. The loop in the following example will vectorize.

 

Vectorizable Loop Invariant Reference

SUBROUTINE FOO (A, B, C, N)
DIMENSION A(N),B(N),C(N)
INTEGER N, I, J
J = 5;
DO I=1, N
A(I) = B(I) * 3.14 + C(J)
ENDDO
RETURN
END

If vectorizable REAL data is provably aligned, the compiler will generate aligned instructions. This is the case for locally declared data. Where data alignment is not known, unaligned references will be used unless a directive is used to override this.

IVDEP Directive

The compiler supports IVDEP directive which instructs the compiler to ignore assumed vector dependences. Use this directive when you know that the assumed loop dependences are safe to ignore. The syntax for the directive is:

CDIR$IVDEP
!DIR$IVDEP
!DIR$VECTOR ALWAYS

!DIR$VECTOR ALIGNED
!DIR$VECTOR UNALIGNED

The usage of the directive differs depending on the loop form, see examples below.

Loop 1

Do i
= A(*) + 1
A(*) =
enddo

Loop 2

Do i
A(*) =
= A(*) + 1
enddo

For loops of the form 1, use old values of A, and assume that there is no loop-carried flow dependencies from DEF to USE.

For loops of the form 2, use new values of A, and assume that there is no loop-carried anti-dependencies from USE to DEF.

In both cases, it is valid to distribute the loop, and there is no loop-carried output dependency.

Example 1

CDIR$IVDEP
do  j=1,n
a(j) = a(j+m) + 1
enddo

Example 2

CDIR$IVDEP
do  j=1,n
a(j) =  b(j) +1
b(j) = a(j+m) + 1
enddo

Example 1 ignores the possible backward dependencies and enables the loop to get software pipelined.

Example 2 shows possible forward and backward dependencies involving array a in this loop and creating a dependency cycle. With IVDEP, the backward dependencies are ignored, reducing the recurrence II.

IVDEP has options: IVDEP:LOOP and IVDEP:BACK. The IVDEP:LOOP option implies no loop-carried dependencies. The IVDEP:BACK option implies no backward dependencies.

The IVDEP directive is also used for Itanium(TM)-based applications.

For more details on the IVDEP directive, see Appendix A in the Intel® Fortran Programmer's Reference.

Overriding Vectorizer's Efficiency Heuristics

In addition to IVDEP directive, there are three directives that can be used to override the efficiency heuristics of the vectorizer:

!DIR$VECTOR ALWAYS
!DIR$VECTOR ALIGNED
!DIR$VECTOR UNALIGNED

The VECTOR ALWAYS Directive

The VECTOR ALWAYS directive can be used to override the default behavior of the compiler in the following situation. Vectorization of non-unit stride references usually does not exhibit any speedup, so the compiler defaults to not vectorizing loops that have a large number of non-unit stride references (compared to the number of unit stride references). The following loop has two references with stride 2. Vectorization would be disabled by default, but the directive overrides this behavior.

Vector Aligned

!DIR$ VECTOR ALWAYS
    do i = 1, 100, 2
      a(i) = b(i)
    enddo

The VECTOR ALIGNED/UNALIGNED Directives

Like VECTOR ALWAYS, these directives also override the efficiency heuristics. The difference is that the qualifiers UNALIGNED and ALIGNED instruct the compiler to use, respectively, unaligned and aligned data movement instructions for all array references. This disables all the advanced alignment optimizations of the compiler, such as determining alignment properties from the program context or using dynamic loop peeling to make references aligned.

Note

The directives VECTOR [ALWAYS, UNALIGNED, ALIGNED] should be used with care. Overriding the efficiency heuristics of the compiler should only be done if the programmer is absolutely sure the vectorization will improve performance. Furthermore, instructing the compiler to implement all array references with aligned data movement instructions will cause a runtime exception in case some of the access patterns are actually unaligned.

The NOVECTOR Directive

If, on the other hand, avoiding vectorization of a loop is more reasonable than using it (if vectorization results in a performance regression rather than improvement), the NOVECTOR directive can be used in the source text to disable vectorization of a loop. For instance, the Intel® Compiler vectorizes the following example loop by default. If this behavior is not desired, the NOVECTOR directive can be used, as shown below.

NOVECTOR

!DIR$ NOVECTOR
    do i = 1, 100
          
     a(i) = b(i) + c(i)
    enddo