ValueSymbolTable 类

LLVM 的符号表。建立从名称到 Value 的映射。无名称的符号不允许存在于符号表。

我怎么感觉这个设计有点混乱。建议所有能存在于符号表的,都实现一个 getUniqueName () 接口方法,所属接口就叫 SymbolInterface 或者 NamedValue

打算自己写编译器的时候就这么干!

Value 类

Value 是一个万能类,有点像某 Java 的 Object, 总之非常恶心 。它可以表示一个打上类型标签的任何值。比如:

  1. 指令的操作数
  2. 常量、变量
  3. 实参、指令、函数。

设计这个类的主要目的是维护双向 def-use 关系。说白了就是依赖关系,双向就是我依赖谁和谁依赖我。

Value 的成员

name:只用于调试,一个昵称,可以留空。

一个误区是用 name 来作为变量名啥的,这在 LLVM 文档中是明令禁止的。

use :一些 Use 边。

type:类型信息

User 类

User 是所有 LLVM 结点基类,当然也是 Value 的子类。

设计这个类的主要目的是容纳操作数 Oprands

换言之,有些东西是 Value 但不是 User,这说明有些东西与操作数没有关系。比如一个变量。

Instruction 类

instruction 类是 所有 LLVM 指令的基类。设计者这个类主要目的是追踪其所在基本块(parent)

典型的 LLVM 指令:

  1. 二元算符(BinaryOperator):代表了所有的两个操作符的指令。

    为啥不叫 BinaryInst 呢?有待研究

  2. 转换指令(CastInst)

  3. 比较指令(CmpInst)

    为啥不归入二元算符?有待研究

Constant 类

顾名思义是常量的基类。是 User 的子类。

LLVM 的常量定义得比较宽泛,只要不是动态分配的量,或者说地址在运行时不会变化的量,就算做常量。

我们实现编译器的时候不要混淆。

子类包括:

  1. 全局值 GlobalValue
  2. ConstantInt
  3. ConstantFP
  4. ConstantArray
  5. ConstantStruct

这里需要特别注意。ConstantInt 等并不是通过 const int a = 100 这种形式搞出来的整数常量(后者称为一个 GlobalVariable x s.t. x.isConstant = true)。ConstantInt 实际上更像是 “立即数” 这种东西。

GlobalValue 类

全局值,是 constant 的子类。分为全局变量和函数。注意 LLVM 全局变量意义不太一样,详见后面。

Function 类

是全局值的子类。没错,函数算是常量

主要负责保存下列状态

  1. 基本块
  2. 函数形参
  3. 符号表

函数也可以只放个名,则其实现 Body 可以留空,并从外部获得。可以用 isDeclaration () 判别是否仅记名。

GlobalVariable

注意这玩意儿不是 GlobalValue,别眼花。确切而言是 GlobalValue 的子类。没错,全局变量也是 “常量”,因为它运行时地址不变。

全局变量的值是可以变,也可以不变的,这就是我们传统意义上的常量,通过 isConstant () 实例方法确定。

我打算在自己的编译器规定几个术语:

  1. konst
  2. symbol 表示地址不变量,包括全局变量和全局常量
  3. constant 表示全量
  4. variable 表示变量

全局变量可以初始化

BasicBlock 类

基本块,简称 BB。这玩意儿就是一列指令。通过 Instruction *getTerminator ()

比较重要的成员:

  1. 前驱
  2. 后继
  3. 所属函数

如果自己实现这个类,一般还会用到:

  1. 它支配的块集合
  2. 支配它的块集合

**一般有个不成文的规定,Phi 指令放在 BB 最前面。**LLVM 似乎没有做严格限制。建议大家规范来,之后方便实现 Mem2Reg.

Argument 类

表示形参,俗称 Parameter。

LLVM 这取名谜语人。