LLVM笔记(1) - TableGen

1. 什么是tablegen
  tablegen是llvm用于开发和维护编译器中公共特性的条目(e.g. 指令描述, 寄存器描述)的代码, 使之灵活的描述与构造的自动化工具. 其本质是一个parser, 将输入的td文件转化为特定的数据结构后再输出为易于阅读的cpp代码. 更多介绍可见http://llvm.org/docs/TableGen/index.html或参见docs/TableGen/下文件说明.

2. tablegen的使用方式
  首次成功编译后, 在[llvm install path]/bin/下会生成可执行文件llvm-tblgen. 通常使用方法(在llvm的cmake工程中)它读入一个td文件, 并将结果输出至一个inc文件中. 以高通的Hexagon架构为例(具体使用命令可以llvm-tblgen --help查询)生成指令信息代码:

1 [12:32:11] hansy@hansy:~/llvm/llvm (master)$ ../llvm_build/bin/llvm-tblgen -gen-instr-info -I ./lib/Target/Hexagon/ -I ./include/ -I ./lib/Target/ ./lib/Target/Hexagon/Hexagon.td -o ~/test.inc

  生成的inc文件实质为cpp代码, llvm工程中会包含这些文件. 当前tablegen生成的代码主要分为前端clang(target independent code, 在[llvm build path]/tools/clang/include/clang/下)以及后端llvm(target dependent code, 在[llvm build path]/lib/Target/[arch]下).
  tablegen代码包含两块: 对td文件的处理, 在lib/TableGen/目录下, 包含lexer与parser, 负责解析tablegen的语法并转换为内部数据结构; 输出cpp代码, 在utils/TableGen/目录下, 用于生成我们需要的cpp代码, 这块与llvm代码逻辑强相关, 基本上一个cpp文件对应一类信息.

3. td文件的语法
  tablegen的输入来源于td文件, 如要了解tablegen就先要了解td文件. 与生成的inc文件类似, td文件也包含两块内容(在[llvm source path]/对应的目录下), 后端还包含部分llvm target independent code(主要为IR相关), 暂不赘述.
  仍以Hexagon架构为例, lib/Target/Hexagon/Hexagon.td是Hexagon架构td的入口(每个架构对应目录下都有一个以架构命令的td文件). 在该文件中定义了一些基础数据结构, 并包含了构建该架构后端所需的所有信息的文件.
  先来看看该文件定义的数据结构. 在td中使用两个关键字定义数据结构(llvm中称为records, 其实质对应的是tablegen中的一个类/类实例), class与def. 其中classes类似于模板, 用于描述一类抽象的records(e.g. Register, RegisterClass, Instruction). 而definitions用于表达一个具体的records(可以理解为一个特定的类). 每个records包含若干数据成员, 这些成员的类型有bit(布尔量), int(整型), string(字符串), code(代码段, 包含一行或多行的字符串), bits<n>(位段)等类型. 数据成员使用let关键字进行赋值, 对于tablegen中解析的成员必须都初始化(为定义的值可以使用?初始化为'未初始化值'), 否则会导致编译失败. 若一个definition record包含一个未初始化成员, 其值将从该definition的superclass中获取. 若tablegen中未解析该成员则不赋值也不会报错. 以Asmparser为例(defined in include/llvm/Target/Target.td):

 1 class AsmParser {
 2   string AsmParserClassName  = "AsmParser";
 3   string AsmParserInstCleanup  = "";
 4   bit ShouldEmitMatchRegisterName = 1;
 5   bit ShouldEmitMatchRegisterAltName = 0;
 6   bit AllowDuplicateRegisterNames = 0;
 7   bit HasMnemonicFirst = 1;
 8   bit ReportMultipleNearMisses = 0;
 9 }
10 Hexagon架构的Asmarser如下(defined in lib/Target/Hexagon/Hexagon.td):
11 def HexagonAsmParser : AsmParser {
12   let ShouldEmitMatchRegisterAltName = 1;
13   bit HasMnemonicFirst = 0;
14 }

Hexagon架构的Asmarser如下(defined in lib/Target/Hexagon/Hexagon.td):

1 def HexagonAsmParser : AsmParser {
2   let ShouldEmitMatchRegisterAltName = 1;
3   bit HasMnemonicFirst = 0;
4 }

Hexagon未定义parser的名字, 因此使用默认模板的字符串'AsmParser'; 默认的parser不匹配寄存器别名, 而Hexagon下ShouldEmitMatchegisterltName为true, 覆写了默认值.

4. tablegen选项
  一般情况下并不会修改tablegen的代码, 而是通过修改td文件实现所需的目标. 对任意一个架构而言, 不是所有tablegen选项都有效(例如不支持vliw的架构就没有DFAPacketizer), 仍以Hexagon为例常见选项如下:
-gen-emitter
  output: [arch]##GenMCCodeEmitter.inc
  usage:  used to generate binary code for given instruction. included in [arch]MCCodeEmitter.cpp
-gen-register-info
  output: [arch]##GenRegisterInfo.inc
  usage:  output register enum and class, mask, etc. included in [arch]##BaseRegisterInfo.* and [arch]##MCTargetDesc.*
-gen-instr-info
  output: [arch]##GenInstrInfo.inc
  usage:  output instruction enum and class, mask, etc. included in [arch]##BaseInstrInfo.* and [arch]##MCTargetDesc.*
-gen-asm-writer
  output: [arch]##GenAsmWriter.inc
  usage:  generate assembly printer. included in [arch]##InstPrinter.cpp
-gen-asm-matcher
  output: [arch]##GenAsmMatcher.inc
  usage:  generate assembly matcher used in assemble parser. included in [arch]##AsmParser.cpp
-gen-disassembler
  output: [arch]##GenDisassemblerTables.inc
  usage:  generate disassembly emitter. included in [arch]##Disassembler.cpp
-gen-callingconv
  output: [arch]##GenCallingConv.inc
  usage:  implement static function used for calling conversion.
-gen-dag-isel
  output: [arch]##GenDAGISel.inc
  usage:  implement a DAG instruction selector. included in [arch]##ISelDAGToDAG.cpp
-gen-dfa-packetizer
  output: [arch]##GenDFAPacketizer.inc
  usage:  generate function to check whether an instruction can be added to a VLIW. included in [arch]##InstrInfo.cpp
-gen-subtarget
  output: [arch]##GenSubtargetInfo.inc
  usage:  generate subtarget enum.

posted @ 2019-04-07 19:23  Five100Miles  阅读(3371)  评论(0编辑  收藏  举报