C66x DSP是TI最新出的定点和浮点混合DSP,后向兼容C64x+和C67x+、C674x系列DSP。本文介绍了基于C66x架构的常用优化技巧,首先介绍C66x相对于C64x+定点DSP的浮点和定点处理能力的增强,以及C66x新引入的128-bit的数据类型。接下来说明c66x特有的特性和相关的优化技术,重点在其浮点增强以及对复数运算和矩阵、向量运算的intrinsics选择,最后是如何解决寄存器不足、SIMD move的使用平衡寄存器和功能单元的分配以及解决寄存器生命周期过长的问题的高级优化技巧。本文中的编译结果基于CCSv4.1中的CGTools v7.2编译器,编译选项–o3 –s –mw –mv6600
C66x DSP简介
C66x DSP是TI最新出的定点和浮点混合DSP,后向兼容C64x+和C67x+、C674x系列DSP。最高主频到1.25GHz,RSA指令集扩展。每个核有32KB的L1P和32KB的L1D,512KB到1MB L2存储区,2MB~4MB的多核共享存储区MSM,多核共享存储控制器MSMC能有效的管理核间内存和数据一致性。针对通信应用,其片内集成了2个TCP3d Turbo码字译码器,一个TCP3e Turbo码编码器,2个FFT/IFFT,DFT/IDFT协处理器以及4个VCP2 Viterbi译码器。高速互联总线,4个串行RapidIO接口,千兆网口、EMIF-DDR3内存控制器。TeraNet Switch用于片内和外设间的快速交互
C66x DSP的架构和指令增强
TMS320C66x ISA架构是对TMS320C674x DSP的增强,也是基于增强VLIW架构的,具有8个功能单元(2个乘法器,6个ALU算术运算单元),该架构的基本增强如下:
4倍的乘累加能力, 每个周期32个 (16x16-bit)或者8个单精度浮点乘法;
浮点运算的增强:优化了将TMS320C67x +和TMS320C64x+ DSP 结合的TMS320C674x DSP,原生支持IEEE 754单精度和双精度浮点运算,包括所有的浮点操作,加减乘除;浮点运算的SIMD支持以及单精度复数乘法,附加的灵活性,如在.L和.S单元完成INT到单精度SP的相互转换
浮点和定点向量处理能力的增强: TMS320C64x+/C674x DSPs支持2-way的16-bit数据SIMD或者4-way的8-bit,C66x增加了SIMD的宽度,增加了128-bit的向量运算。如QMPY32能做2个包含4x32-bit向量的乘法。另外SIMD的处理能力也得到增强;
复数和矩阵运算的引入和增强:针对通信信号处理中的常用复数算术函数和如矩阵运算的线性算法的应用,如单周期可以完成两个[1×2]复数向量和[2×2]的矩阵乘法
图2. QMPY32的向量操作
图2. C64x+/C674x/C66x ISA定点和浮点处理能力对比
消除TMS320C66x寄存器不足的压力
尽量避免4-way的SIMD指令来减少寄存器压力,虽然SIMD能有更好的数据处理的并行,但很多SIMD的处理需要4个寄存器作为源和目的操作数,虽然C66x提供了64个寄存器(A侧和B侧各32个),但这种还是会带来寄存器压力的。寄存器不足的常见编译反馈信息如下
;* ii = 19 Cannot allocate machine registers
;* Regs Live Always : 12/10 (A/B-side)
;* Max Regs Live : 38/31
;* Max Cond Regs Live : 1/0
循环的软件流水给的资源约束在功能单元,但是迭代周期没法在相应的约束内完成,这种提示信息表明寄存器资源不足,因而可以考虑在SIMD指令使用的地方分析是否因为SIMD的引入增大了寄存器压力。因而一个原则是如果循环不被某种功能单元所约束,那么尽量别使用该功能单元的SIMD指令吧。
使用SIMD的move来实现资源平衡
C66x的SIMD move指令能在寄存器间转移数据,需要注意的是如_itoll, _ftod _ito128, _fto128, _dto128 和 _llto128在C66x上对应于非SIMD的move指令。使用这些intrinsic会导致循环对
.L, .S 和 .D单元的约束。因而可以考虑使用SIMD的move指令来代替这些intrinsics,如SIMD intrinsics _dmv(整型) _fdmv(双精度)。对于何时用SIMD的move指令,有如下参考建议:
使用SIMD move如果你需要赋值寄存器到寄存器对;
使用SIMD move如果你确定这些寄存器不会在接下来的指令中使用。
需要注意的是,SIMD的move会增加循环的动态长度。
尽可能避免通用的相同表达式,尤其对于__x128_t类型
对于TMS320C66x编译器而言,那些结果是__x128_t类型的表达式并不会归为相同的表达式,因而可能会重复计算。所以在使用__x128_t数据类型的intrinsic时,尽量吧相同的部分提取出来。如下所示。这种改变不会改变循环的功能功能,但是却能改变性能
void dprod_vcse(double *restrict inputPtr,double *restrict coefsPtr,int
nCoefs,double *restrict sumPtr, int nlength) {
int i, j;
double sumTemp = 0, sumTemp1 = 0, sumTemp2 = 0, sumTemp3 = 0;
for(i = 0; i<nlength/4; i++)
{
for (j = 0; j < nCoefs; j++)
{
sumTemp = _daddsp(sumTemp,_daddsp(_hid128(_cmpysp(inputPtr<span style="font-style: normal;">,coefsPtr</span><span style="font-style: normal;">)),_lod128(_cmpysp(inputPtr</span><span style="font-style: normal;">,coefsPtr</span><span style="font-style: normal;">))));
sumTemp1 = _daddsp(sumTemp1,_daddsp(_hid128(_cmpysp(inputPtr[i+1],coefsPtr</span><span style="font-style: normal;">)),_lod128(_cmpysp(inputPtr[i+1],coefsPtr</span><span style="font-style: normal;">))));
sumTemp2 = _daddsp(sumTemp2,_daddsp(_hid128(_cmpysp(inputPtr[i+2],coefsPtr</span><span style="font-style: normal;">)),_lod128(_cmpysp(inputPtr[i+2],coefsPtr</span><span style="font-style: normal;">))));
sumTemp3 = _daddsp(sumTemp3,_daddsp(_hid128(_cmpysp(inputPtr[i+3],coefsPtr</span><span style="font-style: normal;">)),_lod128(_cmpysp(inputPtr[i+3],coefsPtr</span><span style="font-style: normal;">))));
}
sumPtr</span><span style="font-style: normal;"> = sumTemp;
sumPtr[i+1] = sumTemp1;
sumPtr[i+2] = sumTemp2;
sumPtr[i+3] = sumTemp3;
}
}</span>
修改为:
<span style="font-style: normal;">void dprod_novcse(double *restrict inputPtr,double *restrict coefsPtr,int
nCoefs,double *restrict sumPtr, int nlength) {
int i, j;
double sumTemp = 0, sumTemp1 = 0, sumTemp2 = 0, sumTemp3 = 0;
__x128_t cmpysp_temp, cmpysp_temp1, cmpysp_temp2, cmpysp_temp3;
for(i = 0; i<nlength/4; i++)
{
for (j = 0; j < nCoefs; j++)
{
cmpysp_temp = _cmpysp(inputPtr</span><span style="font-style: normal;">,coefsPtr</span><span style="font-style: normal;">);
sumTemp = _daddsp(sumTemp, _daddsp(_hid128(cmpysp_temp),
_lod128(cmpysp_temp)));
cmpysp_temp1 = _cmpysp(inputPtr[i+1],coefsPtr</span><span style="font-style: normal;">);
sumTemp1 = _daddsp(sumTemp1, _daddsp(_hid128(cmpysp_temp1),
_lod128(cmpysp_temp1)));
cmpysp_temp2 = _cmpysp(inputPtr[i+2],coefsPtr</span><span style="font-style: normal;">);
sumTemp2 = _daddsp(sumTemp2, _daddsp(_hid128(cmpysp_temp2),
_lod128(cmpysp_temp2)));
cmpysp_temp3 = _cmpysp(inputPtr[i+3],coefsPtr</span><span style="font-style: normal;">);
sumTemp3 = _daddsp(sumTemp3, _daddsp(_hid128(cmpysp_temp3),
_lod128(cmpysp_temp3)));
}
sumPtr</span><span style="font-style: normal;"> = sumTemp;
sumPtr[i+1] = sumTemp1;
sumPtr[i+2] = sumTemp2;</span>
sumPtr[i+3] = sumTemp3;
}
}
一周热门 更多>