Canonical Forms - 2023.2 English

Vitis High-Level Synthesis User Guide (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 English

Vitis HLS transforms the region to apply the DATAFLOW optimization. For more predictibility of the resulting dataflow network, AMD recommends writing the code inside this region (referred to as the canonical region) using canonical forms. There are two main canonical forms for the dataflow optimization:

  1. The canonical form for a function where sub-functions are not inlined. These subfunctions can themselves be dataflow in function regions or dataflow inside loop regions. Note also that variable initialization (including those performed automatically by constructors) or passing expressions by value to processes are not part of canonical form. Vitis HLS does its best to implement the resulting dataflow but, if the code is not in canonical form, you should always check the GUI dataflow viewer and the cosimulation timeline trace to ensure that the dataflow happens as expected and the achieved performance is as expected.

    void dataflow(Input0, Input1, Output0, Output1)
    {
     #pragma HLS dataflow
     UserDataType C0, C1, C2;       // UserDataType can be scalars or arrays
     func1(Input0, Input1, C0, C1); // read Input0, read Input1, write C0, write C1 
     func2(C0, C1, C2);             // read C0, read C1, write C2
     func3(C2, Output0, Output1);   // read C2, write Output0, write Output1
    }
  2. Dataflow inside a loop body enclosed in a function without any other code but the loop. For the for loop (where no function inside is inlined), the integral loop variable should have:
    1. The initial value is declared in the loop header and set to 0.
    2. The loop bound is a non-negative numerical constant or scalar argument of the function that encloses the loop.
    3. Increment by 1.
    4. Dataflow pragma needs to be inside the loop as shown below.
    void dataflow(Input0, Input1, Output0, Output1)
    {
        for (int i = 0; i < N; i++)
        {
        #pragma HLS dataflow
            UserDataType C0, C1, C2;       // UserDataType can be scalars or arrays
            func1(Input0, Input1, C0, C1); // read Input0, read Input1, write C0, write C1
            func2(C0, C0, read C1, C2);    // read C0, read C0, read C1, write C2   
            func3(C2, Output0, Output1);   // read C2, write Output0, write Output1
        }
    }