2013-07-31 41 views
3

我一直在對這個主題進行一些研究,還沒有找到好的具體答案。比方說,你在你的代碼有這些表達:編譯器如何更改變量名稱?

B = 2 
… 
B = B + 5 
… 
B = J + B 
… 

(這些都是很簡單的例子,我知道他們是不現實的)

B擁有遍佈這些線的許多不同的值。在第一行它是2,稍後它變成7,以及更後面的7 + J。編譯器需要跟蹤B的這些不同值,所以一種方法是重命名它們。例如,當B被重新定義爲B = B+5時,它可以更改爲B1 = B+5。最後的重新定義將看起來像B2 = J+B1

這個想法背後的動機涉及我正在構建的優化程序。它涉及用他們相關的表達來替換變量。然而,如果一個變量被重新定義,那麼字符'B'可以同時指多個事物。我用來跟蹤事物的方法就是我上面描述的,重新定義變量名稱。

這究竟是如何編譯器的工作?有沒有這個名字?

我試圖找出儘可能多地談談編譯器重新定義變量的情況下重新定義變量的過程。

如果有幫助,我相信這會在編譯預處理階段進行,我相信這是一個類似的概念,以宏擴展。

編輯:我給這個問題增加了一點內容。

+0

請問這個問題是指任何編程語言?像C#,C++,VBA,VB.Net等?如果是這樣,請說明該標籤。如果不是,你可能不會得到很多答案。此外,由於它不完全符合SO標準,所以你的問題將被關閉是相當危險的...... –

+0

我想我正在尋找任何編譯器,而不是任何特定的語言。我正在尋找使用中的概念,而不是特定的用法。 –

+0

在我看來,每個編譯器都會改變/替換之前的變量值,而不會保留任何引用/跟蹤到之前的值(或者它在任何前一階段計算的值)。這是由於編譯過程的效率。程序員的工作是跟蹤B變化的所有必要階段,而不是編譯器。 –

回答

3

您的預感是正確的,許多現代編譯器都使用流分析來重命名變量,以便每個變量都是唯一的。產生的表格被稱爲「單靜態分配」或簡稱SSA。

輸入:

B = 2 
B = B + 5 
B = J + B 

輸出:

B1 = 2 
B2 = B1 + 5 
B3 = J + B2 

有額外的部件,以此與分支和循環中,如工作:

輸入:

if X < 5 
    B = Y + Z 
else 
    B = 2 
B = B + 1 

輸出:

if X < 5: 
    B1 = Y + Z 
else 
    B2 = 2 
B3 = phi(B1, B2) 
B4 = B3 + 1 

「phi」函數選擇其輸入中的哪一個是實時的。

這是預處理過程中不這樣做,代碼被編譯到一些IR後,通常由基本塊它完成。它不像宏觀擴張。

3

您描述的內容已被正式化爲靜態單一分配(SSA)表單。這是一個有點更具侵入性比「在分配重命名變量」,因爲你還必須知道「當前」變量從控制流的臉看,例如,如果你重寫這個:

if (a) x = 0; 
else x = 1; 
print(x); 

到這一點,你要插入一個所謂披節點選擇在print正確的值:

if (a) x0 = 0; 
else x1 = 1; 
print(<which x?>) 

通常情況下,IR已經SSA內置的,因此代碼變成SSA同時被翻譯成IR(或此後不久)。宏擴展在此之前很久,通常在令牌流或AST上,這取決於宏的強大程度。

不過請注意,這是沒有辦法強制。這對於一些優化是有用的,但不是必需的(並且一些優化根本沒有益處)。您可以執行與可變變量一起工作的相同優化(並且許多編譯器IR具有SSA功能,至少將堆作爲非SSA),但它不便利,可能更昂貴。例如,在傳播常量時,必須確保常量和用戶之間沒有任何其他賦值,但是可以在沒有SSA的情況下輕鬆檢查。

+0

我可能沒有選擇此答案作爲我選擇的答案,但最後一段中關於SSA實用性的內容非常有見地。另外,這種宏觀擴展很晚才完成,這並不是我已經意識到的,所以也要感謝這些信息。 –

+0

@JasonNelson在編譯過程中,宏代碼擴展不會比代碼生成/ SSA轉換做得更多。 – delnan

+0

對,對不起,混淆了我的措辭。 –