序言:
一個現代的優化器中包含有各式各樣的技術。編譯器使用貪婪啓發式搜索來探索很大的解空間,使用確定性有限自動機來識別輸入中的單詞,不動點算法用於判斷程序的行爲,通過定理證明程序和代數化簡器來預測表達式的值。編譯器使用快速匹配算法將抽象計算映射到機器層次的操作,它們使用線性丟番圖方程和普銳斯伯格算術來分析數組下標。編譯器使用了大量的經典算法和數據結構,如散列表,圖算法,和稀疏集實現方法等
第一章:編譯概觀
簡介
|| 編譯器是一個計算機程序(類似OS),負責將一種語言編寫的編寫程序轉換爲令一種語言編寫的程序。編譯器的主要組件有:編譯器,解釋器,自動轉換
|| 概念實現的路線圖:
編譯器爲了實現其語言轉換功能,那麼就必須有以下功能:
- 理解輸入語言的形式和內容(即語法和語義)。
- 理解輸出語言的形式和內容(即語法和語義)。
- 映射方案:將源語言映射到目標語言的法則
|| 由以上功能需求,我們可以得到編譯器的結構:
- 前端:用於處理源語言
- 後端:用於處理目標語言
- 中間形式:將前後端連接起來
- 優化器:改進優化轉換,用於分析並重寫中間形式
|| 有關程序設計語言的說明:
作用:我們使用程序設計語言將計算表達爲操作的序列,計算機程序就是一種由程序設計語言編寫的抽象操作序列。
特點:1,其中的程序設計語言是用來精確表示計算的形式語言 2,是一種不允許有二義性的語言。3,往往具有較高的抽象性
|| 編譯器若輸出的仍是面對人類的程序設計語言,而非計算機的彙編語言。則稱其爲 由源到源的轉換器
|| 解釋器和編譯器的區別:
- 編譯器的輸入是一個可執行的規格,輸出的是另一種可執行的規格
- 編譯器的輸入是一個可執行的規格,輸出的是執行該規格的結果
|| 解釋器和編譯器的共同之處:
- 都要分析輸入的可執行規格,判斷是否有效
- 都會建立一個內部模型,表示輸入的結構和語義。
- 都要確定執行期間何處儲存值
|| 一些語言在轉換方案上的區別:
APL,Scheme,更多的是用解釋器實現的,而非編譯器
Java,即包括編譯,也包括解釋來實現:(以下粗略表示過程)
- java源代碼編譯爲一種被稱爲字節碼的形式
- 在對應的java虛擬機(JVM)上運行字節碼執行程序,JVM就是一種字節碼的解釋器
|| 編譯器的基本原則:
1:編譯器必須保存被編譯程序的語義 — 保存是爲了在編譯過程中保持正確性(防止二義性)
2:編譯器必須以某種課察覺的方式來改進輸入程序。例如c語言的源到源的轉換器一定程度上由於輸入程序,將輸入程序改進源程序使得其有更好的可用性和一般性
編譯器的結構
|| 結構說明:
前端的工作涉及理解源程序並將其分析結果以IR的形式記錄下來;
優化器的工作專注於改進IR的形式;
後端的工作則是將轉化優化後的IR映射到有限的資源上
|| 編譯後代碼的實際性能取決於:優化器和後端這兩個階段中使用的技術之間的相互交互的好壞,共同決定(並不是優化功能好,映射功能強,編譯效果就好,之間的關聯很重要)
轉換概述
前端中:
|| 原因:需要先翻譯源代碼
|| 前端中進行的轉換:
-
語法檢查:
|| 什麼是語法:
某種規則的有限集定義,稱爲“語法”。我們通常將句子按詞類劃分,這樣可以通過單一語法規則描述很多句子
|| 前端中進行的兩趟單獨處理,分別稱爲“詞法分析器”和“語法分析器”,來判斷輸入代碼實際上是否屬於語法定義中的有效集合|| 詞類分析器:
進行劃分歸類工作:識別一句話中各個單詞,並將每個單詞歸入對應的詞類中,以形如(p, s)的對的形式歸類(p表示單詞s的詞類)
作用:將句子劃分成已歸類的單詞構成的流|| 語法分析器:
進行解析(語法分析工作):根據指定的輸入語言的語法規則,匹配已分類單詞的流,進行推導
作用:判斷輸入流是不是源語言中的一個句子(即是否滿足源語言語法的句子)。|| 類型檢查
進行類型檢查工作:對語法良構的句子進行類型判斷(字符串/整型…)
作用:檢查輸入程序中對名字的使用在類型上是否一致 -
中間表示
生成出代碼的IR形式,由於會生成各種種類的IR形式,故會涉及到選擇策略問題
優化器中:
|| 原因:IR程序運行時,語句根據其在源代碼中的順序逐條運行時,代碼將在更加有限,更加可預測的上下文中來執行。
功能:爲了更加有效地分析IR代碼,優化器會分析代碼的IR形式,以發現有關上下文的事實,並利用此項有關上下文的知識來重寫代碼,使之更有效地獲得同樣的答案。
|| 優化中發生的轉換
-
分析:判斷程序在何處安全且有利地應用優化技術
常用的分析技術:數據流分析/相關性分析 -
轉換:重寫分析過的代碼
|| 實例
後端中:
|| 原因:後端會遍歷優化後的IR代碼。爲每個IR操作其選擇對應的目標機操作來實現它,確定哪些值能夠駐留在寄存器中,哪些值需要放進內存中,並自行插入代碼以實現這些決策,並選擇出一種執行高效的次序。
|| 後端中發生的轉換
-
指令選擇:
將IR操作重寫爲目標機操作,這個過程稱爲指令選擇 -
寄存器分配:(最小化內存)
指令選擇階段,編譯器會有意忽略目標機寄存器有限的事實。故這個階段會重寫代碼,實現寄存器資源的分配 -
指令調度(最小化時間)
重排指令的次序,最小化指令在等待操作數撒謊給你所浪費的時間