libgccjit和LLVM相比,有哪些優點?
感謝 @bhuztez 大大邀請。
水平有限,不知道從哪裡寫起、按什麼線索寫好。而且要說libgccjit跟LLVM相比,「優點有哪些」這明顯比「缺點有哪些」難寫啊?
只能又記流水賬了。先堆些libgccjit的鏈接:- libgccjit - GCC 5 Release Notes
- JIT-compilation using GCC 5
- libgccjit v5.1.0 documentation
- https://gcc.gnu.org/wiki/JIT
- Just-In-Time compilation using GCC (libgccjit.so)
下面分方面來對比一下。先列些點,細節回頭慢慢補充(希望能邊討論邊補充上來)
1、黑箱API(libgccjit) vs 黑箱/白箱混合API(LLVM IR)
各有千秋。總體看我覺得libgccjit的可控性還是有所欠缺。一旦到需要精密控制的時候它就不能行了。
libgccjit提供了兩套API,一套是C的,一套是C++的,兩者的實質功能一模一樣,後者只是前者的非常輕量級的包裝,讓C++代碼寫起來稍微舒服一點。
libgccjit的API提供的抽象程度跟C語言的的語義類似。換句話說基本上用這組API能達到的效果跟人肉拼接出C源碼然後一股腦扔給GCC去編譯是差不多的。
LLVM也提供了兩套API,同樣一套是C的一套是C++的。但是這兩者不是一回事:
LLVM C++ API是真正的核心API,可以對LLVM進行非常精密的控制,但因為暴露了LLVM的很多實現細節所以版本間不保證兼容。這個是白箱API;LLVM C API則是在此之上的一層封裝,並不怎麼暴露LLVM的內部實現,因而API穩定性較高。這個跟libgccjit的API類似,是黑箱API。LLVM: LLVM-C: C interface to LLVMLLVM IR的抽象程度在C語言以下,更接近底層一些。編譯流程中的很多要素可控,例如說calling convention在需要精密控制的時候可以控制得了。
這在實現VM runtime的JIT時尤其重要,因為很多VM為了一些特殊需求會想用特殊的calling convention提高性能。2、API穩定性
這裡毫無疑問是libgccjit在將來會更佔優;LLVM C API也可以算在同一層面上吧。
3、API的易用性(糖的多少)
用一個超簡單的例子來對比一下這些JIT庫的易用性。要實現的函數是C語義的:
int foo(int x, int y, int z) {
return x + y * z;
}
/* 待補充 */
jit_value x = func.get_param(0),
y = func.get_param(1),
z = func.get_param(2);
// use overloaded operators to build expressions
func.insn_return(x + y * z);
有沒有看起來很爽?完整代碼請看:這裡
可惜libjit的代碼生成質量太差,完全放不上桌面。它在x86上支持0和1兩個優化級別,但感覺生成的代碼也差不了多少。在這裡例子里,兩個級別生成的都是:(Mac OS X/x64)push %rbp
mov %rsp,%rbp
sub $0x20,%rsp
mov %edi,-0x8(%rbp)
mov %esi,-0x10(%rbp)
mov %edx,-0x18(%rbp)
mov -0x10(%rbp),%eax
imul -0x18(%rbp),%eax
mov -0x8(%rbp),%ecx
add %ecx,%eax
mov %rbp,%rsp
pop %rbp
retq
呃?
4、控制流、SSA
libgccjit
需要顯式構造基本塊來形成控制流圖。IR不暴露出SSA的特徵。LLVM
需要顯式構造基本塊來形成控制流圖。IR暴露出SSA的特徵,但是有辦法不用前端自己生成SSA。libjit
通過branch+label表示控制流,5、編譯速度
天啊,拿兩隻烏龜來比有意思么?
這倆都不是天然適合做輕量級JIT編譯器的料。6、對GC的支持
兩者都不咋。相比之下肯定是LLVM更勝一籌,有總比沒有好!
7、待續優點是它是一個JIT,缺點是它不是一個編譯器後端
我認真的.libgccjit簡直就只是一個玩具,根本沒有辦法拿來做即時編譯器。
推薦閱讀:
※LLVM相比於JVM,有哪些技術優勢?
※過程間和過程內的數據流分析演算法在類似LLVM的IR或HotSpot C1的HIR中,是如何實現的?