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