介紹
編譯器的研究綜合了計算機科學中的作業系統、計算機系統結構、圖算法、人工智慧等眾多領域,因此對編譯器的研究要求研究者在各方面都有很深的理解。編譯器的研究可以追溯到卜世紀50年代。從Fortran語言出現的那天起,研究者們就在不斷地探索怎樣使高級語言編譯後能夠和機器語言編’寫的程式具有相當的效率。Fortran語言的成功很大程度卜得益於它從一開始就有很好的編譯器。隨著越來越多的高級語言的出現,計算機的套用領域越來越廣泛,編譯器所扮演的角色顯得越來越重要。
編譯器的結構包括詞法分析器(Lexicai Analyzer),語法分析器(Syntax Parser),語言分析器(Semantic Analyzer),中間代碼生成器(Intermediate Code Generator),代碼最佳化器(CodeOptimizer),符號表(Symbot Table),錯誤處理器(Error Handler)。詞法分析器直到中問代碼生成器又稱為前端(FrontEnd),代碼最佳化器到代碼生成器又稱後端(Back End)。這個界限並不是嚴格的,而且有些研究者喜歡把最佳化過程獨屯提出來討論。這樣的分層是很有工程價值的,在大型的多語言的編譯系統中,任何語言的編譯器都共用一個後端,因為後端與高級語言之間幾乎沒有聯繫,大多與機器相關;如果有開發者想在某編譯系統中添加一種語言的編譯功能,只需編寫該語言的前端即可;如果需要將已有的編譯器移植到新機器上,只需重新編寫一個與機器相關的後端即町,前端可以不加修改或者稍作修改後重複使用。以前要編在m種機器上運行,能編譯n種語言的編譯系統,需要編寫n·m個不同的編譯器;而按照這種一r程分層,則只需編寫n個前端以及m個後端即可。著名的編譯系統GCC(GNU Compiler Collection)就是按照這種工程分層方式開發的。
編譯器如何最佳化
編譯器的最佳化步驟在整個編譯器中是最重要的,也是最難的。它重要是因為一個編譯器的好壞主要就是看這個編譯器最佳化的效果是否良好。如果一個編譯器的最佳化效果很差,那么由該編譯器編譯出與用機器語言編寫的程式對系統資源的開銷是相當大的,而程式設計語言的設計者往往希握編譯器能夠編譯出與用機器語言編寫的程式效率相當的程式;它難是因為最佳化中的眾多問題都沒有定型的好算法。有些最佳化問題的求解甚至是不可計算的。現代系統結構中流水線,超標量以及多核處理器的出現無疑給編譯器的設計實現者加重r任務。
最佳化的正確性原則是最佳化前後的代碼對於任何輸入(合法或者非法),都應給出相同的結果。這條原則是顯然的,但並不是總那么容易做到。曾經有一段時間,GCC在Intel的機器上對浮點數的存取最佳化就沒能做到這一點。最佳化代碼的提供者沒有考慮到Intel的FPU是擴展的80位的,因此對於float,double類型在暫存器中的數據和存在記憶體中的數據是不一樣的,即使邏輯上相等的數據拿暫存器中的與記憶體中的比較也會得到不相等的結果,最佳化者期望通過將l臨時變數存在暫存器中以獲取效率,但導致了與未最佳化的代碼產生不同輸出的結果。
普通最佳化一般都會經過以下幾個過程:常量轉換,將源檔案中的常量變數及常量表達式都用其真實值來代替,這將可以節省一定的時間和空間;公共子表達式求值,將多次出現的子表達式預先求值,並存入臨時變數,這樣可以避免重複求值,但必須保證子表達式的值在任何地方都不會改變;冗餘代碼的刪除,將那些並不會用到的代碼刪除;最佳化存儲器.將頻繁使用的臨時變數放入暫存器中;表達式求值最佳化,改變表達式求值順序,有時矗T能達到最佳化目的;函式過程線上展開,將自程式代碼內嵌到調用代碼中,這樣可以避免函式調用的開銷。普通最佳化還有很多,此處只是試舉幾例。針對流水線的最佳化尤其需要注意代碼的順序以避免各種流水線冒險:結構冒險,當硬體知指令重疊執行中不能支持指令所有可能的組合時發生的資源冒險;數據冒險.在同時執行的幾條指令中,一條指令依賴於前一條指令的數據卻得不到時發生的冒險;控制冒險,流水線中的轉移指令或其他改寫程式計數器的指令造成的冒險。現在的指令集系統和CPU設計一般不會出現結構冒險了。
數據冒險一般出在算術指令中,這是編譯器最好解決的一種冒險。出現這種冒險,最顯然的處理辦法是加上一條nop;但是這種處理方式既浪費了時間,又浪費了能量,如果編譯器能有效地調整指令順序,是有可能避免這兩種冒險的。如在MIPs的五段流水線中:
Add rl,r2,r3
Sub r4,rl,r5
在此出現了數據冒險,如果沒有發生中斷,sub訪問r1時add還沒有及時更新rl中的內容,因此sub會訪問到錯誤的數據。但如果編譯器將後面的一些不會干擾到這塊代碼、也不依賴於這個代碼的指令加到這兩條指令之間,就可以避免數據冒險了。
發展趨勢
最佳化編譯器的設計是一個又深又廣的話題,它不僅要套用計算機系統結構、人工智慧等領域的前沿結果,還要求設計在軟體工程卜給予足夠的考慮。尤其在現今還未能解決的諸多最佳化問題中,編譯器設計還需要和眾多學科共同發展,以求找到可行高效的解決方案。