[分享] gross: 一個實驗性的編譯器作業

看板CompilerDev作者 (夏克維夫)時間3年前 (2020/08/05 12:38), 編輯推噓1(100)
留言1則, 1人參與, 3年前最新討論串1/1
有版友建議可以多分享一些簡單、有趣的編譯器專案 本魯就來拋磚引玉一下 來分享一下去年我修的一門課做的作業 https://github.com/mshockwave/gross 當時花了大概花了10個星期做這個專案 不算長也不算太短 雖然裡面有很大一部分是實驗性質、不太常見的設計,但就是因為實驗性質所以沒有做的 很複雜(掩面)因此只要修過研究所編譯器課程 在理解上應該都沒什麼太大問題 這邊挑幾個重點來講一下: - src/Frontend 很普通的 Lexer, Parser。由於我們的輸入語言是一個簡單的教學用程式語言(好像就 叫做PL241 XDD),用非常簡單的top-down parser就能做完。唯一跟一般 parser 不一樣 的是 parser 會直接生成 IR 而不是 AST。會這樣做到也不是沒時間做,而是等下會提到 的實驗性 IR 其中一個設計哲學就是「整個編譯的流程、都盡量用同一種資料結構」 更具體來說的話就是整個流程都用 Graph 來代表 換句話說,就是不再有 Source Code -> AST -> IR -> Native Code 而是: Source Code -> Graph IR -> Native Code 雖說如此,整個編譯器依然是階段性地慢慢把輸入的高階程式碼 一步一步的轉化為低階 機器碼。其中關鍵就是雖然整個流程裡面都是用 Graph,但其中的 vertex 在每一個階段 的抽象程度不一樣。 例如剛從 Parser 出來的 Graph 每個節點都是非常高階的結構像是 "While" "If-Else" 但是之後就會慢慢降成 "jump", "branch" 等等較為低階的概念 - src/Graph 這邊放的就是前述 Graph IR 的實作。我這個資料夾的 README 花了非常多篇幅在描述 三種不同的 edge ... 有點複雜所以這邊就不提了。用最簡單的說法的話就是每個 edge 都代表一個dependency,而設計來能夠表示三種不同的dependency的原因在於 希望能讓某些優化比較好做。例如最惡名昭彰(笑)的 memory side effect,如果我們 能夠在一開始就把這些 side effect 明確地表示出來(因為或許能從一些高階資訊中 獲得)、而不是等到要用的時候才在那邊分析,在優化上可能會比較輕鬆 - src/Graph/Reductions 雖然這個資料夾有一個酷炫的名字,但其實就是普通的優化而已XD 會取名為 reduction 單純只是因為如果你在 Graph IR 上做優化,大部分時候都是逐漸把 Graph 簡化。這邊 放的優化也只有最簡單的那幾個:CSE, Peephole, ValuePromotion(mem2reg) - src/CodeGen 謝天謝地這個作業只要生成一個超簡單、教學用的指令集(DLX)。所以雖然這個資料夾有 一堆檔案,但真的只是一些必要的東西像是 scheduling, RA, instruction selector 值得一提的是在之前用的 Graph IR 沒有 basic block 的概念(一個函式就是 一個完整的Graph),一直到最終在 scheduling 、要把這個 Graph 做 "linearlize" 轉成一串instruction序列的時候才有 basic block 的概念出現 以上就是幾個有趣的部分,希望大家能從這個實驗性的專案裡面得到一些靈感:) -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 169.234.228.227 (美國) ※ 文章網址: https://www.ptt.cc/bbs/CompilerDev/M.1596602334.A.CDD.html

08/05 18:43, 3年前 , 1F
Graph IR 與 MLIR 在設計上有異曲同工之妙
08/05 18:43, 1F
文章代碼(AID): #1VAZVUpT (CompilerDev)