LLVM学习笔记——目录

来源:互联网 发布:北京优化 编辑:程序博客网 时间:2024/06/13 00:29

前言

2011年前后,GCC后端代码的阅读陷入了举步维艰的境地。GGC-3.4.6后端代码的可读性不友好(当前版本没看过,不予评价。不过据说4.0进行的重构,应该会好些),充斥着动辄数千行的函数,包含着庞大的switch块以及if块,加之函数间的相互调用,看得人昏头转向。

穷极思变,转而看了一下LLVM的源代码。一撇之下,惊为天人。

LLVM是第一次碰到的、几乎完全用C++开发的大规模开源项目。LLVM将C++的潜力发挥得淋漓尽致,相较于直接使用指针,LLVM通过泛型技术构建了大量的容器与迭代器来遍历各种数据结构,使代码的安全性与模块化都得到很大的提高。

通过良好的模块化设计,善用C++提供的抽象支持,LLVM功能模块间实现了松耦合,替换模块或者增加模块就能扩展功能,无需在框架上修改。这一点使LLVM成为了学术界的宠儿。因为与GCC相比,LLVM不要求改写者深入了解各个部分,只需了解接口即可,而GCC则要求改写者对整个GCC代码有相当程度的精通。曾有团队先后使用LLVM与GCC为一款DSP(tricore)开发编译器,结果发现LLVM所需的工作量与难度都远小于GCC。从这点来说,LLVM非常成功。

此外,LLVM的指令生成技术十分先进。它使用一种称为tlbgen的语言来描述目标机器的方方面面(该语言的许多语法成分被LLVM的发明人ChrisLatter借鉴到新发明的Swift语言里),然后在编译LLVM的过程里,通过工具解析生成C++的源代码。

这个过程相当复杂,不过随之而来的是,LLVM有许多代码可以自动生成。而且现有的描述架构可以方便地支持新的处理器。不过,对tblgen语言以及解析工具,LLVM文档并没有深入描述。这也正是我的兴趣所在。

因为集成了大量的算法以及数据结构,编译器从来都是最复杂的软件之一。无论LLVM还是GCC,它们的行数都是以千万计的。如何构建一个模块化、扩展性良好,考虑维护友好性的编译器,绝对是一个困难的任务。但很可惜,常见的编译原理的书重点都在编译器的理论,给出常见算法的概要、框架,以及编译器系统的一般性描述。从这一点来说,编译原理给出的连编译器蓝图都算不上,充其量只是一张比较详细的草图。从草图到活生生的例子、具体的代码,期间的差别,不可以道里计。

因此,看完编译原理,总觉得似懂非懂,好像知道一些,却又说不出所以然——很多细节、答案都藏在源代码里。但另一方面,看编译器源代码也容易陷入细节,只见树木而不见森林,而且代码量也确实很大。不过,不管怎么说,饭要一口口吃,路要一步步走,退一万步来说,LLVM的架构极其先进,如果能从其软件架构中学到些什么,也是有益的。

从今天起(2017-3-10),将不定期更新我学习LLVM的笔记(就我个人经验,阅读复杂的程序,做详细笔记总能事半功倍)。因为LLVM实在庞大,虽穷数年勤苦,就X86目标机器,尚有很大部分代码没有触及,希望慢慢能补齐。

另,原创不易,转载请注明出处。若有错漏,请留言或发邮至wuhui_gdnt@21cn.com,望不吝赐教。谢谢!

 

第一部分目录

 1. 概述

     1.1. DAG指令选择生成器

     1.2. SelectionDAG

2. LLVM的后端描述

     2.1. 类型的描述

     2.2. 指令的描述

             2.2.1. TablgeGen的

                    2.2.1.1. dag

                    2.2.1.2. List

                    2.2.1.3. String

                    2.2.1.4. Bit、Int

                    2.2.1.5. Bits

             2.2.2. 参数描述

                    2.2.2.1. 寄存器

                          2.2.2.1.1. Register

                          2.2.2.2.1. X86的例子

                          2.2.2.3.1. RegisterClass

                          2.2.2.4.1. ARM的例子

                   2.2.2.2. 一般操作数

             2.2.3. 约束条件

             2.2.4. 匹配模板

                   2.2.4.1. SDNode

                          2.2.4.1.1. 类型的描述

                          2.2.4.1.2. 属性的描述

                          2.2.4.1.3. SDNode的派生定义

                   2.2.4.2. 可复用的结构

                          2.2.4.2.1. PatFrag

                                 2.2.4.2.1.1. SDNodeForm

                                 2.2.4.2.1.2. PatFrag的例子

                          2.2.4.2.2. 其他特殊PatFrag派生类

             2.2.5. 另一个匹配方式

                    2.2.5.1. 谓词Predicate

                    2.2.5.2. 指令定义的例子

                    2.2.5.3. 指令展开的例子

             2.2.6. 调度信息

             2.2.7. X86指令的定义

             2.2.8. 指令展开的例子

     2.3. 汇编处理描述

     2.4. 目标机器描述

            2.4.1. 特征描述

            2.4.2. 调度信息

                     2.4.2.1. ATOM的描述

                     2.4.2.2. Sandy Bridge的描述

                          2.4.2.2.1. 资源的描述

                          2.4.2.2.2. 执行的描述

                          2.4.2.2.3. Sandy Bridge的定义

                    2.4.2.3. 总结

3. TableGen生成的代码

     3.1. 概述

     3.2. TD文件的解析结果

     3.3. 寄存器的后端描述

            3.3.1. 概述

            3.3.2. SetTheory

            3.3.3. CodeGenTarget

            3.3.4. CodeGenRegBank

                    3.3.4.1. 复合索引

                    3.3.4.2. Register DAG

                          3.3.4.2.1. 寄存器的表示

                          3.3.4.2.2. 构建子寄存器关系

                          3.3.4.2.3. 隐含的孙子寄存器

                          3.3.4.2.4. 构建上级寄存器关系

            3.3.5. 信息的完善

                    3.3.5.1. 完整的索引信息

                    3.3.5.2. 寄存器单元的权重

                    3.3.5.3. 寄存器单元的同类集

                    3.3.5.4. 寄存器的包含关系

                    3.3.5.5. 其他信息的设置

            3.3.6. 输出代码

                   3.3.6.1. 枚举常量

                   3.3.6.2. MC使用的寄存器描述

                         3.3.6.2.1.MC对寄存器的定义

                         3.3.6.2.2. 差分编码

                         3.3.6.2.3. 生成的差分编码表

                         3.3.6.2.4. 与GCC/GDB编号间的映射

                   3.3.6.3. X86GenRegisterInfo的定义

                   3.3.6.4. CodeGen使用的寄存器描述

                        3.3.6.4.1. 寄存器类型与索引

                        3.3.6.4.2. 寄存器类的描述

                       3.3.6.4.3. 定义composeSubRegIndicesImpl方法

                       3.3.6.4.4. 定义getSubClassWithSubReg方法

                       3.3.6.4.5. 定义获取权重及压力数据方法

                       3.3.6.4.6. X86GenRegisterInfo的构造函数

                       3.3.6.4.7. 被调用者保存的寄存器

     3.4. DAG指令选择器的代码生成

            3.4.1. 概述

            3.4.2. CodeGenDAGPatterns对象

                 3.4.2.1. SDNode的处理

                 3.4.2.2. SDNodeXForm的处理

                 3.4.2.3. ComplexPattern的处理

                 3.4.2.4. PatFrag的处理

                       3.4.2.4.1. 模式树的处理

                       3.4.2.4.2. PatFrag的展开

                       3.4.2.4.3. 类型推导

                             3.4.2.4.3.1. 应用类型限定

                             3.4.2.4.3.2. 简化

                             3.4.2.4.3.3. 类型的最后确定

                       3.4.2.4.4. OperandWithDefaultOps



0 0