C6000点滴学习:c6000系列的C代码优化(七)

2019-07-23 14:17发布

十五、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。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。