UG1448 Referable Content - 2024.1 English

Vitis HLS Messaging (UG1448)

Document ID
UG1448
Release Date
2024-05-30
Version
2024.1 English

Description

Warning: [200-868] Skip long run time warning caused by lots of load/store instructions.

This message reports long run times caused by a large number of loads and store instructions.

Explanation

The number of load/store operations are caused by one of the following reasons:

  • Completely partitioning arrays size > 1024
  • Completely unrolling large loops loops
  • An excessive number of operations generated by the tool

Solution

There are two potential solutions:
Array partitioning
Divide the single dimension into multiple and partition the desired dim by a factor. This will reduce the amount of operations generated.
Loop Unrolling
Move the source code into multiple separate functions and unroll each of them. This will result in fewer operations or refactor the code or unroll it with a factor.

Description

Warning: [200-887] Cannot meet target clock period from %s to %s (combination delay: %s ns) to honor %s constraint in region '%s'.

This message reports a possible critical path error leading to timing violation in the user code.

Explanation

A timing violation is a path of operations requiring more time than the available clock cycle. Each operation may constitute a certain delay in the hardware, and if a set of operations' delays exceed the clock boundary, the HLS tool will inform the user of the violating clock cycle. If the design violates the clock cycle then the overall clock frequency rescales to the factor to accommodate the operations. At the HLS level these delays are estimated.

One of the main reasons for a timing violation is because of the II constraint. If the user specifies a strict II-1 constraint in the user code, the tool packs the operations back-to-back inside a clock boundary to achieve the required II. If a single operation in the user code exceeds the clock boundary then the tool will issue a timing violation.

To view a timing violation in the user code, see .

Solution

The solution to the timing violation is to relax the II constraint or refactor the user code to break the timing path.

Description

Warning: [200-936] Cannot completely unroll a loop with a variable trip count.
This message reports that the code is violating loop unrolling optimization rules.

Explanation

If the tool could not estimate the loop bound, then it's not possible for the tool to generate the number of parallel ops. The following is an example that fails the optimization:

// var is from the input which goes till estimated 128
for(int i=0;i<var;i++)
{
#pragma HLS unroll
...
...
}

Solution

Calculate the loop bound and use it for the loop unrolling optimization.

Description

Warning: [200-927] Ignore complete array reshape directive on '%s' in dimension %s: conflict with memory core assignment directive.
This message reports that the tool is ignoring the array partition directive because of conflicting pragmas.

Solution

Conflicting pragmas in the user code is causing the array partition constraint to be ignored.

Review the pragmas and remove either one of them. The following code sample could lead to this warning:

void cnn( long *pixel, // Input pixel
  int *weights, // Input Weight Matrix
  long *out, // Output pixel
  ... // Other input or Output ports
            
...
int A[256];
#pragma HLS RESOURCE variable=A core=BRAM_T2P latency=3
#pragma HLS ARRAY_RESHAPE variable=A complete dim=1

Description

Warning: [200-880] The II Violation in module '%s': Unable to enforce a carried dependence constraint (II = %s, distance = %s, offset = %s) between %s and %s.
This message reports that the design is violating the user-specified constraint.

Explanation

The II violation message is issued when the tool cannot satisfy the user-specified hard constraint. II violation conceptually occurs because of the hardware dependencies generated by the HLS from user code when the function/loop is pipelined with II=1. These dependencies are the same as the processor dependencies as explained in this wiki: https://en.wikipedia.org/wiki/Data_dependency

These dependencies can be categorized into three sections:

Memory dependencies

Memory dependencies arise when there is memory port contention. This contention only occurs if the loop is pipelined with II=1 and the number of access per loop iteration > 2. This limitation of memory ports is a hardware limit of a storage resource - BRAM/URAM.

So if the user tries to perform >2 access per loop iteration the tool won't be able to schedule the operations in one cycle. This can be visualized in Vitis High-Level Synthesis User Guide (UG1399)

Solution: Partition the array with regards to the user code or refactor the array to multiple dimensions.

Data dependencies

A data dependence is a property of the program, where the current instruction uses the value produced by an earlier instruction. There are 3 main scenarios where these dependencies can arise.

  • The current loop iteration uses the value generated by an earlier loop iteration. and this value takes N cycles to be generated by the earlier iteration. This prevents the current iteration starting at the next cycle.
    • The following snippet displays the behavior.
    • In the below example because of the multiplication of a float variable the loop cannot schedule at II=1.
    float a;
    float b;
    for(...)
    {
    #pragma HLS pipeline II=1
    val *= a*b;
     
    }
  • The current loop iteration uses the value generated by an earlier loop iteration but in infrequent terms. and this value takes N cycles to be generated by the earlier iteration. This prevents the current iteration starting at the next cycle.
  • The current loop iteration exit condition uses the value generated by an earlier loop iteration. and this value takes N cycles to be generated by the earlier iteration. This prevents the current iteration starting at the next cycle.

    The following code snippet shows the behavior.

    float a;
    float b;
    for(...)
    {
    #pragma HLS pipeline II=1
    if(val==3.69)
        break;
    val *= a*b;
     
    }

Solution: These dependencies are visualized in the schedule viewer l to help the user understand. Break up these dependencies in the user code.

False dependencies
void histogram(int in[INPUT SIZE], int hist[VALUE SIZE]) {
int acc = 0;
int i, val;
int old = in[0];
#pragma HLS DEPENDENCE variable=hist intra RAW false
for(i = 0; i < INPUT SIZE; i++)
{
#pragma HLS PIPELINE II=1
val = in[i];
if(old == val)
{
acc = acc + 1;
}
else
{
hist[old] = acc;
acc = hist[val] + 1;
}
old = val;
}
hist[old] = acc;

Description

This message reports that the dataflow region is not following canonical rules.

Solution

Vitis HLS transforms the region to apply DATAFLOW optimization. It is recommended to write the code inside this region (referred to as the canonical region) using canonical forms.

The canonical form for a function where functions are not inlined:

void dataflow(Input0, Input1, Output0, Output1)
{
#pragma HLS dataflow
UserDataType C0, C1, C2;
func1(read Input0, read Input1, write C0, write C1);
func2(read C0, read C1, write C2);
func3(read C2, write Output0, write Output1);
}

For the for loop (where no function inside is inlined), the integral loop variable requires:

  1. Initial value declared in the loop header and set to 0.
  2. The loop condition is a positive numerical constant or constant function argument.
  3. Increment by 1.
  4. Dataflow pragma needs to be inside the loop.
  5. Should have a single loop counter.
void dataflow(Input0, Input1, Output0, Output1)
{
for (int i = 0; i < N; i++)
{
#pragma HLS dataflow
UserDataType C0, C1, C2;
func1(read Input0, read Input1, write C0, write C1);
func2(read C0, read C0, read C1, write C2);
func3(read C2, write Output0, write Output1);
}
}

Description

Warning: [214-169] There are instances of non-canonical statements in the dataflow region.
This message reports that the dataflow region is not following the canonical body.

Solution

Vitis HLS transforms the region to apply DATAFLOW optimization. It is recommended to write the code inside this region (referred to as the canonical region) using canonical forms as listed below:

  1. Use a local, non-static scalar or array/pointer variable, or local static stream variable. A local variable is declared inside the function body (for dataflow in a function) or loop body (for dataflow inside a loop).
  2. A sequence of function calls that pass data forward (with no feedback), from a function to one that is lexically later, under the following conditions:
    1. Variables (except scalar) can have only one reading process and one writing process.
    2. Use write before read (producer before consumer) if you are using local variables, which then become channels.
    3. Use read before write (consumer before producer) if you are using function arguments. Any intra-body anti-dependencies must be preserved by the design.
    4. Function return type must be void.
    5. No loop-carried dependencies among different processes via variables.
      • Inside the canonical loop (i.e., values written by one iteration and read by a following one).
      • Among successive calls to the top function (i.e., inout argument written by one iteration and read by the following iteration).

Description

Warning: [200-929] Ignoring array reshape directive on stream array '%s' as a container array is completely partitioned automatically.
This message reports that tool is ignoring the user-specified optimization.

Solution

The tool is ignoring the array partition directive because of the automatic optimization applied by the tool.

To perform the automatic optimization, the tool applies a global config option, as displayed below. Preview the config option and if not desired, either reduce the default option or remove it.

config_array_partition
 
Description
Specifies the default behavior for array partitioning.
 
Syntax
config_array_partition [OPTIONS]
 
Options
-auto_partition_threshold <int>
Sets the threshold for partitioning arrays (including those without constant indexing).
 
Arrays with fewer elements than the specified threshold limit are partitioned into individual
elements, unless interface or core specification is applied on the array. The default is 4.

Description

Warning: [200-916] Ignored array partition directive %s: cannot locate the real object(s).
This message reports that the array partition/reshape constraint is being ignored.

Solution

The array partition/reshape constraint applied to an array is either out of the scope or the array does not exist.

Description

This message reports that the dataflow region is not following canonical rules.

Solution

Vitis HLS transforms the region to apply DATAFLOW optimization. It is recommended to write the code inside this region (referred to as the canonical region) using canonical forms.

The canonical form for a function where functions are not inlined:

void dataflow(Input0, Input1, Output0, Output1)
{
#pragma HLS dataflow
UserDataType C0, C1, C2;
func1(read Input0, read Input1, write C0, write C1);
func2(read C0, read C1, write C2);
func3(read C2, write Output0, write Output1);
}

For the for loop (where no function inside is inlined), the integral loop variable requires:

  1. Initial value declared in the loop header and set to 0.
  2. The loop condition is a positive numerical constant or constant function argument.
  3. Increment by 1.
  4. Dataflow pragma needs to be inside the loop.
  5. Should have a single loop counter.
void dataflow(Input0, Input1, Output0, Output1)
{
for (int i = 0; i < N; i++)
{
#pragma HLS dataflow
UserDataType C0, C1, C2;
func1(read Input0, read Input1, write C0, write C1);
func2(read C0, read C0, read C1, write C2);
func3(read C2, write Output0, write Output1);
}
}

Description

This message reports that the dataflow region is not following canonical rules.

Solution

Vitis HLS transforms the region to apply DATAFLOW optimization. It is recommended to write the code inside this region (referred to as the canonical region) using canonical forms.

The canonical form for a function where functions are not inlined:

void dataflow(Input0, Input1, Output0, Output1)
{
#pragma HLS dataflow
UserDataType C0, C1, C2;
func1(read Input0, read Input1, write C0, write C1);
func2(read C0, read C1, write C2);
func3(read C2, write Output0, write Output1);
}

For the for loop (where no function inside is inlined), the integral loop variable requires:

  1. Initial value declared in the loop header and set to 0.
  2. The loop condition is a positive numerical constant or constant function argument.
  3. Increment by 1.
  4. Dataflow pragma needs to be inside the loop.
  5. Should have a single loop counter.
void dataflow(Input0, Input1, Output0, Output1)
{
for (int i = 0; i < N; i++)
{
#pragma HLS dataflow
UserDataType C0, C1, C2;
func1(read Input0, read Input1, write C0, write C1);
func2(read C0, read C0, read C1, write C2);
func3(read C2, write Output0, write Output1);
}
}