函数例化是一种最优化技巧,不仅具有维持函数层级的面积优势,还可提供另一个强大的选项:在函数的特定实例上执行针对性局部最优化。这样可以简化围绕函数调用的控制逻辑,也可能改进时延和吞吐量。
鉴于调用函数时,函数的部分输入可能是常量,FUNCTION_INSTANTIATE 编译指示或指令可藉此简化周围控制结构,并生成进一步最优化的、更小的函数块。如下代码所示示例对此进行了最明确的解释。
char func(char inval, char incr) {
#pragma HLS INLINE OFF
#pragma HLS FUNCTION_INSTANTIATE variable=incr
return inval + incr;
}
void top(char inval1, char inval2, char inval3,
char *outval1, char *outval2, char *outval3)
{
*outval1 = func(inval1, 0);
*outval2 = func(inval2, 1);
*outval3 = func(inval3, 100);
}
提示:
Vitis HLS 工具会将小函数自动分解(或内联)到更高层次的调用函数中。将 INLINE 编译指示与
OFF
选项搭配使用即可阻止此自动内联操作。很明显,函数 func
已写为执行三次互斥运算(根据 incr
的值)。函数 func
的每个实例都是以相同方式实现的。虽说这对于函数复用和面积最优化很实用,但也意味着函数内部的控制逻辑必须更为复杂,才能容纳两次互斥运算。请参阅
Vitis-HLS-Introductory-Examples/Pipelining/Functions/function_instantiate
以获取此示例的完整版本。
FUNCTION_INSTANTIATE 最优化允许对每个实例进行独立最优化,从而减少功能和面积。完成 FUNCTION_INSTANTIATE 最优化后,以上代码可有效转换为 2 个独立函数,每个函数都针对模式的不同可能值来完成最优化,如下所示:
void func1() {
// code segment 1
}
void func2() {
// code segment 2
}
如果在未经大幅内联或代码修改的情况下,在不同层级使用该函数而导致函数难以共享,那么函数例化可提供改进面积的最佳方法:大量小型局部最优化的副本比大量无法共享的大型副本更有效。