Function Templates for Data Types - 2023.2 English

Vitis Model Composer User Guide (UG1483)

Document ID
UG1483
Release Date
2023-11-15
Version
2023.2 English

Function templates for data types are functions that can operate with generic data types. This lets you create library functions that can be adapted to support multiple data types without needing to replicate the code or block in the Vitis Model Composer HLS block library to support each type. The xmcImportFunction command in Model Composer will create generic library blocks which the user of the block can connect to signals of any data types supported by the block.

The data type (typename) template parameters are resolved at simulation runtime, when the code and simulation wrapper are generated. The parameters are replaced during simulation by the actual data types that are specified by the signals connecting to the library block. The resolved data types can only be the types that Model Composer supports as discussed in Working with Data Types.

To import a block that accepts multiple data types, you use a function template. For example:
template <typename T>
T max(T x, T y) {
   return (x > y) ? x : y;
}
Or, in the case of a function with complex function arguments, the example would appear as as follows:
#include <complex>
template <typename T>
void mult_by_two(std::complex< T > x, std::complex< T > *y)
{
   *Out = In1 * 2;
}
The determination of the type is made by Model Composer during simulation. The typename (or class) parameters are propagated from input signals on the block, or are customization parameters that must be defined by the user at simulation runtime.
Important: The data type for a function or class cannot be propagated from an output.

For example, the following function template specifies the parameter ‘T’ as a customization parameter. Because it is not associated with either input argument, 'x' or 'y', it must be specified by the user when the block is added to the model:

template <typename T>
T min(int x, int y) {
   return (x < y) ? x : y;
}

The Block Parameters dialog box for the generated Library Function block has an edit field to enter the template argument as shown in the following figure.

Figure 1. Library Function Block Parameters

In the template syntax, the data type template parameters for function or class can be specified with other template parameters. The order of specification is not important. For example:

template <typename T1, int ROWS, int COLS, int W, int I>
T1 func(T1 x[ROW][COLS], ap_fixed<W, I> &y) {
...
}
Important: In the example above, notice that the 'T1' template parameter is used to specify both the function return and the data type of the input 'x'. In this case, because it is a single template parameter, both arguments will resolve to the same data type that is propagated from the input signal to the block.

SUPPORTED_TYPES/UNSUPPORTED_TYPES Pragma

When defining a data type (typename) template parameter (or class), you can also define the accepted data types for the variable by using either the SUPPORTED_TYPES or UNSUPPORTED_TYPES pragma as part of the function signature. This is shown in the following code example.
#pragma XMC INPORT x
#pragma XMC INPORT y
#pragma XMC SUPPORTED_TYPES T: int8, int16, int32, double, single, half
template <class T>
T max(T x, T y) {
   return (x > y) ? x : y;
}

#pragma XMC UNSUPPORTED_TYPES T: boolean
#pragma XMC INPORT x, y
template <typename T>
T min(T x, T y) {
   return (x < y) ? x : y;
}

Model Composer supports an extensive list of data types as discussed in Working with Data Types. To specify which of these data types the template parameter supports, you can either include the list of supported types, or the unsupported types. The SUPPORTED_TYPES and UNSUPPORTED_TYPES pragmas are simply two opposite views of the same thing:

  • SUPPORTED_TYPES: Specifies a template parameter name (param), and the list of data types that are accepted by that parameter. This implies the exclusion of all types not listed.
    #pragma XMC SUPPORTED_TYPES param: type1, type2, ...
  • UNSUPPORTED_TYPES: Specifies a template parameter name (param), and the list of data types that are not accepted by that parameter. This implies the inclusion of all types not listed.
    #pragma XMC UNSUPPORTED_TYPES param: type1, type2, ...

With the SUPPORTED_TYPES or UNSUPPORTED_TYPES pragma in place, Model Composer will check the type of input signal connected to the block to ensure that the data type is supported. Without the use of one of these pragmas, the data type template parameter will accept any of the data types supported by Model Composer.

Function Template Specialization and Overloading

Specialization is supported for function templates in the xmcImportFunction command. Model Composer will create the library block for the generic function template, supporting multiple data types, but the block will also include any specialized functions to be used when connected to input signals with matching data types. Both the generic function, and any specialization functions are compiled into the block DLL. For example:

template <typename T>
T min(T x, T y) {
   return (x < y) ? x : y;
}

template <>
bool min<bool>(bool x, bool y) {
...
}

In this case, Model Composer will call the specialized boolean form of the min function when the block is connected to boolean signals.

Overloading of a function with the same number of input/output arguments is also supported by Model Composer. For example, the following defines two forms of the function:
int func(int x);
float func(float x);
You can also overload a function template as shown below:
template <typename T> 
int func(int x, T y);

template <typename T> 
float func(float x, T y);
Tip: Overloading functions with different numbers of input/output arguments or different argument dimensions is not supported, and must be defined as separate functions.