什麼是 LLVM? Swift、Rust、Clang等背後的力量 - infoworld

banq發表於2022-01-08

新的語言,以及對現有語言的改進,在整個開發環境中如雨後春筍般湧現。Mozilla 的 Rust、Apple 的 Swift、Jetbrains 的 Kotlin和許多其他語言為開發人員提供了速度、安全性、便利性、可移植性和強大功能的新選擇範圍。
為什麼是現在這個時候湧現這種現象?
一個重要原因是用於構建語言的新工具——特別是編譯器。其中最主要的是LLVM,這是一個開源專案,最初由 Swift 語言建立者 Chris Lattner 作為伊利諾伊大學的一個研究專案開發。
LLVM 不僅可以更輕鬆地建立新語言,還可以增強現有語言的開發。它提供了用於自動化語言建立任務中許多最吃力不討好的部分的工具:建立編譯器,將輸出的程式碼移植到多個平臺和架構,生成特定於架構的最佳化,例如向量化,以及編寫程式碼來處理常見的語言隱喻,例如exception。它的自由許可意味著它可以作為軟體元件自由重用或部署為服務。
使用 LLVM 的語言列表有許多熟悉的名稱。Apple 的 Swift 語言使用 LLVM 作為其編譯器框架,Rust 使用 LLVM 作為其工具鏈的核心元件。此外,許多編譯器都有一個 LLVM 版本,例如 Clang,C/C++ 編譯器(這個名稱,“C-lang”),它本身就是一個與 LLVM 密切相關的專案。Mono 是 .NET 實現,可以選擇使用 LLVM 後端編譯為本機程式碼。Kotlin,名義上是一種 JVM 語言,正在開發一種名為Kotlin Native的語言版本,它使用 LLVM 編譯為機器原生程式碼。
 

LLVM 定義
LLVM 的核心是一個用於以程式設計方式建立機器原生程式碼的庫。開發人員使用 API 以稱為中間表示或 IR的格式生成指令。然後,LLVM 可以將 IR 編譯為獨立的二進位制檔案或對程式碼執行 JIT(即時)編譯,以在另一個程式的上下文中執行,例如該語言的直譯器或執行時。
LLVM 的 API 為開發程式語言中的許多常見結構和模式提供了原語。例如,幾乎每一種語言都有函式和全域性變數的概念,而且許多語言都有協程和 C 外部函式介面。LLVM 將函式和全域性變數作為其 IR 中的標準元素,並具有用於建立協程和與 C 庫介面的隱喻。
無需花費時間和精力重新發明那些特定的輪子,您可以只使用 LLVM 的實現並專注於您的語言中需要注意的部分。
 

LLVM:專為便攜性而設計
要理解 LLVM,考慮與 C 程式語言進行類比可能會有所幫助:C 有時被描述為一種可移植的高階組合語言,因為它具有可以緊密對映到系統硬體的結構,並且它已被移植到幾乎每個系統架構。但是 C 作為一種可移植的組合語言只是在一定程度上有用。它不是為特定目的而設計的。
相比之下,LLVM 的 IR 從一開始就被設計為可移植的程式集。它實現這種可移植性的一種方法是提供獨立於任何特定機器架構的原語。例如,整數型別並不侷限於底層硬體的最大位寬(例如 32 位或 64 位)。您可以根據需要使用盡可能多的位建立原始整數型別,例如 128 位整數。您也不必擔心製作輸出以匹配特定處理器的指令集;LLVM 也會為您解決這個問題。
LLVM 的架構中立設計使得支援現在和未來的各種硬體變得更加容易。例如,IBM 最近貢獻了程式碼來支援其 z/OS、Linux on Power(包括對 IBM 的 MASS 向量化庫的支援)以及用於 LLVM 的 C、C++ 和 Fortran 專案的 AIX 架構。 
如果您想檢視 LLVM IR 的實時示例,請訪問ELLCC 專案網站並嘗試在瀏覽器中將 C 程式碼轉換為 LLVM IR的實時演示
  

程式語言如何使用 LLVM

  • 使用 LLVM 進行即時編譯

有些情況需要在執行時動態生成程式碼JIT,而不是提前編譯,如Julia。
其他人正在嘗試使用 LLVM 作為 JIT 的新方法,例如編譯 PostgreSQL 查詢,從而將效能提高五倍。
  •  使用 LLVM 自動最佳化程式碼

LLVM 不只是將 IR 編譯為本機機器碼。您還可以以程式設計方式指導它以高度粒度最佳化程式碼,一直到連結過程。最佳化可能非常激進,包括行內函數、消除死程式碼(包括未使用的型別宣告和函式引數)和展開迴圈。
  • 使用 LLVM 的領域特定語言

LLVM 已用於為許多通用語言生成編譯器,但它也可用於生成高度垂直或專屬於問題域的語言。在某些方面,這是 LLVM 最閃耀的地方,因為它消除了建立這種語言的許多苦差事,並使其表現良好。
 

LLVM 不做什麼
有了 LLVM 提供的所有功能,瞭解它不做什麼也是很有用的。
例如,LLVM 不解析語言的語法。許多工具已經完成了這項工作,例如lex/yaccflex/bisonLark和 ANTLR。無論如何,解析都意味著與編譯解耦,因此 LLVM 沒有嘗試解決任何問題也就不足為奇了。
LLVM 也沒有直接解決圍繞給定語言的更大的軟體文化。安裝編譯器的二進位制檔案、管理安裝中的包以及升級工具鏈——您需要自己完成這些工作。
  

有無垃圾回收機制?
最後,也是最重要的,LLVM 仍然沒有為其提供原語的語言的公共部分。許多語言都有某種方式的垃圾回收記憶體管理,要麼作為管理記憶體的主要方式,要麼作為RAII(C++ 和 Rust 使用的)等策略的輔助。LLVM 沒有為您提供垃圾收集器機制,但它確實提供了實現垃圾收集 的工具,方法是允許使用後設資料標記程式碼,從而更輕鬆地編寫垃圾收集器。
不過,這一切都不能排除 LLVM 最終可能會新增本地機制來實現垃圾收集的可能性。LLVM 發展迅速,每六個月左右釋出一次主要版本。由於許多當前語言將 LLVM 置於其開發過程的核心,因此開發速度可能只會加快。
原文點選標題

相關文章