Description
Vitis HLS detects dependencies within loops: dependencies within the same iteration of a loop are loop-independent dependencies, and dependencies between different iterations of a loop are loop-carried dependencies. The DEPENDENCE pragma allows you to provide additional information to define, negate loop dependencies, and allow loops to be pipelined with lower intervals.
- Loop-independent dependence
- The same element is accessed in a single loop
iteration.
for (i=0;i<N;i++) { A[i]=x; y=A[i]; }
- Loop-carried dependence
- The same element is accessed from a different loop
iteration.
for (i=0;i<N;i++) { A[i]=A[i-1]*2; }
These dependencies impact when operations can be scheduled, especially during function and loop pipelining.
Under some circumstances, such as variable dependent array indexing or when an external requirement needs to be enforced (for example, two inputs are never the same index), the dependence analysis might be too conservative and fail to filter out false dependencies. The DEPENDENCE pragma allows you to explicitly define the dependencies and eliminate a false dependence as described in Managing Pipeline Dependencies.
Syntax
Place the pragma within the boundaries of the function where the dependence is defined.
#pragma HLS dependence variable=<variable> <class> \
<type> <direction> distance=<int> <dependent>
Where:
-
variable=<variable>
- Optionally specifies the variable to consider for the
dependence.Important: You cannot specify a
dependence
for function arguments that are bundled with other arguments in anm_axi
interface. This is the default configuration form_axi
interfaces on the function. You also cannot specify a dependence for an element of a struct, unless the struct has been disaggregated. -
class=[array | pointer]
- Optionally specifies a class of variables in which the dependence
needs clarification. Valid values include
array
orpointer
.Tip:<class>
andvariable=
should not be specified together as you can specify dependence for a variable, or a class of variables within a function. -
type=[inter | intra]
- Valid values include
intra
orinter
. Specifies whether the dependence is:-
intra
- Dependence within the same loop iteration. When dependence
<type>
is specified asintra
, and<dependent>
is false, the HLS tool might move operations freely within a loop, increasing their mobility and potentially improving performance or area. When<dependent>
is specified as true, the operations must be performed in the order specified. -
inter
- dependence between different loop iterations. This is the default
<type>
. If dependence <type> is specified asinter
, and<dependent>
is false, it allows the HLS tool to perform operations in parallel if the function or loop is pipelined, or the loop is unrolled, or partially unrolled, and prevents such concurrent operation when<dependent>
is specified as true.
-
-
direction=[RAW | WAR | WAW]
- This is relevant for loop-carry dependencies only, and specifies the
direction for a dependence:
-
RAW
(Read-After-Write - true dependence) - The write instruction uses a value used by the read instruction.
-
WAR
(Write-After-Read - anti dependence) - The read instruction gets a value that is overwritten by the write instruction.
-
WAW
(Write-After-Write - output dependence) - Two write instructions write to the same location, in a certain order.
-
-
distance=<int>
- Specifies the inter-iteration distance for array access. Relevant only for loop-carry
dependencies where dependence is set to
true
. -
<dependent>
- The
<dependent>
argument should be specified to indicate whether a dependence istrue
and needs to be enforced, or isfalse
and should be removed. However, when not specified, the tool will return a warning that the value was not specified and will assume a value offalse
. The accepted values aretrue
orfalse
.
Example 1
In the following example, the HLS tool does not have any knowledge about
the value of cols
and conservatively assumes that there is
always a dependence between the write to buff_A[1][col]
and
the read from buff_A[1][col]
. In an algorithm such as this,
it is unlikely cols
will ever be zero, but the HLS tool
cannot make assumptions about data dependencies. To overcome this deficiency, you can use
the DEPENDENCE
pragma to state that there is no dependence between loop
iterations (in this case, for both buff_A
and buff_B
).
void foo(int rows, int cols, ...)
for (row = 0; row < rows + 1; row++) {
for (col = 0; col < cols + 1; col++) {
#pragma HLS PIPELINE II=1
#pragma HLS dependence variable=buff_A type=inter false
#pragma HLS dependence variable=buff_B type=inter false
if (col < cols) {
buff_A[2][col] = buff_A[1][col]; // read from buff_A[1][col]
buff_A[1][col] = buff_A[0][col]; // write to buff_A[1][col]
buff_B[1][col] = buff_B[0][col];
temp = buff_A[0][col];
}
Example 2
Removes the dependence between Var1
in the
same iterations of loop_1
in function func
.
#pragma HLS dependence variable=Var1 type=intra false
Example 3
Defines the dependence on all arrays in loop_2
of function func
to inform the HLS tool
that all reads must happen after writes (RAW) in the same loop iteration.
#pragma HLS dependence class=array type=intra direction=RAW true