LLVM語(yǔ)言參考手冊(cè)

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

摘要

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

介紹

<code>LLVM</code>代碼表示常設(shè)計(jì)以下三種情況:作為在內(nèi)存中的編譯器中間語(yǔ)言(<code>Intermediate Representation</code>,簡(jiǎn)稱<code>IR</code>),作為在硬盤上的位碼表示(適合<code>JIT</code>編譯器快速加載),作為適合人類閱讀的匯編語(yǔ)言表示。它允許<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”,使得眾多源語(yǔ)言映射到它)。根據(jù)提供類型信息,<code>LLVM</code>可以作為優(yōu)化的目標(biāo):例如,通過(guò)指針分析證明,<code>C</code>自動(dòng)變量從沒被當(dāng)前函數(shù)以外的外部訪問(wèn)到,允許它提升到一個(gè)簡(jiǎn)單的<code>SSA</code>值從而代替內(nèi)存地址。

好的規(guī)范

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

<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)證通過(guò)(<code>verification pass</code>)。這個(gè)通過(guò)是介于在解釋器解釋輸入?yún)R編和優(yōu)化器輸出位碼之間自動(dòng)運(yùn)行的。這個(gè)驗(yàn)證通過(guò)指出違反表明在轉(zhuǎn)換通過(guò)或者輸入解釋器中的<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,未具名值使用帶有前綴的無(wú)符號(hào)數(shù)值表示。例如,%12、%2、%44。
3,常量,將會(huì)在接下來(lái)的常量章節(jié)詳細(xì)描述。
</pre>

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

<code>LLVM</code>的保留字和其他語(yǔ)言的保留字很相似。有不同的機(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的例子:

簡(jiǎn)單的表示:
<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的最后方式說(shuō)明了<code>LLVM</code>的幾個(gè)重要的詞法特點(diǎn):

<pre>
1,注釋以‘;’分隔,直到這行結(jié)束。
2,未具名臨時(shí)變量在計(jì)算結(jié)果不能賦值給一個(gè)具名變量時(shí)候創(chuàng)建。
3,未具名臨時(shí)變量是按照數(shù)字順序來(lái)的(使用每個(gè)函數(shù)從0開始的自增長(zhǎng)計(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)表組成。模塊可能通過(guò)<code>LLVM</code>連接器組合在一起,包括合并方法(和全局變量)的定義,確定預(yù)聲明,合并符號(hào)表。下面是簡(jiǎn)單的<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>組成。

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

鏈接類型

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

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

<code>available_externally</code>
<pre>
帶有“available_externally”鏈接的全局值相對(duì)于LLVM模塊不會(huì)存入對(duì)象文件中。從鏈接器的觀點(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”鏈接的全局值在鏈接過(guò)程中與其他同名的全局值合并。這可能常用于一些內(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”相同的合并語(yǔ)義。這個(gè)標(biāo)志被使用于在C源代碼中被聲明為“weak”的全局值。
</pre>

<code>common</code>
<pre>
“common”鏈接類似于“weak”鏈接,但是他們常用于C語(yǔ)言的暫定的變量定義(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í)的語(yǔ)義遵循ELF對(duì)象文件模型:除非被鏈接,否則帶有extern_weak的符號(hào)都是weak的。如果沒有被鏈接,該符號(hào)會(huì)變?yōu)閚ull而不是未定義引用。
</pre>

<code>linkonce_odr, weak_odr</code>
<pre>
某些語(yǔ)言允許不同的全局值被合并,例如兩個(gè)具有不同語(yǔ)義的函數(shù)。其他語(yǔ)言,如C++,確保只等效的全局值才可以合并(<code>“one definition rule”</code>簡(jiǎn)寫為<code>“ODR ”</code>) 。這些語(yǔ)言可以使用<code>linkonce_odr</code>和<code>weak_odr</code>鏈接標(biāo)識(shí)來(lái)表明全局值將只與等效的全局值合并。這些鏈接標(biāo)識(shí)類型的其他語(yǔ)義與其非<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)用。每一對(duì)動(dòng)態(tài)調(diào)用者/被調(diào)用者的調(diào)用約定必須匹配,或者程序行為是未定義的。接下來(lái)的調(diào)用匹配是<code>LLVM</code>支持的,更多的將會(huì)在未來(lái)添加:
<code>“ccc”-C語(yǔ)言調(diào)用約定</code>
<pre>
這個(gè)調(diào)用約定(在沒有指定其他調(diào)用約定前提下是默認(rèn)調(diào)用約定)匹配目標(biāo)到C語(yǔ)言調(diào)用約定。這個(gè)調(diào)用約定支持變長(zhǎng)參數(shù)函數(shù)調(diào)用并可容忍函數(shù)的聲明和實(shí)現(xiàn)之間存在一些不匹配的地方(像正常的C語(yǔ)言一樣)。
</pre>

<code>“fastcc”-快速調(diào)用約定</code>
<pre>
這個(gè)調(diào)用約定試圖使調(diào)用盡可能地快速(例如通過(guò)寄存器傳遞)。這個(gè)調(diào)用約定允許目標(biāo)使用任何技巧來(lái)為其產(chǎn)生快速的代碼,而不要求符合外部指定的ABI(Application Binary Interface)。尾部調(diào)用只能在GHC或者HiPE規(guī)范時(shí)被使用的時(shí)候優(yōu)化。這種調(diào)用約定不支持變長(zhǎng)參數(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)用約定不支持變長(zhǎng)參數(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)來(lái)用于Glasgow Haskell Compiler (GHC)。它傳遞所有東西到寄存器中,并通過(guò)停止被調(diào)用者節(jié)省寄存器來(lái)實(shí)現(xiàn)這種極端的方式。這種調(diào)用約定不應(yīng)該輕輕地使用,只能除非像在實(shí)現(xiàn)函數(shù)式編程語(yǔ)言時(shí),一個(gè)可選的the register pinning性能技術(shù)經(jīng)常被使用的情況下。在目前只有X86支持這種約定切它有以下限制:

  • 在X86-32下只支持長(zhǎng)度大于4bit的類型的參數(shù)。不支持浮點(diǎn)型。
  • 在X86-64下只支持長(zhǎng)度大于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)來(lái)用于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ī)制來(lái)保持頻繁訪問(wèn)運(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ù)任意代碼序列來(lái)取代一個(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)用過(guò)程中保護(hù)起來(lái)。它不能提供從非調(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)來(lái)其他函數(shù)。
類似PreserveMost的調(diào)用約定的這個(gè)調(diào)用約定將被用于為了Objective-C運(yùn)行時(shí)的版本,此時(shí)需要考慮實(shí)驗(yàn)性。
</pre>

<code>cxx_fast_tlscc-為訪問(wèn)函數(shù)的CXX_FAST_TLS調(diào)用約定</code>
<pre>
Clang生成一個(gè)訪問(wèn)函數(shù)來(lái)訪問(wèn)C++風(fēng)格的TLS。這個(gè)訪問(wèn)函數(shù)通常有一個(gè)入口塊,一個(gè)出口塊以及一個(gè)初始化塊,這樣就第一時(shí)間可以運(yùn)行。入口和出口塊可以訪問(wèn)少量TLS中間語(yǔ)言變量,每個(gè)訪問(wèn)將低于平臺(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語(yǔ)言的調(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對(duì)象文件格式的目的,默認(rèn)可見性意味著聲明對(duì)于其他模塊是可見的,并且在可共享庫(kù)的話意味著這個(gè)聲明的實(shí)體是可被覆蓋的。在Darwin平臺(tái),默認(rèn)可見性意味著聲明對(duì)于其他模塊是可見的。默認(rèn)可見性與在這種語(yǔ)言中的<code>“external linkage”</code>是一致的。
</pre>

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

<code>“protected”-保護(hù)模式</code>
<pre>
在ELF中,保護(hù)可見性標(biāo)明符號(hào)將會(huì)被防止在動(dòng)態(tài)符號(hào)表中,但是在定義模塊內(nèi)的引用對(duì)本地符號(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)致編譯器通過(guò)一個(gè)指向到被DLL導(dǎo)出符號(hào)創(chuàng)建的指針的全局指針,來(lái)引用一個(gè)函數(shù)或變量。在微軟Windows目標(biāo),這個(gè)指針名由結(jié)合_imp和函數(shù)或變量的名稱來(lái)規(guī)范。
</pre>

<code>dllexport</code>
<pre>
“dllexport”會(huì)導(dǎo)致編譯器提供一個(gè)指向一個(gè)在DLL的指針的全局指針,所以它可以被帶有dllimport的屬性引用到。在微軟Windows目標(biāo),這個(gè)指針名由結(jié)合_imp和函數(shù)或變量的名稱來(lái)規(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)前可共享庫(kù)的變量
</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è)模型可以在別名中指定,但是它僅支配別名怎么訪問(wèn)。它不會(huì)在別名中有實(shí)際效果。

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

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

<code>LLVM</code>的中間語(yǔ)言允許同時(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)說(shuō)明的例子如下:
<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>中間語(yǔ)言選擇允許前端代表在特定地址空間指針通過(guò)<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è)全局變量的定義或聲明可以有明確部分來(lái)放置或者可能有可選明確的隊(duì)列指定。

一個(gè)變量可以被定義為全局長(zhǎng)了,它指明了變量?jī)?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)化,但是這要求語(yǔ)言定義保證基于<code>‘constantness’</code>的優(yōu)化對(duì)于不包含這個(gè)定義的編譯單元是有效的。

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

全局變量可以被<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)地址空間。對(duì)于支持它們的目標(biāo),地址空間會(huì)影響優(yōu)化被怎么執(zhí)行及使用什么指令來(lái)訪問(wèn)變量。默認(rèn)的地址空間是<code>0</code>。地址空間限定符必須放在其他任何屬性前。

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

默認(rèn)下,全局初始化公式通過(guò)假設(shè)被定義全局變量?jī)?yōu)化,它們的來(lái)自在全局初始化公式開始之前初始值的模塊是不會(huì)被修改。對(duì)于可能從外部訪問(wèn)的變量,包括外部鏈接、或者出現(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ì)允許全局變量超過(guò)對(duì)齊。在這種情況下,額外的隊(duì)列是顯而易見的:例如,代碼可能猜想全局變量被集中放置到它們的部分中,并嘗試以數(shù)組形式遍歷它們,但隊(duì)列填充會(huì)打破遍歷過(guò)程。 最大的隊(duì)列是<code>1 << 29</code>。

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

語(yǔ)法如下:
<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)沒有意義。

語(yǔ)法:
<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ù)如下形式所示:

語(yǔ)法:
<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模型

語(yǔ)法:
<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)生對(duì)象文件是僅被檢查的約束提供:

~表達(dá)式定義別名必須在組裝時(shí)間可計(jì)算。因此它僅僅是個(gè)名稱,沒有重定位被使用。
~表達(dá)式中沒有別名可以弱化中間別名被覆蓋而不展示在對(duì)象文件中的可能性。
~表達(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è)通過(guò)動(dòng)態(tài)鏈接器返回另外一個(gè)函數(shù)地址獲得的相關(guān)名稱的函數(shù)調(diào)用解析器。

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

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

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

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

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

語(yǔ)法:
<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è)語(yǔ)法糖,<code>$name</code>如果和全局名稱一致將會(huì)被遺漏:
<pre>
$foo = comdat any
@foo = global i32 2, comdat
</pre>

在COFF對(duì)象文件中,這將創(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部分。

全局對(duì)象屬性有一定的限制。當(dāng)針對(duì)COFF時(shí)候,它,或別名,必須有和COMDAT組一樣的名稱。這個(gè)對(duì)象的內(nèi)容和大小可能在鏈接時(shí)根據(jù)選擇類型決定選擇COMDAT組。因?yàn)閷?duì)象名稱必須與COMDAT組名稱匹配,全局對(duì)象的鏈接器不能是局部的;如果局部符號(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ù)對(duì)象文件觀點(diǎn),這需要?jiǎng)?chuàng)建具有相同名稱的兩個(gè)部分。在對(duì)象文件層次,因?yàn)閷儆诓煌腃OMDAT組和COMDAT的全局通過(guò)部分表現(xiàn),所以這是必要的。

注意,特定中間語(yǔ)言構(gòu)造全局變量和函數(shù)可以在除了任何使用COMDAT中間語(yǔ)言指定的對(duì)象文件創(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ù)字符串)是唯一對(duì)于具名元數(shù)據(jù)有效的操作數(shù)。
<pre>
1.具名元數(shù)據(jù)被表示為一個(gè)帶有元數(shù)據(jù)前綴的字符串。元數(shù)據(jù)名稱的規(guī)則與標(biāo)識(shí)符相同,但不允許引用名稱。“\xx”類型的反斜杠仍然有效,它允許任何字符成為名稱的一部分。
</pre>

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

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

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

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

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

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

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

byval屬性也支持指定隊(duì)列屬性。這指明了棧槽格式和指定調(diào)用地點(diǎn)的指針隊(duì)列屬性。如果隊(duì)列屬性不被指定的話,代碼生成器會(huì)做一個(gè)目標(biāo)相關(guān)的猜測(cè)。
</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ā)起者必須通過(guò)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ù)。這對(duì)于返回值并不是一個(gè)有效的屬性。
</pre>

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

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

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

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

<code>nocapture</code>
<pre>
這表明被調(diào)用者不對(duì)生存期比被調(diào)用者長(zhǎng)的指針做出任何復(fù)制。對(duì)于返回值這不是一個(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ù)返回類型必須是對(duì)于bitcast指令有效的操作數(shù)。這不是一個(gè)有效的返回值屬性,只能應(yīng)用于一個(gè)參數(shù)。
</pre>

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

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

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