在C/C++代码中使用SSE等指令集的指令(1)介绍

http://blog.csdn.net/gengshenghong/article/details/7007100

我们知道,在C/C++代码中,可以插入汇编代码提高性能。现在的指令集有了很多的高级指令,如果我们希望使用这些高级指令来实现一些高效的算法,就可以在代码中嵌入汇编,使用SSE等高级指令,这是可行的,但是如果对汇编不太熟悉,不愿意使用汇编的人来说,其实也是可以的,这就是Compiler Intrinsics(http://msdn.microsoft.com/zh-cn/site/26td21ds)。

PS:下面的内容以Windows平台为主,对于Linux下,也有类似的方法。

(1)什么是Intrinsics

Intrinsics是对MMX、SSE等指令集的指令的一种封装,以函数的形式提供,使得程序员更容易编写和使用这些高级指令,在编译的时候,这些函数会被内联为汇编,不会产生函数调用的开销。在理解intrinsics指令之前,先理解intrinsics函数。

(3)#pragma intrinsic和#pragma function

#pragma intrinsic(function[,function][,function]...):表示后面的函数将进行intrinsic,替换为内部函数,去掉了函数调用的开销,注意:有些地方解释为内联,但是和内联并不完全相同,对于内联,可以指定任意函数为内联,但是此pragma intrinsic只能适用于编译器规定的一部分函数,不是所有函数都能使用,而且,inline关键字一般用于指定自定义的函数,intrinsic则是系统库函数的一部分。参考http://technet.microsoft.com/zh-cn/library/tzkfha43.aspx获取详细的说明。

下面分析这个例子:

  1. #include <math.h>  
  2. void foo()  
  3. {  
  4.     double var = cos(10);  
  5. }  
使用VS2010的32bit的command line编译:

cl /c test.c /FA

输出得到其汇编文件:

  1. ; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01   
  2.   
  3.     TITLE   C:\tempLab\test.c  
  4.     .686P  
  5.     .XMM  
  6.     include listing.inc  
  7.     .model  flat  
  8.   
  9. INCLUDELIB LIBCMT  
  10. INCLUDELIB OLDNAMES  
  11.   
  12. PUBLIC  __real@4024000000000000  
  13. PUBLIC  _foo  
  14. EXTRN   _cos:PROC  
  15. EXTRN   __fltused:DWORD  
  16. ;   COMDAT __real@4024000000000000  
  17. ; File c:\templab\test.c  
  18. CONST   SEGMENT  
  19. __real@4024000000000000 DQ 04024000000000000r   ; 10  
  20. ; Function compile flags: /Odtp  
  21. CONST   ENDS  
  22. _TEXT   SEGMENT  
  23. _var$ = -8                      ; size = 8  
  24. _foo    PROC  
  25. ; Line 3  
  26.     push    ebp  
  27.     mov ebp, esp  
  28.     sub esp, 8  
  29. ; Line 4  
  30.     sub esp, 8  
  31.     fld QWORD PTR __real@4024000000000000  
  32.     fstp    QWORD PTR [esp]  
  33.     call    _cos  
  34.     add esp, 8  
  35.     fstp    QWORD PTR _var$[ebp]  
  36. ; Line 5  
  37.     mov esp, ebp  
  38.     pop ebp  
  39.     ret 0  
  40. _foo    ENDP  
  41. _TEXT   ENDS  
  42. END  
可以看到,这里调用了call _cos函数进行运算,下面代码修改如下:

  1. #include <math.h>  
  2. #pragma intrinsic(cos)  
  3. void foo()  
  4. {  
  5.     double var = cos(10);  
  6. }  
同样的命令编译,得到汇编如下:

  1. ; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01   
  2.   
  3.     TITLE   C:\tempLab\test.c  
  4.     .686P  
  5.     .XMM  
  6.     include listing.inc  
  7.     .model  flat  
  8.   
  9. INCLUDELIB LIBCMT  
  10. INCLUDELIB OLDNAMES  
  11.   
  12. PUBLIC  __real@4024000000000000  
  13. PUBLIC  _foo  
  14. EXTRN   __fltused:DWORD  
  15. EXTRN   __CIcos:PROC  
  16. ;   COMDAT __real@4024000000000000  
  17. ; File c:\templab\test.c  
  18. CONST   SEGMENT  
  19. __real@4024000000000000 DQ 04024000000000000r   ; 10  
  20. ; Function compile flags: /Odtp  
  21. CONST   ENDS  
  22. _TEXT   SEGMENT  
  23. _var$ = -8                      ; size = 8  
  24. _foo    PROC  
  25. ; Line 4  
  26.     push    ebp  
  27.     mov ebp, esp  
  28.     sub esp, 8  
  29. ; Line 5  
  30.     fld QWORD PTR __real@4024000000000000  
  31.     call    __CIcos  
  32.     fstp    QWORD PTR _var$[ebp]  
  33. ; Line 6  
  34.     mov esp, ebp  
  35.     pop ebp  
  36.     ret 0  
  37. _foo    ENDP  
  38. _TEXT   ENDS  
  39. END  
对比之后,它们的主要区别的代码段如下:

  1. sub esp, 8  
  2.     fld QWORD PTR __real@4024000000000000  
  3.   
  4.     fstp    QWORD PTR [esp]  
  5.     call    _cos  
  6.     add esp, 8  
  1. fld QWORD PTR __real@4024000000000000  
  2. call    __CIcos  
显然,使用了Intrinsics之后的cos函数的指令少了很多,其调用的内部函数是_CIcos(http://msdn.microsoft.com/zh-cn/library/ff770589.aspx),此函数会计算对栈顶的元素直接进行cos运算,所以节省了很多函数调用参数传递等的指令。

仍然参考MSDN(http://technet.microsoft.com/zh-cn/library/tzkfha43.aspx)可以看到其中一段话:

The floating-point functions listed below do not have true intrinsic forms. Instead they have versions that pass arguments directly to the floating-point chip rather than pushing them onto the program stack.

当然,这是描述其中一部分Intrinsics函数的,Intrinsics也有不同的方式进行优化/内联,具体参考MSDN查询哪些函数可以使用Intrinsics以及是如何工作的(http://msdn.microsoft.com/zh-cn/site/26td21ds)。

#pragma function:使用格式和intrinsics一样,pragma function用于指定函数不进行intrinsics操作,也就是不生成内部函数。

最后,要知道的一个内容是一个相关的编译选项:/Oi

http://technet.microsoft.com/zh-cn/library/f99tchzc.aspx

/Oi 仅作为对编译器的请求,用于将某些函数调用替换为内部函数;为产生更好的性能,编译器可能会调用函数(而不会将该函数调用替换为内部函数)。

简单的理解,就是告诉编译器尽量使用intrinsics版本的调用,当然,最终的实际调用依赖于编译器的判断。

也可以参考wiki中(http://en.wikipedia.org/wiki/Intrinsic_function)关于intrinsic functions来帮助理解其作用。简单来说,可以理解为编译器的“内置函数”,编译器会根据情况进行一些优化。

(4)指令集相关的intrinsics介绍

上面介绍的是pragma对intrinsic函数的使用,其中介绍了cos,还有很多类似的“内置函数版本”。有时候将上面的这些称之为”intrinsics函数“,除此之外,intrinsics更广泛的使用是指令集的封装,能直接映射到高级指令集,从而使得程序员可以以函数调用的方式来实现汇编能达到的功能,编译器会生成为对应的SSE等指令集汇编。

1. 如何使用这类函数

在windows上,包含#include <**mmintrin.h>头文件即可(不同的指令集扩展的函数可能前缀不一样),也可以直接包含#include <intrin.h>(这里面会根据使用环境判断使用ADM的一些兼容扩展)。

2. 关于数据类型

这些和指令集相关的函数,一般都有自己的数据类型,不能使用一般的数据类型传递进行计算,一般来说,MMX指令是__m64(http://msdn.microsoft.com/zh-cn/library/08x3t697(v=VS.90).aspx)类型的数据,SSE是__m128类型的数据等等。

3. 函数名:

这类函数名一般以__m开头。函数名称和指令名称有一定的关系。

4. 加法实例:

下面使用SSE指令集进行加法运算,一条指令对四个浮点数进行运算:

  1. #include <stdio.h>  
  2. #include <intrin.h>  
  3.   
  4. int main(int argc, char* argv[])  
  5. {  
  6.     __m128  a;  
  7.     __m128  b;  
  8.       
  9.     a = _mm_set_ps(1,2,3,4);        // Assign value to a  
  10.     b = _mm_set_ps(1,2,3,4);        // Assign value to a  
  11.   
  12.     __m128 c = _mm_add_ps(a, b);    // c = a + b  
  13.   
  14.     printf("0: %lf\n", c.m128_f32[0]);  
  15.     printf("1: %lf\n", c.m128_f32[1]);  
  16.     printf("2: %lf\n", c.m128_f32[2]);  
  17.     printf("3: %lf\n", c.m128_f32[3]);  
  18.   
  19.     return 0;  
  20. }  
从代码看,好像很复杂,但是生成的汇编的效率会比较高。一条指令就完成了四个浮点数的加法,其运行结果如下:


(5)总结:

1. Intrinsics函数:能提高性能,会增大生成代码的大小,是编译器的”内置函数“。

2. Intrinsics对指令的封装函数:直接映射到汇编指令,能简化汇编代码的编写,另外,隐藏了寄存器分配和调度等。由于涉及到的数据类型、函数等内容较多,这里只是一个简单的介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/243270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

赋值操作符

赋值操作符 和其他赋值操作符 out in;//将out和in相加并将结果赋值给out //out out in;注意&#xff1a;这些操作符都是阻塞赋值packdage definitions;typedef enum logic[2:0] {ADD,SUB,MULT,DIV,SL.SR} opcode_t;typedef enum logic{UNSIGNED,SIGNED}operand_type_t;typ…

有无关通配符的相等操作符

有无关通配符的相等操作符 逻辑相等操作符 条件相等操作 SystemVerilog通配符相等操作符允许屏蔽某些位 SystemVerilog还增加了两个新的比较操作符&#xff1a; &#xff1f; 和&#xff01;&#xff1f;。这两个操作符允许在比较中屏蔽无关位。 操作符 &#xff1f;&#x…

cab文件介绍及制作方法

转自&#xff1a;http://bbs.pcpop.com/091030/5945399.html 1. 什么是cab文件 CAB在电脑上是一种压缩文件&#xff0c;微软出品的东西&#xff0c;用WinRAR可以解压缩&#xff0c;在DOS启动盘里面可以看见一些CAB压缩文件。其实Windows里面已经带了CAB压缩程序&#xff0c;但…

CVE-2015-0235: GHOST – A Critical Vulnerability in the Glibc Library

GHOST is a ‘buffer overflow’ bug affecting the gethostbyname() and gethostbyname2() function calls in the glibc library. If a remote attacker can make an application call to gethostbyname() or gethostbyname2(), this vulnerability allows the remote attack…

通过ap运行cab安装程序的方法及Sample Code

1. 第一部分&#xff1a;Sample Code 这部分转自&#xff1a;http://blog.csdn.net/hhygcy/archive/2009/05/04/4147870.aspx 最近这个东西很多被问及&#xff0c;软件动态升级的时候可能可以用到&#xff0c;在这里做一下记录。 就知道的方法有2个&#xff0c; 一个是通过Sh…

MFC透明桌面flash金鱼

代码&#xff1a; http://download.csdn.net/detail/hemmingway/6823935 使用方法&#xff1a; //0,添加left.png&#xff0c;right.png资源文件 //1, 头文件定义变量 GoldFish pet; //2, 在CPP文件创建 // Create a goldfishif (!pet.Create(NULL, NULL, WS_CHILD | WS_VISIB…

天才静之

木心说&#xff1a;“最高一层天才&#xff0c;是早熟而晚成的。”我一直认为静之就是一个天才。天才不同于才子&#xff0c;才子早熟&#xff0c;但往往短命&#xff0c;而静之却常胜不衰&#xff0c;愈“老”弥坚。 从诗歌、散文到小说&#xff0c;从电视剧、电影再到话剧、歌…

“象征界”的奇观:刘天怜花鸟工笔作品印象

有人说&#xff1a;“创新”是西洋画的基调&#xff0c;中国画的焦点是“承传”。就是说&#xff0c;西画必须花样翻新&#xff0c;挑战前人&#xff0c;甚至要推倒重来&#xff0c;唯此才可能在艺术史上占有一席之地&#xff1b;中国画强调以古人为师&#xff0c;重视师徒之间…

亚马逊正式发布关系型数据库Amazon Aurora

在去年的AWS re:Invent大会上&#xff0c;亚马逊宣布了Amazon Aurora。Aurora是一个关系型数据库&#xff0c;可以跨3个可用区域复制6份数据&#xff0c;其设计目标是提供高性能和高可用性&#xff08;99.99%&#xff09;&#xff0c;并且存储可以轻松高效地扩展到64TB。近日&a…

刘小东的“空城记”

刘小东的“空城记” 。从“三峡移民”到“金城小子”&#xff0c;从“温床”&#xff0c;再到"新疆和田 ”,今天&#xff0c;刘小东又把“鄂尔多斯” 纳入自己介入现实的创作计划。鄂尔多斯&#xff0c;一个中国曾经最贫瘠的所在&#xff0c;因为矿产开发&#xff0c;迅…

聆听南音

北京。半木空间。聆听南音古曲。 南音亦称弦管、南乐。起于晋唐&#xff0c;盛于南宋&#xff0c;至今流传于泉州闽南地区。被誉为“中国音乐史上的活化石” 。今晚&#xff0c;南音传人蔡雅艺率三位南音大师现场演出、宣讲并与"半木"品牌创始人吕永中先生对话交流…

远程管理 KVM 虚机 - 每天5分钟玩转 OpenStack(5)

上一节我们通过 virt-manager 在本地主机上创建并管理 KVM 虚机。其实 virt-manager 也可以管理其他宿主机上的虚机。只需要简单的将宿主机添加进来 填入宿主机的相关信息&#xff0c;确定即可。 接下来&#xff0c;我们就可以像管理本地虚机一样去管理远程宿主机上的虚机了。 …

KVM 存储虚拟化 - 每天5分钟玩转 OpenStack(7)

KVM 的存储虚拟化是通过存储池&#xff08;Storage Pool&#xff09;和卷&#xff08;Volume&#xff09;来管理的。 Storage Pool 是宿主机上可以看到的一片存储空间&#xff0c;可以是多种类型&#xff0c;后面会详细讨论。Volume 是在 Storage Pool 中划分出的一块空间&…

LVM 类型的 Storage Pool - 每天5分钟玩转 OpenStack(8)

LVM 类型的 Storage Pool 不仅一个文件可以分配给客户机作为虚拟磁盘&#xff0c;宿主机上 VG 中的 LV 也可以作为虚拟磁盘分配给虚拟机使用。 不过&#xff0c;LV 由于没有磁盘的 MBR 引导记录&#xff0c;不能作为虚拟机的启动盘&#xff0c;只能作为数据盘使用。 这种配置下…

UltraEdit中高亮显示verilog HDL关键词

UltraEdit是一款功能强大的文本编辑器&#xff0c;可以编辑文字、Hex、ASCII码&#xff0c;可以取代记事本&#xff0c;内建英文单字检查、C 及 VB 指令突显&#xff0c;可同时编辑多个文件&#xff0c;而且即使开启很大的文件速度也不会慢。是一个使用广泛的编辑器&#xff0c…

CCS的基本操作

CCS的基本操作 1、 创建新工程 方法一&#xff1a; 方法二&#xff1a; 进入工程界面后&#xff0c;第一步选择芯片型号&#xff0c;第二步选择仿真器&#xff0c;第三步编写工程名称&#xff0c;选择工程模板。最后点击finish 2、 编译 方法一&#xff1a; 方法二&…

KVM 网络虚拟化基础 - 每天5分钟玩转 OpenStack(9)

网络虚拟化是虚拟化技术中最复杂的部分&#xff0c;学习难度最大。 但因为网络是虚拟化中非常重要的资源&#xff0c;所以再硬的骨头也必须要把它啃下来。 为了让大家对虚拟化网络的复杂程度有一个直观的认识&#xff0c;请看下图 这是 OpenStack 官网上给出的计算节点&#…

云计算与 OpenStack - 每天5分钟玩转 OpenStack(14)

“云计算” 算是近年来最热的词了。现在 IT 行业见面不说这三个字您都不好意思跟人家打招呼。 对于云计算&#xff0c;学术界有各种定义&#xff0c;大家有兴趣可以百度一下。 CloudMan 这里主要想从技术的角度谈谈对云计算的理解。 基本概念 所有的新事物都不是突然冒出来的&a…

OpenStack 架构 - 每天5分钟玩转 OpenStack(15)

终于正式进入 OpenStack 部分了。 今天开始&#xff0c;CloudMan 将带着大家一步一步揭开 OpenStack 的神秘面纱。 OpenStack 已经走过了 6 个年头。 每半年会发布一个版本&#xff0c;版本以字母顺序命名。现在已经到第 12 个版本 Liberty&#xff08;字母 L&#xff09;。 Op…

部署 DevStack - 每天5分钟玩转 OpenStack(17)

本节按照以下步骤部署 DevStack 实验环境&#xff0c;包括控制节点和计算节点 创建虚拟机 按照物理资源需求创建 devstack-controller 和 devstak-compute 虚拟机 安装操作系统 安装 Ubuntu 14.04&#xff0c;并配置 eth0 的 IP devstack-controller 192.168.104.10 devstak-c…