COSCUP
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Help
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
1
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# 從零開始建構 C 語言最佳化編譯器 > 陳孟鴻, jserv {%hackmd @coscup/BkyL5IdFA %} :information_source: **[簡報檔案](https://docs.google.com/presentation/d/1RoSFZQdy4dqEYR9LRI5ShIFA_LMMlCmJImKIN3V_ry0/edit?usp=sharing)** ## 簡介 儘管許多大學開設編譯器課程,其中若干的資訊系仍將其列為必修,但隨著異質多核在內運算模型的變遷,編譯器技術隨之已有相當不同的面貌。但絕大多數的大學課程僅能勉強涵蓋到語法解析與產生指令,遑論要探討各式最佳化議題。 本議程將介紹一項從無到有開發 C 語言編譯器的嘗試:首先實作 C 語言的解析器與支援 Arm 和 RISC-V 處理器架構的編譯器後端,使其能不依賴任何組譯器或連結器達成自我編譯 ([self-hosting](https://en.wikipedia.org/wiki/Self-hosting_(compilers))),隨後引入 SSA (static single assignment form) 及一系列的最佳化策略,以大約七千行 C 程式碼建構小而精巧的最佳化編譯器: [shecc](https://github.com/sysprog21/shecc)。 > shecc 是以女子天團命名的開放原始碼編譯器專案,讀法: s-h-e-c-c,如同 S.H.E.,亦可讀成 [ʃek] 請善用 [2024 年系統軟體系列課程討論區](https://www.facebook.com/groups/system.software2024) ![PXL_20240803_073203641.RAW-01.COVER](https://hackmd.io/_uploads/SJDOMTotA.jpg) ## 經典的編譯流程 取自《Compilers: Principles, Techniques, and Tools (2/e)》編譯器無所不在,是資訊科技的基石。 涵蓋分詞(tokenizer)、語法/語意分析、中間程式碼產生、中間表示式(IR)、與硬體無關的最佳化、針對標的架構的程式碼產生器,和一系列最佳化。 ## shecc 的 bootstrapping 從無到有建構 C 語言編譯器的前端和後端,顧及最佳化需求,引入額外的中端(middle-end)來銜接前後及後端。 1. stage0: 用 gcc/clang/MSVC 編譯,產生可執行檔 `out/shecc`,針對原生的處理器架構。本身是 cross compiler (交叉編譯器) 2. stage1: 用 stage0 產生的程式編譯 shecc 原始程式碼,產生的執行檔 `out/shecc-stage1.elf` 使用 ArmV7 或 RISC-V 指令集 3. stage2: 用 stage1 產生的 `out/shecc-stage1.elf` 編譯自己 檢驗 bootstrapping 的方式:`out/shecc-stage1.elf` 和 `out/shecc-stage2.elf` 二者內容應該完全相同 ## 控制流圖 (control-flow graph, CFG) 分析 為了確保最佳化後的程式碼能維持正確的執行順序,許多現代最佳化編譯器都用控制流圖來記錄各個基本區塊 (basic block,程式碼單一入口,單一出口的區域,簡稱 BB) 間的關係,並且可藉由 分析 CFG 來取得程式的可達性 (reachability) 與支配性 (domination)。 基本區塊為組成 CFG 的基本單元,為一系列不具分支的指令序列,執行時會由第一條指令開始依序執行。CFG 由許多基本區塊節點所組成,節點與節點 間的有向邊 (directed edge) 則代表基本區塊間的執行順序,箭頭所指向的基本區 塊為發出箭頭的基本區塊的後繼 (successor) 節點,反之稱為前任 (predecessor) 節點。程式執行時會由起始節點依序走訪其後繼節點直到抵達終點。 而基本區塊間的有向邊可為條件分支或是無條件跳躍指令。 透過分析 CFG,我們可以歸納出以下兩項常用於建構最佳化編譯器的性質: - [ ] 可達性 (reachability) 除了起始節點外,若一個基本區塊在最佳化中沒有前任節點連接,則此基本區塊被稱為不可到達 (unreachable),我們可安全的移除該基本區塊來簡化 CFG,如 C 語言關鍵字 break, continue, return 後的程式碼及 if, for, while 中條 件恆為 0 的情況。 - [ ] 支配性 (domination) 若從起始點到節點 n 都必經節點 d,則稱節點 d 為節點 n 的支配節點 (dominator),記作 d dom n;而其中最接近節點 n 的支配節點 m 又稱為直接支配 節點 (immediate dominator),記作 m idom n。將 m 作為親代節點、n 作為子節點,我們可建立另外一種樹狀結構 ── 支配樹 (dominator tree),記錄從起始點到某個基本區塊節點中必經的路徑。 結合可達性分析,若節點 n 不可到達,則其在支配樹中的所有子節點將同樣不可到達,這時我們可快速且安全地從 CFG 中移除這些基本區塊節點。 ## 靜態單賦值 (static single assignment, SSA) 形式 考慮以下程式,我們可以看出第一個賦值是不必要的: ![ssa-case-1](https://hackmd.io/_uploads/S13a2roFA.png =20%x) 但是當程式碼規模擴大,要判斷賦值是否不必要就必須不斷地往下尋找變數是否被使用或是被重新賦值,此過程會加重編譯器最佳化時的成本,因此在 1980 年代中 SSA 的相關概念開始相繼被提出。由於 SSA 大幅地簡化變數定義的追蹤,讓分支控制流中的變數的相依性分析更加明確,因此 SSA 也成為現代最佳化編譯器最常使用的架構。 在靜態單賦值形式中,我們給予每個被賦值的變數一個唯一的版本 (version) 並重新命名,讓所有變數都僅被賦值一次以便追溯其定義。 ![ssa-case-2](https://hackmd.io/_uploads/rkRkpBjKA.png =45%x) 但在條件分支的匯聚點會出現來自不同執行路徑的版本號碼衝突,這時需要在執行基本區塊的指令前插入 $\phi$ (phi) 函數,並為該基本區塊建立一個新的版本碼。 ![ssa-case-3](https://hackmd.io/_uploads/SkDSaSoYR.png =40%x) $\phi$ 函數會標記一個記憶體地址作為不同版本的暫存位置,新版本藉由讀取該地 址就能取得目前程式的執行路徑所使用的版本號碼。因為 $\phi$ 函數涉及記憶體寫入及讀取,如何精準的插入 $\phi$ 函數將左右輸出的執行檔的執行效率。 ## 支配邊界 (dominance frontier) 支配邊界為一個變數的定義恰好不能到達的節點的集合。若節點 n 的前任節點被節點 m 支配,但節點 m 並不支配節點 n 時 (即有其他路徑可略過節點 m 抵達節點 n),節點 n 即為節點 m 的支配邊界之一。 ![ssa-case-4](https://hackmd.io/_uploads/HJTd6SjFR.png =30%x) 一個基本區塊中變數的定義可遍及其支配邊界以內的所有基本區塊,因此我們 可省略這些基本區塊中的 $\phi$ 函數,只需要在支配邊界上插入必要的 $\phi$ 函數。 ## 常見編譯器最佳化策略 - [ ] 常數傳遞 (constant propagation) 利用 SSA 向前化簡指令中的運算元變數,若我們確認數學運算中的兩個運算元都為常數,則在編譯期就可先計算其結果,並將結果傳遞至所有使用其變數的指令中。 - [ ] 死碼消除、共同子表式消除 若一個變數被定義但從未被使用,我們可以將其視為死碼 (dead code),與不可達程式碼一樣,可在最佳化中被移除;若兩個變數擁有相同的定義,我們則可省略其中一個變數的定義,以消除冗餘的計算。 - [ ] 暫存器配置 在 SSA 中,我們將資料分別儲存在無限多個虛擬暫存器中,但在現實世界 中的實體暫存器數量是有限的,我們需要配置及維護暫存器中的內容,讓指令在執行時能存取到正確的運算元。常見的資源配置演算法有圖著色演算法 (graph coloring) 及線性掃描 (linear scanning) 演算法。 - [ ] 指令融合、窺孔優化 (Peephole Optimization) 暫存器配置時產生某些指令序列,如暫存器間移動與寫入後讀取等,則可 以藉由窺孔優化來消除或化簡。 ## 中間表示式 (intermediate representation) 中間表示式 (IR) 是個臨時的結構體,儲存來自編譯器不同階段中的資訊。其優點是可以分離編譯器前、後端,並讓最佳化中端獨立於程式語言與硬體架構之上。換言之,只要有完善的中間表示法即可支援不同的程式語言及目標機器。 shecc 引入二階段的中間表示式作為建立最佳化編譯器的基礎。 * 第一階段 IR 為高階 IR,使用不限數量的虛擬暫存器 (virtual register) 記錄由編譯器前端所解析的變數、運算子與程式控制流,並以這 些資訊建立 SSA 形式及進行後續與 SSA 相關的最佳化。 * 第二階段 IR 為低階 IR,用於記錄由暫存器配置後所對應到的實體 暫存器;由於 shecc 不依賴現有組譯器、直接產生機械碼,我們需要在產生指令的階段計算好分支與跳躍指令的偏移量。而與硬體架構相關的最佳化也將以第二階段 IR 為基礎。 ## shecc - 七千行程式碼,買越多省越多! - 曾在 GitHub 上有看到一萬多行的最佳化編譯器實作 (但過去沒有見到三萬行程式碼以內可 self-hosting 的專案),希望能做更小 - 如今精簡的東西相當難得 - 快來跟我們一起開發! ## 開發最佳化編譯器的背景知識 * 開始讀大學就可以了 * 好好讀難懂的語言規格書 * 程式碼解析器:計算理論、離散數學 * 計算機結構 * 離散數學、圖論(前面講的著色問題)、資料結構、演算法 * 作業系統、計算機結構、資訊安全 ## Q & A * Q: 目前使用 Cortex M55/N55,會不會未來在 NPU 上面有著墨? * 現在 microcontroller (MCU) 已經能做非常多事情,如[上一場議程](https://hackmd.io/f3cs2UxpRKaIsY2ey3itYw) ([Mado 視窗管理系統](https://github.com/sysprog21/mado)) 可在 MCU 等級的硬體順暢執行 * 光有硬體是不夠的,還需要編譯器 * ONNC/ONNX 有不同 layer,目前沒有特別好的方案 * 通用 CPU (RISC-V) 有機會透過小的編譯器做 JIT / Profilling (PGO, Profile-Guided Optimization), Meta BOLT * Q: parser 策略 (LR/LALR?) * 暫時還沒花太多力氣做 parser,歡迎投入 * 也是有遇到很多問題。 * C preprocessor 的還有各種處裡,這邊大就花了 1000 行。 * shecc看起來很完善,有甚麼可以貢獻的東西 * https://github.com/sysprog21/shecc/issues * 有好多 issue 可以解啊。 * c-preprocess 和 frontend 可以一起做R。 * bug 還是很多,也可以去找 bug 提出來。 * 產生的程式碼需要做 bootstrapping,目前只能跑在 QEMU,希望找些其他系統模擬的方法支援非 Linux OS * 目前只支援 ARM/RISC-V,看看有沒有人可以貢獻 x86(-64) 之類的處理器後端。 ## 小結論 * 現在這個時代很多東西都很複雜,反而這種簡單的東西去實作的東西,反而很難找到。 ## 延伸閱讀 * [你所不知道的 C 語言:編譯器和最佳化原理篇](https://hackmd.io/@sysprog/c-compiler-optimization) * [你所不知道的 C 語言:編譯器原理和案例分析](https://hackmd.io/@sysprog/c-compiler-construction) * [可自我編譯的 C 編譯器](https://hackmd.io/@sysprog/HkqE5DKqP) * [可自我編譯的最佳化編譯器](https://hackmd.io/@sysprog/H11Da3FQA)

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully