MLIR: 编译器基础架构重定义
MLIR: 編譯器基礎架構重定義
MLIR(多級中間表示)是語言(如 C)或庫(如 TensorFlow)與編譯器后端(如 LLVM)之間的中間表示 (IR) 系統。允許不同語言的不同編譯器堆棧之間的代碼重用以及其他性能和可用性優勢。
MLIR 由Google開發為一個開源項目,主要是為了改進 TensorFlow 在不同后端的支持,但通常可用于任何語言。
背景
要了解 MLIR 的適用范圍,需要簡要概述 C、Java 和 Swift 等常用語言的編譯器基礎架構,然后繼續介紹 TensorFlow 的編譯器基礎架構。這樣,MLIR 的原理和可交付成果的想法就很清楚了。
編譯器架構情況:
從 C 的編譯器基礎結構開始。C 編譯器接收 C 代碼,轉換為抽象語法樹 (AST),然后將其轉換為 LLVM IR。AST 是一種樹數據結構,其中節點表示算子等代碼組件,葉節點表示數據。例如,像a+b這樣的代碼語句的抽象語法樹如下:
隨后,抽象語法樹被轉換為 LLVM IR(中間表示)。LLVM 是一種編譯器基礎架構,可將 LLVM IR 轉換為機器代碼。LLVM 是一種常用工具,是最流行的語言(如 C、C++、JAVA、Swift 等)的一部分。
所以,C代碼的流程如下:
? C 代碼由 C 編譯器(如 GCC)轉換為 Clang AST
? Clang AST 通過 C 編譯器(如 GCC)轉換為 LLVM IR
? LLVM IR 由 LLVM 轉換為機器碼
C 的這種編譯策略存在一些問題,例如:
? 在 AST 中,將代碼語句鏈接到代碼行號或源代碼的信息丟失了,因為 AST 無法存儲此類信息。導致無法指向源代碼的錯誤。一個常見的例子是,當發生segmentation fault時,錯誤信息并沒有說明是源代碼中的哪一行導致了這個問題。
? 由于 C 代碼直接轉換為 AST,不會進行特定于語言的優化。事實上,如果開發了 C 庫,則在此流程中無法在編譯器期間進行特定于庫的優化。
Java 和 Swift 等語言采用了不同的方法來解決這個問題。
Java是第一個解決這個問題成功的語言。Java 的方法是將 Java 代碼轉換為 Java 字節碼 (JavaBC),是 Java 的內部表示。正是在這種表示進行了 Java 特定和庫特定的優化。在此之后,Java BC 被轉換為 LLVM IR,后者被 LLVM 轉換為機器代碼。因此,Java 的方法是避免創建 AST,是任何程序的通用表示,因此創建了自己的格式,不僅解決了 C 的問題,而且使 Java 成為第一個獨立于平臺的語言。
Java 方法的一個問題是變得非常復雜,需要深入了解 LLVM 才能充分利用。這將現有資源發揮到極致,以獲得最佳優化。
其它語言復制 Java 的技術是一個問題,所以后來,Swift 提出了自己的方法,并被廣泛采用。
Swift代碼被轉換為 AST,其中 Swift 特定表示被轉換為 Swift 的內部表示。正是在這一點上,所有語言特定的優化都完成了。隨后,Swift IR 被轉換為 LLVM IR,后者被 LLVM 獲取并轉換為機器代碼。
這是一種相對簡單的方法,解決了所有 C 的原始問題。在功能上,與 Java 的方法相同。Swift 的方法變得非常流行,并被改編成Rust等新語言。
此時的主要問題,每當創建一種新語言時,必須再次進行所有優化,例如程序流程優化、數據結構優化等(以前的語言已經完成)。唯一不同的是語言特定的優化。LLVM 負責機器級優化。因此,必須為每種語言再次創建整個管道。
如果仔細觀察,語言僅在操作抽象和內部語言特定優化方面有所不同。為了幫助創建新的語言和庫,Google TensorFlow 團隊決定創建 MLIR(多級中間表示)。
實際上,這個問題是在 TensorFlow 中遇到的,谷歌并沒有專門為 TF 解決這個問題,而是決定一勞永逸地修復編譯器基礎架構。
TensorFlow 的編譯器基礎架構:
流程如下:
? 可以使用API 之一(如 C++ 或 Python)來編寫 TensorFlow 代碼
? TensorFlow 代碼被轉換為 TF 圖,Gappler(TensorFlow 中的一個模塊)進行圖級優化,包括幾個機器學習特定的優化,如算子融合。
? 在此之后,TF 圖被轉換為其后端之一(替代 LLVM)的眾多內部表示 (IR) 之一。
? TensorFlow 有許多后端,如 XLA(用于 TPU)、TF Lite(用于移動設備)等
問題是對于每個路徑(如 XLA 和 TF Lite),開發人員必須重新實現所有優化,并且大多數優化是通用的,但代碼重用是不可能的。這個問題將通過 MLIR 解決。
因此,MLIR 的流程如下圖所示:
概括:
? 不同語言的相同編譯器基礎結構,不可重用
? 類似于 Swift 和其他語言中的編譯器基礎結構
? tensorflow 支持許多具有不同 IR 的后端,無需代碼重用
? 目的是增加代碼重用以快速適應新的硬件后端
? 中間 IR 用于捕獲數據流信息并應用優化、比 LLVM 更好的源代碼跟蹤、靈活的設計、重用 LLVM 進行機器代碼生成
使用 MLIR 的優勢
使用 MLIR 的優勢:
? 默認情況下源代碼位置跟蹤
? 默認情況下,所有功能都在多核上運行(使用 OpenMP)
? 更好地重用編譯器堆棧的代碼(用于新庫和硬件),重用其它語言完成的優化
? 通過開發 CIL IR 為 C 提供更好的編譯器堆棧
? 對于 TensorFlow,一條路徑中的優化可以在其它路徑中重用,從而實現大量代碼重用。
內部關鍵思想
MLIR 的主要思想是:
? 沒有預定義的類型或指令。這允許開發人員自定義數據類型和指令抽象
? 沒有預定義的操作
? MLIR 中的基本對象是一種方言dialects,從實現的角度可以認為是一個類
? 需要定義指向 C++ 代碼的方言dialects,方言dialects就像自定義語言的類
? 方言dialects有 3 部分:函數名、輸入參數列表、輸出參數列表
? 對于每種方言dialects,默認功能如類型檢查、映射到 LLVM IR
? MLIR 默認支持線性代數運算,例如方言dialects之間的類型檢查
? 語言被轉換為帶有方言dialects的形式
? 在這種形式(方言dialects集)上,執行優化
? 經過各種級別的lowering,方言dialects可以直接轉換為LLVM IR
? 在 MLIR 中更好地使用 OpenMP,所有信息都可用
? 默認情況下,所有功能都在所有內核上運行(更好的系統使用)
? (優于 LLVM)每個操作數都有一個源代碼內存地址屬性,直接指向發生錯誤的源代碼行
? 將使用 XLA 基礎架構進行性能分析和剖析。
應用
MLIR用于改進 TensorFlow 編譯器基礎架構:
- 通過源代碼跟蹤改進 TF Lite 的生成
編譯流程如下:
? TF代碼
? 方言dialects
? 驗證/優化
? 用于 tf lite 后端的 tf lite 方言dialects - 使用 MLIR 更改 XLA HLO 的路徑
編譯流程如下:
? tf
? 方言dialects
? 驗證/優化
? xla方言dialects
? xla后端
它將重用來自 TF Lite 路徑的一些組件 - 使用 MLIR 支持新的編譯器后端
當一個新平臺 P 出現并且它有一個新的后端 B 時,然后轉換 TensorFlow 代碼通過使用 TF Lite 和 XLA 的現有代碼,轉換為現有的方言dialects/IR。接下來,需要編寫一個新的方言dialects集/IR(針對平臺進行自定義優化)和轉換代碼,轉換為平臺后端編譯器所需的 IR。
MLIR 的使用使該過程更易于管理和快速。
其它應用
MLIR 是一種通用工具,可用于其它目的,例如:
? 通過 MLIR 插入新的 IR 來解決 C 和 C++ 代碼的問題
? 新語言可以直接使用使用 MLIR 的現有語言的優化,因此開發新語言將變得容易和快速。
? 一旦使用MLIR的系統實施,一組編譯技術的創新可以被多個組輕松使用
簡而言之,LLVM 極大地創新了編譯器生態系統,但現在 MLIR 通過利用 LLVM 的最佳部分實現更簡單、更高效的編譯器生態系統,從而進入了下一階段。
總結
以上是生活随笔為你收集整理的MLIR: 编译器基础架构重定义的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GPU特征处理技术
- 下一篇: 网路摄像头技术参数介绍