一、GCC的简介
1.GCC是传统的编译器(该模型同样适用于解释器和JIT 编译器),主要工作原理分为三段式:
(1)前端:解析源代码、检查语法错误、翻译为抽象的语法树
(2)优化器:将抽象语法树翻译生成中间代码,并对中间代码进行优化
(3)后端:将优化器优化后的中间代码转换为目标机器的代码,通用功能包括指令选择、寄存器分配和指令调度
2.架构优势
(1)使用通用的中间代码,新增支持语言只需要新增一个前端,新增支持目标机器只需要新增一个后端 (2)针对前后端,开发人员技术栈不同,开发人员只需要关注自身的技术栈,有利于让更多人员参与进来
3.架构缺陷
(1)GCC的三段式模块必须配套使用,很难做到部分重用
(2)不能将 GCC 部分功能作为库重用的原因有很多,包括滥用全局变量、不可变变量不能更改限制不严、设计不良的数据结构、庞大的代码库、以及使用宏来防止代码库一次编译可以支持多个编译前端-目标机对。不过,最难解决的问题是其早期设计和那个时代所固有的架构设计。具体来说,GCC 饱受分层问题和抽象漏洞的困扰:编译后端遍历编译前端抽象语法树(AST)来生成调试信息(debug info),编译前端生成编译后端数据的结构,整个编译器依赖命令行设置的全局数据结构。
二、LLVM的简介
1.LLVM的提出是为了解决编译器代码重用的问题
2.LLVM是三段式编译器优化器+后端的SDK集合,提供了一系列对外接口供开发者调用
(1)前端:支持各种组件的前端(Clang、llvm-gcc、GHC),需要遵守LLVM的规则,输出中间代码LLVM IR (2)优化器:LLVM IR通过一系列分析和优化从而改进代码,然后输入代码生成器生成目标机器码 (3)后端:将优化器优化后的中间代码转换为目标机器的代码
3.架构优势
(1)LLVM IR既有清晰地规范,又是与优化器的唯一接口。这就意味着为 LLVM 编写编译前端唯一要做的就是生成 LLVM IR。由于LLVM IR具有一流的文本格式,构建一个将 LLVM IR 作为文本输出的前端既可行又合理
(2)在设计完 LLVM IR 之后,LLVM 下一个重要的点就是要把 LLVM 设计成一系列独立的库,而不是像 GCC 那样的不可分离命令行编译器以优化器的设计为例:它将 LLVM IR 作为输入,然后逐步处理输入并生成执行效率更高的 LLVM IR。LLVM 优化器(和其他编译器一样)以流水线的方式为输入做不同的优化。常见的例子是内联(替换调用位置的函数实体)、重新组合表达式、移动循环不变代码等等。根据优化级别,运行不同程度的优化:例如 -O0 是不做优化,-O3 将运行 67 道优化程序(LLVM 2.8 版本)。
(3)LLVM 优化器基于库的设计可以让我们可以灵活选择要组合的优化程序以及自定义优化程序之间的执行顺序
(4)多目标机兼容的 LLVM 代码生成器的设计,LLVM 的代码生成器将代码生成分为多个独立的过程——指令选择、寄存器分配、调度、代码布局优化和代码组装
(5)使用BugPoint减少测试用例