Getting Started with LLVM Core Libraries-工具和设计
Introducing LLVM's basic design principles and its history
追溯llvm的历史要追溯到10年前(2014),起初它着眼于编译器的后端算法和中间表述(今天依然是llvm的重点),当时其他部分还要依赖gcc。其中最重要的是它的IR,llvm在整个编译的过程中有很多种中间表示,如AST(C/C++转换成IR的过程)、DAG(IR转换成特定机器的汇编语言的过程)、某种特定的中间表示(汇编器和链接器使用)等其他中间表示依然起到很重要的作用,但是,真正让llvm与众不同的还是它的IR,甚至llvm这个名字的由来还和IR有很大的关系。
首先看IR(intermediate representation)的特点:
- SSA
- 无限多个寄存器
其存在方式有两种,一种在内存中,一种是在磁盘上,SSA能够更方便的优化,再加上保存在磁盘上的这种编码方式能够达到几近全时优化的效果,这也是llvm的作者在最早介绍llvm的论文中提出的目标,但是IR的描述能力毕竟有限,要想实现全时优化,就要求对诸如程序分布这种行为做出描述,这也意味着实现了此功能的llvm要像jvm那样能够成为一个运行平台,类似jvm的名字,llvm这个名字就是这么来的。
随着llvm项目的发展,其设计目标已经重点放在了通过磁盘上的IR操作实现链接时优化等功能,而不是全时优化,最终只保留了llvm这个名字,但是llvm已经成了一个强大的编译器框架,而不是一个类似jvm的那样的平台。
说到这,说一下个人理解吧,感觉是llvm起初提出了一个比较精妙的编码表示方案,有利于一些编译优化,进而发现可以憧憬的的目标——全时优化,但是又发现实现全时优化比较困难,在llvm的mail list上有人专门就此发起了一个很详细的讨论,详细阐述了llvm不能像java那样成为一个platform或者vm的原因,重点还是要做编译器。
Understanding LLVM tody
不管怎样,llvm这么名字还是保留下来了,现在如果有人跟你提起“LLVM”,可能是指以下内容:
- 整个LLVM Project/框架
- 由LLVM框架构造的编译器
- LLVM框架的可重用代码:库
- LLVM IR
LLVM框架主要包括三个方面的核心内容:
- 前端(frontend):将源码转换成中间代码(IR),包括词法分析、语法分析、语义分析、中间代码生成
- IR:两种方式,readable和binary-encoded
- 后端(backend):将IR转换成汇编代码,包括寄存器分配
LLVM的编译流程如图:
每个步骤中间交互有两种介质:1) in-memory; 2) by-file,前者变现出来通过一些高层的工具如clang,自动进行指定的动作;后者可以每一步每一步分离开来,通过一个个独立的工具完成。
Interacting with the compiler driver
如前文所述,可以使用driver来自动完成一系列动作,对于代码hello.c:
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
return 0;
}
直接编译:
clang hello.c -o hello
即可通过clang来执行一系列编译器的功能,直接生成可执行文件。
-###参数可以查看clang调用了哪些工具:
clang -### hello.c -o hello