DSP

在TI 的DSP 平台下优化AVS 的 IDCT 反变换的方法和代码

2019-07-13 11:05发布

    一, AVS标准规定的IDCT反变换 本条定义将8´8变换系数矩阵CoeffMatrix转换为8´8残差样值矩阵ResidueMatrix的过程,步骤如下: 00001—— 首先,对变换系数矩阵进行如下水平反变换: H¢ = CoeffMatrix ´ T8T 其中,T 8是8´8反变换矩阵,T 8TT8的转置矩阵, H¢ 表示水平反变换后的中间结果。从符合本部分的比特流中解码得到的H¢矩阵元素取值范围应为 –215215–5         8  10  10   9   8   6   4   2          8   9   4  -2  -8 -10 -10  -6          8   6  -4 -10  -8   2  10   9          8   2 -10  -6   8   9  -4 -10  T8 8  -2 -10   6   8  -9  -4  10        8  -6  -4  10  -8  -2  10  -9        8  -9   4   2  -8  10 -10   6       8 -10  10  -9   8  -6   4  -2   00002—— 第二步,对矩阵H¢中的每个系数4右移3位,得到矩阵H¢¢ 00003—— 第三步,对矩阵H¢¢进行如下垂直反变换: H = T8 ´ H¢¢ 其中,H表示反变换后的8´8矩阵。从符合本部分的比特流中解码得到的H矩阵元素取值范围应为 –215215–65 00004—— 第四步,残差样值矩阵ResidueMatrix的元素rij计算如下: rij = (hij + 26) >> 7 i, j = 0..7 其中hijH矩阵的元素。   二, C语言实现   void idct_c_dsp(short* blk) { int i, j; short* b = blk; short  x[8]; int    r[12]; int    z[8];   for(i=0; i<8; i++, b+=8) // horizontal transform { for(j=0; j<8; j++) { x[j] = b[j]; }   r[0] = 8  * x[0] + 8  * x[4]; r[1] = 8  * x[0] - 8  * x[4];   r[2] = 10 * x[1] + 6   * x[5]; r[3] = 9  * x[1] - 10  * x[5]; r[4] = 6  * x[1] + 2  * x[5]; r[5] = 2  * x[1] + 9  * x[5];   r[6] = 10 * x[2] + 4  * x[6]; r[7] = 4  * x[2] - 10 * x[6];   r[8] = 9  * x[3] + 2  * x[7]; r[9] = 2  * x[3] + 6  * x[7]; r[10]= 10 * x[3] - 9  * x[7]; r[11]= 6  * x[3] + 10 * x[7];    z[0] = r[0] + r[6]; z[1] = r[2] + r[8];   z[2] = r[1] + r[7]; z[3] = r[3] - r[9];   z[4] = r[1] - r[7]; z[5] = r[4] - r[10];   z[6] = r[0] - r[6]; z[7] = r[5] - r[11];   b[0] = (short) (CLIP3(-32768, 32767, (z[0] + z[1] + 4)) >> 3); b[1] = (short) (CLIP3(-32768, 32767, (z[2] + z[3] + 4)) >> 3); b[2] = (short) (CLIP3(-32768, 32767, (z[4] + z[5] + 4)) >> 3); b[3] = (short) (CLIP3(-32768, 32767, (z[6] + z[7] + 4)) >> 3); b[4] = (short) (CLIP3(-32768, 32767, (z[6] - z[7] + 4)) >> 3); b[5] = (short) (CLIP3(-32768, 32767, (z[4] - z[5] + 4)) >> 3); b[6] = (short) (CLIP3(-32768, 32767, (z[2] - z[3] + 4)) >> 3); b[7] = (short) (CLIP3(-32768, 32767, (z[0] - z[1] + 4)) >> 3); }   b = blk; for(i=0; i<8; i++, b+=1) // vertical transform { for(j=0; j<8; j++) { x[j] = b[j*8]; }   r[0] = 8  * x[0] + 8  * x[4]; // 0x080008 r[1] = 8  * x[0] - 8  * x[4]; // 0x080008   r[2] = 10 * x[1] + 6  * x[5]; // 0x0a0006 r[3] = 9  * x[1] - 10 * x[5]; // 0x09000a r[4] = 6  * x[1] + 2  * x[5]; // 0x060002 r[5] = 2  * x[1] + 9  * x[5]; // 0x020009   r[6] = 10 * x[2] + 4  * x[6]; // 0x0a0004 r[7] = 4  * x[2] - 10 * x[6]; // 0x04000a   r[8] = 9  * x[3] + 2  * x[7]; // 0x090002 r[9] = 2  * x[3] + 6  * x[7]; // 0x020006 r[10]= 10 * x[3] - 9  * x[7]; // 0x0a0009 r[11]= 6  * x[3] + 10 * x[7]; // 0x06000a   z[0] = r[0] + r[6]; z[1] = r[2] + r[8];   z[2] = r[1] + r[7]; z[3] = r[3] - r[9];   z[4] = r[1] - r[7]; z[5] = r[4] - r[10];   z[6] = r[0] - r[6]; z[7] = r[5] - r[11];   b[0*8] = (short) (CLIP3(-32768, 32767, (z[0] + z[1] + 64)) >> 7); b[1*8] = (short) (CLIP3(-32768, 32767, (z[2] + z[3] + 64)) >> 7); b[2*8] = (short) (CLIP3(-32768, 32767, (z[4] + z[5] + 64)) >> 7); b[3*8] = (short) (CLIP3(-32768, 32767, (z[6] + z[7] + 64)) >> 7); b[4*8] = (short) (CLIP3(-32768, 32767, (z[6] - z[7] + 64)) >> 7); b[5*8] = (short) (CLIP3(-32768, 32767, (z[4] - z[5] + 64)) >> 7); b[6*8] = (short) (CLIP3(-32768, 32767, (z[2] - z[3] + 64)) >> 7); b[7*8] = (short) (CLIP3(-32768, 32767, (z[0] - z[1] + 64)) >> 7); } }   三,C语言实现的算法分析   仔细分析系数矩阵可以看到特点:偶数列上的上四行和下四行是对称的,奇数列上的上四行和下四行是反对称的。这样就可以得出十二个基本项,就是c代码中的r[12],进而得到8个值z[8],最后得到反变换的值。仔细阅读代码就会清楚的明白了。 需要注意的是,CLIP3函数实际是用来求16位的有符号数的饱和计算。在理想情况下系数矩阵经过变换后是不会出现超出16位可表示的数值的,但在实际中还是会出现极少数情况超出,为了优化又需要在16位之内计算,因此,采用折中的办法将超出进行饱和处理,保证IDCT的精度损失较小。   四,基于TI 的6000系列DSP优化   1,利用dsp的乘加指令和32位加载伪指令进行初步优化,代码实现如下   void idct_intrinsic_dsp(short* blk) { int i; short* b = blk; int    x[4]; int    r[12]; int    z[8];   _nassert(((int)(blk) & 0x03) == 0); for(i=0; i<8; i++, b+=8) // horizontal transform { x[0] = _mem4(&b[0]); // b[1] b[0] , little endian x[1] = _mem4(&b[2]); // b[3] b[2] x[2] = _mem4(&b[4]); // b[5] b[4] x[3] = _mem4(&b[6]); // b[7] b[6]   r[0] = x[0]; // save x[0] r[1] = x[1]; // save x[1]   x[0] = _pack2 (r[0], x[2]); // b[0] b[4]  x[1] = _packh2(r[0], x[2]); // b[1] b[5]  x[2] = _pack2 (r[1], x[3]); // b[2] b[6]  x[3] = _packh2(r[1], x[3]); // b[3] b[7]    r[0] = _dotp2 (0x080008, x[0]); // r[0] = 8  * x[0] + 8  * x[4]; // 0x080008 r[1] = _dotpn2(0x080008, x[0]); // r[1] = 8  * x[0] - 8  * x[4]; // 0x08fff8 r[2] = _dotp2 (0x0a0006, x[1]); // r[2] = 10 * x[1] + 6  * x[5]; // 0x0a0006 r[3] = _dotpn2(0x09000a, x[1]); // r[3] = 9  * x[1] - 10 * x[5]; // 0x09000a r[4] = _dotp2 (0x060002, x[1]); // r[4] = 6  * x[1] + 2  * x[5]; // 0x060002 r[5] = _dotp2 (0x020009, x[1]); // r[5] = 2  * x[1] + 9  * x[5]; // 0x020009 r[6] = _dotp2 (0x0a0004, x[2]); // r[6] = 10 * x[2] + 4  * x[6]; // 0x0a0004 r[7] = _dotpn2(0x04000a, x[2]); // r[7] = 4  * x[2] - 10 * x[6]; // 0x04000a r[8] = _dotp2 (0x090002, x[3]); // r[8] = 9  * x[3] + 2  * x[7]; // 0x090002 r[9] = _dotp2 (0x020006, x[3]); // r[9] = 2  * x[3] + 6  * x[7]; // 0x020006 r[10]= _dotpn2(0x0a0009, x[3]); // r[10]= 10 * x[3] - 9  * x[7]; // 0x0a0009 r[11]= _dotp2 (0x06000a, x[3]); // r[11]= 6  * x[3] + 10 * x[7]; // 0x06000a   z[0] = r[0] + r[6]; z[1] = r[2] + r[8]; z[2] = r[1] + r[7]; z[3] = r[3] - r[9]; z[4] = r[1] - r[7]; z[5] = r[4] - r[10]; z[6] = r[0] - r[6]; z[7] = r[5] - r[11];   b[0] = (short)(CLIP3(-32768, 32767, (z[0] + z[1] + 4)) >> 3); b[1] = (short)(CLIP3(-32768, 32767, (z[2] + z[3] + 4)) >> 3); b[2] = (short)(CLIP3(-32768, 32767, (z[4] + z[5] + 4)) >> 3); b[3] = (short)(CLIP3(-32768, 32767, (z[6] + z[7] + 4)) >> 3); b[4] = (short)(CLIP3(-32768, 32767, (z[6] - z[7] + 4)) >> 3); b[5] = (short)(CLIP3(-32768, 32767, (z[4] - z[5] + 4)) >> 3); b[6] = (short)(CLIP3(-32768, 32767, (z[2] - z[3] + 4)) >> 3); b[7] = (short)(CLIP3(-32768, 32767, (z[0] - z[1] + 4)) >> 3); }   b = blk; for(i=0; i<8; i++, b+=1) // horizontal transform { short* p = (short*)x; p[0] = b[4*8]; p[1] = b[0*8]; p[2] = b[5*8]; p[3] = b[1*8]; p[4] = b[6*8]; p[5] = b[2*8]; p[6] = b[7*8]; p[7] = b[3*8];   r[0] = _dotp2 (0x080008, x[0]); // r[0] = 8  * x[0] + 8  * x[4]; // 0x080008 r[1] = _dotpn2(0x080008, x[0]); // r[1] = 8  * x[0] - 8  * x[4]; // 0x08fff8 r[2] = _dotp2 (0x0a0006, x[1]); // r[2] = 10 * x[1] + 6  * x[5]; // 0x0a0006 r[3] = _dotpn2(0x09000a, x[1]); // r[3] = 9  * x[1] - 10 * x[5]; // 0x09000a r[4] = _dotp2 (0x060002, x[1]); // r[4] = 6  * x[1] + 2  * x[5]; // 0x060002 r[5] = _dotp2 (0x020009, x[1]); // r[5] = 2  * x[1] + 9  * x[5]; // 0x020009 r[6] = _dotp2 (0x0a0004, x[2]); // r[6] = 10 * x[2] + 4  * x[6]; // 0x0a0004 r[7] = _dotpn2(0x04000a, x[2]); // r[7] = 4  * x[2] - 10 * x[6]; // 0x04000a r[8] = _dotp2 (0x090002, x[3]); // r[8] = 9  * x[3] + 2  * x[7]; // 0x090002 r[9] = _dotp2 (0x020006, x[3]); // r[9] = 2  * x[3] + 6  * x[7]; // 0x020006 r[10]= _dotpn2(0x0a0009, x[3]); // r[10]= 10 * x[3] - 9  * x[7]; // 0x0a0009 r[11]= _dotp2 (0x06000a, x[3]); // r[11]= 6  * x[3] + 10 * x[7]; // 0x06000a   z[0] = r[0] + r[6]; z[1] = r[2] + r[8]; z[2] = r[1] + r[7]; z[3] = r[3] - r[9]; z[4] = r[1] - r[7]; z[5] = r[4] - r[10]; z[6] = r[0] - r[6]; z[7] = r[5] - r[11];   b[0*8] = (short)(CLIP3(-32768, 32767, (z[0] + z[1] + 64)) >> 7); b[1*8] = (short)(CLIP3(-32768, 32767, (z[2] + z[3] + 64)) >> 7); b[2*8] = (short)(CLIP3(-32768, 32767, (z[4] + z[5] + 64)) >> 7); b[3*8] = (short)(CLIP3(-32768, 32767, (z[6] + z[7] + 64)) >> 7); b[4*8] = (short)(CLIP3(-32768, 32767, (z[6] - z[7] + 64)) >> 7); b[5*8] = (short)(CLIP3(-32768, 32767, (z[4] - z[5] + 64)) >> 7); b[6*8] = (short)(CLIP3(-32768, 32767, (z[2] - z[3] + 64)) >> 7); b[7*8] = (short)(CLIP3(-32768, 32767, (z[0] - z[1] + 64)) >> 7); }   从代码实现可以看出利用dsp的乘加指令实现求r数组的12个基本值比较简洁,但是,注意到,关键的内存加载部分代码优化效果一般,而存储部分还没有改变。下面,着重说明该部分的优化方法。   2,存储优化分析   注意:由于语言表达不太清楚,请仔细看矩阵的行列坐标,和代码就很容易理解这样做的好处了。   CoeffMatrix 为, 其中,x01 代表第0行,第1列的元素, 以此类推,以下的矩阵推导中都是用x表示的,只是为了写起来方便,实际上每次变换后,值都是改变的。                  x00  x01  x02  x03  x04  x05  x06  x07                    x10  x11  x12  x13  x14  x15  x16  x17                    x20  x21  x22  x23  x24  x25  x26  x27                    x30  x31  x32  x33  x34  x35  x36  x37                    x40  x41  x42  x43  x44  x45  x46  x47                   x50  x51  x52  x53  x54  x55  x56  x57                   x60  x61  x62  x63  x64  x65  x66  x67                   x70  x71  x72  x73  x74  x75  x76  x77     通过改变frame或者field的扫描矩阵改变CoeffMatrix 的存储方式,这样做是为了加载和计算时快捷,改变后如下,   x04  x00  x05  x01  x06  x02  x07  x03   x44  x40  x45  x41  x46  x42  x47  x43   x14  x10  x15  x11  x16  x12  x17  x13   x54  x50  x55  x51  x56  x52  x57  x53   x24  x20  x25  x21  x26  x22  x27  x23   x64  x60  x65  x61  x66  x62  x67  x63   x34  x30  x35  x31  x36  x32  x37  x33   x74  x70  x75  x71  x76  x72  x77  x73     对上面的矩阵0,1两行,2,3两行,4,5两行,6,7两行,同时进行行变换,之后进行饱和及压缩,存储, 得到的矩阵如下,   x40   x00   x50   x10    x60    x20   x70    x30   x41  x01  x51  x11  x61  x21  x71  x31 x42   x02   x52   x12    x62   x22    x72    x32 x43   x03   x53    x13   x63   x23    x73    x33 x44  x04  x54  x14  x64  x24  x74  x34   x45  x05  x55  x15  x65  x25  x75  x35 x46  x06  x56  x16  x66  x26  x76  x36 x47  x07  x57  x17  x67  x27  x77  x37   进行完上面的行变换后,进行列变换,上面矩阵的每一行,就是原来的要变换的列,而且也已经是按4 0 5 1 6 2 7 3的顺序排列的,同时对两行  进行变换,也就是原来的列变换,或者说是垂直变换也行。把变换后的值存储在原来的残差矩阵的对应位置,   x00  x01  x02  x03  x04  x05  x06  x07                 x10  x11  x12  x13  x14  x15  x16  x17                 x20  x21  x22  x23  x24  x25  x26  x27                 x30  x31  x32  x33  x34  x35  x36  x37                 x40  x41  x42  x43  x44  x45  x46  x47                 x50  x51  x52  x53  x54  x55  x56  x57                 x60  x61  x62  x63  x64  x65  x66  x67                 x70  x71  x72  x73  x74  x75  x76  x77     通过以上变换方法,就实现了加载和存储全都是按整数进行的,并减少了原来要调整数据进行的_pack2和_packh2操作来。 用到的dsp内联指令有,_pack2, _packh2, _amemd8_const, _dotp2, _dotpn2, _spack2, _shr2等。   3, 按照上述想法,优化的代码如下   void idct_intrinsic_dsp(short* blk)
{
    int    i;
    int    x[4] , n[4] ;
    int    r[12], p[12];
    int    z[8] , m[8] ;
    int    t[8][4];
    short* b = blk;

    _nassert(((int)(blk) & 0x03) == 0);

    for(i=0; i<4; i++, b+=16) // horizontal transform
    {
        // 取第0行的系数值,假定原始系数值是按 b[4] b[0] b[5] b[1] b[6] b[2] b[7] b[3] 排列的

                                                               // high | low    
        x[0] = _lo(_amemd8_const(b));     // b[0]   b[4]   
        x[1] = _hi(_amemd8_const(b));     // b[1]   b[5]   
        x[2] = _lo(_amemd8_const(b+4)); // b[2]   b[6]   
        x[3] = _hi(_amemd8_const(b+4)); // b[3]   b[7]   
        // 取第1行的系数值                               
        n[0] = _lo(_amemd8_const(b+8)); // b[0]   b[4]   
        n[1] = _hi(_amemd8_const(b+8)); // b[1]   b[5]   
        n[2] = _lo(_amemd8_const(b+12));// b[2]   b[6]   
        n[3] = _hi(_amemd8_const(b+12));// b[3]   b[7]                              

        r[0] = _dotp2 (0x080008, x[0]); // r[0] = 8  * x[0] + 8  * x[4]; // 0x080008
        r[1] = _dotpn2(0x080008, x[0]); // r[1] = 8  * x[0] - 8  * x[4]; // 0x08fff8
        r[2] = _dotp2 (0x0a0006, x[1]); // r[2] = 10 * x[1] + 6  * x[5]; // 0x0a0006
        r[3] = _dotpn2(0x09000a, x[1]); // r[3] = 9  * x[1] - 10 * x[5]; // 0x09000a
        r[4] = _dotp2 (0x060002, x[1]); // r[4] = 6  * x[1] + 2  * x[5]; // 0x060002
        r[5] = _dotp2 (0x020009, x[1]); // r[5] = 2  * x[1] + 9  * x[5]; // 0x020009
        r[6] = _dotp2 (0x0a0004, x[2]); // r[6] = 10 * x[2] + 4  * x[6]; // 0x0a0004
        r[7] = _dotpn2(0x04000a, x[2]); // r[7] = 4  * x[2] - 10 * x[6]; // 0x04000a
        r[8] = _dotp2 (0x090002, x[3]); // r[8] = 9  * x[3] + 2  * x[7]; // 0x090002
        r[9] = _dotp2 (0x020006, x[3]); // r[9] = 2  * x[3] + 6  * x[7]; // 0x020006
        r[10]= _dotpn2(0x0a0009, x[3]); // r[10]= 10 * x[3] - 9  * x[7]; // 0x0a0009
        r[11]= _dotp2 (0x06000a, x[3]); // r[11]= 6  * x[3] + 10 * x[7]; // 0x06000a

        p[0] = _dotp2 (0x080008, n[0]); // r[0] = 8  * x[0] + 8  * x[4]; // 0x080008
        p[1] = _dotpn2(0x080008, n[0]); // r[1] = 8  * x[0] - 8  * x[4]; // 0x08fff8
        p[2] = _dotp2 (0x0a0006, n[1]); // r[2] = 10 * x[1] + 6  * x[5]; // 0x0a0006
        p[3] = _dotpn2(0x09000a, n[1]); // r[3] = 9  * x[1] - 10 * x[5]; // 0x09000a
        p[4] = _dotp2 (0x060002, n[1]); // r[4] = 6  * x[1] + 2  * x[5]; // 0x060002
        p[5] = _dotp2 (0x020009, n[1]); // r[5] = 2  * x[1] + 9  * x[5]; // 0x020009
        p[6] = _dotp2 (0x0a0004, n[2]); // r[6] = 10 * x[2] + 4  * x[6]; // 0x0a0004
        p[7] = _dotpn2(0x04000a, n[2]); // r[7] = 4  * x[2] - 10 * x[6]; // 0x04000a
        p[8] = _dotp2 (0x090002, n[3]); // r[8] = 9  * x[3] + 2  * x[7]; // 0x090002
        p[9] = _dotp2 (0x020006, n[3]); // r[9] = 2  * x[3] + 6  * x[7]; // 0x020006
        p[10]= _dotpn2(0x0a0009, n[3]); // r[10]= 10 * x[3] - 9  * x[7]; // 0x0a0009
        p[11]= _dotp2 (0x06000a, n[3]); // r[11]= 6  * x[3] + 10 * x[7]; // 0x06000a

        z[0] = r[0] + r[6];
        z[1] = r[2] + r[8];
        z[2] = r[1] + r[7];
        z[3] = r[3] - r[9];
        z[4] = r[1] - r[7];
        z[5] = r[4] - r[10];
        z[6] = r[0] - r[6];
        z[7] = r[5] - r[11];

        m[0] = p[0] + p[6];
        m[1] = p[2] + p[8];
        m[2] = p[1] + p[7];
        m[3] = p[3] - p[9];
        m[4] = p[1] - p[7];
        m[5] = p[4] - p[10];
        m[6] = p[0] - p[6];
        m[7] = p[5] - p[11];
                                                                                                // high | low
        t[0][i] = _shr2(_spack2(z[0]+z[1]+4, m[0]+m[1]+4), 3); // x00    x40
        t[1][i] = _shr2(_spack2(z[2]+z[3]+4, m[2]+m[3]+4), 3); // x01    x41
        t[2][i] = _shr2(_spack2(z[4]+z[5]+4, m[4]+m[5]+4), 3); // x02    x42
        t[3][i] = _shr2(_spack2(z[6]+z[7]+4, m[6]+m[7]+4), 3); // x03    x43
        t[4][i] = _shr2(_spack2(z[6] -z[7]+4, m[6] -m[7]+4), 3); // x04    x44
        t[5][i] = _shr2(_spack2(z[2] -z[3]+4, m[2] -m[3]+4), 3); // x05    x45
        t[6][i] = _shr2(_spack2(z[4] -z[5]+4, m[4] -m[5]+4), 3); // x46    x46
        t[7][i] = _shr2(_spack2(z[0] -z[1]+4, m[0] -m[1]+4), 3); // x47    x47
    }    

    b = blk;

    for(i=0; i<4; i++, b+=2) // horizontal transform
    {                
        // 取第0行的系数值                                          // high | low
        x[0] = _lo(_amemd8_const(&t[2*i+0][0])); // b[0]   b[4]
        x[1] = _hi(_amemd8_const(&t[2*i+0][0])); // b[1]   b[5]
        x[2] = _lo(_amemd8_const(&t[2*i+0][2])); // b[2]   b[6]
        x[3] = _hi(_amemd8_const(&t[2*i+0][2])); // b[3]   b[7]
        // 取第1行的系数值
        n[0] = _lo(_amemd8_const(&t[2*i+1][0])); // b[0]   b[4]
        n[1] = _hi(_amemd8_const(&t[2*i+1][0])); // b[1]   b[5]
        n[2] = _lo(_amemd8_const(&t[2*i+1][2])); // b[2]   b[6]
        n[3] = _hi(_amemd8_const(&t[2*i+1][2])); // b[3]   b[7]

        r[0] = _dotp2 (0x080008, x[0]); // r[0] = 8  * x[0] + 8  * x[4]; // 0x080008
        r[1] = _dotpn2(0x080008, x[0]); // r[1] = 8  * x[0] - 8  * x[4]; // 0x08fff8
        r[2] = _dotp2 (0x0a0006, x[1]); // r[2] = 10 * x[1] + 6  * x[5]; // 0x0a0006
        r[3] = _dotpn2(0x09000a, x[1]); // r[3] = 9  * x[1] - 10 * x[5]; // 0x09000a
        r[4] = _dotp2 (0x060002, x[1]); // r[4] = 6  * x[1] + 2  * x[5]; // 0x060002
        r[5] = _dotp2 (0x020009, x[1]); // r[5] = 2  * x[1] + 9  * x[5]; // 0x020009
        r[6] = _dotp2 (0x0a0004, x[2]); // r[6] = 10 * x[2] + 4  * x[6]; // 0x0a0004
        r[7] = _dotpn2(0x04000a, x[2]); // r[7] = 4  * x[2] - 10 * x[6]; // 0x04000a
        r[8] = _dotp2 (0x090002, x[3]); // r[8] = 9  * x[3] + 2  * x[7]; // 0x090002
        r[9] = _dotp2 (0x020006, x[3]); // r[9] = 2  * x[3] + 6  * x[7]; // 0x020006
        r[10]= _dotpn2(0x0a0009, x[3]); // r[10]= 10 * x[3] - 9  * x[7]; // 0x0a0009
        r[11]= _dotp2 (0x06000a, x[3]); // r[11]= 6  * x[3] + 10 * x[7]; // 0x06000a

        p[0] = _dotp2 (0x080008, n[0]); // r[0] = 8  * x[0] + 8  * x[4]; // 0x080008
        p[1] = _dotpn2(0x080008, n[0]); // r[1] = 8  * x[0] - 8  * x[4]; // 0x08fff8
        p[2] = _dotp2 (0x0a0006, n[1]); // r[2] = 10 * x[1] + 6  * x[5]; // 0x0a0006
        p[3] = _dotpn2(0x09000a, n[1]); // r[3] = 9  * x[1] - 10 * x[5]; // 0x09000a
        p[4] = _dotp2 (0x060002, n[1]); // r[4] = 6  * x[1] + 2  * x[5]; // 0x060002
        p[5] = _dotp2 (0x020009, n[1]); // r[5] = 2  * x[1] + 9  * x[5]; // 0x020009
        p[6] = _dotp2 (0x0a0004, n[2]); // r[6] = 10 * x[2] + 4  * x[6]; // 0x0a0004
        p[7] = _dotpn2(0x04000a, n[2]); // r[7] = 4  * x[2] - 10 * x[6]; // 0x04000a
        p[8] = _dotp2 (0x090002, n[3]); // r[8] = 9  * x[3] + 2  * x[7]; // 0x090002
        p[9] = _dotp2 (0x020006, n[3]); // r[9] = 2  * x[3] + 6  * x[7]; // 0x020006
        p[10]= _dotpn2(0x0a0009, n[3]); // r[10]= 10 * x[3] - 9  * x[7]; // 0x0a0009
        p[11]= _dotp2 (0x06000a, n[3]); // r[11]= 6  * x[3] + 10 * x[7]; // 0x06000a

        z[0] = r[0] + r[6];
        z[1] = r[2] + r[8];
        z[2] = r[1] + r[7];
        z[3] = r[3] - r[9];
        z[4] = r[1] - r[7];
        z[5] = r[4] - r[10];
        z[6] = r[0] - r[6];
        z[7] = r[5] - r[11];

        m[0] = p[0] + p[6];
        m[1] = p[2] + p[8];
        m[2] = p[1] + p[7];
        m[3] = p[3] - p[9];
        m[4] = p[1] - p[7];
        m[5] = p[4] - p[10];
        m[6] = p[0] - p[6];
        m[7] = p[5] - p[11];

        _amem4(&b[0*8])    = _shr2(_spack2(m[0]+m[1]+64, z[0]+z[1]+64), 7); // x10    x00
        _amem4(&b[1*8])    = _shr2(_spack2(m[2]+m[3]+64, z[2]+z[3]+64), 7); // x11    x01
        _amem4(&b[2*8])    = _shr2(_spack2(m[4]+m[5]+64, z[4]+z[5]+64), 7); // x12    x02
        _amem4(&b[3*8])    = _shr2(_spack2(m[6]+m[7]+64, z[6]+z[7]+64), 7); // x13    x03
        _amem4(&b[4*8])    = _shr2(_spack2(m[6]- m[7]+64,  z[6]-z[7]+64), 7); // x14    x04
        _amem4(&b[5*8])    = _shr2(_spack2(m[4]- m[5]+64,  z[4]-z[5]+64), 7); // x15    x05
        _amem4(&b[6*8])    = _shr2(_spack2(m[2]- m[3]+64,  z[2]-z[3]+64), 7); // x16    x06
        _amem4(&b[7*8])    = _shr2(_spack2(m[0]- m[1]+64,  z[0]-z[1]+64), 7); // x17    x07
    }    
}   五,结果对比 优化效果显著!!!             望对dsp优化有经验的的大侠多多指点,看看有没有更好的方法进行优化,及代码写法方面的问题。     刘春龙:欢迎转载!