LLVM語言參考手冊

翻譯自:http://llvm.org/docs/LangRef.html
#######重啟翻譯

摘要

這篇文檔是<code>LLVM</code>匯編語言(<code>assembly language</code>)的參考手冊打洼。LLVM是一個(gè)基于靜態(tài)單賦值(<code>Static Single Assignment</code>试躏,簡寫為<code>SSA</code>)的表示形式匙奴,它提供了類型安全(<code>type safety</code>)、低級(jí)別操作(<code>low-level operations</code>)获枝、靈活性、清晰表示“所有”高級(jí)語言的能力。它是貫穿LLVM編譯策略全階段的通用代碼表示鳖链。

介紹

<code>LLVM</code>代碼表示常設(shè)計(jì)以下三種情況:作為在內(nèi)存中的編譯器中間語言(<code>Intermediate Representation</code>呢袱,簡稱<code>IR</code>)官扣,作為在硬盤上的位碼表示(適合<code>JIT</code>編譯器快速加載),作為適合人類閱讀的匯編語言表示羞福。它允許<code>LLVM</code>為編譯器的高效轉(zhuǎn)換和分析提供強(qiáng)大的<code>IR</code>惕蹄,同時(shí)提供自然方法去調(diào)試和可視化轉(zhuǎn)換。這<code>LLVM</code>的三種不同方式是等價(jià)的治专。這個(gè)文檔描述的是適合人類閱讀的表示和標(biāo)注卖陵。

<code>LLVM</code>表示的目標(biāo)是輕量級(jí)和低級(jí)別,同時(shí)變得更具表示力看靠、類型化赶促、可擴(kuò)展行。它的目的是變成“通用<code>IR</code>”序列挟炬,在一個(gè)足夠的低級(jí)別上高級(jí)別思維可以清晰地映射到它(類似微處理器都是“通用IR”鸥滨,使得眾多源語言映射到它)。根據(jù)提供類型信息谤祖,<code>LLVM</code>可以作為優(yōu)化的目標(biāo):例如婿滓,通過指針分析證明,<code>C</code>自動(dòng)變量從沒被當(dāng)前函數(shù)以外的外部訪問到粥喜,允許它提升到一個(gè)簡單的<code>SSA</code>值從而代替內(nèi)存地址凸主。

好的規(guī)范

重要的是記錄這個(gè)文檔描述<code>LLVM</code>匯編語言“好的規(guī)范”。這有別于被認(rèn)為是“好格式”解釋概念额湘。例如卿吐,下面描述是語法可接受,但是不是好格式:

<code>
%x = add i32 1, %x
</code>

因?yàn)?lt;code>%x</code>的定義并不支配它所有的使用者锋华。<code>LLVM</code>基礎(chǔ)結(jié)構(gòu)提供了可以用于驗(yàn)證<code>LLVM</code>模塊是否好格式的驗(yàn)證通過(<code>verification pass</code>)嗡官。這個(gè)通過是介于在解釋器解釋輸入?yún)R編和優(yōu)化器輸出位碼之間自動(dòng)運(yùn)行的。這個(gè)驗(yàn)證通過指出違反表明在轉(zhuǎn)換通過或者輸入解釋器中的<code>bug</code>毯焕。

標(biāo)識(shí)符

<code>LLVM</code>標(biāo)識(shí)符有兩種基本類型:全局和局部衍腥。全局標(biāo)識(shí)符(函數(shù)、全局變量)以‘@’字符開始。局部標(biāo)識(shí)符(寄存器名婆咸,類型)以‘%’字符開始竹捉。此外,還有三種用于不同目的的標(biāo)識(shí)符定義:

<pre>
1尚骄,具名值被表示為一個(gè)帶有前綴字符的string块差。例如,%foo倔丈,@DivisionByZero憾儒,%a.really.long.identifier。它的正則表達(dá)式可以描述為‘[%@][-a-zA-Z$._][-a-zA-Z$._0-9]*’乃沙。標(biāo)識(shí)符需要名稱中的其他字符可以使用引號(hào)包圍起趾。特殊字符使用“\xx”可能溢出,警儒,xx是字符十六進(jìn)制ASCII碼轉(zhuǎn)義训裆。這種方式下,任何字符可以在名稱中使用蜀铲,甚至引號(hào)自身边琉。“\01”前綴可以禁止全局變量的名字改編记劝。
2变姨,未具名值使用帶有前綴的無符號(hào)數(shù)值表示。例如厌丑,%12定欧、%2、%44怒竿。
3砍鸠,常量,將會(huì)在接下來的常量章節(jié)詳細(xì)描述耕驰。
</pre>

<code>LLVM</code>需要值以前綴開始的原因有兩點(diǎn):編譯器不需要擔(dān)心名稱會(huì)和保留字沖突爷辱;保留字集在未來可以無危害的擴(kuò)展。此外朦肘,未具名標(biāo)識(shí)符允許編譯器迅速提出臨時(shí)變量饭弓,且避免和符號(hào)表沖突。

<code>LLVM</code>的保留字和其他語言的保留字很相似媒抠。有不同的機(jī)內(nèi)碼(<code>opcode</code>弟断,又可譯為操作碼)的關(guān)鍵字(‘<code>add</code>’,‘<code>bitcast</code>’领舰,‘<code>ret</code>’夫嗓,等等),原始類型名(‘<code>void</code>’, ‘<code>i32</code>’, 等等)冲秽,以及其他舍咖。這些保留字不可能和變量名沖突,因?yàn)樗鼈儾灰?lt;code>‘%’</code>或者<code>‘@’</code>前綴開始锉桑。

下面是<code>LLVM</code>代碼整型變量<code>%x</code>乘以8的例子:

簡單的表示:
<pre>
%result = mul i32 %X, 8
</pre>

強(qiáng)度折減(<code>strength reduction</code>)后:
<pre>
%result = shl i32 %X, 3
</pre>

困難方法:
<pre>
%0 = add i32 %X, %X ; yields i32:%0
%1 = add i32 %0, %0 ; yields i32:%1
%result = add i32 %1, %1
</pre>

<code>%X</code>乘8的最后方式說明了<code>LLVM</code>的幾個(gè)重要的詞法特點(diǎn):

<pre>
1排霉,注釋以‘;’分隔,直到這行結(jié)束民轴。
2攻柠,未具名臨時(shí)變量在計(jì)算結(jié)果不能賦值給一個(gè)具名變量時(shí)候創(chuàng)建。
3后裸,未具名臨時(shí)變量是按照數(shù)字順序來的(使用每個(gè)函數(shù)從0開始的自增長計(jì)數(shù)器)瑰钮。值得注意的是基本塊和未具名函數(shù)參數(shù)被包含在這個(gè)編號(hào)方式中。例如微驶,如果整個(gè)基本塊未被賦予標(biāo)簽名稱浪谴,以及函數(shù)參數(shù)被命名了,它就會(huì)被未具名為數(shù)字0因苹。
</pre>

它也展示了在這個(gè)文檔應(yīng)該遵循一條約定苟耻。當(dāng)演示指令時(shí),我們應(yīng)該在這條指令后面跟進(jìn)定義被生成值的類型和名稱的注釋扶檐。

高級(jí)結(jié)構(gòu)

模塊結(jié)構(gòu)

<code>LLVM</code>程序由<code>Module</code>組成凶杖,每個(gè)都是輸入程序的轉(zhuǎn)換單元。每個(gè)模塊包括函數(shù)款筑,全局變量智蝠,符號(hào)表組成。模塊可能通過<code>LLVM</code>連接器組合在一起奈梳,包括合并方法(和全局變量)的定義寻咒,確定預(yù)聲明,合并符號(hào)表颈嚼。下面是簡單的<code>“hello world”</code>模塊:

<pre>
; Declare the string constant as a global constant.
@.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00"

; External declaration of the puts function
declare i32 @puts(i8* nocapture) nounwind

; Definition of main function
define i32 @main() { ; i32()*
; Convert [13 x i8]* to i8 ...
%cast210 = getelementptr [13 x i8], [13 x i8]
@.str, i64 0, i64 0

; Call puts function to write out the string to stdout.
call i32 @puts(i8* %cast210)
ret i32 0
}

; Named metadata
!0 = !{i32 42, null, !"string"}
!foo = !{!0}
</pre>

這個(gè)例子有一個(gè)全局變量<code>.str</code>毛秘、一個(gè)外部聲明的<code>“puts”</code>函數(shù),一個(gè)函數(shù)定義<code>“main”</code>和具名元數(shù)據(jù)<code>“foo”</code>組成阻课。

通常來講叫挟,一個(gè)模塊有全局值(函數(shù)和全局變量成為全局值)列表組成。全局值通過指針指向內(nèi)存的位置表示(在這個(gè)例子中限煞,一個(gè)指針指向字符數(shù)組抹恳,一個(gè)指向函數(shù)),有下面的鏈接類型署驻。

鏈接類型

所有全局變量和函數(shù)有下面鏈接類型的一種:
<code>private</code>
<pre>
“private”鏈接的全局值僅僅被當(dāng)前模塊中的對象直接訪問到奋献。特別地健霹,使用private全局變量鏈接代碼到一個(gè)模塊在必要情況下為了避免沖突可能會(huì)被重命名。因?yàn)檫@個(gè)符號(hào)對當(dāng)前模塊來說是private瓶蚂,所有引用可能被更新糖埋。這個(gè)不會(huì)再對象文件中展現(xiàn)任何符號(hào)表。
</pre>

<code>internal</code>
<pre>
和private一樣窃这,但是在對象文件中值常被顯示為本地符號(hào)(例如ELF中的STB_LOCAL)瞳别。這對應(yīng)著C語言中的‘static’關(guān)鍵字的概念。
</pre>

<code>available_externally</code>
<pre>
帶有“available_externally”鏈接的全局值相對于LLVM模塊不會(huì)存入對象文件中杭攻。從鏈接器的觀點(diǎn)看祟敛,一個(gè)available_externally全局值等于一個(gè)外部聲明。它們的存在是為了內(nèi)聯(lián)和其他優(yōu)化行為的發(fā)生提供當(dāng)前模塊的一份全局定義兆解,被認(rèn)為在外部模塊的某些地方馆铁。帶有“available_externally”鏈接的全局值允許隨意定義,允許內(nèi)聯(lián)和其他優(yōu)化行為锅睛。這個(gè)鏈接類型僅允許定義叼架,而不能聲明。
</pre>

<code>linkonce</code>
<pre>
帶有“l(fā)inkonce”鏈接的全局值在鏈接過程中與其他同名的全局值合并衣撬。這可能常用于一些內(nèi)聯(lián)函數(shù)乖订、模板或者其他必須在每個(gè)轉(zhuǎn)換單元中生成使用的代碼等形式,但是之后主體可以被一個(gè)更詳細(xì)的定義覆蓋具练。未引用的linkonce全局值允許被丟棄乍构。注意,linkonce鏈接實(shí)際上并不允許優(yōu)化器函數(shù)的函數(shù)體內(nèi)聯(lián)為調(diào)用者扛点,因?yàn)樗恢篮瘮?shù)定義是程序的最終定義或是否將被一個(gè)更明確定義重寫陵究。使用“l(fā)inkonce_odr”鏈接可以內(nèi)聯(lián)和優(yōu)化。
</pre>

<code>weak</code>
<pre>
除了未引用的帶“weak”鏈接標(biāo)識(shí)的全局值可能會(huì)被拋棄外铜邮,“weak”鏈接擁有與“l(fā)inkonce”相同的合并語義。這個(gè)標(biāo)志被使用于在C源代碼中被聲明為“weak”的全局值扔茅。
</pre>

<code>common</code>
<pre>
“common”鏈接類似于“weak”鏈接,但是他們常用于C語言的暫定的變量定義(tentative definitions)秸苗,例如在全局作用域的“int X;”惊楼。帶有“common”鏈接的符號(hào)和“weak”符號(hào)被合并的方式相同,但這些符號(hào)即使未被引用也不會(huì)被刪除璃诀。“common”符號(hào)可能不會(huì)有一個(gè)明確的部分殖演,單必須被初始化為0值趴久,且不可能被標(biāo)志為‘constant’彼棍。函數(shù)和切片不可以帶有“common”鏈接標(biāo)識(shí)座硕。
</pre>

<code>appending</code>
<pre>
“appending”鏈接只能用于數(shù)組類型的全局指針變量涕蜂。但兩個(gè)帶有appending鏈接標(biāo)識(shí)的全局變量被鏈接到一起,這兩個(gè)全局?jǐn)?shù)組追加合并到一起。 當(dāng).o文件鏈接時(shí)旭旭,這是類型安全的LLVM具有系統(tǒng)鏈接器接連接具有相同名稱的“部分”等效持寄。
不幸的是际看,這不能符合.o文件的任何特征仲闽,所以它僅被用于類似llvm.global_ctors這些llvm特別解釋的變量赖欣。
</pre>

<code>extern_weak</code>
<pre>
這個(gè)鏈接標(biāo)識(shí)的語義遵循ELF對象文件模型:除非被鏈接顶吮,否則帶有extern_weak的符號(hào)都是weak的搏恤。如果沒有被鏈接熟空,該符號(hào)會(huì)變?yōu)閚ull而不是未定義引用息罗。
</pre>

<code>linkonce_odr, weak_odr</code>
<pre>
某些語言允許不同的全局值被合并迈喉,例如兩個(gè)具有不同語義的函數(shù)挨摸。其他語言,如C++澈圈,確保只等效的全局值才可以合并(<code>“one definition rule”</code>簡寫為<code>“ODR ”</code>) 瞬女。這些語言可以使用<code>linkonce_odr</code>和<code>weak_odr</code>鏈接標(biāo)識(shí)來表明全局值將只與等效的全局值合并诽偷。這些鏈接標(biāo)識(shí)類型的其他語義與其非<code>ODR</code>版本相同报慕。
</pre>

<code>external</code>
<pre>
如果上述標(biāo)識(shí)符都沒被使用,那么該全局值的是外部可見的蜗顽,這意味著它參與鏈接雇盖,可用于處理外部符號(hào)引用崔挖。
</pre>

一個(gè)函數(shù)聲明擁有除<code>“external”</code>或<code>“extern_weak”</code>以外的鏈接標(biāo)識(shí)是不合法的薛匪。

調(diào)用約定

<code>LLVM</code>的函數(shù)蛋辈、調(diào)用反射全可以有一個(gè)選擇調(diào)用約定指定調(diào)用。每一對動(dòng)態(tài)調(diào)用者/被調(diào)用者的調(diào)用約定必須匹配尊浓,或者程序行為是未定義的。接下來的調(diào)用匹配是<code>LLVM</code>支持的瓦堵,更多的將會(huì)在未來添加:
<code>“ccc”-C語言調(diào)用約定</code>
<pre>
這個(gè)調(diào)用約定(在沒有指定其他調(diào)用約定前提下是默認(rèn)調(diào)用約定)匹配目標(biāo)到C語言調(diào)用約定菇用。這個(gè)調(diào)用約定支持變長參數(shù)函數(shù)調(diào)用并可容忍函數(shù)的聲明和實(shí)現(xiàn)之間存在一些不匹配的地方(像正常的C語言一樣)。
</pre>

<code>“fastcc”-快速調(diào)用約定</code>
<pre>
這個(gè)調(diào)用約定試圖使調(diào)用盡可能地快速(例如通過寄存器傳遞)卦绣。這個(gè)調(diào)用約定允許目標(biāo)使用任何技巧來為其產(chǎn)生快速的代碼滤港,而不要求符合外部指定的ABI(Application Binary Interface)劲藐。尾部調(diào)用只能在GHC或者HiPE規(guī)范時(shí)被使用的時(shí)候優(yōu)化聘芜。這種調(diào)用約定不支持變長參數(shù)汰现,且要求所有被調(diào)用者的原型與函數(shù)定義相匹配瞎饲。
</pre>

<code>“coldcc”-冷調(diào)用約定</code>
<pre>
這種調(diào)用約定試圖使調(diào)用者內(nèi)的代碼在假定這個(gè)調(diào)用不會(huì)被經(jīng)常執(zhí)行的情況下盡可能地高效。像這種情況驮捍,這些調(diào)用通常會(huì)保護(hù)所有寄存器东且,因此這個(gè)調(diào)用不會(huì)破壞任何調(diào)用者內(nèi)的活動(dòng)范圍。這種調(diào)用約定不支持變長參數(shù)色查,且要求所有被調(diào)用者的原型與函數(shù)定義相匹配秧了。更進(jìn)一步地講,內(nèi)聯(lián)器不會(huì)考慮把這種函數(shù)進(jìn)行內(nèi)聯(lián)米罚。
</pre>

<code>“cc 10” - GHC(Glasgow Haskell Compiler)約定</code>
<pre>
這種調(diào)用約定被明確的實(shí)現(xiàn)來用于Glasgow Haskell Compiler (GHC)录择。它傳遞所有東西到寄存器中塘秦,并通過停止被調(diào)用者節(jié)省寄存器來實(shí)現(xiàn)這種極端的方式尊剔。這種調(diào)用約定不應(yīng)該輕輕地使用须误,只能除非像在實(shí)現(xiàn)函數(shù)式編程語言時(shí),一個(gè)可選的the register pinning性能技術(shù)經(jīng)常被使用的情況下祭椰。在目前只有X86支持這種約定切它有以下限制:

  • 在X86-32下只支持長度大于4bit的類型的參數(shù)。不支持浮點(diǎn)型臣淤。
  • 在X86-64下只支持長度大于10bit的類型參數(shù)且只支持6位浮點(diǎn)參數(shù)。
    這種調(diào)用約定支持尾部調(diào)用優(yōu)化 要求調(diào)用者和被調(diào)用者都使用它。
    </pre>

<code>“cc 11” - HiPE調(diào)用約定</code>
<pre>
這種調(diào)用約定被明確實(shí)現(xiàn)來用于High-Performance Erlang (HiPE) 編譯器逮京,Ericsson’s Open Source Erlang/OTP system的本地代碼編譯器懒棉。它比普通C調(diào)用約定使用了更多寄存器實(shí)現(xiàn)實(shí)參傳遞,并且還定義非被調(diào)用者保存寄存器妻导。這個(gè)調(diào)用約定正確地支持尾部調(diào)用優(yōu)化术浪,但調(diào)用者和被調(diào)用者都是用這個(gè)調(diào)用約定胰苏。它使用一個(gè)與GHC約定相似的寄存器釘扎機(jī)制來保持頻繁訪問運(yùn)行時(shí)組件時(shí)候被壓在指定硬件寄存器上的碟联。在目前,只有X86支持這種調(diào)用約定(包括32位和64位)普监。
</pre>

<code>“webkit_jscc”-Webkit的JavaScript調(diào)用約定</code>
<pre>
這個(gè)調(diào)用約定為WebKit FTL JIT實(shí)現(xiàn)。它從右到左向棧傳遞參數(shù)廊散,并返回一個(gè)值到平臺(tái)所定義的返回寄存器中允睹。
</pre>

<code>“anyregcc”-代碼修復(fù)的動(dòng)態(tài)調(diào)用約定</code>
<pre>
這是個(gè)特殊的約定支持修復(fù)任意代碼序列來取代一個(gè)調(diào)用地點(diǎn)。這種調(diào)用約定強(qiáng)制調(diào)用參數(shù)到寄存器中米者,但是允許它們被動(dòng)態(tài)分配。這種調(diào)用約定一般只能被llvm.experimental.patchpoint調(diào)用使用喂分。因?yàn)檫@個(gè)本質(zhì)記錄參數(shù)在表中的位置酸员。詳見Stack maps and patch points in LLVM幔嗦。
</pre>

<code>“preserve_mostcc”-PreserveMost調(diào)用約定</code>
<pre>
這種調(diào)用約定試圖使調(diào)用者中的代碼盡可能地少受干擾。這種調(diào)用約定在如何傳遞參數(shù)與返回值上和C調(diào)用約定是完全一致汇恤,但它使用不同的調(diào)用者保存寄存器和非調(diào)用者保存寄存器。這樣可以減輕在調(diào)用開始和結(jié)束需要保存和恢復(fù)大量寄存器集的負(fù)擔(dān)财岔。如果參數(shù)傳遞到非調(diào)用者保存寄存器,那么它們會(huì)被被調(diào)用者在調(diào)用過程中保護(hù)起來夷恍。它不能提供從非調(diào)用者保存寄存器返回值。
~ 在X86-64中执虹,被調(diào)用者保護(hù)所有除了R11外的普通目的寄存器。R11可能被用作額外備用寄存器(scratch register)。浮點(diǎn)寄存器(XMMs/YMMs)不會(huì)被保護(hù)并且由被調(diào)用者保存蚁鳖。
這種調(diào)用約定背后的想法支持調(diào)用運(yùn)行時(shí)函數(shù)钾腺,而不需要調(diào)來其他函數(shù)放棒。
類似PreserveMost的調(diào)用約定的這個(gè)調(diào)用約定將被用于為了Objective-C運(yùn)行時(shí)的版本,此時(shí)需要考慮實(shí)驗(yàn)性厢破。
</pre>

<code>cxx_fast_tlscc-為訪問函數(shù)的CXX_FAST_TLS調(diào)用約定</code>
<pre>
Clang生成一個(gè)訪問函數(shù)來訪問C++風(fēng)格的TLS。這個(gè)訪問函數(shù)通常有一個(gè)入口塊,一個(gè)出口塊以及一個(gè)初始化塊鳄梅,這樣就第一時(shí)間可以運(yùn)行。入口和出口塊可以訪問少量TLS中間語言變量孙蒙,每個(gè)訪問將低于平臺(tái)特征順序。
這個(gè)調(diào)用約定目標(biāo)是保存盡可能多寄存器的調(diào)用者中實(shí)現(xiàn)最小覆蓋(所有寄存器都是存儲(chǔ)在與入口塊和出口塊組成的快速路勁)坦胶。
這個(gè)調(diào)用約定行為與C調(diào)用約定在參數(shù)和返回值如何傳遞上是一樣,但是它使用了不同調(diào)用者保存寄存器和非調(diào)用者保存寄存器集纪岁。
已知每個(gè)平臺(tái)都有它自己的低序列漩氨,因此它擁有保存寄存器集,我們不能使用存在的PreserveMost赋访。
~在X86-64上蚓耽,被調(diào)用者保存除了RDI和RAX外的所有通用寄目的寄存器。
</pre>

<code>“swiftcc”-用于Swift語言的調(diào)用約定</code>
<pre>
~在X86-64上,RCX和R8都支持額外的整型返回谚咬,XMM2和XMM3都支持額外的浮點(diǎn)/向量返回。
~在iOS平臺(tái)上秉继,使用的是AAPCS-VFP調(diào)用約定尚辑。
</pre>

<code>“cc <n>”-編號(hào)約定</code>
<pre>
任何一個(gè)調(diào)用約定可能有數(shù)字指定,允許使用目標(biāo)明確的調(diào)用約定盔腔。目標(biāo)明確調(diào)用約定是在64位開始的杠茬。
</pre>

更多調(diào)用約定會(huì)以使用為依據(jù)被添加/定義,如支持<code>Pascal</code>約定或者其他知名目的獨(dú)立的約定铲觉。

可見性模式

所有全局變量和函數(shù)有一個(gè)如下的可見性模式:

<code>“default”-默認(rèn)模式</code>
<pre>
在那些使用ELF對象文件格式的目的,默認(rèn)可見性意味著聲明對于其他模塊是可見的撵幽,并且在可共享庫的話意味著這個(gè)聲明的實(shí)體是可被覆蓋的。在Darwin平臺(tái)礁击,默認(rèn)可見性意味著聲明對于其他模塊是可見的盐杂。默認(rèn)可見性與在這種語言中的<code>“external linkage”</code>是一致的逗载。
</pre>

<code>“hidden”-隱藏模式</code>
<pre>
如果一個(gè)帶有隱藏可見性的對象的兩個(gè)聲明處于一個(gè)相同可共享對象,那么它們會(huì)被引用到同一對象链烈。通常來說厉斟,隱藏可見性表明符號(hào)不會(huì)被放置到動(dòng)態(tài)符號(hào)表,因此其他模塊(可執(zhí)行程序或共享庫)不可以直接引用這個(gè)符號(hào)强衡。
</pre>

<code>“protected”-保護(hù)模式</code>
<pre>
在ELF中擦秽,保護(hù)可見性標(biāo)明符號(hào)將會(huì)被防止在動(dòng)態(tài)符號(hào)表中,但是在定義模塊內(nèi)的引用對本地符號(hào)表是捆綁的漩勤。因此符號(hào)是不可被其他模塊覆蓋的感挥。
</pre>

<code>internal</code>和<code>private</code>鏈接的符號(hào)表必須有默認(rèn)可見性。

DLL存儲(chǔ)類別

所有全局變量越败、函數(shù)和別名可以有一個(gè)如下<code>DLL</code>存儲(chǔ)類別:
<code>dllimport</code>
<pre>
“dllimport”會(huì)導(dǎo)致編譯器通過一個(gè)指向到被DLL導(dǎo)出符號(hào)創(chuàng)建的指針的全局指針触幼,來引用一個(gè)函數(shù)或變量。在微軟Windows目標(biāo)究飞,這個(gè)指針名由結(jié)合_imp和函數(shù)或變量的名稱來規(guī)范置谦。
</pre>

<code>dllexport</code>
<pre>
“dllexport”會(huì)導(dǎo)致編譯器提供一個(gè)指向一個(gè)在DLL的指針的全局指針,所以它可以被帶有dllimport的屬性引用到亿傅。在微軟Windows目標(biāo)媒峡,這個(gè)指針名由結(jié)合_imp和函數(shù)或變量的名稱來規(guī)范。為了使編譯器葵擎,匯編器和鏈接器知道某個(gè)符號(hào)是被外部引用并且防止它被刪除丝蹭,這個(gè)存儲(chǔ)類別為了定義一個(gè)dll接口而存在。
</pre>

線程本地存儲(chǔ)模型

一個(gè)變量可能被定義為<code>thread_local</code>坪蚁,這意味著它不會(huì)被線程分享(每個(gè)線程有獨(dú)立的變量拷貝)奔穿。并不是所有目標(biāo)支持線程本地存儲(chǔ)變量。作為一個(gè)選項(xiàng)敏晤,<code>TLS</code>模型可能被指定:
<code>localdynamic</code>
<pre>
標(biāo)識(shí)僅用于當(dāng)前可共享庫的變量
</pre>

<code>initialexec</code>
<pre>
標(biāo)識(shí)在模塊中不會(huì)被動(dòng)態(tài)加載的變量
</pre>

<code>localexec</code>
<pre>
標(biāo)識(shí)只能定義且只能使用在可執(zhí)行程序中的變量
</pre>

如果沒有給于明確類型贱田,<code>“general dynamic”</code>將會(huì)被使用。

這種模型與<code>ELF TLS</code>模型是一致的嘴脾;更多關(guān)于不同模塊可能被使用的情況信息詳見ELF Handling For Thread-Local Storage男摧。如果指定的模型不支持或者有更合適的模型可供選擇,目標(biāo)可能會(huì)選擇不同<code>TLS</code>模型译打。

一個(gè)模型可以在別名中指定耗拓,但是它僅支配別名怎么訪問。它不會(huì)在別名中有實(shí)際效果奏司。

對于鏈接器不支持<code>ELF TLS</code>模型的平臺(tái)乔询,<code>-femulated-tls</code>標(biāo)記可被使用生成<code>GCC</code>兼容的競爭<code>TLS</code>代碼。

結(jié)構(gòu)類型

<code>LLVM</code>的中間語言允許同時(shí)指定<code>“identified”</code>和<code>“l(fā)iteral”</code>結(jié)構(gòu)類型韵洋。文字類型是唯一結(jié)構(gòu)竿刁,但是確定類型永遠(yuǎn)不是唯一的黄锤。一個(gè)不透明結(jié)構(gòu)類型也可以用于直接定義一個(gè)不可使用的類型。

確定結(jié)構(gòu)說明的例子如下:
<pre>
%mytype = type { %mytype*, i32 }
</pre>

在<code>LLVM 3.0</code>發(fā)布版本之前食拜,確定類型是結(jié)構(gòu)唯一的鸵熟。僅文字類型在<code>LLVM</code>最近版本是唯一的。

非整型指針類型

注意:非整型指針類型是在進(jìn)程中執(zhí)行的负甸,它們此時(shí)被認(rèn)為是實(shí)驗(yàn)的流强。

<code>LLVM</code>中間語言選擇允許前端代表在特定地址空間指針通過<code>:ref:datalayout string<langref_datalayout></code>作為<code>“non-integral”</code>。非整型指針類型展示有未指明按位表現(xiàn)的指針呻待,那是整型表現(xiàn)可能目標(biāo)獨(dú)立或者易變的(不被合適整型返回)打月。

<code>inttoptr</code>指令轉(zhuǎn)換整型到非整型指針類型是病態(tài)類型,因此<code>ptrtoint</code>指令轉(zhuǎn)換非整型指針類型值到整型带污。指令中提到的向量版本也是病態(tài)類型僵控。

全局變量

全局變量在編譯期定義存儲(chǔ)分配范圍,而不是運(yùn)行時(shí)鱼冀。

全局變量定義必須被初始化报破。

全局變量在其他的轉(zhuǎn)換單元也可以被聲明,但在這種情況下它們沒有初始化公式。

每個(gè)全局變量的定義或聲明可以有明確部分來放置或者可能有可選明確的隊(duì)列指定。

一個(gè)變量可以被定義為全局長了禁筏,它指明了變量內(nèi)容永遠(yuǎn)不會(huì)被改變(為了更好優(yōu)化,允許全局?jǐn)?shù)據(jù)放置在執(zhí)行塊的只讀部分盹靴,諸如此類)。注意的是需要運(yùn)行時(shí)初始化的變量不可以標(biāo)記<code>constant</code>瑞妇,那只能存儲(chǔ)到變量稿静。

<code>LLVM</code>明確允許全局變量聲明標(biāo)記為常量,甚至全局變量的最終定義不是的辕狰。這個(gè)功能常用于程序輕微更好的優(yōu)化改备,但是這要求語言定義保證基于<code>‘constantness’</code>的優(yōu)化對于不包含這個(gè)定義的編譯單元是有效的。

作為<code>SSA</code>值蔓倍,全局變量定義為指針值悬钳,其作用域(例如它們的影響范圍)是程序中的所有基本塊。全局變量總是定義為一個(gè)其<code>‘content’</code>所對應(yīng)類型的指針偶翅,因?yàn)樗鼈兠枋鲆粋€(gè)存儲(chǔ)范圍默勾,所有這些<code>LLVM</code>中的存儲(chǔ)對象被通過這個(gè)指針訪問。

全局變量可以被<code>unnamed_addr</code>標(biāo)識(shí)聚谁,表明它的地址是沒有意義的母剥,僅僅是指向?qū)?yīng)內(nèi)容。一個(gè)被這樣標(biāo)識(shí)的常量可以被合并到其他擁有相同初始化公式的常量。注意媳搪,一個(gè)地址有意義的常量可以被合并一個(gè)<code>unnamed_addr</code>常量铭段,并且合并結(jié)果是地址有意義的常量骤宣。

如果給于一個(gè)<code>local_unnamed_addr</code>屬性秦爆,在模塊內(nèi)的地址是沒有意義的。

一個(gè)全局變量可能被聲明駐留在一個(gè)目標(biāo)指定的編號(hào)地址空間憔披。對于支持它們的目標(biāo)等限,地址空間會(huì)影響優(yōu)化被怎么執(zhí)行及使用什么指令來訪問變量。默認(rèn)的地址空間是<code>0</code>芬膝。地址空間限定符必須放在其他任何屬性前望门。

LLVM允許一個(gè)明確部分用于指定全局變量。如果目標(biāo)支持它锰霜,它會(huì)發(fā)步全局變量到這個(gè)指定部分筹误。 此外如果目標(biāo)必要支持,全局變量可以存放在此選項(xiàng)允許編譯器以封裝函數(shù)癣缅。

默認(rèn)下厨剪,全局初始化公式通過假設(shè)被定義全局變量優(yōu)化,它們的來自在全局初始化公式開始之前初始值的模塊是不會(huì)被修改友存。對于可能從外部訪問的變量祷膳,包括外部鏈接、或者出現(xiàn)在<code>@llvm.used</code>屡立、或者<code> dllexported</code>變量直晨,這種也是正確的。這種猜想會(huì)被帶有<code>externally_initialized</code>的變量抑制膨俐。

一個(gè)顯式隊(duì)列可能被標(biāo)識(shí)于一個(gè)全局變量勇皇,這個(gè)一定是2的次冪。如果隊(duì)列不存在焚刺,或者隊(duì)列被設(shè)置為0敛摘,那么這個(gè)全局變量的隊(duì)列將會(huì)被目標(biāo)根據(jù)方便性設(shè)置。如果一個(gè)顯式隊(duì)列被標(biāo)識(shí)檩坚,這個(gè)全局變量被迫完全擁有精確隊(duì)列着撩。如果這個(gè)全局變量有一個(gè)被分配到部分,目標(biāo)和優(yōu)化器不會(huì)允許全局變量超過對齊匾委。在這種情況下拖叙,額外的隊(duì)列是顯而易見的:例如,代碼可能猜想全局變量被集中放置到它們的部分中赂乐,并嘗試以數(shù)組形式遍歷它們薯鳍,但隊(duì)列填充會(huì)打破遍歷過程。 最大的隊(duì)列是<code>1 << 29</code>。

全局變量同樣可以擁有一個(gè)<code>DLL</code>存儲(chǔ)類別和可選的附加元數(shù)據(jù)列表挖滤,變量與別名可以有TLS模型崩溪。

語法如下:
<pre>
@<GlobalVarName> = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal]
[(unnamed_addr|local_unnamed_addr)] [AddrSpace]
[ExternallyInitialized]
<global | constant> <Type> [<InitializerConstant>]
[, section "name"] [, comdat [($name)]]
[, align <Alignment>] (, !name !N)*
</pre>

例如,下面定義了在編號(hào)地址空間的全局變量斩松,它有初始化公式伶唯、部分和隊(duì)列:
<pre>
@G = addrspace(5) constant float 1.0, section "foo", align 4
</pre>

下面的例子僅僅聲明了全局變量:
<pre>
@G = external global i32
</pre>

下面的例子定義了一個(gè)帶有<code>initialexec</code>的TLS模型的線程本地全局變量:
<pre>
@G = thread_local(initialexec) global i32 0, align 4
</pre>

函數(shù)

<code>LLVM</code>函數(shù)定義由<code>“define”</code>關(guān)鍵字,一個(gè)可選的鏈接標(biāo)識(shí)惧盹,一個(gè)可選的可見性模式乳幸,一個(gè)可選的DLL存儲(chǔ)類別,一個(gè)可選的調(diào)用約定钧椰,一個(gè)可選的<code>unnamed_addr</code>屬性粹断,一個(gè)返回值類型,一個(gè)可選的返回值類型的參數(shù)屬性嫡霞,一個(gè)函數(shù)名瓶埋,一個(gè)(可能為空的)參數(shù)列表(每一個(gè)都帶有可選的參數(shù)屬性),可選的函數(shù)屬性诊沪,一個(gè)可選的部分养筒,一個(gè)可選的隊(duì)列,一個(gè)可選的此選項(xiàng)允許編譯器以封裝函數(shù)娄徊,一個(gè)可選垃圾回收期的名稱闽颇,一個(gè)可選的前綴,一個(gè)序言寄锐,一個(gè)可選的特征兵多,一個(gè)可選附加元數(shù)據(jù)列表,一個(gè)左括號(hào)橄仆,一個(gè)基本塊列表和一個(gè)右括號(hào)剩膘。

<code>LLVM</code>函數(shù)聲明由<code>“declare”</code>關(guān)鍵字,一個(gè)可選的鏈接標(biāo)識(shí)盆顾,一個(gè)可選的可見性模式怠褐,一個(gè)可選的DLL存儲(chǔ)類別,一個(gè)可選的調(diào)用約定您宪,一個(gè)可選的<code>unnamed_addr</code>屬性奈懒,一個(gè)返回值類型,一個(gè)可選的返回值類型的參數(shù)屬性宪巨,一個(gè)函數(shù)名磷杏,一個(gè)可能為空的參數(shù)列表,一個(gè)可選的隊(duì)列捏卓,一個(gè)可選垃圾回收器名稱极祸,一個(gè)可選的前綴和一個(gè)可選的序言。

一個(gè)函數(shù)定義包含一個(gè)基本塊的列表,可以為函數(shù)形成<code>CFG</code>(控制流圖形)遥金。每一個(gè)基本塊可選的開始于一個(gè)標(biāo)簽(給定這個(gè)基本塊一個(gè)符號(hào)表入口)浴捆,包含一個(gè)指令列表,并且以一個(gè)終止指令(例如分支或函數(shù)返回)結(jié)束稿械。如果一個(gè)明確標(biāo)簽不被提供选泻,一個(gè)塊會(huì)分配到一個(gè)隱式編號(hào)標(biāo)簽,使用與匿名臨時(shí)變量使用同一個(gè)計(jì)數(shù)器的下一個(gè)值溜哮。例如滔金,如果一個(gè)函數(shù)入口塊不具有一個(gè)顯示標(biāo)簽色解,他會(huì)被分配到一個(gè)標(biāo)簽<code>“%0”</code>茂嗓,然后第一個(gè)在這個(gè)塊中的匿名臨時(shí)變量將會(huì)是<code>“%1”</code>,諸如此類科阎。

函數(shù)中的第一基本塊特殊在兩個(gè)方面:它是在函數(shù)進(jìn)入后馬上執(zhí)行的述吸,并且它是不允許有前置基本塊(即函數(shù)入口塊不能擁有任何分支)。因?yàn)檫@個(gè)塊沒有前置塊锣笨,所以也不能有任何<code>PHI</code>節(jié)點(diǎn)蝌矛。

<code>LLVM</code>允許函數(shù)指定一個(gè)明確部分。如果目標(biāo)支持它错英,它會(huì)放步函數(shù)到這個(gè)指定塊入撒。此外,函數(shù)可以被放置在<code>COMDAT</code>椭岩。

一個(gè)顯示隊(duì)列可能會(huì)被指定到一個(gè)函數(shù)茅逮。如果沒有展示,或者隊(duì)列被設(shè)置為<code>0</code>判哥,那么這個(gè)函數(shù)的隊(duì)列將會(huì)根據(jù)目標(biāo)的方便設(shè)定献雅。如果一個(gè)顯式隊(duì)列被指定,這個(gè)函數(shù)被迫至少想指定的那么多隊(duì)列塌计。所有隊(duì)列必須為2的次冪挺身。

如果<code>unnamed_addr</code>屬性被給于,函數(shù)地址會(huì)被認(rèn)為是沒有意義锌仅,并且兩個(gè)相同的函數(shù)之間可以被合并章钾。

如果<code>local_unnamed_addr</code>屬性被給于,地址將會(huì)在模塊內(nèi)沒有意義热芹。

語法:
<pre>
define [linkage] [visibility] [DLLStorageClass]
[cconv] [ret attrs]
<ResultType> @<FunctionName> ([argument list])
[(unnamed_addr|local_unnamed_addr)] [fn Attrs] [section "name"]
[comdat [($name)]] [align N] [gc] [prefix Constant]
[prologue Constant] [personality Constant] (!name !N)* { ... }
</pre>

參數(shù)列表是逗號(hào)分隔參數(shù)序列贱傀,每個(gè)參數(shù)如下形式所示:

語法:
<pre>
<type> [parameter Attrs] [name]
</pre>

別名

別名和函數(shù)活變量不同,不產(chǎn)生任何新的數(shù)據(jù)剿吻。它僅僅是已存在位置的一個(gè)新的符號(hào)和元數(shù)據(jù)窍箍。

別名有一個(gè)名稱和一個(gè)別名,不管是全局變量還是常量表達(dá)式。

別名可以擁有一個(gè)可選的鏈接標(biāo)識(shí)椰棘,一個(gè)可選的可見性模式纺棺,一個(gè)可選的DLL存儲(chǔ)類別和一個(gè)可選的tls模型

語法:
<pre>
@<Name> = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] [(unnamed_addr|local_unnamed_addr)] alias <AliaseeTy>, <AliaseeTy>* @<Aliasee>
</pre>

鏈接標(biāo)識(shí)必須是<code>private</code>邪狞,<code>linker_private</code>祷蝌,<code>linker_private_weak</code>,<code>internal</code>帆卓,<code>linkonce</code>巨朦,<code>weak</code>,<code>linkonce_odr</code>剑令,<code>weak_odr</code>糊啡,<code>external</code>中的一個(gè)。注意一些系統(tǒng)鏈接器可能會(huì)不正確地處理一個(gè)降級(jí)弱符號(hào)作為非別名吁津。

非<code>unnamed_addr</code>的別名被別名表達(dá)式的同樣地址保護(hù)棚蓄。<code>unnamed_addr</code>僅僅保護(hù)指向同樣的內(nèi)容。

如果<code>local_unnamed_addr</code>屬性被給于碍脏,地址將會(huì)在模塊內(nèi)沒有意義梭依。

因此別名僅僅是第二名稱,一些在產(chǎn)生對象文件是僅被檢查的約束提供:

~表達(dá)式定義別名必須在組裝時(shí)間可計(jì)算典尾。因此它僅僅是個(gè)名稱役拴,沒有重定位被使用。
~表達(dá)式中沒有別名可以弱化中間別名被覆蓋而不展示在對象文件中的可能性钾埂。
~表達(dá)式中沒有全局值可以聲明河闰,因此需要一個(gè)重定位,但是不是可能的勃教。

IFuncs

<code>IFuncs</code>和別名一樣淤击,不產(chǎn)生任何新的數(shù)據(jù)或函數(shù)。它們僅僅一個(gè)動(dòng)態(tài)鏈器調(diào)用一個(gè)解析函數(shù)在運(yùn)行時(shí)解析(resolves)的新符號(hào)故源。

<code>IFuncs</code>有一個(gè)名字和一個(gè)通過動(dòng)態(tài)鏈接器返回另外一個(gè)函數(shù)地址獲得的相關(guān)名稱的函數(shù)調(diào)用解析器污抬。

<code>IFuncs</code>有一個(gè)可選的鏈接類型和一個(gè)可選的可視性模型。

語法:
<pre>
@<Name> = [Linkage] [Visibility] ifunc <IFuncTy>, <ResolverTy>* @<Resolver>
</pre>

此選項(xiàng)允許編譯器以封裝函數(shù)

此選項(xiàng)允許編譯器以封裝函數(shù)的中間語言提供了進(jìn)入<code>COFF</code>和<code>ELF</code>對象文件的<code>COMDAT</code>功能性绳军。

<code>Comdat</code>有個(gè)展示<code>COMDAT key</code>的名稱印机。如果鏈接器選擇用<code>key</code>覆蓋其他的,所有指定<code>key</code>的全局對象將會(huì)在最終對象中結(jié)束门驾。如果真有的話射赛,別名放置在和需要計(jì)算別名的<code>COMDAT</code>一樣的位置。

語法:
<pre>
$<Name> = comdat SelectionKind
</pre>

這種選擇必須是下面的一種:
<code>any</code>
<pre>
鏈接器可能選擇任意<code>COMDAT key</code>奶是,這個(gè)選擇是隨意的楣责。
</pre>

<code>exactmatch</code>
<pre>
這個(gè)鏈接器可能選擇任意<code>COMDAT key</code>竣灌,但是選擇部分必須包含同樣的數(shù)據(jù)。
</pre>

<code>largest</code>
<pre>
這個(gè)鏈接器將會(huì)選擇包含最大<code>COMDAT key</code>部分秆麸。
</pre>

<code>noduplicates</code>
<pre>
這個(gè)鏈接器需要這個(gè)<code>COMDAT key</code>存在的唯一部分初嘹。
</pre>

<code>samesize</code>
<pre>
這個(gè)鏈接器可能選擇任意<code>COMDAT key</code>,但是部分必須包含相同數(shù)量的數(shù)據(jù)沮趣。
</pre>

注意屯烦,<code>Mach-O</code>平臺(tái)不支持<code>COMDAT</code>,ELF僅支持<code>any</code>作為選項(xiàng)房铭。

下面是一個(gè)如果<code>COMDAT key</code>部分是最大的驻龟,函數(shù)僅將被選擇的COMDAT組例子:

<pre>
$foo = comdat largest
@foo = global i32 2, comdat($foo)

define void @bar() comdat($foo) {
ret void
}
</pre>

作為一個(gè)語法糖,<code>$name</code>如果和全局名稱一致將會(huì)被遺漏:
<pre>
$foo = comdat any
@foo = global i32 2, comdat
</pre>

在COFF對象文件中缸匪,這將創(chuàng)建一個(gè)包含@foo符號(hào)內(nèi)容的IMAGE_COMDAT_SELECT_LARGEST選擇類型的COMDAT部分和另一個(gè)與COMDAT第一部分和包含@bar符號(hào)內(nèi)容相關(guān)的IMAGE_COMDAT_SELECT_ASSOCIATIVE選擇類型的COMDAT部分翁狐。

全局對象屬性有一定的限制。當(dāng)針對COFF時(shí)候豪嗽,它谴蔑,或別名,必須有和COMDAT組一樣的名稱龟梦。這個(gè)對象的內(nèi)容和大小可能在鏈接時(shí)根據(jù)選擇類型決定選擇COMDAT組。因?yàn)閷ο竺Q必須與COMDAT組名稱匹配窃躲,全局對象的鏈接器不能是局部的计贰;如果局部符號(hào)在符號(hào)表與其他的沖突了可以修改名稱。

COMDAT和部分屬性的結(jié)合使用可以產(chǎn)生令人驚訝的結(jié)果蒂窒。例如:
<pre>
$foo = comdat any
$bar = comdat any
@g1 = global i32 42, section "sec", comdat($foo)
@g2 = global i32 42, section "sec", comdat($bar)
</pre>

根據(jù)對象文件觀點(diǎn)躁倒,這需要?jiǎng)?chuàng)建具有相同名稱的兩個(gè)部分。在對象文件層次洒琢,因?yàn)閷儆诓煌腃OMDAT組和COMDAT的全局通過部分表現(xiàn)秧秉,所以這是必要的。

注意衰抑,特定中間語言構(gòu)造全局變量和函數(shù)可以在除了任何使用COMDAT中間語言指定的對象文件創(chuàng)建COMDAT象迎。這是當(dāng)代碼生成器被配置為在個(gè)別部分發(fā)出全局(比如-data-sections或者-function-sections支持llc)。

具名元數(shù)據(jù)

具名元數(shù)據(jù)是一個(gè)元數(shù)據(jù)的集合呛踊。元數(shù)據(jù)節(jié)點(diǎn)(但非元數(shù)據(jù)字符串)是唯一對于具名元數(shù)據(jù)有效的操作數(shù)砾淌。
<pre>
1.具名元數(shù)據(jù)被表示為一個(gè)帶有元數(shù)據(jù)前綴的字符串。元數(shù)據(jù)名稱的規(guī)則與標(biāo)識(shí)符相同谭网,但不允許引用名稱汪厨。“\xx”類型的反斜杠仍然有效愉择,它允許任何字符成為名稱的一部分劫乱。
</pre>

語法:
<pre>
; Some unnamed metadata nodes, which are referenced by the named metadata.
!0 = !{!"zero"}
!1 = !{!"one"}
!2 = !{!"two"}
; A named metadata.
!name = !{!0, !1, !2}
</pre>

參數(shù)屬性

返回類型和每一個(gè)函數(shù)的參數(shù)類型可能擁有一個(gè)參數(shù)屬性集织中。參數(shù)屬性是用于交流函數(shù)返回值和參數(shù)的額外信息≈愿辏可以認(rèn)為參數(shù)類型是函數(shù)的一部分抠璃,但不是函數(shù)類型的一部分,因此用不同參數(shù)屬性的函數(shù)可以擁有相同的函數(shù)類型脱惰。

參數(shù)屬性是跟隨指定類型后的簡單關(guān)鍵字搏嗡。如果需要多個(gè)參數(shù)屬性,它們需要被空白符分隔開拉一。下面是詳細(xì)例子:
<pre>
declare i32 @printf(i8* noalias nocapture, ...)
declare i32 @atoi(i8 zeroext)
declare signext i8 @returns_signed_char()
</pre>

注意采盒,任何對于函數(shù)結(jié)果(nounwind, readonly)的屬性跟隨在參數(shù)列表后。

當(dāng)前僅定義了以下的參數(shù)屬性:

<code>zeroext</code>
<pre>
這表明了在代碼生成器時(shí)蔚润,參數(shù)或返回值應(yīng)該被擴(kuò)充零到通過調(diào)用者(參數(shù)長度)和被調(diào)用者(返回值值)得到目標(biāo)ABI磅氨。
</pre>

<code>signext</code>
<pre>
這表明在代碼生成器時(shí),參數(shù)或返回值應(yīng)該被符號(hào)擴(kuò)展到通過調(diào)用者(參數(shù)長度)和被調(diào)用者(返回值值)得到目標(biāo)ABI(一般來說是32位)嫡纠。
</pre>

<code>inreg</code>
<pre>
這表明參數(shù)和返回值在函數(shù)調(diào)用的發(fā)散代碼或返回值的期間被一個(gè)特定目標(biāo)獨(dú)立方法處理(通常來說烦租,把它們放到寄存器而不是放到內(nèi)存中,即使一些目標(biāo)使用它來區(qū)分兩種不同的寄存器)除盏。這個(gè)屬性的使用的針對指定目標(biāo)的叉橱。
</pre>

<code>byval</code>
<pre>
這表明指針參數(shù)應(yīng)該通過值方式傳遞給函數(shù)。這個(gè)屬性包含了指針隱藏復(fù)制在調(diào)用者和被調(diào)用者之間者蠕,因此使被調(diào)用者不能修改在調(diào)用者值窃祝。這個(gè)屬性僅在LLVM指針參數(shù)里是有效的。這通常用于傳遞值的結(jié)構(gòu)體和數(shù)組踱侣,但這對于數(shù)量指針也是有效的粪小。 這個(gè)復(fù)制被認(rèn)為是從屬于調(diào)用者而不是被調(diào)用者的(例如,readonly函數(shù)不應(yīng)該寫一個(gè)byval 的參數(shù))抡句。這個(gè)屬性對于返回值是無效的探膊。

byval屬性也支持指定隊(duì)列屬性。這指明了棧槽格式和指定調(diào)用地點(diǎn)的指針隊(duì)列屬性待榔。如果隊(duì)列屬性不被指定的話逞壁,代碼生成器會(huì)做一個(gè)目標(biāo)相關(guān)的猜測。
</pre>

<code>inalloca</code>
<pre>
inalloca參數(shù)屬性允許調(diào)用者帶有即將離開棧參數(shù)地址究抓。一個(gè)inalloca參數(shù)必須是一個(gè)使用 alloca 指令創(chuàng)建指向棧內(nèi)存地址的指針猾担。這個(gè)分配的堆棧空間或參數(shù)分配必須也以inalloca關(guān)鍵字標(biāo)識(shí)刺下。只有最后的參數(shù)可以使用inalloca屬性绑嘹,并且這個(gè)參數(shù)保證必須在內(nèi)存中傳遞。

一個(gè)參數(shù)分配可能被函數(shù)調(diào)用至少一次因?yàn)檫@個(gè)調(diào)用可能會(huì)釋放它橘茉。這個(gè)inalloca屬性不可能與其他會(huì)影響參數(shù)存儲(chǔ)的屬性結(jié)合使用工腋,例如inreg姨丈,nest,sret擅腰,和byval蟋恬。這個(gè)inalloca屬性也禁止LLVM隱式降低大量聚合返回值,這意味著前端發(fā)起者必須通過sret指針降低它們趁冈。

當(dāng)?shù)竭_(dá)調(diào)用地點(diǎn)時(shí)歼争,參數(shù)分配必須是仍然存活的最新棧分配,或者結(jié)果是未定義的渗勘。在一個(gè)參數(shù)分配后和這個(gè)實(shí)參的調(diào)用地點(diǎn)前額外分配堆椼迦蓿空間是可能的,但這必須清除llvm.stackrestore旺坠。
更多關(guān)于這個(gè)屬性的使用乔遮,詳見Design and Usage of the InAlloca Attribute
</pre>

<code>sret</code>
<pre>
這表明這個(gè)指針參數(shù)指向一個(gè)在源程序中作為函數(shù)返回值的結(jié)構(gòu)體地址。這個(gè)指針必須由調(diào)用者保證是有效的:這個(gè)結(jié)構(gòu)的加載和存儲(chǔ)必須與被調(diào)用者所假定是一致的取刃。這只適用于第一個(gè)參數(shù)蹋肮。這對于返回值并不是一個(gè)有效的屬性。
</pre>

<code>align<n></code>
<pre>
這表明可以由優(yōu)化器假定指針值具有指定隊(duì)列璧疗。
注意當(dāng)結(jié)合byval屬性時(shí)坯辩,這個(gè)屬性有額外的語義。
</pre>

<code>noalias</code>
<pre>
這表明在執(zhí)行函數(shù)時(shí)病毡,通過基于參數(shù)或者返回值的指針值傳遞的訪問對象是不可訪問的濒翻,傳遞的指針值沒有基于參數(shù)或者返回值。返回值的屬性還有額外的語義描述啦膜。調(diào)用者與被調(diào)用者分享責(zé)任確保那些需求匹配。關(guān)于NoAlias的更多信息可以詳見alias analysis淌喻。

注意noalias的定義故意定義得與C99中的函數(shù)實(shí)參的restrict定義相似僧家,盡管restrict的定義稍微弱一些。

因?yàn)閷τ诤瘮?shù)返回至裸删,C99的restrict是無意義的八拱,而LLVM的noalias是有意義的。此外涯塔,noalias返回值的屬性語義比使用函數(shù)參數(shù)的屬性語義強(qiáng)肌稻。在函數(shù)返回值上,noalias屬性標(biāo)明該函數(shù)的行為像一個(gè)系統(tǒng)的內(nèi)存分配函數(shù)匕荸,返回一個(gè)指針分配存儲(chǔ)不相交的可以訪問其他任何對象的調(diào)用者爹谭。
</pre>

<code>nocapture</code>
<pre>
這表明被調(diào)用者不對生存期比被調(diào)用者長的指針做出任何復(fù)制。對于返回值這不是一個(gè)有效的屬性榛搔。

用于在易變操作中使用的地址認(rèn)為是可被捕獲的诺凡。
</pre>

<code>nest</code>
<pre>
這表明指針參數(shù)可以使用彈性內(nèi)聯(lián)函數(shù)刪除东揣。這不是一個(gè)有效的返回值屬性,只能被應(yīng)用于一個(gè)參數(shù)腹泌。
</pre>

<code>returned</code>
<pre>
這表明函數(shù)始終返回這個(gè)參數(shù)作為它的返回值嘶卧。在生成調(diào)用者時(shí)使用優(yōu)化器和代碼生成器生成一個(gè)提示,允許尾部調(diào)用優(yōu)化和在某種情況下忽略寄存器的保存和恢復(fù)凉袱;在省城被調(diào)用者是芥吟,它不會(huì)被檢查或執(zhí)行。參數(shù)和函數(shù)返回類型必須是對于bitcast指令有效的操作數(shù)专甩。這不是一個(gè)有效的返回值屬性,只能應(yīng)用于一個(gè)參數(shù)钟鸵。
</pre>

PS,未完待續(xù)...

本文轉(zhuǎn)載請注明原作者呆萌院長配深,如果你對這篇文章有更好的見解可以通過微信聯(lián)系我携添。利益相關(guān):本篇文章所有涉及到的軟件均為筆者日常所用工具,無任何廣告費(fèi)用篓叶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末烈掠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缸托,更是在濱河造成了極大的恐慌左敌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俐镐,死亡現(xiàn)場離奇詭異矫限,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)佩抹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門叼风,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人棍苹,你說我怎么就攤上這事无宿。” “怎么了枢里?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵孽鸡,是天一觀的道長。 經(jīng)常有香客問我栏豺,道長彬碱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任奥洼,我火速辦了婚禮巷疼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘溉卓。我一直安慰自己皮迟,他們只是感情好搬泥,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伏尼,像睡著了一般忿檩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上爆阶,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天燥透,我揣著相機(jī)與錄音,去河邊找鬼辨图。 笑死班套,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的故河。 我是一名探鬼主播吱韭,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鱼的!你這毒婦竟也來了理盆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤凑阶,失蹤者是張志新(化名)和其女友劉穎猿规,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宙橱,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姨俩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了师郑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片环葵。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宝冕,靈堂內(nèi)的尸體忽然破棺而出积担,到底是詐尸還是另有隱情,我是刑警寧澤猬仁,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站先誉,受9級(jí)特大地震影響湿刽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褐耳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一诈闺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铃芦,春花似錦雅镊、人聲如沸襟雷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耸弄。三九已至,卻和暖如春卓缰,著一層夾襖步出監(jiān)牢的瞬間计呈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來泰國打工征唬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捌显,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓总寒,卻偏偏與公主長得像扶歪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子摄闸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 原文地址:C語言函數(shù)調(diào)用棧(一)C語言函數(shù)調(diào)用棧(二) 0 引言 程序的執(zhí)行過程可看作連續(xù)的函數(shù)調(diào)用善镰。當(dāng)一個(gè)函數(shù)執(zhí)...
    小豬啊嗚閱讀 4,624評(píng)論 1 19
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)贪薪,斷路器媳禁,智...
    卡卡羅2017閱讀 134,693評(píng)論 18 139
  • 前言 2000年,伊利諾伊大學(xué)厄巴納-香檳分校(University of Illinois at Urbana-...
    星光社的戴銘閱讀 15,905評(píng)論 8 180
  • 現(xiàn)在的女人即便在月經(jīng)期間,做任何事情都是一種毫無禁忌,殊不知些這些事情正危害女人月經(jīng)來潮的健康狀態(tài)!下面伊凡就告訴...
    伊凡講師閱讀 551評(píng)論 4 2
  • 余于庚寅年八月廿九日攜友曾游越秀山鎮(zhèn)海樓画切,因先賢元孝題有“五嶺北來峰在地竣稽,九州南盡水浮天”句,感慨不已霍弹,苦無佳句毫别,...
    摩訶摩瑜利閱讀 385評(píng)論 0 0