Intel® High Level Synthesis Compiler Pro Edition: Reference Manual

ID 683349
Date 10/02/2023
Public

A newer version of this document is available. Customers should click here to go to the newest version.

Document Table of Contents

6.2. Loop-Carried Dependencies (ivdep Pragma)

When compiling your components, the HLS compiler generates hardware to avoid any data hazards between load and store instructions to component memories, agent memories, and external memories (through Avalon® -MM host interfaces). In particular, read-write dependencies can limit performance when they exist across loop iterations because they prevent the compiler from beginning a new loop iteration before the current iteration finishes executing its load and store instructions.
You have the option to guarantee to the HLS compiler that there are no implicit memory dependencies across loop iterations in your component by adding the ivdep pragma in your code.

The ivdep pragma tells the compiler that a memory dependency between loop iterations can be ignored. Ignoring the dependency saves area and lowers the loop initiation interval (II) of the affected loop because the hardware required for avoiding data hazards is no longer required.

You can provide more information about loop dependencies by adding the safelen(N) clause to the ivdep pragma. The safelen(N) clause specifies the maximum number of consecutive loop iterations without loop-carried memory dependencies. For example, #pragma ivdep safelen(32) indicates to the compiler that there are a maximum of 32 iterations of the loop before loop-carried dependencies might be introduced. That is, while #pragma ivdep promises that there are no implicit memory dependency between any iteration of this loop, #pragma safelen(32) promises that the iteration that is 32 iterations away is the closest iteration that could depend on this iteration.

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 component code. The array specified by the ivdep pragma must be one of the following items:
  • a component memory array
  • a pointer argument
  • a pointer variable that points to a component memory
  • a reference to an mm_host object
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.
CAUTION:
Incorrect usage of the ivdep pragma might introduce functional errors in hardware.

Use Case 1:

If all accesses to memory arrays inside a loop do not cause loop-carried dependencies, add #pragma ivdep before the loop.

1  // no loop-carried dependencies for A and B array accesses
2  #pragma ivdep
3  for(int i = 0; i < N; i++) {
4      A[i] = A[i + N]; 
5      B[i] = B[i + N];
6  }

Use Case 2:

You may specify #pragma ivdep array (array_name) on particular memory arrays instead of all array accesses. This pragma is applicable to arrays, pointers, or pointer members of structs. If the specified array is a pointer, the ivdep pragma applies to all arrays that may alias with the specified pointer.

 1  // No loop-carried dependencies for A array accesses
 2  // Compiler inserts hardware that reinforces dependency constraints for B
 3  #pragma ivdep array(A)
 4  for(int i = 0; i < N; i++) {
 5      A[i] = A[i - X[i]];
 6      B[i] = B[i - Y[i]];
 7  }
 8
 9  // No loop-carried dependencies for array A inside struct
10  #pragma ivdep array(S.A)
11  for(int i = 0; i < N; i++) {
12      S.A[i] = S.A[i - X[i]];
13  }
14
15  // No loop-carried dependencies for array A inside the struct pointed by S
16  #pragma ivdep array(S->X[2][3].A)
17  for(int i = 0; i < N; i++) {
18      S->X[2][3].A[i] = S.A[i - X[i]];
19  }
20
21  // No loop-carried dependencies for A and B because ptr aliases
22  // with both arrays
23  int *ptr = select ? A : B;
24  #pragma ivdep array(ptr)
25  for(int i = 0; i < N; i++) {
26      A[i] = A[i - X[i]];
27      B[i] = B[i - Y[i]];
28  }
29
30  // No loop-carried dependencies for A because ptr only aliases with A
31  int *ptr = &A[10];
32  #pragma ivdep array(ptr)
33  for(int i = 0; i < N; i++) {
34      A[i] = A[i - X[i]];
35      B[i] = B[i - Y[i]];
36  }
To learn more about the effects of applying the ivdep loop pragma, review the following tutorial:
<quartus_installdir>/hls/examples/tutorials/best_practices/loop_memory_dependency