打印

c6000系列的C代码优化总结

[复制链接]
5110|15
手机看帖
扫描二维码
随时随地手机跟帖
沙发
五谷道场|  楼主 | 2012-12-14 15:42 | 只看该作者
具体内容如下:
一、c6x 的编译的常用选项  
(一)c6x 的编译程序为“cl6x.exe”使用的方法  
Cl6x [options] [filenames]   
Cl6x:   编译程序  
Options:    编译选项  
Filenames: C或汇编源文件  
说明:  
编译选项是一个字母或者两个字母, 对大小写不敏感。 编译选项的前面需要有一个 “-”
符号。  一个字母的选项可以合并在一起。比如“-sgq”与“-s  -g -q”相同。  两个字母的选项如果第一个字母相同也可以合并在一起。比如“-mgt”与“-mg-mt”相同。
(二)有关优化的选项  
-mt:表示在程序中没有使用 alaising 技术,这使得编译器可以进行比较好的优化。  
-o3:对文件级别进行最强的优化,一般在编译时应该使用这个选项。但是在个别情况下使
用这个选项优化程序可能会出现错误(-o2 有相同现象,-o0 和-o1 不会出现错误) 。可能是在优化循环,组织流水线的时候发生错误。如果有这种现象出现可以同时使用-g 选项,程序优化就不会出现错误,但是优化效果会下降。另外可以调整程序的表达方式,可能会避免编译器发生错误。  
-pm:在程序级别进行优化。可以将所以文件联合在一起进行优化,主要有去掉没有被调用
的函数、总是常数的变量以及没有使用的函数返回值。建议由程序员自己进  行这种优化工
作。使用这个选项在 win98 下编译可能会出现找不到编译程序的情况。  
-ms0:不使用冗余循环进行优化,减小程序的大小。一般情况下这个选项对程序大小的优化
作用不明显。  
-mh[n]:去掉流水线的 epilog,减小程序的大小。这个选项的作用比较明显。但是有可能出
现读取地址超出有效范围的问题,所以要在数据段的开始和结尾处增加一些 pading,或者在分配内存时保证数组的前面和后面一段范围内都是有效的地址。  
可选的参数 n 给出这种 pading 的长度字节数。  
(三)保留编译和优化信息的选项  
-k:保留优化后生成汇编语言文件。  
-s:汇编语言文件中加入优化信息,如果没有则加入 C语言源程序作为注释。  
-mw:在汇编语言文件加入软件流水线信息。

(四)有关调试和剖析的选项  
-g:允许符号调试,在“out”文件中包含符号信息和行号信息,可以在 c 语言级别进行调
试和剖析。使用联合使用-g、-mt 和-o3 可以保证能够进行符号调试的情况下最大限度
的优化。  
-mg:允许 profile 优化后的程序。  在“out”文件中包含符号信息和很少的行号信息。允许在 c 语言的函数基本进行剖析。
如果联合使用这两个选项,-g 选项可能被忽略,结果与只用-mg 相同。  
(五)其它类型  
-mln:生成大内存模式的程序。  
    -ml0:缺省情况下将集合变量(数组和结构)作为 far 型。  
    -ml1:缺省情况下将全部函数作为 far 型  
    -ml2:等于-ml0 加-ml1  
    -ml3:缺省情况下将全部数据和函数作为 far 型  
(六)建议使用的编译方式  
Cl6x  -gk -mt   -o3 -mw  -ss   “filename”  
方式 1 用于程序的调试,这种方式具有比较强的优化能力,并且支持符号调试。在编译的过程中不会发生错误。由于生成的“out”文件中包含了符号信息和行号信息,所以比较大。  
Cl6x  -k  -mgt   -o3 -mw  -ss   “filename”  
方式 2 用于程序的剖析(profile) ,这种方式的优化能力几乎最强(绝大多数情况下与方式 3相同) , 并且支持对程序进行 profile。 文件中只包含了符号信息和很少的行号信息, 所以 “out”文件比较小。  
Cl6x  -k  -mt   -o3  -mw  -ss   “filename”  
方式 3 用于最终的发行版本程序,可以对程序进行最强的优化,并且去掉了全部的符号和行号信息,所以“out”文件比较小。由多个文件组成的程序应该编写 makefile,将编译参数放在该文件中,并在其中说明使用的编译器的版本号。  
(七)连接参数  
-heap:指定堆的大小  
-stack:指定栈的大小  
连接的各种选项应该统一放在“cmd”文件中  
二、双重循环和多重循环的优化总结  
双重循环多重循环看起来比较复杂,但实际上多重循环优化方法比较简单,就在于一个
字: “拆” ,一旦完成这一步之后,多重循环就成为单层循环,优化就可以按照普通的单层循环来做了。  多重循环的特点是在优化器优化时只在最内层循环中形成一个 pipeline,这样循环语句就不能充分利用 C6 的软件流水线,而且对于内部循环的次数较少的情况,消耗在 prolog 和eplog 上的 cycle 数也是不可忽视的。针对这种状况可以考虑将多重循环拆开形成一个单层循环,可以拆外层循环也可以拆内层循环,一般视具体情况而定。这样就可以充分利用优化器构成的 Pipeline。如下例:  
        void fir2(const short input[], const short coefs[], short out[])   
    {  
        int i, j;  
        int sum = 0;  
        for (i = 0; i < 40; i++)  
        {  
            for (j = 0; j < 16; j++)  
                     sum += coefs[j] * input[i + 15 - j];   
            out = (sum >> 15);  
    }  
内层循环循环次数较少,运算量也不大,资源方面只占用了一个乘法器,一个 cycle 只
使用一次乘法器,而事实上我们可以在一个 cycle 内使用两个乘法器,所以还可以充分利用另外的一个乘法器。因此考虑将内层循环拆开来执行,如下:  
        void fir2_u(const short input[], const short coefs[], short out[])   
    {  
    int i, j;  
    int sum;  
        for (i = 0; i < 40; i++)  
            {  
                  sum = coefs[0] * input[i + 15];   
          sum += coefs[1] * input[i + 14];  
          sum += coefs[2] * input[i + 13];  
          sum += coefs[3] * input[i + 12];  
          sum += coefs[4] * input[i + 11];  
          sum += coefs[5] * input[i + 10];  
          sum += coefs[6] * input[i + 9];  
          sum += coefs[7] * input[i + 8];  
          sum += coefs[8] * input[i + 7];  
          sum += coefs[9] * input[i + 6];  
                  sum += coefs[10] * input[i + 5];   
                  sum += coefs[11] * input[i + 4];   
                  sum += coefs[12] * input[i + 3];   
                  sum += coefs[13] * input[i + 2];   
                  sum += coefs[14] * input[i + 1];   
                  sum += coefs[15] * input[i + 0];   
          out = (sum >> 15);  
        }  
         这样虽然代码长度增加了,可变成了单循环,所有的运算都参加到 pipeline 中来,
在 Piped loop kernal 中产生每一个 cycle 内都使用了两个乘法器,充分利用了 DSP 内部的资
源,提高了运行效率。又如下例:  
tot = 4;   
for (k = 0; k < 4; k++)   
     {  
        max = 0;  
          for (i = k; i < 44; i += STEP)   
        {  
            s = 0;  
                  for (j = i; j < 44; j++)   
            s = L_mac(s, x[j], h[j - i]);  
            y32 = s;  
            s = L_abs(s);  
            if (L_sub(s, max) > (Word32) 0)  
            max = s;  
        }  
        tot = L_add(tot, L_shr(max, 1));  
    }  
这个多层循环中一共有三层循环, 而最内层的循环的运算量很小, 只有一次乘累加操作,
而我们知道 C6 中一个 packet中可以做两个乘累加运算,所以为了增加内部循环的运算,减少外部循环的层数,我们可以将第一层循环的操作拆开,其负责的运算加入到内部循环中,
也就是在内层循环中一次做四次的乘累加运算,这样将多次操作形成 pipeline,提高了运行
效率,优化后的 C代码如下:   
   tot = 4;  
     max0=0;  
     max1=0;  
     max2=0;  
     max3=0;  
    for (i = 0; i <44; i += STEP)                 //STEP=4,  11 times cirs  
     {  
                       //code  
         for (j=0;j<=40-i;j++)  
         {
s0=(Word32)(_sadd(s0,_smpy(hh[j],xx[j+i])));  
          s1=(Word32)(_sadd(s1,_smpy(hh[j],xx[j+i+1])));  
          s2=(Word32)(_sadd(s2,_smpy(hh[j],xx[j+i+2])));  
          s3=(Word32)(_sadd(s3,_smpy(hh[j],xx[j+i+3])));  
          }  
     }  
                //code  
CCS的优化:  
三、16位变为 32 位操作,使用 intrinsi函数,用 const等。   
1、源代码:  
Word32 L_mpy_ll(Word32 L_var1, Word32 L_var2)   
{  
   double  aReg;  
    Word32 lvar;  
    /* (unsigned)low1 * (unsigned)low1 */  
        aReg = (double)(0xffff & L_var1) * (double)(0xffff & L_var2) * 2.0;   
      /* >> 16 */   
        aReg = (aReg / 65536);   
    aReg = floor(aReg);  
    /* (unsigned)low1 * (signed)high2 */  
        aReg += (double)(0xffff & L_var1) * ((double)L_shr(L_var2,16)) * 2.0 ;   
    /* (unsigned)low2 * (signed)high1 */  
        aReg += (double)(0xffff & L_var2) * ((double)L_shr(L_var1,16)) * 2.0 ;   
      /* >> 16 */   
        aReg = (aReg / 65536);   
    aReg = floor(aReg);  
      /* (signed)high1 * (signed)high2 */   
        aReg += (double)(L_shr(L_var1,16)) * (double)(L_shr(L_var2,16)) * 2. 0;   
    /* saturate result.. */  
    lvar = L_saturate(aReg);  
    return(lvar);  
}  
2、改编后的代码:  
static inline Word32 L_mpy_ll(Word32 L_var1, Word32 L_var2)   
{  
    Word32 aReg_hh;  
    Word40 aReg,aReg_ll,aReg_lh,aReg_hl;  
    aReg_ll = (Word40)_mpyu(L_var1, L_var2)>>16;  
    aReg_lh = (Word40)_mpyluhs(L_var1, L_var2);  
    aReg_hl = (Word40)_mpyhslu(L_var1, L_var2);  
    aReg_hh = _smpyh(L_var1, L_var2);  
    aReg    = _lsadd(aReg_ll, _lsadd(aReg_lh, aReg_hl));  
    aReg    = _lsadd(aReg>>15, aReg_hh);  
    return(_sat(aReg));  
}  

3、优化方法说明:  
C6000 编译器提供的 intrinsic  可快速优化 C代码,intrinsic 用前下划线表示同调用函数
一样可以调用它, 即直接内联为 C6000 的函数。 例如, 在上例的源代码中没有使用 intrinsics,每一行 C代码需多个指令周期,在改编后的代码中,每一行代码仅需一个指令周期。例如,   
“aReg_ll = (Word40)_mpyu(L_var1, L_var2)>>16”中“_mpyu”就是一个 intrinsics 函数,它表示两个无符号数的高 16 位相乘,结果返回。C6000 支持的所有 intrinsics指令及其功能参见《TMS320C6000 系列 DSP 的原理与应用》一书的第 265、266 页,该书还提供了另外的例子。这些内联函数定义在 CCS所在的 C6000\CGTOOLS\Include 目录下的 C6X.h 文件中。下面这个例子是 C6000的 “Programmer's Guide” 上提取的使用 intrinsics优化 C代码的例子。源代码:  
int dotprod(const short *a, const short *b, unsigned int N)   
{  
        int i, sum = 0;   
        for (i = 0; i < N; i++)   
        sum += a * b;  
    return sum;  
}  
改编后代码:  
int dotprod(const int *a, const int *b, unsigned int N)   
{  
        int i, sum1 = 0, sum2 = 0;   
        for (i = 0; i < (N >> 1); i++)   
    {  
        sum1 += _mpy (a, b);  
        sum2 += _mpyh(a, b);  
    }  
     return sum1 + sum2;  
}  
技巧:  
在 C语言的调试全部通过以后,可以尝试将尽可能多的语句使用 intrinsics函数加以改
编,尤其在循环体内,这种改编可以大幅度减少执行时间。  

使用特权

评论回复
板凳
五谷道场|  楼主 | 2012-12-14 15:42 | 只看该作者
四、使用 const可以限定目标优化
1、源代码:  
void fir_fxd1(short input[], short coefs[], short out[])   
{      int i, j;  
        for (i = 0; i < 40; i++)   
    {  
      for (j = 0; j < 16; j++)  
            out[i*16+j]= coefs[j] * input[i + 15 - j];  
   }  
}  
2、改编后的代码:  
void fir_fxd2(const short input[], const short coefs[], short out[])   
{  
   int i, j;  
        for (i = 0; i < 40; i++)   
    {  
      for (j = 0; j < 16; j++)  
            out[i*16+j]= coefs[j] * input[i + 15 - j];  
   }  
3、优化方法说明:  
C6000 编译器如果确定两条指令是不相关的,则安排它们并行执行。  关键字 const可以
指定一个变量或者一个变量的存储单元保持不变。这有助于帮助编译器确定指令的不相关
性。例如上例中,源代码不能并行执行,而结果改编后的代码可以并行执行。  
4、技巧:  
使用 const 可以限定目标,确定存在于循环迭代中的存储器的不相关性。  
五、 使用内联指令优化算法
1、源代码:  
void vecsum(short *sum, short *in1, short *in2, unsigned int N)   
{  
    int i;  
          for (i = 0; i < N; i++)   
        sum = in1 + in2;  
}  
2、改编后的代码:  
void vecsum6(int *sum, const int *in1, const int *in2, unsigned int N)   
{  
    int i;  
        int sz = N >> 2;   
    _nassert(N >= 20);  
        for (i = 0; i < sz; i += 2)   
    {  
        sum   = _add2(in1  , in2);  
        sum[i+1] = _add2(in1[i+1], in2[i+1]);  
    }  
}  
3、优化方法说明:  
源代码中,函数变量的定义是  short *sum, short *in1, short *in2,    改编后的代码函数变
量是  int *sum, const int *in1, const int *in2,    整数类型由 16 位改编成 32 位,这时使用内联指令“_add2”一次可以完成两组 16位整数的加法,效率提高一倍。注意这里还使用了关键字 const和内联指令_nassert优化源代码。  
4、技巧:  
用内联指令_add2、_mpyhl、_mpylh 完成两组 16 位数的加法和乘法,效率比单纯 16 位数的加法和乘法提高一倍。

六、if...else...语句的优化  
实例(一)  
1、源代码:  
        if (sub (ltpg, LTP_GAIN_THR1) <= 0)   
    {  
        adapt = 0;  
    }  
    else  
    {  
        if (sub (ltpg, LTP_GAIN_THR2) <= 0)  
        {  
            adapt = 1;  
        }  
        else  
        {              adapt = 2;  
        }  
    }  
  2、改编后的代码:  
        adapt = (ltpg>LTP_GAIN_THR1) + (ltpg>LTP_GAIN_THR2);   
   实列(二)
1、源代码:  
    if (adapt == 0)  
    {  
        if (filt>5443)  
        {  
            result = 0;  
        }  
        else  
        {  
            if (filt < 0)  
            {  
                result = 16384;  
            }  
            else  
            {  
                filt = _sshl (filt, 18)>>16; // Q15  
                result = _ssub (16384, _smpy(24660, filt)>>16);   
            }  
        }  
    }  
    else  
    {  
        result = 0;  
    }  
2、改编后的代码:  
        filt1 = _sshl (filt, 18)>>16;   
    tmp = _smpy(24660, filt1)>>16;  
        result = _ssub(16384, tmp * (filt>=0));   
        result = result * (!((adapt!=0)||(filt>5443)));  
实例(三)  
1、源代码:  
static Word16 saturate(Word32 L_var1)   
{   
  Word16 swOut;  
    if (L_var1 > SW_MAX)  
    {  
        swOut = SW_MAX;  
        giOverflow = 1;  
    }  
        else if (L_var1 < SW_MIN)   
    {  
        swOut = SW_MIN;  
        giOverflow = 1;  
    }  
    else  
        swOut = (Word16) L_var1;        /* automatic type conversion */  
    return (swOut);  
}  
2、改编后的代码:  
static inline Word32 L_shl(Word32 a,Word16 b)   
{  
return ((Word32)((b) < 0 ? (Word32)(a) >> (-(b)) : _sshl((a),(b)))) ;   
}  
3、优化方法说明:  
如果在循环中出现 if...else...语句,由于 if...else...语句中有跳转指令,而每个跳转指令有
5 个延迟间隙,因此程序执行时间延长;另外,循环内跳转也使软件流水受到阻塞。直接使
用逻辑判断语句可以去除不必要的跳转。例如在例 1 的源代码最多有两次跳转,而改编后不
存在跳转。例 2 和例 3同样也去掉了跳转。  
4、技巧:
尽可能地用逻辑判断语句替代 if...else...语句,减少跳转语句。  
七、数组最小值运算优化  
1、源程序  
    dm = 0x7FFF;  
        for (j = 0; j < nsiz[m]; j = add(j, 1))   
    {  
        if (d[j] <= dm)  
        {  
            dm = d[j];  
            jj = j;  
        }  
    }  
    index[m] = jj;  
2、优化后的程序  
        dm0 = dm1 = 0x7fff;   
            d0  = (Word16 *)&d[0];  
            d1  = (Word16 *)&d[1];  
    #pragma MUST_ITERATE(32,256,64);  
        for (j = 0; j < Nsiz; j+=2)   
    {  
        n0 = *d0;  
        d0 += 2;  
        n1 = *d1;  
        d1 += 2;  
        if (n0 <= dm0)  
        {  
            dm0 = n0;  
            jj0 = j;  
        }  
        if (n1 <= dm1)  
        {  
            dm1 = n1;  
            jj1 = j+1;  
        }  
    }  
    if (dm1 != dm0)  
    {  
        index[m] = (dm1 < dm0)? jj1:jj0;  
}      
else  
    {  
       index[m] = (jj1 > jj0)? jj1:jj0;  
    }  
  3、优化说明  
     求数组的最小值程序,优化时为了提高程序效率在一个循环之内计算 N=1,3,5..和
n=2,4,6...的最小值,然后在比较二者的大小以求得整个数组的最小值。  
八、 循环内部存在 if判断程序的优化
1、源程序  
        for (k = 0; k < NB_PULSE; k++)   
    {  
        i = codvec[k];  
        j = sign;  
        index = mult(i, Q15_1_5);  
        track = sub(i, extract_l(L_shr(L_mult(index, 5), 1)));  
        if (j > 0)  
        {  
            if (i < l_subfr) code = add(code, 4096);
             codvec[k] += (2 * L_SUBFR);  
        }  
        else  
        {  
            if (i < l_subfr) code = sub(code, 4096);  
            index = add(index, 16);  
        }  
        if (indx[track] < 0)  
        {  
            indx[track] = index;  
        }  
        else  
        {  
            if (((index ^ indx[track]) & 16) == 0)  
            {  
                if (sub(indx[track], index) <= 0)  
                {  
                    indx[track] = shl((indx[track] & 16), 3)  
                   + shr(extract_l(L_mult((indx[track]&15), NB_POS)), 1) + (index & 15);  
                }  
                else  
                {   indx[track] = shl((index & 16), 3)  
                   + shr(extract_l(L_mult((index & 15),NB_POS)), 1) + (indx[track] & 15);  
                }  
            }  
            else
            {  
                if (sub((indx[track] & 15), (index & 15)) <= 0)  
                {  
                    indx[track] = shl((index & 16), 3)  
                  + shr(extract_l(L_mult((index & 15),NB_POS)), 1) + (indx[track] & 15)
                }  
                else  
                {   indx[track] = shl((indx[track] & 16), 3)  
                    + shr(extract_l(L_mult((indx[track] & 15),NB_POS)), 1) + (index & 1
                }  
            }  
        }  
    }  
2、优化后的程序  
        for (k = 0; k < 8; k++)   
    {  
        i         = codvec[k];  
        j         = sign;  
        index           = _smpy(i, 6554)>>16;  
        track         = i - index*5;  
        con              = (j > 0);  
                codvec[k]    = codvec[k] + 110*con;  
                           index     = index + (!con)*16;  
        conn      = (i < l_subfr);  
        cono    = (j > 0)? 1:-1;  
        code  = code + 4096*conn*cono;  
                           n0   = index;  
                           t0   = indx[track];  
                           n1   = n0&16;  
                           t1   = t0&16;  
                           n2   = n0&15;  
                           t2   = t0&15;  
        tmp0    = (_sshl(n1,19)>>16) + n2*NB_POS + t2;  
        tmp1    = (_sshl(t1,19)>>16) + t2*NB_POS + n2;  
        conp    = (((n1 == t1)&&(t0 > n0))||((n1 != t1)&&(t2 <= n2)));  
                           tmp   = conp*tmp0 + (!conp)*tmp1;  
        if (t0 < 0)  
            indx[track] = n0;  
        else  
            indx[track] = tmp;  
}  
  3、优化说明  
     源程序中在循环中含有许多的 if 结构,在优化时对 if 结构首先进行化简,再将化简后的 if结构用条件运算表达式进行改写,最后使循环可以 Pipeline。  
九、 少量中值问题的优化
1、源程序  
        for (i = 0; i < n; i++)   
    {  
            max = -32767;  
            for (j = 0; j < n; j++)  
            {  
                    if (sub (tmp2[j], max) >= 0)  
                            {  
                                max = tmp2[j];  
                                ix = j;  
                    }  
                     }  
                     tmp2[ix] = -32768;  
                     tmp = ix;  
        }  

2、优化后的程序  
       if (n0>n1) {temp=n0;n0=n1;n1=temp;}  
       if (n1>n2) {temp=n1;n1=n2;n2=temp;}  
       if (n2>n3) {temp=n2;n2=n3;n3=temp;}  
       if (n3>n4) {temp=n3;n3=n4;n4=temp;}  
       if (n0>n1) {temp=n0;n0=n1;n1=temp;}  
       if (n1>n2) {temp=n1;n1=n2;n2=temp;}  
       if (n2>n3) {temp=n2;n2=n3;n3=temp;}  
       if (n0>n1) {temp=n0;n0=n1;n1=temp;}  
       if (n1>n2) {return n1;}  
3、优化说明  
     源程序也为一个求中值的问题,由于已知循环次数固定为 5,因此将循环展开使用 if语句直接求取中值。  
十、 位操作优化
1、源程序  
static Word16 Bin2int (Word16 no_of_bits,    Word16 *bitstream)   
{  
    Word16 value, i, bit;  
    value = 0;  
        for (i = 0; i < no_of_bits; i++)   
    {  
        value = shl (value, 1);  
        bit = *bitstream++;  
        if (sub (bit, BIT_1) == 0)  
        value = add (value, 1);  
    }  
    return (value);  
}  
        for (i = 0; i < prmno[mode]; i++)   
    {  
        prm = Bin2int (bitno[mode], bits);  
        bits += bitno[mode];  
    }  
2、优化后的程序  
    value = 0;  
    bitsp = bits;  
    bitnop= &bitno[mode][0];  
    j  = *bitnop++;  
    j1 = *bitnop++;  
    j2 = *bitnop++;  
    j3 = *bitnop++;  
    j4 = *bitnop++;  
    _nassert(loop[mode]>=35);  
        for (i = 0; i < loop[mode]; i++)   
    {  
        value = value*2 + *bitsp++;  
        j--;  
        if (j == 0)  
        {  
           *prm++ = value;  
           value = 0;  
           j  = j1;  
           j1 = j2;  
           j2 = j3;  
           j3 = j4;  
           j4 = *bitnop++;  
        }  
    }  
3、优化说明  
源程序按照数据位流定义取出参数,为双重循环结构,优化中采用重新根据位流的 bit
长度定义循环次数,化简为单重循环,然后优化循环,去除 boundary,使 pipeline 的数目最小。

使用特权

评论回复
地板
五谷道场|  楼主 | 2012-12-14 15:43 | 只看该作者
十一、copy程序的优化  
    1、源代码:  
    Word16 i;  
        for (i = 0; i < L; i++)   
    {  
        y = x;  
    }  
     2、改编代码:  
(1)要求数组长度能被 2 整除  
    Word32  i;  
    Word32      temp;  
        int *p1 = (int *)&x[0];   
        int *q1 = (int *)&y[0];   
        for (i = 0; i < L/2; i++)   
    {  
        temp = *p1++;  
        *q1++ = temp;  
    }  
(2)要求数组长度能被 4 整除  
    Word32  i;  
    Word32      temp1, temp2;  
    Word32  *pin1, *pin2, *pout1, *pout2;  
        pin1 = (Word32 *)&x[0];   
        pin2 = (Word32 *)&x[2];   
    pout1= (Word32 *)&y[0];  
    pout2= (Word32 *)&y[2];  
        for (i = 0; i < L/4; i++)   
    {  
        temp1 = *pin1;  
        temp2 = *pin2;  
        pin1+=2;  
        pin2+=2;  
        *pout1= temp1;  
        *pout2= temp2;  
        pout1+=2;  
        pout2+=2;  
    }  
3、优化方法说明:  
把一次循  拷贝一个 word16 的数改为一次循环拷贝 2 个 word16 或4 个 word16 的数。  
4、技巧:  
充分利用 c6xx 一次读取32 位数的特性,并利用一个指令周期能读取两个数据的特点。   
十二、set_zero 程序的优化  
    1、源代码:  
    Word16 i;  
        for (i = 0; i < L; i++)   
    {  
       x = 0;  
   }  
2、改编代码:  
(1)数组长度能被 2 整除  
    Word32 i;  
        int *x1 = (int *)&x[0];   
        for (i = 0; i < L/2; i++)   
    {  
        *x1++ = 0;  
    }  
(2)数组长度能被 4 整除  
    Word32 i;  
        int *x1 = (int *)&x[0];   
        int *x2 = (int *)&x[2];   
        for (i = 0; i < L/4; i++)   
    {  
        *x1 = 0;  
        *x2 = 0;  
        x1++;  
        x2++;  
        x1++;  
        x2++;  
    }  
3、优化方法说明:  
把一次循环为一个 word16 的数赋值改为一次为 2个或 4 个 word16 的数赋值。  
4、技巧:  
充分利用C6XX一次读取32位数的特点, 并利用一个指令周期能读取两个数据的特点。   
十三、32bit数与 16bit 数相乘  
1、源代码:  
L_tmp0 = Mac_32_16(L_32, hi1, lo1, lo2);   
2、改编代码:  
L_tmp0=_sadd(_sadd(_smpyhl(hl32, lo2),   
    (_mpyus(hl32, lo2)>>16)<<1), L_32);  
3、优化方法说明:  
    hl32 是32bit 的数, hi1 和 lo1 是 16bit的数, 且  hl32 = hi1<<16 + lo1 << 1  , 即 hi1 和 lo1分别是 hl32的高 16 位数和低 16 位数。 函数 Mac_32_16(L_32, hi1, lo1, lo2)实现  
  L_32 = L_32 + (hi1*lo2)<<1 + ((lo1*lo2)>>15)<<1  
     源代码是把一个 32 位的数拆成两个 16 位的数与一个 16 位的数相乘,优化后的代码不拆开 32 位的数,直接用 32 位的数与16 位的数相乘。运用这种方法必须保证 hl32 的最低一位数必须为 0,否则应用指令_clr(hl32, 0, 0)把最低位清零。  
4、技巧:  
     源代码中的低 16 位数 lo1 是hl32 的低16 位右移一位得到的(留出一位符号位) 。在与lo2 相乘时又右移了 15 位,所以在改编代码中右移 16 位,并且是以无符号数与 lo2 相乘。  
十四、32bit数与 32bit 数相乘  
1、源代码:  
                      L_tmp = Mac_32 (L_32, hi1, lo1, hi2, lo2);   
2、改编代码:  
L_tmp = _sadd(_sadd(_smpyh(hl1_32, hl2_32),   
     ((_mpyhslu(hl1_32, hl2_32)>>16)<<1)+((_mpyhslu(hl2_32, hl1_32)>>16)<<1)), L_32);  
3、优化方法说明:  
     两个 32位的数相乘,不必分成四个 16 位的数相乘,直接用 32 位相乘。其中:  
        hl1_32 = hi1<<16 + lo1<<1,       hl2_32 = hi2 <<16 + lo2 <<1  。  
源代码实现:  L_32 = L_32 + (hi1*hi2)<<1 + ( (hi1*lo2)>>15 + (lo1*hi2)>>15) <<1   
4、技巧:  
低 16 位与高16 位相乘时,低 16 位使用的是无符号数。  

十五、16 位除法的优化  
1、源代码:  
Word16 div_s (Word16 var1, Word16 var2) //实现  var1/var2  
{  
    Word16 var_out = 0;  
    Word16 iteration;  
    Word32 L_num = (Word32)var1;  
    Word32 L_denom = (Word32)var2;  
            for (iteration = 0; iteration < 15; iteration++)  
            {  
                var_out <<= 1;  
                L_num <<= 1;  
                if (L_num >= L_denom)  
                {  
                    L_num = L_sub (L_num, L_denom);  
                    var_out = add (var_out, 1);  
                }  
            }  
    return (var_out);  
}  

2、改编代码:  
Word16 div_s1 (Word16 var1, Word16 var2)   
{  
    Word32 var1int;  
    Word32 var2int;  
        var1int = var1 << 16;   
        var2int = var2 << 15;   
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    var1int = _subc(var1int,var2int);  
    return (var1int & 0xffff);  
}  
3、优化方法说明:  
实现 16 位的除法,要求被除数 var1和除数 var2都是整数,且 var1<=var2。利用 C6XX特有的指令 subc,实现除法的循环移位相减操作。  
4、技巧:  
把被除数和除数都转换成 32 位数来操作,返回时取低 16 位数。
十六、C6X优化 inline 举例:  
1、原程序:  
        for (i = LO_CHAN; i <= HI_CHAN; i++)   
    {  
        norm_shift = norm_l(st->ch_noise);  
        Ltmp = L_shl(st->ch_noise, norm_shift);  
        norm_shift1 = norm_l(st->ch_enrg);  
        Ltmp3 = L_shl1(st->ch_enrg, norm_shift1 - 1);  
        Ltmp2 = L_divide(Ltmp3, Ltmp);  
                Ltmp2 = L_shr(Ltmp2, 27 - 1 + norm_shift1 - norm_shift);   
                    // * scaled as 27,4 *  
        if (Ltmp2 == 0)  
           Ltmp2 = 1;  
        Ltmp1 = fnLog10(Ltmp2);  
        Ltmp3 = L_add(Ltmp1, LOG_OFFSET - 80807124);   
                    // * --ound(log10(2^4)*2^26 *  
        Ltmp2 = L_mult(TEN_S5_10, extract_h(Ltmp3));  
        if (Ltmp2 < 0)  
            Ltmp2 = 0;  
        // * 0.1875 scaled as 10,21 *  
        Ltmp1 = L_add(Ltmp2, CONST_0_1875_S10_21);  
                // * tmp / 0.375    2.667 scaled as 5,10, Ltmp is scaled 15,16 *   
        Ltmp = L_mult(extract_h(Ltmp1), CONST_2_667_S5_10);  
        ch_snr = extract_h(Ltmp);  
    }  

2、优化后程序:  
    //因循环体太大,拆成两个循环并把相应的函数内嵌以使程序能 pipeline,  
    //用 L_div_tmp[]保存因拆分而产生的中间变量。  
        for (i = LO_CHAN; i <= HI_CHAN; i++)   

    {  
        //norm_shift = norm_l(st->ch_noise);  
        norm_shift = _norm(st->ch_noise);  
        Ltmp = _sshl(st->ch_noise, norm_shift);  
        //norm_shift1 = norm_l(st->ch_enrg);  
        norm_shift1 = _norm(st->ch_enrg);  
        //Ltmp3 = L_shl1(st->ch_enrg, norm_shift1 - 1);  
        LLtmp1 = st->ch_enrg;  
        LLtmp1 = LLtmp1 << (norm_shift1 + 7);  
        Ltmp3 = (Word32)(LLtmp1 >> 8);  
        Ltmp2 = IL_divide(Ltmp3, Ltmp);  
        //Ltmp2 = L_shr(Ltmp2, 27 - 1 + norm_shift1 - norm_shift);  
                Ltmp2 = (Ltmp2 >> (27 - 1 + norm_shift1 - norm_shift));   
        if (Ltmp2 == 0)  
            Ltmp2 = 1;  
        L_div_tmp = Ltmp2;  
    }  
        for (i = LO_CHAN; i <= HI_CHAN; i++)   
    {  
        Ltmp2 = L_div_tmp;  
        Ltmp1 = IfnLog10(Ltmp2);  
        //Ltmp3 = L_add(Ltmp1, LOG_OFFSET - 80807124);   
        Ltmp3 = _sadd(Ltmp1, LOG_OFFSET - 80807124);  
        //Ltmp2 = L_mult(TEN_S5_10, extract_h(Ltmp3));  
        Ltmp2 = _smpy(TEN_S5_10, (Ltmp3 >> 16));  
        if (Ltmp2 < 0)  
            Ltmp2 = 0;  
        Ltmp1 = _sadd(Ltmp2, CONST_0_1875_S10_21);  
        //Ltmp = L_mult(extract_h(Ltmp1), CONST_2_667_S5_10);  
        Ltmp = _smpy((Ltmp1 >> 16), CONST_2_667_S5_10);  
        //ch_snr = extract_h(Ltmp);  
        ch_snr = (Ltmp >> 16);  
    }  
3、优化说明  
     观察上面这个循环,循环体本身比较大,且含有两个函数 L_divide()和 fnLog10() ,而 C62 内部只有 32 个寄存器,且有些寄存器是系统用的,如 B14、B15 这样循环体太大将会导致寄存器不够分配,从而导致系统编译器无法实现循环的 pipeline。  
     为了实现循环的 pipeline。我们需要把循环体进行拆分,拆分时要考虑以下几点:  
(1) 、拆分成几个循环比较合适?在各个循环能 pipeline 的前提下,拆开的循环个数越少越好。这就要求尽可能让各个循环的运算量接近。  
(2)考虑在什么地方把程序拆开比较合适?循环体里的数据流往往并不是单一的  ,
在拆开的断点处势必要用中间变量保存上次的循环运算结果,供以后的循环用。  适当的拆开循环体,使所需的中间变量越少越好。  
     (3)循环体中的函数调用必须定义成内嵌形式,含有函数调用的循环系统是无法使之pipeline 的;各个循环体中的判断分支机构不可太多,否则系统也无法使之 pipeline,为此应近可能把可以确定下来的分支确定下来,并尽可能用内嵌指令。  
     针对上面这个例子,考虑:  
     (1)为让各个循环的运算量大致相当,应把 L_divide()和 fnLog10()分到两个循环中去,从循环体大小上考虑,估计拆成两个循环比较合适。  
     (2)考虑在什么地方把程序拆开比较合适?在         
if (Ltmp2 == 0)  
            Ltmp2 = 1;  
后拆开,因为后面用到的数据只有 Ltmp2,故只需用一个数组保存每次循环的 Ltmp2 值即可。  
(3) 循环体中的两处函数调用L_divide () 和fnLog10 () 都定义了其内嵌形式,  IL_divide()和 IfnLog10() 。当把可以确定下来的分支作确定处理,并尽可能用内嵌指令后,该循环体中所剩的分支结构已很少,循环体可以 pipeline。优化前程  序用 2676 cycle,优化后用400 cycle。优化后两个子循环的 MII 分别为14和 6cycle。

使用特权

评论回复
5
shibalihuandao| | 2012-12-16 18:41 | 只看该作者
好有用的**

使用特权

评论回复
6
zgsxhzac| | 2012-12-16 18:55 | 只看该作者
学习一下

使用特权

评论回复
7
sishangcine| | 2012-12-16 19:29 | 只看该作者
值得学习

使用特权

评论回复
8
heibaiyinjiag| | 2012-12-16 19:41 | 只看该作者
呵呵 多谢楼主了

使用特权

评论回复
9
taihezhibanh| | 2012-12-16 19:58 | 只看该作者
内容很实用

使用特权

评论回复
10
beiwaroad| | 2012-12-16 20:08 | 只看该作者
多谢楼主分享,辛苦啦

使用特权

评论回复
11
xichengmadia| | 2012-12-16 20:13 | 只看该作者
好给力的总结啊

使用特权

评论回复
12
拿起书本| | 2012-12-17 15:40 | 只看该作者
真心需要,感谢楼主,每次都这么给力。顶了

使用特权

评论回复
13
ma411246470| | 2012-12-18 10:54 | 只看该作者
顶呀、、

使用特权

评论回复
14
shenmu2012| | 2012-12-18 17:59 | 只看该作者
楼主很强悍的,谢谢分享了啊

使用特权

评论回复
15
hawksabre| | 2012-12-20 17:53 | 只看该作者
很实用  谢谢楼主   谢谢了  呵呵   顶一个   希望楼主能够多多共享   哦呵呵

使用特权

评论回复
16
supstudent| | 2013-8-28 20:22 | 只看该作者
谢谢分享,先收留了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7647

主题

9805

帖子

11

粉丝