LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time),对开发者保持开放,并兼容已有脚本。是模块化和可重用的编译器和工具链技术的集合.
本来只是想写一个底层的虚拟机(low level virtual machine),但做出来后实际上跟虚拟机几乎没有关系。LLVM就是这个项目的全名
本文只是学习并记录笔记,如有错误或不足请谅解指正,谢谢!
LLVM简介
传统GCC编译器架构
传统静态编译器主要流行分为三个阶段:前端(词法分析、语法分析、语义分析、生成中间代码)、优化器(中间代码优化)和后端(生成机器码)

- 前端解析源代码,检查错误,并构建特定语言的抽象语法树 (AST)
- 优化器负责进行各种转换以尝试提高代码的运行时间,例如消除冗余计算
- 后端将代码映射到目标指令集,编译器后端的常见部分包括指令选择、寄存器分配和指令调度
这种GCC“一条龙”服务的好处是:不会暴露中间接口来给你操作它的IR,是强耦合的;但缺点是,对于不同的、新的语言,需要完成全部的从前端、优化器到后端的流程设计。
LLVM架构
目的:支持多种源语言或目标架构(三阶段设计)

LLVM与传统GCC编译器的主要不同就是:对于不同的语言它都提供了同一种中间表示。优化器只对中间表示IR操作,通过一系列的pass对IR做优化。使用这种设计,移植编译器以支持新的源语言需要实现新的前端,但可以重用现有的优化器和后端。
优点:LLVM由于共享优化器的中转,不同的前端语言最终都转换成同一种的IR,不仅仅支持一种源语言和一个目标
LLVM IR
官方文档:https://llvm.org/docs/Reference.html#llvm-ir
LLVM IR(Intermediate Representation)是LLVM的代码表示,是用于在编译器中表示代码的形式。旨在轻量级和低级,同时具有表现力、类型和可扩展性。旨在成为某种“通用 IR”,通过处于足够低的级别,可以将高级想法清晰地映射到它。
LLVM IR有三种形式:①内存中的编译中间表示 ②磁盘上的二进制码 bitcode ③可读汇编文本
这三种形式之间是等价的。
结构:

- Module,可以被视为一个.c文件的 IR 表示,每个 Module都是相对独立的东西,主要包含了声明或者定义的函数、声明或定义的全局变量、当前 Module的基本信息
- Function,是 Module中以List的方式存放的。函数内的第一个基本块叫做入口基本块。无法单独存在,必须是在某个 Module里,包含了大量 BasicBlock 、参数和返回值类型、可变参数列表、函数的attribute和其他函数的基本信息
- BasicBlock,是 Function 中以List方式存放。包含了大量的 Instruction ,前驱、后继的 BasicBlock,以及一些基本信息,每个 BasicBlock都可以视为一段顺序执行的代码
- Instruction,是 BasicBlock 中以List方式存放的,LLVM IR中的最小可执行单位,每一条指令都单占一行
LLVM简单使用
|
- 将C文件编译为LLVM IR文件
clang -emit-llvm -S hello_llvm.c -o hello_llvm.ll |
查看hello_llvm.ll
; ModuleID = 'hello_llvm.c' |
- 将C文件编译为LLVM bitcode文件
clang -emit-llvm -c hello_llvm.c -o hello_llvm.bc |
- 查看bitcode文件对应的LLVM 程序集
llvm-dis < hello_llvm.bc |
与上面生成的IR文件内容一致
- 可以通过
lli指令运行上面生成的.ll及.bc文件
$ lli hello_llvm.bc |
附LLVM常用命令,详细信息可以查看官方命令指南:
llvm-ar:存档器生成一个包含给定 LLVM 位码文件的存档,可选地带有一个索引以便更快地查找 |
