LLVM简要介绍

LLVM总体架构图:总体分为三部分,分别是前端、中间优化层、编译器后端。前端经过词法、语法、语义分析生成IR,中间优化层会经过若干个pass,不同的pass会对IR进行不同的优化处理,将优化处理后的IR传递给后端,后端根据不同的硬件生成与硬件相关的机器码。后端流程:指令选择->寄存器分配->指令调度->代码布局->代码组装,生成硬件所对应的汇编指令。
LLVM简要介绍_第1张图片

运行过程:c代码进行一系列的预处理变成.i文件,使用前端编译变成IR文件——.ll(人类可读的代码语言)和.bc(在硬盘上存储的二进制中间语言)文件,通过llc把IR变成汇编的机器码,然后把机器码编译成二进制文件。
LLVM简要介绍_第2张图片

clang -E -c hello.c -o hello.i 对c++源代码进行预处理生成.i文件
clang -emit-llvm hello.i -c -o hello.bc 把.i文件导出成.bc形式的llvm IR
clang -emit-llvm hello.i -S -o hello.ll 把.i文件导出成.ll形式的llvm IR
llc hello.ll -o hello.s 通过llc导出成.s文件
code hello.s 可以看到里面是一些汇编指令
clang hello.s -o hello 变成可执行的二进制文件

后端的详细工作流程:

后端的主要任务是代码生成,即将LLVM IR变换为目标代码(或者汇编)。
1、指令选择
• 内存中 LLVM IR 变换为目标特定 SelectionDAG 节点(有向无环图);
• 每个DAG能够表示单一基本块的计算;
• 节点表示指令,而边编码了指令间的数据流依赖;
• 让LLVM代码生成程序库能够运用基于树的模式匹配指令选择算法。
主要过程:第一步是根据LLVM IR指令构建DAG,从而创建一个其节点执行IR操作的SelectionDAG对象。接着,这些节点经过降级、DAG合并和合法化等过程,使它更容易与目标指令相匹配。然后,指令选择使用节点模式匹配方法进行DAG到DAG的变换(目的是通过使用模式匹配将目标无关节点转换成目标相关节点),将SelectionDAG节点转换为代表目标指令的节点。
2、指令调度
• 第1次指令调度(Instruction Scheduling),也称为前寄存器分配(RA)调度;
• 对DAG指令排序,同时尝试发现尽可能多的指令层次的并行;
• 然后指令被变换为MachineInstr三地址表示。
3、寄存器分配
LLVMIR 两个中哟特性之一:LLVM IR 寄存器集是无限;这个性质一直保持着,直到寄存器分配(Register Allocation);
• 寄存器分配将无限的虚拟寄存器引用转换为有限的目标特定的物理寄存器;
• 寄存器不够时挤出(spill)到内存。
四个寄存器分配算法:pbqp、greedy、basic、fast
4、指令调度
• 第2次指令调度,也称为后寄存器分配(RA)调度;
• 此时可获得真实的寄存器信息,某些类型寄存器存在延迟,它们可被用以改进指令顺序。
5、代码输出
• 代码输出阶段将指令从 MachineInstr 表示变换为 MCInst 实例;
• 新的表示更适合汇编器和链接器,可以输出汇编代码或者输出二进制块特定目标代码格式。
如此,整个后端流水线用到了四种不同层次的指令表示:内存中的LLVM IR,SelectionDAG节点,MachineInstr,和MCInst。
LLVM简要介绍_第3张图片

你可能感兴趣的:(LLVM,开发语言,LLVM)