一、循环优化
1.循环可以流水线化,可以展开,可以部分展开,可以扁平化,可以合并。
2.对于循环的索引index变量,避免使用全局变量,这个不利于优化。
二、变量循环边界
1.循环的边界如果是变量,将禁止执行vivado hls可应用的某些最优化操作;
2.如果循环的边界是顶层函数的参数传入过来的,那么认为循环边界是变量
3.如果循环的边界是变量,那么会阻止工具去判断循环的时延,时延将是?问号
解决办法:
使用tripcount行程来约束说明;
或者将c语言代码中使用assert宏定义。
4.由于变量边界循环无法展开,因此不仅阻止应用展开 (unroll) 指令,而且还会阻止将循环上层的层次流水线化
5.当循环或函数实现流水线化后,Vivado HLS 即可将函数或循环下层层级中的所有循环展开。如果在此层
级中存在具有变量边界的循环,它就会阻止流水线化。
三、对含有变量边界的循环的解决办法
对于含变量边界的循环,解决方案是通过循环内部的条件执行来将循环迭代次数设置为固定值。可重写变量循环边界示
例中的代码,如以下代码示例所示。此处循环边界显式设置为变量宽度的最大值,循环主体则以有条件方式来执行
#include "ap_cint.h"
#define N 32
typedef int8 din_t;
typedef int13 dout_t;
typedef uint5 dsel_t;
dout_t loop_max_bounds(din_t A[N], dsel_t width) {
dout_t out_accum=0;
dsel_t x;
LOOP_X:for (x=0;x<N; x++) {
if (x<width) {
out_accum += A[x];
}
}
return out_accum;
}
以上示例中的 for 循环 (LOOP_X) 可展开。由于此循环的上限固定,因此 Vivado HLS 知晓需创建的硬件数量。在 RTL
设计中包含 N(32) 份循环主体副本。每份循环主体副本都包含与之关联的条件逻辑,并根据变量宽度值来执行。
四、循环流水化
1.当循环或函数流水线化时,所在层级比流水线化的循环或函数层级更低的所有循环都必须展开
五、循环流水化示例说明
#include "loop_pipeline.h"
dout_t loop_pipeline(din_t A[N]) {
int i,j;
static dout_t acc;
LOOP_I:for(i=0; i < 20; i++){
LOOP_J: for(j=0; j < 20; j++){
acc += A[i] * j;
}
}
return acc;
}
1.上述代码中,如果对loop_pipeline函数进行流水化设计:
dout_t loop_pipeline(din_t A[N]) {
int i,j;
static dout_t acc;
#pragram pipeline II= 1
LOOP_I:for(i=0; i < 20; i++){
LOOP_J: for(j=0; j < 20; j++){
acc += A[i] * j;
}
}
return acc;
}
如果上面是这样优化,那么LOOP_I和LOOP_J都需要被展开!
2.如果对LOOP_I进行pipeline流水化设计
dout_t loop_pipeline(din_t A[N]) {
int i,j;
static dout_t acc;
LOOP_I:for(i=0; i < 20; i++){
#pragram pipeline II= 1
LOOP_J: for(j=0; j < 20; j++){
acc += A[i] * j;
}
}
return acc;
}
如果代码是这么设计的化,那么LOOP_J循环被全部展开unroll
3.如何对LOOP_J进行pipeline优化
dout_t loop_pipeline(din_t A[N]) {
int i,j;
static dout_t acc;
LOOP_I:for(i=0; i < 20; i++){
LOOP_J: for(j=0; j < 20; j++){
#pragram pipeline II= 1
acc += A[i] * j;
}
}
return acc;
}