日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

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

發(fā)布時(shí)間:2023/12/15 c/c++ 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在C/C++代码中使用SSE等指令集的指令(1)介绍 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
http://blog.csdn.net/gengshenghong/article/details/7007100

我們知道,在C/C++代碼中,可以插入?yún)R編代碼提高性能。現(xiàn)在的指令集有了很多的高級(jí)指令,如果我們希望使用這些高級(jí)指令來(lái)實(shí)現(xiàn)一些高效的算法,就可以在代碼中嵌入?yún)R編,使用SSE等高級(jí)指令,這是可行的,但是如果對(duì)匯編不太熟悉,不愿意使用匯編的人來(lái)說(shuō),其實(shí)也是可以的,這就是Compiler Intrinsics(http://msdn.microsoft.com/zh-cn/site/26td21ds)。

PS:下面的內(nèi)容以Windows平臺(tái)為主,對(duì)于Linux下,也有類似的方法。

(1)什么是Intrinsics

Intrinsics是對(duì)MMX、SSE等指令集的指令的一種封裝,以函數(shù)的形式提供,使得程序員更容易編寫(xiě)和使用這些高級(jí)指令,在編譯的時(shí)候,這些函數(shù)會(huì)被內(nèi)聯(lián)為匯編,不會(huì)產(chǎn)生函數(shù)調(diào)用的開(kāi)銷。在理解intrinsics指令之前,先理解intrinsics函數(shù)。

(3)#pragma intrinsic和#pragma function

#pragma intrinsic(function[,function][,function]...):表示后面的函數(shù)將進(jìn)行intrinsic,替換為內(nèi)部函數(shù),去掉了函數(shù)調(diào)用的開(kāi)銷,注意:有些地方解釋為內(nèi)聯(lián),但是和內(nèi)聯(lián)并不完全相同,對(duì)于內(nèi)聯(lián),可以指定任意函數(shù)為內(nèi)聯(lián),但是此pragma intrinsic只能適用于編譯器規(guī)定的一部分函數(shù),不是所有函數(shù)都能使用,而且,inline關(guān)鍵字一般用于指定自定義的函數(shù),intrinsic則是系統(tǒng)庫(kù)函數(shù)的一部分。參考http://technet.microsoft.com/zh-cn/library/tzkfha43.aspx獲取詳細(xì)的說(shuō)明。

下面分析這個(gè)例子:

  • #include?<math.h>??
  • void?foo()??
  • {??
  • ????double?var?=?cos(10);??
  • }??
  • 使用VS2010的32bit的command line編譯:

    cl /c test.c /FA

    輸出得到其匯編文件:

  • ;?Listing?generated?by?Microsoft?(R)?Optimizing?Compiler?Version?16.00.30319.01???
  • ??
  • ????TITLE???C:\tempLab\test.c??
  • ????.686P??
  • ????.XMM??
  • ????include?listing.inc??
  • ????.model??flat??
  • ??
  • INCLUDELIB?LIBCMT??
  • INCLUDELIB?OLDNAMES??
  • ??
  • PUBLIC??__real@4024000000000000??
  • PUBLIC??_foo??
  • EXTRN???_cos:PROC??
  • EXTRN???__fltused:DWORD??
  • ;???COMDAT?__real@4024000000000000??
  • ;?File?c:\templab\test.c??
  • CONST???SEGMENT??
  • __real@4024000000000000?DQ?04024000000000000r???;?10??
  • ;?Function?compile?flags:?/Odtp??
  • CONST???ENDS??
  • _TEXT???SEGMENT??
  • _var$?=?-8??????????????????????;?size?=?8??
  • _foo????PROC??
  • ;?Line?3??
  • ????push????ebp??
  • ????mov?ebp,?esp??
  • ????sub?esp,?8??
  • ;?Line?4??
  • ????sub?esp,?8??
  • ????fld?QWORD?PTR?__real@4024000000000000??
  • ????fstp????QWORD?PTR?[esp]??
  • ????call????_cos??
  • ????add?esp,?8??
  • ????fstp????QWORD?PTR?_var$[ebp]??
  • ;?Line?5??
  • ????mov?esp,?ebp??
  • ????pop?ebp??
  • ????ret?0??
  • _foo????ENDP??
  • _TEXT???ENDS??
  • END??
  • 可以看到,這里調(diào)用了call _cos函數(shù)進(jìn)行運(yùn)算,下面代碼修改如下:

  • #include?<math.h>??
  • #pragma?intrinsic(cos)??
  • void?foo()??
  • {??
  • ????double?var?=?cos(10);??
  • }??
  • 同樣的命令編譯,得到匯編如下:

  • ;?Listing?generated?by?Microsoft?(R)?Optimizing?Compiler?Version?16.00.30319.01???
  • ??
  • ????TITLE???C:\tempLab\test.c??
  • ????.686P??
  • ????.XMM??
  • ????include?listing.inc??
  • ????.model??flat??
  • ??
  • INCLUDELIB?LIBCMT??
  • INCLUDELIB?OLDNAMES??
  • ??
  • PUBLIC??__real@4024000000000000??
  • PUBLIC??_foo??
  • EXTRN???__fltused:DWORD??
  • EXTRN???__CIcos:PROC??
  • ;???COMDAT?__real@4024000000000000??
  • ;?File?c:\templab\test.c??
  • CONST???SEGMENT??
  • __real@4024000000000000?DQ?04024000000000000r???;?10??
  • ;?Function?compile?flags:?/Odtp??
  • CONST???ENDS??
  • _TEXT???SEGMENT??
  • _var$?=?-8??????????????????????;?size?=?8??
  • _foo????PROC??
  • ;?Line?4??
  • ????push????ebp??
  • ????mov?ebp,?esp??
  • ????sub?esp,?8??
  • ;?Line?5??
  • ????fld?QWORD?PTR?__real@4024000000000000??
  • ????call????__CIcos??
  • ????fstp????QWORD?PTR?_var$[ebp]??
  • ;?Line?6??
  • ????mov?esp,?ebp??
  • ????pop?ebp??
  • ????ret?0??
  • _foo????ENDP??
  • _TEXT???ENDS??
  • END??
  • 對(duì)比之后,它們的主要區(qū)別的代碼段如下:

  • sub?esp,?8??
  • ????fld?QWORD?PTR?__real@4024000000000000??
  • ??
  • ????fstp????QWORD?PTR?[esp]??
  • ????call????_cos??
  • ????add?esp,?8??
  • fld?QWORD?PTR?__real@4024000000000000??
  • call????__CIcos??
  • 顯然,使用了Intrinsics之后的cos函數(shù)的指令少了很多,其調(diào)用的內(nèi)部函數(shù)是_CIcos(http://msdn.microsoft.com/zh-cn/library/ff770589.aspx),此函數(shù)會(huì)計(jì)算對(duì)棧頂?shù)脑刂苯舆M(jìn)行cos運(yùn)算,所以節(jié)省了很多函數(shù)調(diào)用參數(shù)傳遞等的指令。

    仍然參考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.

    當(dāng)然,這是描述其中一部分Intrinsics函數(shù)的,Intrinsics也有不同的方式進(jìn)行優(yōu)化/內(nèi)聯(lián),具體參考MSDN查詢哪些函數(shù)可以使用Intrinsics以及是如何工作的(http://msdn.microsoft.com/zh-cn/site/26td21ds)。

    #pragma function:使用格式和intrinsics一樣,pragma function用于指定函數(shù)不進(jìn)行intrinsics操作,也就是不生成內(nèi)部函數(shù)。

    最后,要知道的一個(gè)內(nèi)容是一個(gè)相關(guān)的編譯選項(xiàng):/Oi

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

    /Oi 僅作為對(duì)編譯器的請(qǐng)求,用于將某些函數(shù)調(diào)用替換為內(nèi)部函數(shù);為產(chǎn)生更好的性能,編譯器可能會(huì)調(diào)用函數(shù)(而不會(huì)將該函數(shù)調(diào)用替換為內(nèi)部函數(shù))。

    簡(jiǎn)單的理解,就是告訴編譯器盡量使用intrinsics版本的調(diào)用,當(dāng)然,最終的實(shí)際調(diào)用依賴于編譯器的判斷。

    也可以參考wiki中(http://en.wikipedia.org/wiki/Intrinsic_function)關(guān)于intrinsic functions來(lái)幫助理解其作用。簡(jiǎn)單來(lái)說(shuō),可以理解為編譯器的“內(nèi)置函數(shù)”,編譯器會(huì)根據(jù)情況進(jìn)行一些優(yōu)化。

    (4)指令集相關(guān)的intrinsics介紹

    上面介紹的是pragma對(duì)intrinsic函數(shù)的使用,其中介紹了cos,還有很多類似的“內(nèi)置函數(shù)版本”。有時(shí)候?qū)⑸厦娴倪@些稱之為”intrinsics函數(shù)“,除此之外,intrinsics更廣泛的使用是指令集的封裝,能直接映射到高級(jí)指令集,從而使得程序員可以以函數(shù)調(diào)用的方式來(lái)實(shí)現(xiàn)匯編能達(dá)到的功能,編譯器會(huì)生成為對(duì)應(yīng)的SSE等指令集匯編。

    1. 如何使用這類函數(shù)

    在windows上,包含#include <**mmintrin.h>頭文件即可(不同的指令集擴(kuò)展的函數(shù)可能前綴不一樣),也可以直接包含#include <intrin.h>(這里面會(huì)根據(jù)使用環(huán)境判斷使用ADM的一些兼容擴(kuò)展)。

    2.?關(guān)于數(shù)據(jù)類型

    這些和指令集相關(guān)的函數(shù),一般都有自己的數(shù)據(jù)類型,不能使用一般的數(shù)據(jù)類型傳遞進(jìn)行計(jì)算,一般來(lái)說(shuō),MMX指令是__m64(http://msdn.microsoft.com/zh-cn/library/08x3t697(v=VS.90).aspx)類型的數(shù)據(jù),SSE是__m128類型的數(shù)據(jù)等等。

    3. 函數(shù)名:

    這類函數(shù)名一般以__m開(kāi)頭。函數(shù)名稱和指令名稱有一定的關(guān)系。

    4. 加法實(shí)例:

    下面使用SSE指令集進(jìn)行加法運(yùn)算,一條指令對(duì)四個(gè)浮點(diǎn)數(shù)進(jìn)行運(yùn)算:

  • #include?<stdio.h>??
  • #include?<intrin.h>??
  • ??
  • int?main(int?argc,?char*?argv[])??
  • {??
  • ????__m128??a;??
  • ????__m128??b;??
  • ??????
  • ????a?=?_mm_set_ps(1,2,3,4);????????//?Assign?value?to?a??
  • ????b?=?_mm_set_ps(1,2,3,4);????????//?Assign?value?to?a??
  • ??
  • ????__m128?c?=?_mm_add_ps(a,?b);????//?c?=?a?+?b??
  • ??
  • ????printf("0:?%lf\n",?c.m128_f32[0]);??
  • ????printf("1:?%lf\n",?c.m128_f32[1]);??
  • ????printf("2:?%lf\n",?c.m128_f32[2]);??
  • ????printf("3:?%lf\n",?c.m128_f32[3]);??
  • ??
  • ????return?0;??
  • }??
  • 從代碼看,好像很復(fù)雜,但是生成的匯編的效率會(huì)比較高。一條指令就完成了四個(gè)浮點(diǎn)數(shù)的加法,其運(yùn)行結(jié)果如下:


    (5)總結(jié):

    1.?Intrinsics函數(shù):能提高性能,會(huì)增大生成代碼的大小,是編譯器的”內(nèi)置函數(shù)“。

    2. Intrinsics對(duì)指令的封裝函數(shù):直接映射到匯編指令,能簡(jiǎn)化匯編代碼的編寫(xiě),另外,隱藏了寄存器分配和調(diào)度等。由于涉及到的數(shù)據(jù)類型、函數(shù)等內(nèi)容較多,這里只是一個(gè)簡(jiǎn)單的介紹。

    總結(jié)

    以上是生活随笔為你收集整理的在C/C++代码中使用SSE等指令集的指令(1)介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。