豆瓣读书:https://book.douban.com/subject/34802579/

    image.png


    花了两周的时间,终于把这本书读完了,
    本书虽然不厚(200 页),但是干货很多,茶余饭后值得一读。

    本书主要介绍了 LLVM 项目(基础架构),LLVM 编译器主要的执行逻辑,
    以及与 LLVM 相关的一些工具和库。

    LLVM 项目包含一个驱动程序,以及它所整合的编译器的核心部分,
    驱动程序整合了所有必要的库和工具,
    编译器的核心部分包括,前端、优化器,后端、链接器。

    LLVM 是使用 C++ 编写的,因此充分利用了面向对象语言的种种便利性,
    整条编译链路,都是面向接口进行设计的(依赖倒置原则 DIP),
    提供很强的灵活性,很多环节可以通过继承现有类的方式,对具体实现进行重写。

    除此之外,LLVM 还配备很多可以整合到一起的独立小工具,
    比如代码检查、转换、替换旧代码、格式化、模块化、查看预处理器活动、AST 匹配器等工具。
    这些工具可以集成到 LLVM 项目中,大大丰富了 LLVM 的能力范围。


    LLVM 本来是一个教学框架,起始于 Chris Lattner 个人对编译器的热情。
    LLVM 使得对编译器感兴趣的用户,可以观察到编译过程的诸多步骤。
    与其他编译器项目不同的是,LLVM 的中间表示(IR)是可以写入磁盘的,然后交由其他工具继续处理。

    在读本书之前,我对 LLVM 的认识也仅限于是略读过 《LLVM Cookbook》的水平。
    原以为 LLVM 的发展目标,就是借助 LLVM IR 成为一个编译平台( Low Level Virtual Machine 低级虚拟机)。

    然而读了本书相关章节(Ch3 P27)之后,才知道维护 LLVM IR 的磁盘表示,更多是为了实现链接时优化,
    以及随着 LLVM 项目的成熟,LLVM 正式表明自身对成为一个平台不感兴趣,
    而是“立志成为强大和实用的 C/C++ 编译器”了。

    这一点,在通读本书之后,或许会有更多的体会,
    因为所有的例子,要么在展示 LLVM 内部处理逻辑 / 自定义编译流程的办法,
    要么在展示如何处理、分析 C++ 的源代码,并没有要涉及其他语言的意思。


    Ch4 ~ Ch6 介绍了 LLVM 前端、LLVM IR、LLVM 后端,我认为是最为干货的三章。

    • 前端

    前端主要介绍了 Clang 项目,它提供了 LLVM 体系中的编译器前端,支持 C/C++/Ojbective-C,
    最终生成 LLVM IR(位码 或者 可读的汇编码 两种格式),其间会进行词法分析、预处理、语法和语义分析。
    语义分析采用了“语法制导翻译(syntax-directed tanslation)”的方式执行类型检查。

    • LLVM IR

    LLVM IR 章节,介绍了 LLVM IR (SSA 静态单赋值形式)的语法,以及手动生成 SSA 的接口,
    还介绍了 LLVM 中实现的 SSA 便捷操作方法,例如如何轻松访问 use-def 链。

    除此之外,编译器优化肯定也是必不可少的内容,但是本书重点讲解的是 LLVM 对 pass 的处理逻辑,
    以及如何自定义优化 pass,而并非 LLVM 用户可以使用哪些优化手段进行优化。

    • 后端

    LLVM 后端这一章,介绍了从指令选择、指令调度、寄存器分配,到代码输出的全过程。
    与常规的编译器相似,后端通常包含一些非常复杂琐碎的内容。

    包括指令选择阶段构建 DAG(有向无环图),DAG 合并 与 类型合法化,模式匹配算法。
    以及寄存器分配阶段的,指令调度,寄存器合并,虚拟寄存器重写。
    更复杂的是,在代码输出环节中 LLVM 采用了机器代码框架(MC),对函数和指令进行低层操作。

    印象比较深刻的是 LLVM 后端使用了面向记录的方式 TableGen,来描述各阶段的信息。
    TableGen 使得人们可以在一个单独的位置声明目标机器的相关信息,
    然后根据 TableGen 信息生成后端需要的功能,例如生成基于模式匹配的指令选择算法。


    Ch7 ~ Ch9,介绍了 JIT、跨平台编译、Clang 静态分析器,
    最后一章 Ch10,介绍了 Clang 外部项目中常用的工具,
    例如 ,Clang Format(格式化工具),Clang Check(语法检查),Clang Modernizer(代码重构工具)等等。

    印象比较深刻的 Clang 静态分析器(Ch9)这一章,
    它没有引入过多的静态分析相关的术语,甚至连停机问题都没提,
    但是通过实例介绍了,常规的数据流框架用来排错的局限性,对比看到了 LLVM “符号执行引擎”的优势。

    然后本章的后续部分介绍了 Clang 静态分析器的使用方式,
    例如,结合 XCode IDE 使用,生成 HTML 报告,自定义检查器,等内容,
    同时也反映了静态分析(指数级复杂度),是在准确性与计算时间之间的一个权衡过程。


    综上所述,本书内容非常的扎实好用,有时间最好还是能手动跑一下书中的示例,
    读完之后对于整个 LLVM 项目的复杂性,能有一个全局的认识,
    另外 LLVM 源码中处理某些编译环节的逻辑还是非常复杂的,不是几周甚至几个月就能完全理解清楚的。

    遗憾的是,在读本书之前,我是想看看能否借助 LLVM 之力支持非 C++ 语言,
    但一路看下来,却发现这条路也许太难走了,LLVM 编译器核心部分(前、IR、后端),其实只是很小的一部分,
    书中介绍的大多数工具,都是为 C++ 服务的,也不知道社区中有没有基于 LLVM 的非 C++ 语言的支持方案。

    总之,本书很值得阅读,尤其是为了夯实编译相关的实践知识,
    书山有路勤为径,学海无涯苦作舟。