C66x定点浮点混合DSP循环编程优化指南

图1. KeyStone 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个 (16×16-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个包含4×32-bit向量的乘法。另外SIMD的处理能力也得到增强;
  • 复数和矩阵运算的引入和增强:针对通信信 处理中的常用复数算术函数和如矩阵运算的线性算法的应用,如单周期可以完成两个[1×2]复数向量和[2×2]的矩阵乘法

图2. QMPY32的向量操作

 

图2. C64x+/C674x/C66x ISA定点和浮点处理能力对比

 

128-bit数据类型

C66x DSP的浮点运算和向量、复数、矩阵运算的优化

浮点操作

C66x的浮点支持可以原生的运行很多的浮点算法,即便是从Matlab或者C代码刚刚转换的算法,就可以评估性能和算法精度。本节主要以单精度浮点为例,虽然C66x可以很好的支持双精度浮点的运行。

使用C66x的浮点操作有以下好处,由于不用考虑精度和数据范围权衡而进行的定点数据Q定标和数据转换,因而在通用C和MatlAB上验证的算法可以直接在C66x的DSP上实现。浮点处理还能从减少的缩放和Q值调整带来的cycle减少,浮点操作还提供快速的出发和求平方根的指令,单精度浮点处理能带来很高的动态范围和固定的24-bit精度,和32-bit定点相比更节省功耗。而快速的数据格式转换指令更能有效的处理定点和浮点混合的代码,带来更多的便利性。

C66x的浮点算术运算包括如下:

考虑C64x+平台的优化

考虑C66x平台的优化

继续C66x平台的优化

C66x有更强的SIMD处理能力,进一步的优化可以考虑浮点乘法、数据加载等。如数据加载采用对于加载的寄存器对的数据,可以采用_hif(src)来得到实部,用_lof(src)来得到虚部,类似于C64x+中的_hill(src) 和 _loll(src)。组成一个寄存器对,可以采用类似_itoll(srcq, src2) 的_fod(src1, scr2).

DMPYSP:浮点的C[i] = A[i] * B[i] for i=0 to 1

混合的定点和浮点代码

消除TMS320C66x寄存器不足的压力

 

尽量避免4-way的SIMD指令来减少寄存器压力,虽然SIMD能有更好的数据处理的并行,但很多SIMD的处理需要4个寄存器作为源和目的操作数,虽然C66x提供了64个寄存器(A侧和B侧各32个),但这种还是会带来寄存器压力的。寄存器不足的常见编译反馈信息如下

使用SIMD move如果你需要赋值寄存器到寄存器对;

使用SIMD move如果你确定这些寄存器不会在接下来的指令中使用。

需要注意的是,SIMD的move会增加循环的动态长度。

 

尽可能避免通用的相同表达式,尤其对于__x128_t类型

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[i],coefsPtr[i])),_lod128(_cmpysp(inputPtr[i],coefsPtr[i]))));

sumTemp1 = _daddsp(sumTemp1,_daddsp(_hid128(_cmpysp(inputPtr[i+1],coefsPtr[i])),_lod128(_cmpysp(inputPtr[i+1],coefsPtr[i]))));

sumTemp2 = _daddsp(sumTemp2,_daddsp(_hid128(_cmpysp(inputPtr[i+2],coefsPtr[i])),_lod128(_cmpysp(inputPtr[i+2],coefsPtr[i]))));

sumTemp3 = _daddsp(sumTemp3,_daddsp(_hid128(_cmpysp(inputPtr[i+3],coefsPtr[i])),_lod128(_cmpysp(inputPtr[i+3],coefsPtr[i]))));

}

sumPtr[i] = sumTemp;

sumPtr[i+1] = sumTemp1;

sumPtr[i+2] = sumTemp2;

sumPtr[i+3] = sumTemp3;

}

}

修改为

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[i],coefsPtr[i]);

sumTemp = _daddsp(sumTemp, _daddsp(_hid128(cmpysp_temp),

_lod128(cmpysp_temp)));

cmpysp_temp1 = _cmpysp(inputPtr[i+1],coefsPtr[i]);

sumTemp1 = _daddsp(sumTemp1, _daddsp(_hid128(cmpysp_temp1),

_lod128(cmpysp_temp1)));

cmpysp_temp2 = _cmpysp(inputPtr[i+2],coefsPtr[i]);

sumTemp2 = _daddsp(sumTemp2, _daddsp(_hid128(cmpysp_temp2),

_lod128(cmpysp_temp2)));

cmpysp_temp3 = _cmpysp(inputPtr[i+3],coefsPtr

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2012年4月5日
下一篇 2012年4月5日

相关推荐