# LINEAR Clause

Parallel Directive Clause: Specifies that all variables in a list are private to a SIMD lane and that they have a linear relationship within the iteration space of a loop.

## Syntax

It takes one of the following forms:

In Construct Directive !$OMP SIMD:

LINEAR (var-list[: linear-step])

In Declarative Directive !$OMP DECLARE SIMD:

LINEAR (linear-list[: linear-step])

var-list | Is a comma-separated list of one or more integer variables. Each list item must comply with PRIVATE clause semantics. For each iteration of a scalar loop, the value of each var is incremented by linear-step. For each iteration of a vector loop, the value of each var is incremented by linear-step times the vector length for the loop.
linear-step | Is a compile-time positive, integer, scalar constant expression. If linear-step is not specified, it is assumed to be 1.
linear-list | Takes one of the following forms: list modifier (list)
list | Is a comma-separated list of one or more dummy arguments of the procedure that will be invoked concurrently on each SIMD lane. Each list item must comply with PRIVATE clause semantics. If modifier is not specified or it is VAL or UVAL, each list item must be a scalar of type integer. If modifier is REF, each list item must be a scalar of intrinsic type.
modifier | Is one of the following: REF Specifies that the storage location of each list item on each lane corresponds to an array at the storage location upon entry to the function indexed by the logical number of the lane times linear-step. The referenced values passed into the routine (which forms a vector for calculations) are located sequentially, like in an array, with the distance between elements equal to step. This modifier can be used only for dummy arguments passed by reference. VAL Specifies that the value of each list item on each lane corresponds to the value of the list item upon entry to the function plus the logical number of the lane times linear-step. On each iteration of the loop from which the routine is called, the value of the parameter can be calculated as (value_on_previous_iteration + step). UVAL Similar to VAL but each invocation uses the same storage location for each SIMD lane. This storage location is updated with the final value of the logically last lane. It differs from VAL as follows: For VAL, a vector of addresses (references) is passed to the vector variant of the routine. For UVAL, only one address (reference) is passed, which may improve performance. This modifier can be used only for dummy arguments passed by reference. If modifier is not specified or it is VAL or UVAL, the value of each list item on each lane corresponds to the value of the list item upon entry to the function plus the logical number of the lane times linear-step. You can only use REF or VAL if the list item is a dummy argument without the Fortran Standard VALUE attribute.

If more than one linear-step is specified for a var, a compile-time error occurs. Multiple LINEAR clauses can be used to specify different values for linear-step. The linear-step expression must be invariant (must not be changed) during the execution of the associated construct. Multiple LINEAR clauses are merged as a union.

The value corresponding to the sequentially last iteration of the associated loops is assigned to the original list item.

A list item in a LINEAR clause cannot appear in any other data scope attribute clause, in another LINEAR clause, or more than once in list. For a list of data scope attribute clauses, see the first table in Clauses Used in Multiple OpenMP* Fortran Directives.

In the sequentially last iteration, any list item with the ALLOCATABLE attribute must have an allocation status of allocated upon exit from that iteration.

If a list item is a dummy argument without the Fortran Standard VALUE attribute and the REF modifier is not specified, then a read of the list item must be executed before any writes to the list item.

If a LINEAR clause appears in a directive that also contains a REDUCTION clause with the INSCAN modifier, only a loop iteration variable of a loop associated with the construct can appear as a list item in the LINEAR clause.

The following cannot appear in a LINEAR clause:

- Variables that have the POINTER attribute

- Cray* pointers

The LINEAR (REF) clause is very important because Fortran passes dummy arguments by reference. By default, the compiler places consecutive addresses in a vector register, which leads to an inefficient gather of the addresses.

In the following example, LINEAR (REF (X)) tells the compiler that the 4 addresses for the dummy argument X are consecutive, so the code only needs to dereference X once and then copy consecutive values to a vector register.

    subroutine test_linear(x, y)
    !$omp declare simd (test_linear) linear(ref(x, y))    ! arguments by reference
        real(8),intent(in)  :: x
        real(8),intent(out) :: y
        y = 1. + sin(x)**3
    end subroutine test_linear
    …                               ! procedure that calls test_linear
    interface                       ! test_linear needs an explicit interface
    …
    do j = 1,n
         call test_linear(a(j), b(j))    ! loop vectorized via qopenmp-simd
    enddo
    …

## Example

Consider the following:

    ! universal but slowest definition; it matches the use of func in loops 1, 2, and 3:
    !$OMP DECLARE SIMD
    !
    ! matches the use of func in loop 1:
    !$OMP DECLARE SIMD LINEAR(in1) LINEAR(REF(in2)) UNIFORM(mul)
    !
    ! matches the use of func in loops 2 and 3:
    !$OMP DECLARE SIMD LINEAR(REF(in2))
    !
    ! matches the use of func in loop 2:
    !$OMP DECLARE SIMD LINEAR(REF(in2)) LINEAR(mul)
    !
    ! matches the use of func in loop 3:
    !$OMP DECLARE SIMD LINEAR(VAL(in2:2))

    function func(in1, in2, mul)
    integral   in1
    integral   in2
    integral   mul
    ...
    integral a, k
    integral b(100)
    integral c(100)
    integral ndx(100)
    ...

The following are the loop examples referenced above.

    !loop 1
    !$OMP SIMD
       DO i=1,100
          c(i) = func(a + i, b(i), mul) ! the value of the 1st parameter is changed linearly,
                                        !   the 2nd parameter reference is changed linearly,
                                        !   the 3rd parameter is not changed
       END DO

    !loop 2
    !$OMP SIMD
       DO i=1,100
          c(i) = func(b(ndx(i)), b(i), i + 1 ! the value of the 1st parameter is unpredictable,
                                             !   the 2nd reference is changed linearly,
                                             !   the 3rd parameter is changed linearly
       END DO

    !loop 3
    !$OMP SIMD
       DO i=1,100
          k = i * 2                       ! during vectorization, private variables are
          c(i) = func(b(ndx(i)), k, b(i)) !     transformed into arrays: k -> k_vec(simdlen)
                                          ! the value of the 1st parameter is unpredictable,
                                          ! for the 2nd parameter both value and reference
                                          !     to its location can be considered linear,
                                          ! the value for the 3rd parameter is unpredictable
                                          !
                                          ! the !$OMP DECLARE SIMD LINEAR(VAL(in2:2))) will
       END DO                             !     be chosen from the two matching variants)

Parent topic: J to L

## See Also

VALUE statement and attribute
SIMD Directive (OpenMP* API)
DECLARE SIMD