Intel® FPGA SDK for OpenCL™ Standard Edition: Best Practices Guide

ID 683176
Date 9/24/2018
Public
Document Table of Contents

5.2. Removing Loop-Carried Dependencies Caused by Accesses to Memory Arrays

Include the ivdep pragma in your single work-item kernel to assert that accesses to memory arrays will not cause loop-carried dependencies.
During compilation, the creates hardware that ensures load and store instructions operate within dependency constraints. An example of a dependency constraint is that dependent load and store instructions must execute in order. The presence of the ivdep pragma instructs the offline compiler to remove this extra hardware between load and store instructions in the loop that immediately follows the pragma declaration in the kernel code. Removing the extra hardware might reduce logic utilization and lower the II value in single work-item kernels.
  • If all accesses to memory arrays that are inside a loop will not cause loop-carried dependencies, add the line #pragma ivdep before the loop in your kernel code.
    Example kernel code:
    // no loop-carried dependencies for A and B array accesses
    #pragma ivdep
    for (int i = 0; i < N; i++) {
        A[i] = A[i - X[i]];
        B[i] = B[i - Y[i]];
    }
  • To specify that accesses to a particular memory array inside a loop will not cause loop-carried dependencies, add the line #pragma ivdep array (array_name) before the loop in your kernel code.

    The array specified by the ivdep pragma must be a local or private memory array, or a pointer variable that points to a global, local, or private memory storage. If the specified array is a pointer, the ivdep pragma also applies to all arrays that may alias with specified pointer.

    The array specified by the ivdep pragma can also be an array or a pointer member of a struct.

    Example kernel code:

    // No loop-carried dependencies for A array accesses
    // The offline compiler will insert hardware that reinforces dependency constraints for B
    #pragma ivdep array(A)
    for (int i = 0; i < N; i++) {
        A[i] = A[i - X[i]];
        B[i] = B[i - Y[i]];
    }
    
    // No loop-carried dependencies for array A inside struct
    #pragma ivdep array(S.A)
    for (int i = 0; i < N; i++) {
        S.A[i] = S.A[i - X[i]];
    }
    
    // No loop-carried dependencies for array A inside the struct pointed by S
    #pragma ivdep array(S->X[2][3].A)
    for (int i = 0; i < N; i++) {
        S->X[2][3].A[i] = S.A[i - X[i]];
    }
    
    // No loop-carried dependencies for A and B because ptr aliases
    // with both arrays
    int *ptr = select ? A : B;
    #pragma ivdep array(ptr)
    for (int i = 0; i < N; i++) {
        A[i] = A[i - X[i]];
        B[i] = B[i - Y[i]];
    }
    
    // No loop-carried dependencies for A because ptr only aliases with A
    int *ptr = &A[10];
    #pragma ivdep array(ptr)
    for (int i = 0; i < N; i++) {
        A[i] = A[i - X[i]];
        B[i] = B[i - Y[i]];
    }