![]()
前言:在編譯器技術領域,LLVM 憑借其精妙的 IR 設計、靈活的 Pass 架構成為工業標桿,但其底層依賴的 C++ 卻日益成為負擔。從編寫 Lua/C 編譯器到參與 LLVM 開發,我親歷了 C++ 的復雜性如何侵蝕開發效率:模板元編程的“黑魔法”、標準庫的陷阱、緩慢的編譯調試體驗,以及構建系統的混亂,迫使團隊將精力耗費在語言細節而非核心算法上。 這種困境催生了 MoonLLVM 的構想——它并非替代 LLVM,而是作為其“友好伴侶”,通過輕量級設計規避 C++ 的弊端。
MoonLLVM 基于 MoonBit 語言,提供簡潔的字符串處理、快速編譯和模塊化結構,同時保持與原生 LLVM 的互操作性。其目標是降低編譯器開發門檻,讓開發者更專注于語言語義與優化創新,而非與工具鏈搏斗。本文將探討這一實踐如何為編譯器工程提供新思路。
求學期間,我曾經非常迷戀 C++:模板元編程很酷,標準庫看起來很「工程」、很「專業」。那會兒,我也用 C++ 寫過不少東西:Lua 編譯器、C 編譯器,還有各種各樣的小工具等等。后來畢業以后,又在國內某知名芯片公司,也做過 LLVM / MLIR 相關工作,寫過優化 Pass、后端代碼生成等。
但當我的經驗越來越豐富,見到的東西越來越多之后,我越來越有一種感覺:
如果LLVM不是建構在C++上的就好了。LLVM -- 杰出的設計
作為知名的編譯器后端框架,LLVM 的架構設計是非常優秀的。它的 IR 設計、Pass 管線、Def-Use 鏈,以及對硬件的抽象,都是教科書級別的。也正因如此,LLVM 成了工業界編譯器后端的標準。2013年,LLVM被授予了2012ACM軟件系統獎,已足以說明工業界對它的認可。
但 LLVM 的基石語言C++,則是另一個極端。
問題頻出的C++ 1. 語言太復雜
我們在“對付語言”上花的精力,可能超過了“對付業務”。編譯器本身已經是一個超級復雜的系統,但 C++ 又額外疊加了一層復雜度:
一個變量可能有二十幾種初始化方式
一個類可以有足足六種構造函數;
模板元編程的各種黑魔法,且與C++主體編程范式大為不同的函數式范式。
標準庫里大量行為細節、陷阱、爛尾特性和詞不達意,例如變長數組叫vector,而真正的變長數組valarray是一個爛尾的特性;vector 并不是bool的容器;std::regex離譜的性能問題;std::remove實際上的作用是把元素移動到末尾等等。
各種看起來炫酷,實際上有些“故作高深”的名詞,例如SFINAE,CRTP,RTTI,RAII,monostate等等。
寫編譯器的工程師,本來應該把大部分時間花在「語言語義、優化算法、后端架構」上,但在 C++ 世界,團隊不得不在很長時間里花大量精力,放在給新人培訓 C++ 語法和習慣用法,或者是與各種構建配置、ABI、模板錯誤信息搏斗。
2. 字符串處理上問題頻出
編譯器本質上你可以看做是一個復雜的字符串處理程序,但一個很不幸的事實是: C++ 標準庫在字符串處理上的支持并不友好,缺少真正可靠的字符串處理庫,常用的std::string或者std::regex都有不小的問題。這使得現實世界中,很多經典的庫可能會選擇自己動手制作字符串庫,但是C++難以集成第三方庫的特點由阻礙了開發者去使用它們。
而這對于想用 C++ 入門寫編譯器的學生來說就非常不友好了,很多人連第一關「詞法分析」可能都過不去。
3. 編譯慢,調試體驗差
C++的編譯實在是太慢了,越大的項目這個問題越明顯。這是C++本身模板展開和頭文件的重復編譯導致的這個問題,很多情況下,開發者稍微改一點點,就要重新等很久。
但編譯器又是一個「必須頻繁讀源碼、單步調試」的系統軟件,因為編譯器與Web程序或者游戲程序不同,很多 bug 無法靠打 log 簡單定位;需要頻繁重編譯 + GDB / LLDB 調試。
這使得日常開發體驗非常不友好,debug 版 LLVM + C++ 的組合,有時慢到讓人懷疑人生。編譯和調試的效率低下結果導致的問題就是企業的開發成本非常高。
4. 構建系統和第三方依賴太折騰
幾乎每個寫 C++ 的人都和各種構建系統打過交道,Makefile / Ninja / Bazel / MSBuild / SCons / ...等等。而CMake 雖然是事實標準,但在語法和使用體驗上,實在是一言難盡。
構建系統混亂帶來的直接后果就是引入第三方庫極其麻煩,因為不同的包可能使用了不同的構建工具。即使都使用了CMake,ABI、編譯選項、鏈接方式的兼容性問題也常常出現。一些GitHub Star很高的項目,會推崇單頭文件模式,但是這樣又會帶來編譯速度的問題。
構建系統和第三方庫的問題,造成了一個C++特色:C++ 程序員,對「重復造輪子」往往已經習以為常。
如果有一個「非 C++ 的 LLVM 伴侶」……
假如我們有這樣一個東西:
能和真實的 LLVM 平滑互操作,能夠生成兼容 LLVM 工具鏈的 IR / bytecode;
有著非常優秀的字符串處理,ADT,模式匹配語法,而且語法簡單,上手容易,AI友好。
更輕量、編譯速度快、源碼更容易讀;
這就是 MoonLLVM 想做的事情。
MoonLLVM:A Tiny, Friendly Companion to LLVM
GitHub 地址:moonbitlang/MoonLLVM
MoonLLVM 的定位:不是「重寫 LLVM」,而是「LLVM 的友好伴侶」
先把預期講清楚:
MoonLLVM 不是 LLVM 的重構版;也不打算直接取代 LLVM。
現實是:LLVM 過去二十多年集結了多家大公司的巨大投入,在優化、多后端支持、生態廣度上,有壓倒性的優勢。MoonLLVM 短期內不可能、也沒必要在這些維度上正面進攻。
MoonLLVM 想填補的是另一塊空白:
讓學生和初學者更容易接觸 IR / Pass / 后端;
讓小型芯片公司、小團隊可以用更低成本做原型和特定場景的后端;
讓熟悉 LLVM 的工程師多一個更輕量、可退出的選項。
MoonLLVM 和很多「自建小框架」,例如QBE,Cranelift等最大的不同,是我們從一開始就認真設計了與真 LLVM 的互操作,而不是造一個完全封閉的「私有宇宙」。
可以分三層來看:
1.1 代碼級互操作
我們有一個 llvm.mbt 包,它是一個真 LLVM 的 MoonBit 綁定,需要本地安裝 LLVM。調用llvm.mbt得到的IR,就是原版LLVM生成出來的IR。 github: https://github.com/moonbitlang/llvm
MoonLLVM 的 API 與 llvm.mbt 有意識地對齊:數據結構、接口設計都保持相似。
用戶只需改一處:調整 moon.pkg.json 配置,即可在 MoonLLVM 和真 LLVM 之間切換:
設計目標是:MoonLLVM → 真 LLVM 平滑切換;
需要注意的是,反向切回來我們無法保證,這是因為MoonLLVM還是比真LLVM簡單太多。
MoonLLVM / llvm.mbt 的 API 很大程度上參考了原版 C++ LLVM:
Context / Module / Function / BasicBlock / IRBuilder 等核心概念一一對應;
操作順序、調用方式盡量保持一致;
對熟悉 C++ LLVM 的工程師來說,幾乎不需要換腦子。
MoonLLVM 與 llvm.mbt 可以在同一工程中共存;
提供轉換函數,將 MoonLLVM 的中間數據結構轉成 llvm.mbt 的數據結構;
這意味著:你可以在 MoonLLVM 中做自定義 IR 生成、輕量優化,然后把 IR 交給真 LLVM 做后續優化和后端。
MoonLLVM 生成的 LLVM IR / bytecode:
可以被現有 LLVM 工具鏈(如 llc、opt)識別和處理;
MoonLLVM 對其能力范圍內的 IR 支持 Parse 和再處理。
一條典型鏈路可以是:
MoonLLVM → LLVM IR → llvm-opt 優化 → LLVM IR →(可選)再回 MoonLLVM
從一開始,MoonLLVM 就內建了一個清晰的「退出機制」:
用戶不用擔心「用了 MoonLLVM 以后就被架死在這里」;
未來如果有需要:可以逐步把關鍵路徑遷回真 LLVM;或者只在某些階段用 MoonLLVM 快速試驗和開發。
運行速度:用「適度取舍」換來輕盈
MoonLLVM 一開始就明確做了一個選擇:不追求覆蓋所有稀奇古怪的 C 語言特性(比如 VLA 等),C++特性(例如各種C++專用的異常)。也不追求支持所有冷門架構與擴展。
這樣做的好處是:數據結構和算法可以更簡單,內部可以大量使用定長整數和更直接的實現,在「生成 IR / 做基礎轉換」這類場景下,MoonLLVM 在 MoonBit 里調用的整體運行速度,有機會顯著快于直接調用真 LLVM。
編譯速度快,組件細粒度模塊化 MoonLLVM 有意識地把組件拆得更細,做到用到哪個編譯哪個,沒用到的完全不參與構建;整體編譯時間可以維持在較低水平;對開發者來說:改一個 Pass,不需要重編整個「工程」;非常適合做在線 Playground / REPL 的后端;或者是新 Pass / 新后端的實驗平臺。
無外部依賴:只依賴 MoonBit 工具鏈 MoonLLVM 只需要 MoonBit 自身的工具鏈即可:不需要外部 C++ 編譯器;也不需要 CMake / TableGen 等復雜構建工具。對于只會 MoonBit 的開發者來說,安裝過程非常簡單;
輕量,適合「弱環境」和多種部署形態
得益于整體設計的輕量化和 MoonBit 語言本身的特性:MoonLLVM 可以跑在性能不算強的 PC 上,也可以通過 WebAssembly 部署到瀏覽器中,這使得它在部分嵌入式 / 邊緣計算環境中也有實際落地的希望;
這為「MoonBit 在線 Playground」、「嵌入式腳本 / DSL 環境」等場景,提供了很自然的技術路徑。
下面這個示例展示了如何用 MoonLLVM 創建一個簡單的加法函數:
輸出的 LLVM IR 大致如下:
注意頂部的注釋部分明確標注了「Generated by MoonLLVM, not llvm」,這與原版 C++ LLVM 的輸出可以清晰區分。
這份 IR 既可以交給官方 LLVM 工具鏈(例如 llc)繼續編譯,也可以作為 MoonMIR 的輸入,進一步生成 riscv64 或 aarch64 匯編。
對應的 C++ LLVM 程序對比
下面是一段等價的 C++ LLVM API 示例代碼,實現同樣的 add(i32, i32) -> i32 函數:
MoonLLVM 目前已經做到什么?
當前,MoonLLVM 已經具備以下能力:
支持 LLVM IR 的構建;
在此基礎上,完成了初步的后端代碼生成,可以獨立生成 RISC-V 匯編代碼,和 AArch64 匯編代碼。
基于 MoonLLVM,我們實現了一個 MiniMoonBit 編譯器,除基礎特性外,還支持模式匹配、高階函數等特性,完成MiniMoonBit編譯器后,我們還用 MiniMoonBit 跑了一個光線追蹤程序,效果可以在 B 站視頻中看到:
B 站視頻:MiniMoonBit + MoonLLVM 光線追蹤示例
性能測試:與 tcc / clang 的對比
為了測試 MoonLLVM 的實際表現,我們設計了 5 個小例子:
ack.mbt:Ackermann 遞歸函數;
fib.mbt:遞歸 Fibonacci;
eigen.mbt:矩陣求特征值;
svd.mbt:矩陣 SVD 分解;
queen.mbt:八皇后問題。
測試方式如下:
MiniMoonBit(基于 MoonLLVM)
MiniMoonBit 生成 AArch64 匯編;
使用 clang -O0 編譯匯編文件和 runtime.c,得到可執行程序。
tcc
使用 MoonBit 將對應 .mbt 文件通過 --target native 轉為 C 程序;
使用 tcc 將 C 文件與 MoonBit 標準 runtime.c 編譯為可執行程序。
clang -O0
同樣先轉為 C,再用 clang -O0 編譯。
clang -O1
同樣先轉為 C,再用 clang -O1 編譯。
然后分別運行所得可執行程序,記錄時間(單位:秒):
配圖如下:
![]()
性能結果分析
整體來看:
基于 MoonLLVM 的 MiniMoonBit 性能明顯優于 tcc 和 clang -O0;
與 clang -O1 相比,MiniMoonBit 仍有差距,但在同數量級之內。
主要原因在于:
MoonLLVM 當前后端已經做了寄存器分配(采用圖著色寄存器分配);
而 tcc 和 clang -O0 不做寄存器分配,因此在部分算例中會出現明顯性能劣勢;
clang -O1 在寄存器分配之外,還開啟了更多優化 Pass,因此通常會比當前版本的 MiniMoonBit 更快。
換句話說,在仍然相對「年輕」的優化管線下,MoonLLVM 已經能在不少場景中跑到接近 clang -O1 的表現;后續優化空間依然很大。
展望:MoonLLVM 接下來要做什么?
未來一段時間內,MoonLLVM 會重點在以下方向持續演進:
兌現互操作承諾:持續完善與真 LLVM 的互操作能力;保證「隨時可以退出到真 LLVM」這條路徑長期有效。
擴展指令與類型系統:豐富 IR 指令和類型支持;增強優化能力,引入更多調試與診斷信息。
增加更多體系結構后端:補充 x86_64 等后端;在更多架構上驗證當前抽象方案的通用性與簡潔性。
打造完整工具鏈閉環:開發配套匯編器(MoonAs)與鏈接器(MoonLD);構建由 MoonLLVM 驅動的、可獨立運作的工具鏈閉環。
我們希望,MoonLLVM 既能成為教學與研究的友好平臺,也能在特定場景下,成為真正落地可用的輕量級編譯后端。
如果你對 LLVM 生態已經很熟悉,希望有一個更輕量、可實驗、可與真 LLVM 平滑切換的伴侶;或者你只是想用一種更現代、更干凈的方式來認識「編譯器后端」這個世界,歡迎試試 MoonLLVM:
[1]: MoonLLVM鏈接:https://github.com/moonbitlang/MoonLLVM
[2]: MiniMoonBit編譯器:https://github.com/moonbitlang/MiniMoonBit2025
[3]: B站視頻,用MoonBit寫個MiniMoonBit跑了一個光線追蹤: https://www.bilibili.com/video/BV1kSS4BqETn
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.