跳转至

llvm Backend

llvm 后端 概述

  • 后端(backend)由一套分析转换Pass组成,它们的任务是代码生成,即将LLVM中间表示(IR)变换为目标代码(或者汇编)。
  • LLVM支持广泛的目标:ARM,AArch64,Hexagon,MSP430,MIPS,Nvidia PTX,PowerPC,R600,SPARC,SystemZ,X86,和XCore。
  • 所有这些后端共享一套共用的接口,它是目标无关代码生成器的一部分,以通用API的方法抽象化后端任务。每个目标必须特殊化代码生成通用类,以实现目标特定的行为。

后端的基本流程

  • 下图给出了将LLVM IR转换为目标汇编代码必需的步骤

Backend

  • 浅灰色的中间框,也叫super pass,是必需的,它们是后端的核心部分。
  • 白色框所指示的,可以执行非必需的优化Pass以进一步改进翻译的质量。对于提高所生成的代码的效率更重要。
  • 比如-O3的优化,而且其顺序对结果也有影响。

详细解释各阶段:

  1. 指令选择(Instruction Selection):将三地址结构的LLVM IR变换为DAG(Directed Acyclic Graph)
  2. 每个DAG能够表示单一基本块的计算。DAG内节点表示机器指令,边表示数据依赖关系。
  3. 第1次指令调度(Instruction Scheduling),也称为前寄存器分配(RA)调度,对指令排序,同时尝试发现尽可能多的指令层次的并行。然后这些指令被变换为MachineInstr三地址表示。
  4. 寄存器分配(Register Allocation),它将无限的虚拟寄存器的引用转换为有限的目标特定的寄存器集,寄存器不够时挤出(spill)到内存。
  5. 第2次指令调度,也称为后寄存器分配(RA)调度。因为此时在这个点可获得真实的寄存器信息,某些类型寄存器存在额外的风险和延迟,它们可被用以改进指令顺序。
  6. 代码输出(Code Emission)阶段将指令从MachineInstr表示变换为MCInst实例。这种新的表示更适合汇编器和链接器,它有两种选择:输出汇编代码或者输出二进制块(blob)到一种特定的目标代码格式。

后端代码结构

后端的实现分散在LLVM源代码树的不同目录中。代码生成背后的主要程序库位于lib目录和它的子文件夹CodeGen、MC、TableGen、和Target中, 具体参考文档

Tablegen位置在类似 llvm/lib/Target/X86/X86.td的地方

llvm 编译优化

  • 通过llvm的分析和转换Pass相结合实现的。
  • 首先,通过分析Pass获取程序的一些特性和数据流等信息,例如控制流分析、数据流分析、依赖分析等。
  • 然后,根据所得到的分析信息,llvm会执行转换Pass,对程序进行一系列的重构、优化和变换,例如常量传播、死代码消除、内联函数、循环展开等。

举例:O3优化实现

程序优化选项 -O3 是通过启用 LLVM Pass Manager 并按照顺序执行包含多个具体优化 Pass 的过程实现的。包括:

  1. 函数内部优化 Pass,如内联、函数内联、无用函数清理、控制流扁平化;
  2. 函数间优化 Pass,如基于静态单走边分析的间接调用目标推导、函数每次调用的参数的重复计算消除、通过符号解析执行的函数简介化等。
  3. 模块优化 Pass,如死代码消除、全局优化、常量传播、数值宽化和窄化、整除优化等;
  4. 特定于架构的优化 Pass,包括指令调度和寄存器分配等。

这些 Pass 的执行范围涵盖 LLVM IR 与 LLVM 后端。

TableGen

  • LLVM的TableGen是一种表格驱动代码生成工具,主要用于生成汇编器、反汇编器、指令选择器、调度器等代码。
  • 它使用基于LLVM IR的DSL(Domain-Specific Language)来描述目标指令集的特性和规则,然后将这些信息转换为C++代码。
  • 使用TableGen可以将目标指令集的实现与源代码分离,从而提高代码的可读性和可维护性。

TableGen的输入文件使用扩展名“.td”(TableGen的缩写),它们可以描述如下内容:

  1. Instruction Set Architecture (ISA) - 描述目标机的指令集特性,例如指令集架构、寄存器、寄存器类、操作数类型、地址模型、端对齐性等。
  2. Selection DAG - 描述了如何将LLVM IR节点映射到目标机指令集的指令,例如指令的操作码、操作数、调用约定、指令延迟等。
  3. Pattern Matching - 对匹配到的指令模板做出生成想要的IR节点的选择。
  4. Instruction Scheduling - 描述调度器行为、指令之间的时间关系,以及如何将指令插入到调度图中的规则等。

  5. TableGen自动化了目标机指令集的大部分工作,同时也使得自定义目标机变得相对容易。

  6. 该工具支持针对多种平台和编译器的后端代码生成。
  7. 对于嵌入式系统和非标准指令集架构等领域,TableGen有着广泛的应用。

相关的概念

  • 目标描述语言(Target Description Language,TDL)来定义目标架构特定的指令和寄存器。其中,TDL可用于目标架构中指令定义和寄存器定义的映射关系和动态生成机器指令的规则。

实践:llvm IR 后端

实现一个简单的LLVM IR后端,将LLVM IR转换为x86汇编代码,能line by line的输出。

参考LLVM官方文档中的“Writing an LLVM Backend”以及“TableGen Backends”

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://getting-started-with-llvm-core-libraries-zh-cn.readthedocs.io/zh_CN/latest/ch06.html#id2