• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • GCC 4.0 的新特性

    發表于:2007-07-04來源:作者:點擊數: 標簽:
    本文側重介紹了 GCC 4.0 內部結構相對于 3.4.x 版本的一些全新變化。 本文側重介紹了 GCC 4.0 內部結構相對于 3.4.x 版本的一些全新變化。 GCC(GNU Compiler Collection) 是 GNU(GNU's Not Unix ) 計劃提供的編譯器家族,它能夠支持 C, C++, Objective-C, Fo

    本文側重介紹了 GCC 4.0 內部結構相對于 3.4.x 版本的一些全新變化。

    本文側重介紹了 GCC 4.0 內部結構相對于 3.4.x 版本的一些全新變化。

    GCC(GNU Compiler Collection) 是 GNU(GNU's Not Unix) 計劃提供的編譯器家族,它能夠支持 C, C++, Objective-C, Fortran, Java 和 Ada 等等程序設計語言前端,同時能夠運行在 x86, x86-64, IA-64, PowerPC, SPARC 和 Alpha 等等幾乎目前所有的硬件平臺上。鑒于這些特征,以及 GCC 編譯代碼的高效性,使得 GCC 成為絕大多數自由軟件開發編譯的首選工具。雖然對于程序員們來說,編譯器只是一個工具,除了開發和維護人員,很少有人關注編譯器的發展,但是 GCC 的影響力是如此之大,它的性能提升甚至有望改善所有的自由軟件的運行效率,同時它的內部結構的變化也體現出現代編譯器發展的新特征,所以 2005年4月20日,GNU 組織發布的 GCC 4.0 引起了廣泛的關注。那么這次 GCC 從 3.4.x 直接躍遷到 4.x 的主版本變化到底有什么值得關注的呢?

    我們可以從不同的角度看待 GCC 的這次變遷,對于普通程序員來說,關注的主要是GCC 的前端支持情況以及編譯性能的變化。

    1. GCC 4.0 的前端支持
    GCC 的開發者和使用者當中,大多數人都是 C 或者 C++ 的用戶,所以 GCC 對Fortran 語言支持不足也不令人奇怪。但是,這并不代表 Fortran 是無足輕重的,事實上,開發商業的 Fortran 編譯器的公司要遠遠多于開發 C 和 C++ 編譯器的公司。

    在科學計算和工程應用領域,程序員們仍然在頻繁使用 Fortran 程序,同時,大量的經過長時間考驗的函數庫也為Fortran語言的數值計算提供了強有力的支持,所以,在一些"超級計算機" (supercomputer)上,Fortran仍然是絕大多數應用的首選語言。

    然而,在GCC 4.0發布之前,如果不想購買商用的Fortran編譯器,那么程序員們的唯一選擇就是GNU的g77編譯器。但是g77編譯器是一個相當陳舊的技術,很多Fortran語言的新特性都不能支持,比如流行的Fortran 95,它能夠支持的模塊化編程,并行處理和數組操作等等,g77編譯器基本上都無法支持。

    這次GCC 4.0發布時推出了支持Fortran 95語言前端的編譯器gfortran,它已經能夠大大超越g77編譯器,支持Fortran 95標準中的很多新特性,雖然gfortran還有一些缺陷,比如不能支持自動并行化(automatic parallelization),不能支持Fortran 2003中的面向對象特性等等,它已經給了Fortran程序員除了商業編譯器和g77以外一個更好的選擇。

    2. GCC 4.0的編譯性能
    編譯器的性能主要可以從三個方面來考查:

    1. 編譯時間(compile time),指編譯器編譯一個源程序得到目標代碼所需要的時間。

    2. 目標代碼的大小(object size),編譯得到的目標代碼當然是越精悍越好了。

    3. 目標代碼運行時間(run time),運行時間體現了速度和效率。

    這里,作者沒有親自測試和實驗,引用了Scott Robert Ladd的《GCC 4.0: A Review for AMD and Intel Processors》文章中的一些實驗結果。這篇文章引起了比較大的反響,其實驗結果和結論也得到了廣泛的認可,如果對Scott的具體測試采用的軟硬件平臺和工具方法感興趣,原文可以在http://www.coyotegulch.com/reviews/gcc4/index.html看到。

    Scott 使用AMD和Intel的兩款處理器:64位的Opteron處理器和32位的Pentium 4處理器,分別針對GCC 3.4.3和GCC 4.0來進行測試。他選用了POV-Ray 3.6.1, LAME 3.96.1, SciMark 2.0和Linux 2.6.11.8作為benchmark來進行測試,分別記錄了GCC 3.4.3和GCC 4.0在ADM Opteron和Intel Pentium 4下的編譯時間、代碼大小和代碼運行時間進行比較,具體的實驗結果請參見原文。

    這樣,根據這些實驗數據,我們可以給出一個粗糙的結論,在編譯性能方面,GCC 4.0似乎不如GCC 3.4.3,因為在很多時候,GCC 4.0的編譯時間、代碼大小以及代碼運行時間全面高于GCC 3.4.3。這樣的結果看似出人意料,GCC這次大的版本變化就是因為引入了新的優化框架,怎么會編譯性能有所下降呢?這主要是因為:首先,這是一次主版本變化,我們可以理解巨大的變化帶來的性能損耗;另外,更主要的是,GCC新的優化框架的潛力尚未完全發揮出來,這一點,在我們文章結束的時候,讀者會有更深的理解。

    3. GCC 4.0 的內部結構變化
    GCC 遵循 GPL 協議,是開放源代碼的,其開發過程也是完全開放的,任何人都可以對 GCC 的發展作出貢獻,因而 GCC 特別適合用于學習和研究編譯器。對于學習和研究編譯器本身來說,GCC 內部的結構變化顯然更吸引人。

    目前 GCC 發行維護者 Mark Mitchell 在接受 internetnews.com 網站采訪時這樣說到:"毫無疑問地,GCC 4.0 中最引人注意的特性以及為何把 GCC 的這個版本稱作 4.0 而不是 3.5,就是因為其新的優化框架(optimization infrastructure)。大體上來說,GCC 以前的版本的代碼優化工作主要在底層機器指令級別進行的。不幸的是,到了底層的時候,很多信息已經丟失了,因此,GCC 4.0 在更接近輸入高級語言程序的級別上做了很多優化工作。"

    Mark Mitchell 所說的 GCC 新的優化框架主要就是指 Tree SSA(Static Single Assignment),Tree SSA 經過長時間的獨立開發,最終整合進了 GCC 的主流(mainstream)中,可見這種設計是意義非凡的。Tree SSA 是什么?為什么要采用 Tree SSA? 使用了 Tree SSA 的 GCC 有什么不同?新的 GCC 編譯和優化框架是什么樣的?等等,這些將是本文探討的主要問題。

    這部分文章內容是這樣組織的:首先回顧 GCC 4.0 版本之前的編譯流程,以便進行對比;接下來介紹 GCC 4.0 的編譯流程以及新的優化框架結構,這里先介紹 GENERIC Tree和 GIMPLE Tree,SSA 形式等基本概念,在讀者對這些概念和理論有了一定的了解之后,再介紹 GCC 中是如何實現 Tree SSA 框架結構的。

    3.1 GCC 4.0 之前的編譯流程
    這里有必要回顧一下 GCC4.0 之前的版本進行代碼優化的框架結構,以便進行對比分析。GCC 的前端在接受了輸入的源程序之后,經過分析器(parser)處理得到 Parse Tree(通常是一種抽象語法數,AST, Abstract Syntax Tree),根據這個 Parse Tree 生成程序的RTL(Register Transfer Language)表示,然后在 RTL 表示的基礎上進行優化處理,然后生成相應的目標代碼,如下圖 1 所示。

    但是 RTL 表示是一個相當接近底層的表示,也就是說它更接近目標代碼,適合進行目標相關的優化工作,比如寄存器分配等等。然而,很多的優化轉換工作需要更高層的程序信息,比如數組引用、數據類型、控制流結構等等,這些很難用 RTL 表示,或者無法用 RTL表示。

    圖1. GCC 4.0之前版本的代碼編譯流程和優化框架
    javascript:window.open(this.src);" style="CURSOR: pointer" onload="return imgzoom(this,550)">

    3.2 GCC 4.0 的優化框架(Optimization Infrastructure)
    提供一個可移植性強、跨平臺以及編譯高效代碼的編譯器,是 GCC 一貫追求的目標,為了使 GCC 能夠獲得更好的編譯性能,高層程序信息級別的優化工作是必須的。Tree SSA設計的主要目的就在于此,它既與前端語言無關,又與后端目標無關,而且能夠提供在 RTL表示層很難或者無法進行的高級分析和轉換。

    Tree SSA 起先是作為 GCC 的一個分支(branch)進行獨立開發的,經過兩年多的努力開發,終于在 2004 年 5 月 13 日進入了 GCC 的主流版本。在 GCC 的 SSA for Trees 分支的網頁上明確說明了,這個項目的目的就是構建一個對基于 SSA 形式的樹的優化框架。在學習編譯原理的時候我們知道,編譯器通常會使用樹的形式來描述程序,GCC 也是這樣,在接受了輸入的源程序后,GCC 驅動其相應語言的前端分析器(parser),處理得到一個 Tree。從圖 1 可以看到,4.0 版本之前的 GCC 幾乎是立即把這些 Tree 轉換成了 RTL 表示。那么現在 GCC4.0 的 Tree SSA 優化框架就是在前端生成 Parse Tree 之后,把這些 Tree 轉換成基于 SSA 的 Tree,對這些 SSA 形式的 Tree 進行高層次的優化,然后才把 Tree 轉換成 RTL 表示。

    3.2.1 GENERIC Tree 和 GIMPLE Tree

    這個框架結構看起來比較簡單,而且 GCC 的 Parse Tree 能夠提供足夠的信息來實現SSA,但是在真是實施的時候,還是有很大的困難的,最主要的兩個困難是這樣的:

    1. GCC 中的樹沒有統一的表示形式,每一個前端都定義了自己的樹。這就意味著要得到基于 SSA 形式的樹必須要對每種前端分析生成的樹都進行處理。

    2. GCC 前端得到的 Parse Tree 的復雜度是無法估量的。把這些樹轉換成基于 SSA形式的樹需要進行復雜的處理工作。

    為了解決以上兩個問題,GCC Tree SSA 分支的開發小組引入了 GENERIC Tree 和GIMPLE Tree 兩個概念:

    1. GENERIC Tree 是特意創造出來的 GCC 通用的樹的表示形式,它能夠表示不同的前端所需要的所有的結構,而且又能夠去除語言相關性。

    2. GIMPLE Tree是取自GENERIC Tree和SIMPLE兩個短語的。因為GENERIC Tree的復雜性導致實現SSA形式的困難,需要把GENERIC Tree進行簡化,這種簡化的GENERIC Tree就稱之為GIMPLE Tree。

    好了,了解了這些內容之后,我們可以看看 GCC 4.0 的編譯流程和優化框架,如下圖2所示:

    圖2. GCC 4.0 的編譯流程和優化框架

    3.2.2 Single Static Assignment Form 的基礎介紹

    到現在為止,我們基本搞清了新的 GCC 的編譯過程,也大概了解了所謂的新的 Tree SSA 優化框架。上面提到的 GENERIC Tree 和 GIMPLE Tree 都是為了實現 SSA 而做的準備工作,那么 SSA 本身究竟是什么?為什么 GCC 要把 Parse Tree 轉換成基于 SSA 形式的 Tree 再做優化工作呢?為弄清楚這些問題,我們有必要多花一些篇幅對SSA的基本概念和理論做一些介紹。

    SSA 的全稱是 Static Single Assignment,直譯過來就是靜態單一賦值,它是IBM公司在上個世紀 80 年代研究的成果。從前面的討論可以看出,Tree SSA 與 RTL 一樣,也是一種中間表示形式,不過相比 RTL 要更高層一點。SSA 形式是一種相對而言比較新穎的中間表示形式,早期的講編譯原理或者編譯器的課本中大多沒有提及。

    簡單的說,SSA 形式就是每個變量只能被賦值一次。這樣,非 SSA 形式的程序在轉換成 SSA 形式的時候,其中的部分變量就會被分割成很多版本,通常使用下標來表示這些不同的版本。下面舉一個簡單的例子來說明,如下圖 3 所示:

    圖3. 程序的非 SSA 形式和 SSA 形式

    上圖中所示的代碼片段,由于 y 變量被賦值兩次,所以在轉化成 SSA 形式的時候,y變量被分割成兩個版本 y1 和 y2,這樣就保證了每個變量僅僅被賦值一次。

    由于 SSA 形式中每個變量只能被賦值一次,那么 SSA 形式就能有效地把程序中所操作的數值和這些數值的存儲位置這兩者分開,這樣就能方便一些優化工作。比如我們剛才看的圖 3 中的代碼片段,我們可以通過肉眼分析發現在非 SSA 形式中的第一條語句y := 1是一條無效的冗余語句,真正決定 y 變量值的是第二條 y := 2 賦值語句。那么在代碼優化的時候,第一條語句就應該被刪除掉。但是這是我們人工發現的優化結果,如果想要編譯器來完成這個優化工作,需要進行復雜的分析,在編譯原理中稱之為"定義可達性分析"(reaching definition analysis)。而在 SSA 形式中,顯然,做出這樣的優化決定則無需進行太多分析。

    這只是 SSA 形式諸多優點中的一個而已,使用 SSA 形式可以利用更多的編譯器優化算法或者是提高這些算法的效率,比如 constant propagation, sparse conditional constant propagation, dead code elimination, global value numbering, partial redundancy elimination 以及register allocation 等等。這里涉及太多編譯理論和算法,本文不作詳細討論。

    SSA 形式具有上文所述的優點,當然也會有其復雜和困難的地方了,下面我們通過一個稍微復雜點的程序片段來說明把非 SSA 形式的程序轉換成 SSA 形式程序的時候有些什么需要考慮的問題:


    圖 4-a 所示的非 SSA 形式的程序在轉換成了圖 4-b 所示的 SSA 形式的程序后,有一個問題很難解決,就是圖 4-b 中最下面程序塊中 y 的值無法確定。因為在此之前有一條選擇語句,導致程序控制流產生了分支,此時 y 的值可能是 y1 也可能是 y2,這是由程序具體執行時經過哪一條控制流來決定的。處理的方法是在最后一塊程序片段之前加上一個 Φ 函數,定義一個新的 y3,并從 y1 或者 y2 中選擇一個適當的值賦給 y3,如圖 4-c 所示。

    推而廣之,在將非 SSA 形式的程序轉換成 SSA 形式后,如果某個變量被分割成了 n個不同版本的變量后,在某一點需要會合,那么在這個會合點 (joint point) 就需要加入一個 Φ 函數來確定應該選擇這 n 個不同版本的變量中的某一個值。這樣問題就轉變成了如何計算這個 Φ 函數以及確定在程序中的什么位置應該插入 Φ 函數,這個可以使用 dominance frontiers 來進行計算,關于如何高效計算這個 Φ 函數的算法研究本文不作深入討論。

    3.2.3 GCC 4.0 中的 Tree SSA 框架的設計和實現

    至此,我們已經比較清楚的了解了什么是 SSA,SSA 形式有什么好處,如何將非 SSA表示轉換成基于SSA形式的表示以及這個過程中需要解決的主要問題等等,本文將不再對SSA進行深入的討論了,回到我們的主題,繼續討論GCC 4.0 的 Tree SSA 優化框架是如何設計和實現的,它是怎樣把 Tree SSA 融入到 GCC 的編譯過程中去的。

    回顧上圖 2表示的 GCC 4.0 編譯流程,在得到 GIMPLE Tree 之后,經過 GIMPLE optimizer 和 GIMPLE expander 的處理,得到了程序的 RTL 表示。其實把程序轉換成 SSA形式和在此基礎上進行優化就在這個過程中完成的,下面我們就來具體看看 GCC 4.0 是怎么做的。在 GIMPLE 和 RTL 之間是樹優化 (Tree Optimization) 的過程,如下圖 5 所示。圖 5 中所示的樹優化器 (Tree Optimizer) 主要完成這幾個功能:

    1. 生成一個控制流轉換圖 CFG(Control Flow Graph)。

    2. 將 GIMPLE Tree 轉換成基于 SSA 形式的 Tree。

    3. 進行 Tree SSA 的優化。

    4. 將優化后的基于 SSA 形式的 Tree 轉換成 RTL 接口所能識別的非 SSA Tree 的形式。

    圖5. GCC 4.0 的 Tree Optimizer 結構

    結合 GCC 4.0 代碼中的部分源文件來說明:圖 5 中這個 Tree Optimizer 的行為是由tree-optimize.c 文件驅動的,tree-ssa.c, tree-into-ssa.c 以及 tree-outof-ssa.c 負責完成 SSA 形式的轉換、驗證以及其他需要與 SSA 形式交互的功能,建立和管理控制流轉換圖 CFG 的工作由 tree-cfg.c 完成。不同的樹分析和優化功能分別在相應的源文件中獨立實現,這些分析和優化函數必須向 GCC 注冊,然后才能由 tree-optimize.c 進行驅動和管理,結合圖 5來看,SSA pass1, SSA pass2 … SSA passn 代表了實現各種不同功能的 SSA 分析器,他們向 Tree Optimizer 注冊,在編譯時刻 Tree Optimizer 根據編譯選項等等選擇相應的SSA分析器進行優化或者其他處理工作,并保證在基于 SSA 形式的處理完成之后將 SSA 樹轉換成非 SSA樹,交給下面的 RTL 模塊處理。

    至此,GCC 4.0 的 Tree SSA 優化框架結構應該比較清楚了。讀者可能會注意到,文中多次提到Tree SSA是一個優化框架結構(Optimization Infrastructure),為什么說是一個Infrastructure 呢?其實把 Infrastructure 稱作框架結構或許并不貼切,更精確地說 Tree SSA是 GCC 提供的一種進行優化工作的基礎設施。圖 5 中已經體現出了這一點,Tree SSA 的分析和優化工作不是一成不變的,具體選擇哪些優化功能和算法是由Tree Optimizer選擇驅動的,而且這個Infrastructure是相當靈活的,我們可以很方便的加入一個 SSA 分析器,只需要如下步驟:

    1. 創建一個 struct tree_opt_pass 類型的全局變量。

    2. 在 tree-pass.h 頭文件中為這個新的分析器添加一個外部聲明(extern declaration)。

    3. 調用 NEXT_PASS 把這個新的分析器加入到 tree-optimize.c: init_tree_optimization_passes 序列中。

    所以這種 Infrastructure 是一個相當靈活和方便的設計,使得我們可以便利地加入新的SSA 分析器,或者使用更高效的算法來重新設計完成一些優化功能等等。

    4. 總結
    GCC 4.0 發布以來得到了引起了廣泛的關注,新的 gfortran 前端給 Fortran 程序員帶來了福音,但也有很多不盡如人意的地方,比如編譯性能的損耗,以及向后兼容問題。比如KDE(K Desktop Environment) 開發小組在發現 GCC 4.0 無法正常編譯 KDE 后,迅速的拋棄了 GCC 4.0。而且,出于穩定性的考慮,GCC 3.x 版本的開發仍然在進行中。這些似乎給 GCC 4.0 的前景籠罩上了一層陰影,但我們應該容忍一點,給 GCC 4.0 一些信心,向后兼容的問題應該是能夠解決的。

    至于編譯性能的問題,通過我們這篇文章的討論,我們可以看到 GCC 4.0 Tree SSA 的優化框架結構并沒有充分發揮出其潛能,還可以增加和改進更多 Tree SSA 的優化工作,假以時日,GCC 4.0 的編譯性能會得到提高的。

    總的來說,這次 GCC 從 3.x 版本躍遷到 4.x 版本更像一個進化 (evolution) 的過程,而非一個革命性 (revolution) 的過程,它采用的 Tree SSA 優化框架代表了編譯器發展的方向,我們應該關注 GCC 4.0 的進一步發展。

    原文出處:http://fanqiang.chinaunix.net/program/c++/2005-06-21/3325.shtml

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>