llvm-project/llvm/include/
从LLVM库导出的公共头文件。 三个主要子目录:
llvm/include/llvm/,所有LLVM特定的头文件,以及LLVM的不同部分的子目录:Analysis,CodeGen,Target,Transforms等。
llvm/include/llvm/Support/,LLVM附带的通用支持库,但不一定特定于LLVM。 例如,某些C ++ STL实用程序和命令行选项处理库在此处存储头文件。
llvm/include/llvm/Config/,由cmake配置的头文件。 它们包装“标准” UNIX和C头文件。 源代码可以包括这些头文件,这些头文件会自动处理cmake生成的条件#include。
llvm-project/llvm/lib/
大多数源文件在这里。 通过将代码放入库中,LLVM使得在工具之间共享代码变得容易。
llvm/lib/IR/,实现诸如Instruction和BasicBlock之类的核心类的核心LLVM源文件。
llvm/lib/AsmParser/,LLVM汇编语言解析器库的源代码
llvm/lib/Bitcode/,用于读取和写入LLVM bitcode的代码。
llvm/lib/Analysis/,各种程序分析,例如调用图,归纳变量,自然循环标识等。
llvm/lib/Transforms/,IR到IR程序的转换,例如积极的死代码消除,稀疏条件常量传播,内联,循环不变代码运动,死全局消除等。
llvm/lib/Target/,描述用于代码生成的目标体系架构(ISA)的文件。 例如,llvm/lib/Target/X86保存X86计算机的描述。
llvm/lib/CodeGen/,代码生成器的主要部分:指令选择器,指令调度和寄存器分配。
llvm/lib/MC/,该目录的代码主要是处理机器码(Machine Code),以及处理生成ELF格式的obj文件的代码。
llvm/lib/ExecutionEngine/,用于在运行时直接执行LLVM bitcode的库。
llvm/lib/Support/,该目录存放与llvm/include/ADT/和llvm/include/Support/中的头文件相对应的源代码。
1、由LLVM IR创建SelectionDAG。 (create bySelectionDAGBuilder类)
2、SelectionDAG节点合法化。(SDNode合法化包括数据类型和操作两个方面。)
3、DAG合并优化。
4、针对目标指令的指令选择。(SDNode需要被转为MachineSDNode,为目标平台的机器指令,基于表的.td文件描述,之后这些文件通过tablegen工具转为.inc文件)
5、调度并发射机器指令。(要对线性指令集进行顺序上的优化, 这个过程叫作指令调度。调度器会发射机器基本块中的机器指令,最终解构DAG。)
6、寄存器分配——SSA解构、寄存器赋值、寄存器溢出。(有限的寄存器需要被有效分配。如果无法做到,就会造成寄存器溢出(register spilling))
7、发射机器码。
要实现一个LLVM编译器的后端需要以下步骤:
First step: describe the characteristic of target machine(create class of Target Machine like :SparcTargetMachine.cpp & SparcTargetMachine.h
Second step:describe the register set of target machine(generate register by TableGen,TargetRegisterInfo.td has all the register class definition)
Third step:describe the instruction set of target machine
描述目标机器的特性
描述目标机器的寄存器
描述目标机器的指令集
描述指令选择器(也就是如何将IR转换成Target指令)
描述MC层(Machine code)
Tablegen就是用于记录这些信息的描述性语言。目标体系结构目录下的*.td文件都是用tablegen语言来描述的。经过tablegen工具批量生成C++源文件,它的好处就是我们描述的是大量信息的共同点,然后由工具批量生成,减少我们描述的工作量,使用tablegen语言也十分简单灵活。
Tablegen主要由Class(类)和Definition(定义)组成。其中Class是用于描述构建其它记录的抽象记录,可以理解成模板。描述目标的共同特点以便批量生成记录。Definition是具体的描述实例,不包含任何未定义的变量。
先从指令描述部分看。在目标体系结构目录下XXXInstrFormat.td文件中,定义了指令的多种格式。
每个变量都有注释,在这里选几个比较重要的变量说明:
dag OutOperandList MI(Machine Instruction)改写的操作数
dag InOperandList MI(Machine Instruction)使用的操作数
string AsmString 汇编输出格式
list Pattern 匹配的dag
list Users 使用的不包含在操作数中的寄存器(例如和状态位有关指令,某些体系结构HILO寄存器相关指令等)
list Defs 改写的不包含在操作数中的寄存器(同上)
list Predicates 指令匹配的条件
描述一条指令,也就是描述这条指令的属性,总结一下:
1.指令编码(encoding)
2.汇编输出(asm string)
3.对寄存器的操作(使用、改写什么寄存器,寄存器的分类)
4.指令匹配的条件(在什么条件下能将LLVM dag转化成这条指令)
5.匹配LLVM的dag(LLVM dag的操作数和指令操作数的对应关系)
6.其它一些指令属性(例如标记成跳转指令,立即数生成指令,用于编译器优化)
• 创建TargetMachine类的子类来描述你的目标机器的特性。拷贝特定目标机器类和头文件的已存在例子。比如以SparcTargetMachine.cpp和SparcTargetMachine.h,但是要为你的目标平台修改文件名。相似地,改变引用了Sparc的代码为你目标平台。
• 描述目标平台的寄存器集,用TableGen从一个特定目标平台的RegisterInfo.td输入文件来生成寄存器定义,寄存器别名,寄存器类。你应该为TargetRegisterInfo类写一些额外的代码来表示该类文件数据用来为寄存器分配并且描述它们之间的相互作用关系。
• 描述目标平台的指令集。通过TableGen使用特定目标平台版本的TargetInstrFormat.td与TargetInstrInfo.td来生成特定目标平台的指令代码。你需要为TargetInstrInfo类写一些额外的代码来表示目标机器支持的机器指令。
• 描述从指令的DAG表示到本地目标机器平台的指令的LLVM IR的选择与转化。使用TableGen来生成匹配模式的代码和选择基于目标特定版本的TargetInstrInfo.td中的额外信息的指令。并且在XXXIselLowering.cpp编写代码来替换或者删除在SelectionDAG中不被本地支持操作和数据类型。
• 编写写为目标平台将LLVM IR转为一个GAS格式的汇编打印器。你应该添加汇编字符串到你指定目标平台版本的TargetInstrInfo.td中定义的指令。你需要为AsmPringter的子类写一些进行LLVM到汇编的转化与一个TargetAsmInfo无关紧要的子类。
• 可选地,增加对子平台的支持(比如,不同功能的变量)。你应该编写TargetSubtarget类的子类代码,来允许你可以使用 -mcpu= 和 -mattr=命令行选项。
• 可选地,增加JIT支持与创建机器码发射器用来直接发射二进制代码到内存中。
此外,XXXtargetMachine构造函数应该指定一个TargetDescription串来决定目标机器的data layout。对于目标机器,包括了指针大小、对齐、大小端等特征。例如,SparcTargetMachine构造器包含了下面特征:
DataLayout(“E-p:32:32-f128:128:128”),
Subtarget(M, FS), InstrInfo(Subtarget),
FrameInfo(TargetFrameInfo::StackGrowsDown, 8, 0) {
}
连字符分割了TargetDescription串的各个部分。
• 字符串中一个大写的“E”表示一个大尾端的目标平台数据模型。小写的“e”表示小尾端。
• “p:”后跟随着指针信息:大小、ABI对齐和偏好对齐。如果只有两个数字在“p”后面,那么第一个值是指针大小,第二个值同时是ABI对齐与偏好对齐。
• 数字类型对齐的字母:“i”、“f”、“v”或者“a”(对应于整型,浮点型,向量型或聚合型)。“i”, “v”, or “a”后跟着ABI对齐与优化对齐。“f”跟随着三个值:第一个值表示long double的大小,然后是ABI对齐,另外是ABI优化对齐。
从 源文件 生成 bitcode 文件
clang -c -emit-llvm const.c -o const.bc
cfg 图
opt –view-cfg const.bc
call 图
opt -view-callgraph file.bc
中间代码优化
用 opt ,还可以调用 LLVM 提供的优化器对 bitcode 文件进行代码优化
opt -mem2reg const.bc -o const.reg.bc
bitcode 文件生产 .ll ,中间代码 IR 文件
llvm-dis const.bc
可以对 .ll 进行即时运行(JIT)
lli const.ll
bitcode 文件生成目标平台机器码
llc -march=x86 ex0.reg.bc -o ex0.reg.x86