簡(jiǎn)介
LLVM 是一個(gè)發(fā)展中的前言編輯器技術(shù)框架,它易于擴(kuò)展并設(shè)計(jì)成多個(gè)庫(kù)的形式,可以為編譯器開發(fā)者提供流暢的體驗(yàn),并能使編譯器開發(fā)所涉及的學(xué)習(xí)過(guò)程變得非常流暢吐绵。
LLVM 架構(gòu)特性
- C++ 語(yǔ)言實(shí)現(xiàn)
- 前端與后端分離,支持多種前端和后端河绽,使用中間代碼 IR 進(jìn)行銜接
- 第一個(gè) Release 版本發(fā)布于 2003 年己单,代碼開源
- 提供了很多工具用于編譯和優(yōu)化代碼
- 與 GCC 相比,編譯出的程序運(yùn)行效率更高
Tools 使用
LLVM 的一些優(yōu)化和繪圖都針對(duì) bitcode 文件耙饰,這里介紹與之相關(guān)的工具使用
從 源文件 生成 bitcode 文件
clang -c -emit-llvm const.c -o const.bc
clang 是 LLVM 的前端編譯工具纹笼,可以用它來(lái)生成目標(biāo)文件,這個(gè)指令將 .c 代碼生成 .bc 文件.
warning:
使用這個(gè)命令的時(shí)候會(huì)自動(dòng)帶有 -O0 級(jí)別的優(yōu)化(新版本中)苟跪,可以禁止它廷痘,參考
clang -c -emit-llvm -Xclang -disable-O0-optnone const.c -o const.bc
llvm tools 提供了產(chǎn)生 cfg callgraph 等圖片參數(shù)的工具(opt),注意件已,不會(huì)自己生成圖片笋额,還需要工具(如:graphviz MacOS下安裝 brew install graphviz)
cfg 圖
opt –view-cfg const.bc
call 圖
opt -view-callgraph file.bc
中間代碼優(yōu)化
用 opt ,還可以調(diào)用 LLVM 提供的優(yōu)化器對(duì) bitcode 文件進(jìn)行代碼優(yōu)化
opt -mem2reg const.bc -o const.reg.bc
-constprop 臨時(shí)變量
-early-cse 消除公共部分
運(yùn)行 help 篷扩,可以查看 LLVM 提供的優(yōu)化器
opt -help
-load 可以加載自定義的優(yōu)化器(或其他分析器)兄猩,如
opt -load LLVMCountOp.dylib -opCounter file.bc -o file.oc.bc
opt -load LLVMCountOp.dylib -help
-opCounter LLVMCountOp.dylib 里面 Pass 的注冊(cè)標(biāo)記
如果僅僅分析代碼,可以用 -disable-output 禁用輸出
opt -load LLVMCountOp.dylib -opCounter -disable-output -time-passes file.bc
-time-passes pass 運(yùn)行時(shí)間
bitcode 文件生產(chǎn) .ll ,中間代碼 IR 文件
llvm-dis const.bc
可以對(duì) .ll 進(jìn)行即時(shí)運(yùn)行(JIT)
lli const.ll
bitcode 文件生成可執(zhí)行文件
clang const.ll
./a.out
bitcode 文件生成目標(biāo)平臺(tái)機(jī)器碼
llc -march=x86 ex0.reg.bc -o ex0.reg.x86
使用官方二進(jìn)制庫(kù)
LLVM 官網(wǎng)提供了各個(gè)版本的下載瞻惋,有二進(jìn)制文件和源碼厦滤,使用二進(jìn)制文件中包含了可以直接運(yùn)行在目標(biāo)平臺(tái)的 Tools 和 LLVM 的基礎(chǔ)功能靜態(tài)庫(kù)。
直接使用二進(jìn)制靜態(tài)庫(kù)歼狼,可以開發(fā)出我們自己的編譯工具掏导,Tools 里有 llvm-config 提供了補(bǔ)充 LLVM 各個(gè)依賴參數(shù)功能,可以方便編寫 MakeFile 文件羽峰,編譯工程趟咆。
倉(cāng)庫(kù)下 JIT 提供了一個(gè)編譯工具的工程添瓷,依賴的 LLVM 版本是 3.4 。提供了一個(gè)通用的 MakeFile 模板值纱。
LLVM_CONFIG ?= ../bin_3.4/bin/llvm-config
ifndef VERBOSE
QUIET := @
endif
SRC_DIR ?= $(PWD)
LLVM_LDFLAGS := $(shell $(LLVM_CONFIG) --ldflags)
COMMON_FLAGS = -Wall -Wextra
LLVM_CXXFLAGS += $(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cxxflags)
LLVM_CPPFLAGS += $(shell $(LLVM_CONFIG) --cppflags) -I$(SRC_DIR)
LLVM_LIBS = $(shell $(LLVM_CONFIG) --libs jit interpreter nativecodegen)
objects = Driver.o Expr.o Lexer.o Parser.o
name = driver
default: $(name)
$(name) : $(objects)
@echo Linking $@
$(QUIET)$(CXX) -o $@ $(LLVM_CXXFLAGS) $(LLVM_LDFLAGS) $^ $(LLVM_LIBS)
%.o : %.cpp
@echo Compiling $*.cpp
$(QUIET)$(CXX) -c $< $(LLVM_CPPFLAGS) -o $@
clean::
$(QUIET)rm -f $(name) $(objects)
系統(tǒng)下配置好 clang 環(huán)境鳞贷,然后設(shè)置好 LLVM_CONFIG 目錄,即可運(yùn)行 make 命令虐唠,進(jìn)行編譯搀愧。
使用官方源碼
借助于官網(wǎng)提供的源代碼也能開發(fā)出高效工具,這里以 Pass 的開發(fā)為例疆偿。
從官網(wǎng)找到一個(gè)版本(如:3.4)的代碼后咱筛,下載到本地,代碼工程由 cmake 工具組織杆故,可以在工程下創(chuàng)建目錄llvm_xcode迅箩,然后進(jìn)入目錄執(zhí)行
cmake -G Xcode ../llvm
就能生成支持 Xcode 的項(xiàng)目,用 Xcode IDE 可以打開工程(還支持其他IDE工具处铛,詳情參考官網(wǎng))饲趋。
在源碼工程下我們可以找到一個(gè)實(shí)例工程 Hello ,這是一個(gè) Pass 工程撤蟆,在 llvm/lib/Transforms 目錄下(不是 llvm_xcode 下的 lib)奕塑。我們使用目錄工具進(jìn)入該文件下,模仿Hello工程的配置家肯,新建自己的工程爵川,修改 Transforms 目錄下的 CMakeList.txt Makefile 和 子目錄下的文件。然后回到 llvm_xcode 目錄下息楔,再執(zhí)行一遍 cmake 指令。
Xcode IDE 可以對(duì)工程代碼進(jìn)行編輯扒披,編譯完成后值依,可以對(duì)目標(biāo) Target 進(jìn)行編譯。會(huì)生成以動(dòng)態(tài)鏈接庫(kù)碟案,放在工程下驗(yàn)證愿险, 倉(cāng)庫(kù) Passes 下提供了編譯好的庫(kù),可以直接使用价说。
常見錯(cuò)誤:
Error opening 'LLVMCountOp.dylib': dlopen(LLVMCountOp.dylib, 9): Symbol not found: __ZN4llvm12FunctionPass17assignPassManagerERNS_7PMStackENS_15PassManagerTypeE
Referenced from: LLVMCountOp.dylib
Expected in: flat namespace
加載的 Pass 和 opt 版本不對(duì)辆亏,或者 Release Debug 不一致