LLVM系列(一)致敬

1.了解历史

        LLVM 是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time),对开发者保持开放,并兼容已有脚本。

        LLVM 计划启动于2000年,最初由美国UIUC大学的 Chris Lattner 博士主持开展。2006年Chris Lattner 加盟Apple Inc. 并致力于LLVM 在Apple 开发体系中的应用。Apple 也是 LLVM 计划的主要资助者。

        ICON 如下:

Chris Lattner 尊容如下(也是Swift之父):

 致敬!!!

2.充满思考的架构

        LLVM 是一个模块化和可重用的编译器和工具链技术的集合,Clang 是 LLVM 的子项目,是 C,C++ 和 Objective-C 编译器,因为多模块的复用,所以提供了惊人的快速编译,据说比 GCC 快3倍。

        LLVM 当时是为了解决一个小问题而开发的(一个小故事):当使用OpenGL 函数库的时候(Mac OS 10.4 和 10.5环境下),比如你要调用这个函数,glVertex3f(),编译器必须将其转化为特定的GPU可以理解的数据。但是这带来一个问题:市面上有海量的GPU,每个GPU的性能和参数也不尽相同,所要求的数据格式也不同。这时 LLVM 可以产生很小的一部分代码去解决这个问题,这是 LLVM 诞生的初衷。

        一开始 LLVM 是开源的,所有代码在转成二进制时就叫做 bytecode -- 因为 java 当年就是这么叫的。当时这一部分有很多问题:比如不能扩展,无法兼容,非常脆弱。后来采用的是 bitcode 机制。LLVM 2.0 将所有代码以比特流(bit stream)而不是字节流(byte stream)的形式来编码。这就是 bitcode 这一术语的由来。这个就是iOS为什么一个字节是8bit(比特),1比特是0.125字节。说起这个bitcode,我们来看看下面的这张广为流传的图:

        看过《趣谈网络协议》的同学都非常熟悉这张开篇图。这张图完美解释了LLVM的工作过程。当然还有另外一张简单明了的图如下:

        解释一下上图:

  • Frontend(编译器前端):编译器前端的任务是解析源代码。它会进行:词法分析语法分析语义分析检查源代码是否存在错误,然后构建抽象语法树(Abstract Syntax Tree,AST) ,LLVM的前端还会生成中间代码(intermediate representation , IR)。

  • Optimizer(优化器):优化器负责进行各种优化。改善代码的运行时间,例如消除冗余计算等。

  • Backend(后端):将代码映射到目标指令集。生成机器语言,并且进行机器相关的代码优化

        有的同学就会说了这两张图区别在哪?实际上我们讲的不是区别,而是想说这个bitcode就是上面图中的中间部分,可能这2张图还是无法说清楚,我们再看下面这张图:

         上图中可以清楚地知道这个中间代码,就是这个Optimizer部分就是bitcode部分。上图的大概意思是:

  1. 不同的前端后端使用统一的中间代码 bitcode
  2. 如果需要支持一种新的编程语言,那么只需要实现一个新的前端
  3. 如果需要支持一种新的硬件设备,那么只需要实现一个新的后端
  4. 优化阶段是一个通用的阶段,它针对的是统一的LLVM IR,不论是支持新的编程语言,还是支持
  5. 新的硬件设备,都不需要对优化阶段做修改

        到此我们的来意就明显了,我们这一系列的文章主要探讨Frontend,也就是词法分析、语法分析、语义分析、生成中间代码这一阶段。这里面的水很深,我们浅尝辄止😌😌😌。下面我们来看我们研究的主角:Clang。

3.我们的主角:Clang

        说起这个Clang,他只是这个LLVM整个项目的一个子项目,是基于LLVM架构的C/C++/Objective-C编译器前端。其官方网站http://clang.llvm.org/。由于Clang采用库的模块化设计,易于 IDE 集成及其他用途的重用,其设计清晰简单,容易理解,所以就给我们扩展带来的便利。在编译过程中,Clang 创建并保留了大量详细的元数据 (metadata),有利于我们对其进行调试和查看错误报告。下面又有了一张图介绍了Clang所处的具体位置:

        下面我们来浅尝一下:通过终端了解一下main.m文件的编译阶段干了什么, 在终端中输入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 //绑定

        可以看出整个过程经历了input、preprocessor、compiler、backend、assembler、linker、bind-arch 7步。您肯定想知道里面每一步具体做了什么,请看下一篇Clang的编译过程详解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值