• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            歲月流轉(zhuǎn),往昔空明

            C++博客 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
              118 Posts :: 3 Stories :: 413 Comments :: 0 Trackbacks

            在設(shè)計(jì)一門語(yǔ)言與其他語(yǔ)言交互的API與ABI(Application Binary Interface,二進(jìn)制接口)時(shí),調(diào)用協(xié)議和內(nèi)存對(duì)齊是兩個(gè)無(wú)從回避的問(wèn)題。

            本文將討論如何在LLVM上生成正確的內(nèi)存對(duì)齊和調(diào)用協(xié)議的代碼。

            在這里為了方便和標(biāo)準(zhǔn)起見(jiàn),假定應(yīng)用LLVM的語(yǔ)言的Extending和Embedding的對(duì)象都是C。

            調(diào)用協(xié)議

            先來(lái)討論調(diào)用協(xié)議。調(diào)用協(xié)議用于保證調(diào)用方和被調(diào)用方在二進(jìn)制/匯編一級(jí)上是相容的。合適的調(diào)用協(xié)議可以幫助構(gòu)造出以下代碼:

            // Callee Signature of LLVM code
            void __cdecl foo( int a, float b, float4 c);
            
            // C caller
            typedef void (__cdecl* fn_ptr)(int, float, float4)
            fn_ptr p = static_cast<fn_ptr>( get_jit_function("foo") );
            p(1, 1.0, vec);
            

            一般來(lái)說(shuō)調(diào)用協(xié)議包括參數(shù)傳遞和返回值傳遞和堆棧平衡三個(gè)部分。在x86平臺(tái)上的C/C++編譯器中常見(jiàn)的調(diào)用協(xié)議有cdecl, fastcall和stdcall。具體的協(xié)議內(nèi)容請(qǐng)參見(jiàn)MSDN。

            在C++中還有一類特殊的調(diào)用協(xié)議thiscall,用于調(diào)用對(duì)象的成員函數(shù)。但是這一類調(diào)用協(xié)議不同的平臺(tái),不同的編譯器實(shí)現(xiàn)皆有不同,既無(wú)書面標(biāo)準(zhǔn),也無(wú)事實(shí)標(biāo)準(zhǔn),再加上virtual call等復(fù)雜的情況存在,并不適合用于做跨語(yǔ)言的調(diào)用。

            對(duì)于x64平臺(tái)而言,在windows下和linux下分別有兩種調(diào)用協(xié)議。

            先來(lái)看x86。由于x86在cdecl和fastcall上是有著跨平臺(tái)的標(biāo)準(zhǔn)的,因此LLVM對(duì)它的支持是比較完整的。程序只要在創(chuàng)建Function的時(shí)候指定Call Convention即可。

            但是對(duì)于x64,LLVM的支持便不是那么完善。以windows為例,windows的x64調(diào)用協(xié)議要求以rcx,rdx,r8,r9寄存器傳遞前四個(gè)不大于64bit的參數(shù),其余參數(shù)放在棧上。如果參數(shù)大于64bit,則要求傳遞它的指針。浮點(diǎn)使用xmm0-3來(lái)傳遞。但是對(duì)于LLVM而言,一旦參數(shù)大于64bit,它便會(huì)將整個(gè)對(duì)象而不是指針壓到棧上傳遞。因此在遇到x64時(shí),需要小心處理API部分的調(diào)用協(xié)議。

            在這里,我們需要將所有超過(guò)64bit的結(jié)構(gòu)體處理成指針(或者拷貝后處理成指針)傳遞。

            同時(shí),LLVM提供了readonly和byval兩個(gè)參數(shù)屬性(Attribute)來(lái)確保參數(shù)的值語(yǔ)義。前者意味著傳入的指針?biāo)赶虻闹凳遣槐恍薷牡模愃朴赥 const*),而后者會(huì)對(duì)傳入的指針做一份內(nèi)存拷貝,確保寫值不被傳遞出函數(shù)(類似于值拷貝)。這樣,LLVM生成的函數(shù)便可以MSVC生成的x64代碼正確調(diào)用了。

            內(nèi)存對(duì)齊

            與移動(dòng)平臺(tái)的體系結(jié)構(gòu)相比,x86對(duì)內(nèi)存對(duì)齊的條件算是相當(dāng)寬松的了。大部分的指令對(duì)內(nèi)存對(duì)齊基本上是沒(méi)有特殊要求的。只有一些SIMD的指令會(huì)對(duì)內(nèi)存對(duì)齊有所限定,例如movaps。

            為了方便后端生成SIMD代碼,LLVM提供了vector類型,例如vector<float, 1>。在代碼生成的時(shí)候,vector會(huì)編譯成最有可能的SIMD類型。因此在x86平臺(tái)上,vector<float, 1-4>都被處理成類似于__m128的類型,更長(zhǎng)的vector則被拆分成多個(gè)__m128類型。

            這實(shí)際上意味著,所有的vector都應(yīng)該遵循16Bytes對(duì)齊的原則。

            考慮到我們的需求,類似于struct{ float[3]; }這樣的結(jié)構(gòu),如果能表示為vector<float, 3>顯然適合一些數(shù)學(xué)運(yùn)算,例如shuffle,逐元素的add,sub,mul,同時(shí)LLVM指令的選擇也更加靈活。但是顯然,這個(gè)結(jié)構(gòu)體有兩個(gè)條件是不滿足的:16字節(jié)對(duì)齊和16字節(jié)的大?。╩ovups和movaps都是一次取16字節(jié))。這會(huì)造成邊界下讀寫的內(nèi)存越界。因此非??上?,這些數(shù)據(jù)必須表示為struct{ float ,float, float }。在讀取的時(shí)候,也會(huì)生成正確的指令:movss。

            那么,對(duì)于一般的非對(duì)齊的vec4應(yīng)用vector<float,4>行不行呢?

            答案是,很困難。對(duì)于LLVM而言,他們?cè)谠O(shè)計(jì)的時(shí)候就沒(méi)有過(guò)多的考慮vector在非對(duì)齊時(shí)候的應(yīng)用。盡管load和store都能夠指定alignment以生成非對(duì)齊的內(nèi)存操作(例如movups)并且確實(shí)會(huì)起效,但是由于代碼優(yōu)化、臨時(shí)存取等特性的存在,導(dǎo)致一些非load和store的內(nèi)存操作仍然是要求對(duì)齊的(例如生成了addaps xmm, [addr])。此時(shí)仍然有可能為非對(duì)齊的數(shù)據(jù)生成了內(nèi)存對(duì)齊的指令。

            因此綜合權(quán)衡,SASL在API界面上使用了struct{float x,y,z,w;} 這樣的ABI來(lái)表示數(shù)據(jù),在代碼生成時(shí),會(huì)首先將struct的數(shù)據(jù)轉(zhuǎn)換成vector,然后再執(zhí)行其它的操作,兼顧ABI與SIMD;同時(shí)對(duì)于Intrinsic,由于并不暴露給Host,所以它們?nèi)匀槐M可能使用Vector,便于LLVM進(jìn)行優(yōu)化。

            posted on 2011-08-17 13:58 空明流轉(zhuǎn) 閱讀(3463) 評(píng)論(3)  編輯 收藏 引用

            評(píng)論

            # re: LLVM的調(diào)用協(xié)議與內(nèi)存對(duì)齊 2011-08-17 16:38 陳梓瀚(vczh)
            好復(fù)雜啊  回復(fù)  更多評(píng)論
              

            # re: LLVM的調(diào)用協(xié)議與內(nèi)存對(duì)齊 2011-08-18 00:36 ooseven
            期待空轉(zhuǎn)兄的大作,希望做成一個(gè)系列。  回復(fù)  更多評(píng)論
              

            # re: LLVM的調(diào)用協(xié)議與內(nèi)存對(duì)齊 2014-04-03 09:56 往往
            在建立扎實(shí)收入之前的那種開(kāi)支需求的一種保障在生活,保障在房租,保障在零用之間建立起來(lái)的三個(gè)基本的扎實(shí)收入的過(guò)程當(dāng)中所需要的一種付出其中的基本的一個(gè)事實(shí)的努力的參考的基本含量在于確定起來(lái)的是基于一個(gè)現(xiàn)實(shí)的暫時(shí)的扎實(shí)的基礎(chǔ)收入建立起來(lái)對(duì)于溝通模式暢通的一個(gè)局面上面建立起來(lái)的扎實(shí)收入的基本面,這樣的一個(gè)基本面不是說(shuō)自己具備的這樣的一種自我意識(shí)的過(guò)程當(dāng)中來(lái)尋找這樣的一個(gè)扎實(shí)基礎(chǔ)收入的可能,而是一定需要建立這樣扎實(shí)收入的基本面,在這個(gè)之前付出就需要更加斟酌的保持其中的一個(gè)安全的自我層面來(lái)考量。  回復(fù)  更多評(píng)論
              

            国产一区二区三区久久| 99久久亚洲综合精品网站| 久久无码AV中文出轨人妻| 久久精品中文字幕无码绿巨人| 久久久亚洲欧洲日产国码aⅴ| 99久久精品国产毛片| 久久婷婷色综合一区二区| 久久精品草草草| 国产69精品久久久久观看软件| 狠狠久久亚洲欧美专区| 亚洲国产小视频精品久久久三级 | 国产精品久久久久…| 久久99精品久久久久久齐齐| 国产69精品久久久久久人妻精品 | 欧美日韩精品久久免费| 亚洲一本综合久久| 综合久久国产九一剧情麻豆 | 中文字幕久久精品无码| 国产精品无码久久久久| 久久久久久久久无码精品亚洲日韩 | 99久久综合狠狠综合久久| 波多野结衣AV无码久久一区| 久久精品无码一区二区日韩AV| 精品久久久久久久无码 | 久久精品成人欧美大片| 精品久久久久久综合日本| 亚洲伊人久久大香线蕉综合图片| 久久国产热这里只有精品| 久久99国产精一区二区三区 | 久久人妻少妇嫩草AV蜜桃| 狠狠色丁香久久综合婷婷| 成人国内精品久久久久一区| 一本久久知道综合久久| 久久人人爽人人爽人人片AV不| 蜜臀久久99精品久久久久久| 国产亚洲色婷婷久久99精品91| 日本福利片国产午夜久久| 老司机国内精品久久久久| 久久综合九色综合欧美狠狠| 精品久久久久久久| 久久免费小视频|