LLVM基本框架结构

一、基本框架

1、概述

 LLVM编译器采用了如下图所示的三段式设计:前端,优化组件和后端。前端组件解析程序源代码,检查语法错误,生成一个基于语言特性的AST来表示输入代码,并将其转换为LLVM IR;优化器作用是中间代码(IR)优化,比如去除无用的变量或者无用的计算,来提高代码运行效率;后端生成目标机器码。

2、源码结构

位于llvm-project/llvm/中

  • llvm/examples/:包含LLVM官网中一些教程的代码实现。
  • llvm/include/:存放源码中的公共头文件
  • llvm/lib/(主要目录如下)
    • llvm/lib/IR/:包含所有和IR层有关的源码文件,这些文件实现了很多核心的类(class),比如:Instruction类,BasicBlock类,Function类,Module类。
    • llvm/lib/MC/:包含MachineCode层面的类和方法的实现。
    • llvm/lib/CodeGen/:包含从IR代码->目标中间代码的实现文件,指令选择、指令调度、寄存器分配以及它们所需的辅助分析函数。
    • llvm/lib/Passes/:包含llvm pass的构造文件。
    • llvm/lib/Target/:存放描述代码生成的目标架构的文件。如果编写一个新的后端,其后端代码仅存于此文件夹的子文件夹中。
    • llvm/lib/TableGen/:包含TableGen工具的完整实现,该工具用于根据.td文件中的高层目标描述来生成C++代码。
  • llvm/test/:这个目录是LLVM的测试套件,包含了很多测试用例,这些测试用例是测试LLVM的所有基本功能的,比如从测试IR->汇编,汇编->机器码。
  • llvm/tools/:这个目录是各个工具的源码(也就是驱动那些库的驱动程序)。比如做 LLVM IR 汇编的 llvm-as,后端编译器 llc,优化驱动器 opt 等。
  • llvm/utils/:这个目录包含了一些和LLVM源码一起工作的应用。有些应用在LLVM的编译过程中是不可或缺的。
    FORTRAN等。

二、前端

官方项目——Language Frontend with LLVM Tutorial
 主要包括以下4个阶段,词法分析、语法分析、语义分析、LLVM IR生成器。

1、词法分析

 负责处理源代码的文本输入,将语言结构拆分成一组单词和记号(token),并删除诸如注释、空格和制表符之类的字符。
 预处理,在进行语义分析之前使用,负责通过处理以 '#' 开头的预处理指令来扩展宏,或包括头文件,或跳过部分代码。预处理器与词法分析器紧密相关,并连续相互作用。

2、语法分析

 负责根据一组记号的代码布局决定把它们组合在一起是否合理,不涉及含义分析,只关心语法是否正确,不关心具体的语义表达。它的输入为一个记号流,输出为抽像语法树(AST)。

3、语义分析

 借助于符号表来确保代码是否违反编程语言的类型系统。该表主要存储了标识符(符号)与其各自类型之间的映射。Clang在生成AST节点的同时执行类型检查。

4、LLVM IR生成

 遍历AST,同时生成LLVM IR代码,该代码能实现与树中所表示的代码完全相同的行为。

三、中间代码(IR)

官方手册——LLVM Language Reference Manual

  • LLVM IR是 LLVM Immediate Representation的简称,即LLVM的中间表示。LLVM IR是连接前后端的枢纽,贯穿了整个编译生命周期,是LLVM编译框架的核心。
  • LLVM IR 有三种表示形式:内存中的LLVM IR,比特码形式的LLVM IR,可读形式的LLVM IR。
    • 内存中的LLVM IR:即在内存中处理抽象语法树AST时,生成对应的LLVM IR;
    • 可读形式的LLVM IR和比特码形式的LLVM IR:则是将内存中的LLVM IR持久化的方法。
      • 生成可读形式的LLVM IR文件:clang -c test.c -emit-llvm -S -o test.ll
      • 生成比特码形式的LLVM IR文件:llvm-as test.ll,得到 test.bc
      • .bc转化为.llllvm-dis test.bc -o test.ll

四、后端

开源项目——Tutorial: Creating an LLVM Backend for the Cpu0 Architecture

1、概述

 LLVM backend的主要功能是code gen,也就是代码生成,其中包括若干个code gen分析转换pass将LLVM IR转换成特定目标架构的机器代码。如下图所示,指令经过各个阶段,从LLVM IR到SelectionDAG,再到MachineDAG,再到MachineInstr,最后到MCInst。这其中经过的各个阶段实际是不同的pass,不同的target的backend根据需要对不同pass做customization。

2、后端流程简介

  • SelectionDAGBuilder,遍历LLVM IR中的每一个function以及function中的每一个basic block,将其中的指令转成SDNode,整个function或basic block转成SelectionDAG。
  • 指令选择。SelectionDAG经过legalization和其它optimizations,将DAG节点映射到目标指令。这个映射过程是指令选择过程。这时DAG中的LLVM IR节点转换成了目标架构节点,即SelectionDAG转化为MachineDAG。
  • 指令调度。指令选择完成后的MachineDAG内容虽然是机器指令,但仍以DAG形式存在,CPU/GPU不能执行DAG,只能执行指令的线性序列。所以通过instruction scheduling将MachineDAG转化为MachineInstr三地址表示,得到机器指令的线性序列。
  • 寄存器分配。为virtual Register分配physical Register,并优化 Register分配过程使溢出最小化。
  • 寄存器分配后的指令调度器作用于机器指令,也就是MachineInstr。这时能得到physical寄存器信息,可以结合physical Register的安全性和执行效率,对指令顺序做调整。
  • Code emission阶段将机器指令转成MCInstr,并发射汇编或二进制代码。

五、参考

1、官方文档:

http://www.aosabook.org/en/llvm.html
https://llvm.org/docs/CodeGenerator.html
https://llvm.org/docs/GettingStarted.html
https://llvm.org/docs/WritingAnLLVMBackend.html#introduction
https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/index.html

2、博客:

https://zhuanlan.zhihu.com/p/52724656
https://zhuanlan.zhihu.com/p/351848328
https://jonathan2251.github.io/lbd/index.html
https://www.cnblogs.com/lqerio/p/16009042.html

3、书籍:

《LLVM编译器实战教程》
《Learn LLVM 12》中文版
《LLVM Cookbook》中文版

posted @ 2023-04-11 19:50  lixycc  阅读(1152)  评论(0)    收藏  举报