首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

GCC中SIMD指令的应用方法--MMX实用一例 合成滤波器

GCC中SIMD指令的应用方法--MMX实用一例 合成滤波器

下面是合成滤波器(Synthesis Filter)的一个优化过程, 合成滤波器在语音编解码中有广泛应用, 运行时也占用了整个算法中较高比例的时间。
1
2
3
4
5
6
7
8
9
10
11
for (i = 0; i < lg; i++)
{
  s = L_mult(x, a[0]);/*L_mult是相乘后左移*/
  for (j = 1; j <= M; j++){/*M这里固定为10*/
    s = L_msu(s, a[j], yy[-j]);/*L_msu是乘减后左移操作*/
  }

  s = L_shl(s, 3); /*左移三位*/
  *yy++ = g729round(s);
}
#endif




上面的代码,因为内存循环为10,可以考虑展开,并统一操作为乘加指令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*为了使用乘加操作,需要调整10个系数的顺序*/
for(i = 0; i < M; i++)
  ta = -a[M - i];
ta[11] = 0;
ta[10] = a[0];
for (i = 0; i < lg; i++){
  *yy = x;
  yy[1] = 0;
  s = L_mac(s, ta[11], yy[1]);
  s = L_mac(s, ta[10], yy[0]);
  s = L_mac(s, ta[9], yy[-1]);
  s = L_mac(s, ta[8], yy[-2]);
  s = L_mac(s, ta[7], yy[-3]);
  s = L_mac(s, ta[6], yy[-4]);
  s = L_mac(s, ta[5], yy[-5]);
  s = L_mac(s, ta[4], yy[-6]);
  s = L_mac(s, ta[3], yy[-7]);
  s = L_mac(s, ta[2], yy[-8]);
  s = L_mac(s, ta[1], yy[-9]);
  s = L_mac(s, ta[0], yy[-10]);
   
  s = L_shl(s, 3);
  *yy++ = g729round(s);
}




以上循环内核正好可以将MMX的8个寄存器全部利用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  /*为了使用乘加操作,需要调整10个系数的顺序*/
  for(i = 0; i < M; i++)
    ta = -a[M - i];
  ta[11] = 0;
  ta[10] = a[0];
  /*11个系数分别放入3个MMX寄存器,0作填充*/
  asm("movq %0,%%mm0;\
  movq %1,%%mm1;\
  movq %2,%%mm2"\
  :\
  : "m" (ta[0]), "m" (ta[4]), "m"(ta[8]));
   
  /*利用MMX技术进行滤波器核心操作*/
  for (i = 0; i < lg; i++){
    *yy = x;
    yy[1] = 0;
    asm("pandn %%mm6,%%mm6;\
    movq %1,%%mm3;\
    movq %2,%%mm4;\
    movq %3,%%mm5;\
    pmaddwd %%mm0,%%mm3;\
    pmaddwd %%mm1,%%mm4;\
    pmaddwd %%mm2,%%mm5;\
    paddd %%mm3, %%mm6;\
    paddd %%mm4, %%mm6;\
    paddd %%mm5, %%mm6;\
    movq  %%mm6, %%mm7;\
    psrlq $32, %%mm6;\
    paddd %%mm7, %%mm6;\
    movd %%mm6,%0;\
    emms"
    :
    :"r"(s), "m" (yy[-10]), "m" (yy[-6]), "m"(yy[-2]));
/*因为指令结果饱和属性的限制,s还没有左移,所以下面多做一位饱和左移*/
    s = L_shl(s, 4);
    *yy++ = g729round(s);
  }




几点说明:
  • 注意:以上嵌入的汇编代码输出结果s放在了输入处,属于实践中的个案;
  • MMX没有乘左移之类的DSP指令,甚至还没有加饱和之类的操作,SSE中有一定增强;
  • 以上操作,理论上存在溢出可能,所以最后使用原有的饱和左移操作,减少了一定风险;
  • 上面的部分代码操作显然允许并行,这在VLIW系统中十分有用;
  • 这已经形成了该滤波器全面优化的核心。
返回列表