获取LLVM IR方法示例
获取LLVM IR方法示例
LLVM IR三种形式
LLVM IR有三种形式,分别是内存中的编译中间表示、磁盘上的二进制码和可读汇编文本,后两种形式可以通过以下命令获取
# 二进制码形式
clang -emit-llvm -c main.c -o main.bc
# 可读汇编文本形式
clang -emit-llvm –S -c main.c -o main.ll
所得LLVM IR可读汇编文本形式的示例,如图6.1所示。
图6.1 LLVM IR可读汇编文本形式的示例
分号是注释。
第7-11行是main函数。
第14-23行是add函数。
第25行是函数属性。
第27-32行是模块元信息。
第7-11行是main函数。
第14-23行是add函数。
第25行是函数属性。
第27-32行是模块元信息。
6.2.2 LLVM IR结构
图6.2所示表示LLVM IR的几个具有依次包含关系的模块。
图6.2 几个具有依次包含关系
需要首先理解四个具有依次包含关系的基本概念:
1)Module(模块)是一份LLVM IR的顶层容器,对应于编译前端的每个翻译单元(TranslationUnit)。每个模块由目标机器信息、全局符号(全局变量和函数)及元信息组成。
2)Function(函数)就是编程语言中的函数,包括函数签名和若干个基本块,函数内的第一个基本块叫做入口基本块。
3)BasicBlock(基本块)是一组顺序执行的指令集合,只有一个入口和一个出口,非头尾指令执行时,不会违背顺序,跳转到其他指令上去。每个基本块最后一条指令一般是跳转指令(跳转到其它基本块上去),函数内最后一个基本块的最后条指令是函数返回指令。
4)Instruction(指令)是LLVM IR中的最小可执行单位,每一条指令都单占一行。
LLVM IR头部是一些目标信息,信息内容为:
; ModuleID = 'add.c'
source_filename
=
"add.c"
target
datalayout
=
"e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target
triple
=
"x86_64-apple-macosx10.14.0"每一行分别是:
1
)
ModuleID
:编译器用于区分不同模块的ID。2
)
source_filename
:源文件名。3
)
target datalayout
:目标机器架构数据布局。4
)
target triple
:用于描述目标机器信息的一个元组,一般形式是<architecture>-<vendor>-<system>[-extra-info]
。
需要关注的是
target datalayout
,它由-
分隔的一列规格组成1
)
e
:内存存储模式为小端模式。2
)
m:o
:目标文件的格式是Mach格式。3
)
i64:64
:64位整数的对齐方式是64位,即8字节对齐。4
)
f80:128
:80位扩展精度浮点数的对齐方式是128位,即16字节对齐。5
)
n8:16:32:64
:整型数据有8位的、16位的、32位的和64位的。6
)
S128
:128位栈自然对齐。标识符与变量
LLVM IR中的标识符有两种基本类型:全局标识符(以
@
开头)和局部标识符(以%
开头)。LLVM IR要求标识符以前缀开头有两个原因:一个是无需担心带有保留字的名称冲突,并且将来可以扩展保留字的集合,而不会带来任何损失。另一个是未命名的标识符,使编译器可以快速提出一个临时变量,而不必避免符号表冲突。
全局标识符,包括全局变量、全局常量和函数,比如
@globalVar
=
global
i32
20,
align
4
@c
=
constant
i32
100,
align
4
define
i32
@main()
{
ret
i32
0
}
globalVar其实是个指针。
局部标识符,即局部变量。LLVM IR中的局部变量有两种分类方案:
按照是否命名分类:
1)命名局部变量:顾名思义,比如
%tmp
。2)未命名局部变量:以带前缀的无符号数字值表示,比如
%1
、%2
,按顺序编号,函数参数、未命名基本块都会增加计数。按照分配方式分类:
1)寄存器分配的局部变量:此类局部变量多采用
%1 = some value
形式进行分配,一般是接受指令返回结果的局部变量。2)栈分配的局部变量:使用
alloca
指令在栈帧上分配的局部变量,比如%2 = alloca i32
,%2
也是个指针,访问或存储时必须使用load
和store
指令。例如,以下是LLVM IR代码示例。
define
i32
@main()
{
%1
=
alloca
i32,
align
4
%tmp
=
alloca
i32,
align
4
store
i32
1,
i32*
%1,
align
4
store
i64
2,
i32*
%tmp,
align
8
%2
=
add
nsw
i32
%1,
%tmp
%result
=
add
nsw
i32
%1,
%2
}
其中
%1
是栈分配的未命名局部变量,%tmp
是栈分配的命名局部变量,%2
是寄存器分配的未命名局部变量,%result
是寄存器分配的命名局部变量。
人工智能芯片与自动驾驶
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2022-06-22 芯片硅片与流片技术
2021-06-22 摄像头模组(CCM)与镀膜
2020-06-22 将深度学习低延迟推理性能提高一倍
2020-06-22 TensorRT 3:更快的TensorFlow推理和Volta支持
2020-06-22 低层级GPU虚拟内存管理引论
2020-06-22 将HLSL射线追踪到Vulkan
2020-06-22 10分钟内基于gpu的目标检测