llvm
- LLVM项目或基础架构:这是对整个LLVM编译器框架的程序,包括了前端、优化器、后端、汇编器、链接器,以及libc++、JIT等。上下文如:“LLVM项目由以下几个模块组成”。
- 基于LLVM开发的编译器:这是指一部分或全部基于LLVM项目开发的编译器软件,软件可能基于LLVM的前端或后端来实现。上下文如:“我用LLVM将C语言编译到MIPS平台”。
- LLVM库:LLVM项目由库代码和一些工具组成,有时会指代LLVM库内容。上下文如:“我的项目使用了LLVM的即时编译框架”(JIT是其中一个库)。
- LLVM核心:在IR和后端算法上的内容,就是LLVM核心,也就是通常Clang/LLVM中的LLVM。上下文如:“LLVM和Clang是两个项目”。
- LLVM IR:有些时候也会指代其中间表示。上下文如:“Clang是一个前端,能将源代码翻译成LLVM”。
-
LLVM编译器架构
- Frontend:前端。词法分析,语法分析,语义分析,生成中间代码。(不管哪种source code生成的IR都是一样的)
- Optimizer:优化器。IR代码优化。编写
Pass
->IR - Backend:后端。编译,汇编,linker生成
Machine code
。(不管哪种后端,使用的IR都是一样的) - 相比之下,GCC的前后端耦合在一起。所以GCC为了支持一门新的语言,或者支持一种新的平台,变得非常困难
-
模块化,可重用的编译器及工具链技术集合
-
创始人
Chris Lattner
,swift之父 -
之前Apple公司一直使用gcc作为编译器,后来GCC对Objective-C的语言特性支持一直不够,Apple自己开发的GCC模块又很难得到GCC委员会的合并,所以老乔不开心。等到Chris Lattner毕业时,Apple就把他招入靡下,去开发自己的编译器,所以LLVM最初受到了Apple的大力支持。
-
LLVM是一个编译器框架,框架的意思是,你可以基于LLVM提供的功能开发自己的模块,并集成在LLVM系统上,增加它的功能,或者就单纯自己开发软件工具,而利用LLVM来支撑底层实现。
-
Clang/LLVM的简单架构
-
LLVM IR
是LLVM的中间表示,大多数的优化都依赖于LLVM IR展开。LLVM的一个设计思想是优化可以渗透在整个编译流程中各个阶段,比如编译时、链接时、运行时等。 -
LLVM backend
就是LLVM真正的后端,也被称为LLVM核心,包括编译、汇编、链接这一套,最后生成汇编文件或者目标码。这里的LLVM compiler和gcc中的compiler不一样,这里的LLVM compiler只是编译LLVM IR。
gcc
gcc
的编译器,输入是源代码,输出是汇编代码,相当于是LLVM中Clang一级加上IR linker再加上LLVM compiler中的生成汇编代码部分。- gcc的汇编器,输入是汇编代码,输出是目标文件,相当于是LLVM中的llvm-mc
- gcc的链接器,输入是目标文件,输出是最终可执行文件,相当于LLVM中的Linker
Clang,llvm frontend
- llvm项目的一个子项目,LLVM项目中一个很重要的前端工具
- 基于llvm架构的C/C++/OC编译器前端
- 编译速度快
- 占用内存小,生成的AST语法树占用内存是GCC的五分之
Clang查看各阶段
- 查看编译过程
mkdir llvm基础 && cd ./llvm基础 && vs main.m
main.m
#define AGE 40
int main(int argc, const char * argv[]) {
int a = 10;
int b = 20;
int c = a + b + AGE;
return 0;
}
iTerm
clang -ccc-print-phases main.m
+- 0: input, "main.m", objective-c
+- 1: preprocessor, {0}, objective-c-cpp-output
+- 2: compiler, {1}, ir
+- 3: backend, {2}, assembler
+- 4: assembler, {3}, object
+- 5: linker, {4}, image
+- 6: bind-arch, "x86_64", {5}, image
导入文件,预处理,编译生成ir,后端编译成汇编,汇编生成.o,linke各种库,linke archive生成对应架构可执行文件
- preprocessor(预处理)。导入头文件,宏替换
clang -E main.m
Applying Apple Clang Hooks...
# 1 "main.m"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 378 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "main.m" 2
int main(int argc, const char * argv[]) {
int a = 10;
int b = 20;
int c = a + b + 40;
return 0;
}
3-1. 前端词法分析,生成Token。对每一个字符生成token
clang -fmodules -E -Xclang -dump-tokens main.m
3-2. 前端语法分析,生成AST(AST,Abstract Syntax Tree)。
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
3-3. 前端生成IR。中间人码LLVM IR有3种表示形式
- text:便于阅读的文本格式,类似于汇编语言,拓展名.ll。
- memory:内存格式。
- bitcode:二进制格式,拓展名.bc。
0101
格式 - 等价,只是格式不同
text格式 .ll
clang -S -emit-llvm main.m
bitcode:二进制格式,拓展名.bc
clang -c -emit-llvm main.m
llvm-dis main.bc #可以把.bc转换成.ll
- 后端汇编
clang -S -fobjc-arc main.m
- 生成.o目标文件
clang -fmodules -c main.m
- 生成可执行文件
clang main.o -o output
file output
#output: Mach-O 64-bit executable x86_64
安装LLVM
mkdir LLVM && cd LLVM
git clone https://github.com/llvm/llvm-project
mkdir llvm-build && cd llvm-build
cmake -G Ninja ../llvm-project/llvm -DCMAKE_INSTALL_PREFIX=/Users/liangze/opt/llvm-release
mkdir llvm-xcode && cd llvm-xcode
cmake -G Xcode ../llvm-project/llvm
# Loadable modules 编写插件