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

GCC中SIMD指令的应用方法--性能优化

GCC中SIMD指令的应用方法--性能优化

当使用C/C++完成了一个嵌入式应用的所有功能,性能问题常摆在面前, 这时可以使用profile工具(如gprof)找出产生瓶颈的函数, 将这些函数使用汇编彻底重写, 例如MPEG-4编解码器xvid项目 [4]就使用了这种方法, 而且针对不同处理器/指令集分别给出了不同的优化, 正是如此该项目无论功能、还是性能均为一流, 显然这是深度优化的目标所在。
在使用流水线、VLIW以及SIMD的体系结构(比如某些DSP)上, 整个函数的手工优化可以带来几倍到几十倍的性能提升。 不过,性能允许,对于函数内关键部分使用一些特定的实现, 既突出重点提高性能,又可以尽多地利用C/C++的高级特征, 相对缩短开发周期。 下面给出使用GCC时,应用MMX指令的几种混合编程方法:
  • Intel C/C++ 编译器intrinsics
  • GCC builtin操作
  • 嵌入汇编asm construct
Intel C/C++ 编译器intrinsics ...Intel C/C++ Compiler Intrinsics查看IA-32 Intel指令集手册 时, 部分指令的解释中会有一项“Intel C/C++ Compiler Intrinsic Equivalent”, 会指出该指令对等的intrinsic。 intrinsic在C/C++程序中的语法是以函数形式出现, 编译时可以直接翻译为一条MMX指令(复合情况会生成最直接的几条), 换言之,如果不使用intrinsic,可能需要多条C/C++语句完成, 而编译器却并不能保证将这几条语句能够生成这条最高效的MMX指令。 并不是每条MMX指令都有对等的intrinsic, 手册的附录中列出了所有的, 它们分为简单型(simple)和复合型(composite)两种, 每个简单型的就是对应一条指令,而复合型则对应多条指令。      
GCC支持Intel C/C++ Compiler Intrinsics。用法如下示例:
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
#include <stdio.h>
#include <xmmintrin.h> /*一定需要包括此头文件*/
/*gcc -Wall -march=pentium4 -mmmx -o ins  mmx_ins.c*/
int main(int argc,char *argv[])
{
  /*使用MMX做以下向量的点积*/
  short in1[] = {1, 2, 3, 4};
  short in2[] = {2, 3, 4, 5};
  int out1;
  int out2;
  __m64 m1;    /* MMX支持64位整数的mm寄存器 */
  __m64 m2;    /* MMX操作需要使用mm寄存器 */
  __m128 m128; /* for SSEn only*/
  /*每次往mm寄存器装入两个short型的数,注意是两个*/
  m1 = _mm_cvtsi32_si64(((int*)in1)[0]);
  m2 = _mm_cvtsi32_si64(((int*)in2)[0]);
  /*一条指令进行4个16位整数的乘加*/
  /*生成两个32位整数*/
  m2  = _mm_madd_pi16(m1, m2);
  /*将低32位整数放入通用寄存器*/
  out1 =  _mm_cvtsi64_si32(m2);
  /*将高32位整数右移后,放入通用寄存器*/
  m2  = _mm_slli_pi32(m2, 32);
  out2 =  _mm_cvtsi64_si32(m2);
  /*清除MMX状态*/
  _mm_empty();
  /*将两个32位数相加,结果为8*/
  out1 += out2;
  printf("a: %d\n", out1);
  return(0);
}




几点说明:
  • 即使你不是P4平台,编译时也请使用以下选项,         
    /*gcc -Wall -march=pentium4 -mmmx -o ins  mmx_ins.c*/
    否则,会出现如下类似信息:           
    ...xmmintrin.h:34:3: #error "SSE instruction set not enabled"
  • 最终结果实际并没有求得四对乘积的和,只是前两对的, instrinsic _mm_cvtsi32_si64只向mm寄存器放入了低32位,高32位为零, 但mmx有指令movq可以做到64位的数据传送,intrinsic没有对应, 这也说明并不是所有的指令有等价的intrinsic。
  • 当计算的向量为两对0x8000, 0x8000时,即(-2^15)*(-2^15) + (-2^15)*(-2^15) , 结果应该为 2^31,但计算出来的值是-2^31, 因为发生了溢出,可程序无从知道。 这是使用MMX时,应特别注意的,计算溢出没有任何标志位指示,一个极大的值变为极小,SSE对此做了改善。
  • 程序不再使用MMX之时,注意使用emms指令清除MMX状态。
返回列表