修改的LLVM IR基本指令
SysY2022语言定义中不包含无符号整数、结构体、移位操作,整数和浮点数均为32位,比赛测试样例不包含错误。鉴于SysY2022语言的特点,为了IR的简洁,对LLVM IR进行筛选和修改得到如下指令集
目录
1. 终结符指令
- ret
- br(修改)
- jump(增加)
- switch
- indirectbr
- invoke
- callbr
- resume
- catchswitch
- catchret
- cleanupret
- unreachable
2. 一元运算
- fneg
3. 二元运算
- add
- fadd
- sub
- fsub
- mul
- fmul
- udiv
- div(修改)
- fdiv
- urem
- rem(修改)
- frem
4. 按位二元运算
- shl
- lshr
- ashr
- and
- or
- xor
5. 向量运算
- extractelement
- insertelement
- shufflevector
6. 聚合操作
- extractvalue
- insertvalue
7. 内存访问和寻址操作
- alloca
- load
- store
- fence
- cmpxchg
- atomicrmw
- getelementptr
8. 转换操作
- trunc … to
- zext … to
- sext … to
- fptrunc … to
- fpext … to
- ftoi … to(修改)
- uitofp … to
- itof … to(修改)
- ptrtoint … to
- inttoptr … to
- bitcast … to
- addrspacecast … to
9. 其他操作
- icmp
- fcmp
- phi
- select
- freeze
- call
- va_arg
- landingpad
- catchpad
- cleanuppad
1. 终结符指令
程序中的每个基本块都以“终结符”指令结束,该指令指示在当前块完成后应该执行哪个块。
ret指令
概述:
“ret”指令用于将控制流(以及可选的值)从函数返回给调用者。
“ret”指令有两种形式:一种是返回一个值然后导致控制流,另一种只是导致控制流发生。
语法:
ret <type> <value> ; Return a value from a non-void function
ret void ; Return from void function
例子:
ret i32 5 ; Return an integer value of 5
ret void ; Return from a void function
br指令
概述:
“br”指令用于使控制流转移到当前函数中的不同基本块,条件分支
语法:
br i1 <cond>, label <iftrue>, label <iffalse> ; Conditional branch
i1 <cond>
表示一个布尔值,为真跳转到<iftrue>
标签,为假跳转到<iffalse>
标签
例子:
Test:%cond = icmp eq i32 %a, %bbr i1 %cond, label %IfEqual, label %IfUnequal
IfEqual:ret i32 1
IfUnequal:ret i32 0
jump指令
概述:
“jump”指令用于使控制流转移到当前函数中的不同基本块,无条件跳转指令
语法:
jump label <dest> ; Unconditional branch
- 无条件跳转到
<dest>
标签
例子:
br label %12
- 无条件跳转到
12
标签
2. 一元运算
一元运算符需要单个操作数,对其执行操作并产生单个值。结果值与其操作数具有相同的类型。
fneg指令
概述:
“fneg”指令返回浮点数的相反数
语法:
<result> = fneg <ty> <op1>
例子:
%8 = fneg float %7
%8
= -%7
3. 二元运算
二元运算符用于执行程序中的大部分计算。它们需要两个相同类型的操作数,对它们执行操作,并产生一个值。结果值与其操作数具有相同的类型。
add指令
概述:
“add”指令返回它的两个整数的和。
语法:
<result> = add <ty> <op1>, <op2>
<result> = add nsw <ty> <op1>, <op2>
nsw
代表“No Signed Wrap”。如果存在 nsw 关键字,则如果发生有符号溢出,则 add 的结果值是poison value
。
例子:
%7 = add nsw i32 %5, %6
fadd指令
概述:
“add”指令返回它的两个浮点数的和。
语法:
<result> = fadd <ty> <op1>, <op2>
例子:
%14 = fadd float %8, %13
sub指令
概述:
“sub”指令返回其两个整数的差。
“sub”指令用于表示大多数其他中间表示中存在的“neg”指令。
语法:
<result> = sub <ty> <op1>, <op2>
<result> = sub nsw <ty> <op1>, <op2>
例子:
%11 = sub nsw i32 %10, 1
fsub指令
概述:
“fsub”指令返回其两个浮点数的差。
语法:
<result> = fsub <ty> <op1>, <op2>
例子:
%8 = fsub float %6, %7
mul指令
概述:
“mul”指令返回其两个整数的乘积。
语法:
<result> = mul <ty> <op1>, <op2>
<result> = mul nsw <ty> <op1>, <op2>
例子:
%6 = mul nsw i32 %4, %5
fmul指令
概述:
“mul”指令返回其两个浮点数的乘积。
语法:
<result> = fmul <ty> <op1>, <op2>
例子:
%54 = fmul double %53, 1.000000e+01
div指令
概述:
“div”指令返回两个整数的商。产生的值是向零舍入的两个操作数的有符号整数商。
语法:
<result> = div <ty> <op1>, <op2>
<result> = div exact <ty> <op1>, <op2>
- 如果存在
exact
关键字,并发生了舍入(没有整除),则产生的结果值是poison value
例子:
%9 = div i32 %8, 2
fdiv指令
概述:
“fdiv”指令返回两个浮点数的商。
语法:
<result> = fdiv <ty> <op1>, <op2>
例子:
%15 = fdiv float %14, 2.000000e+00
rem指令
概述:
“rem”指令返回其两个整数的有符号除法的余数。
语法:
<result> = rem <ty> <op1>, <op2>
例子:
%4 = rem i32 %3, 3
%4
=%3
% 3
4. 按位二元运算
按位二元运算符用于在程序中进行各种形式的位转换。位运算通常是非常高效的指令。它们需要两个相同类型的操作数,对它们执行操作产生一个与操作数的类型相同的结果值。
xor指令
概述:
“xor”指令返回其两个整数的按位逻辑异或。
语法:
<result> = xor <ty> <op1>, <op2>
例子:
%5 = xor i1 %4, -1
%5
= !%4
7. 内存访问和寻址操作
读取、写入和分配内存
alloca指令
概述:
“alloca”指令在当前执行函数的栈上分配内存,当这个函数返回给它的调用者时自动释放。
语法:
<result> = alloca <type> [, <ty> <NumElements>] [, align <alignment>]
<ty> <NumElements>
要分配的内存数量,分配的内存大小就是该数量*单个类型空间,如果没有指定,默认情况下该值为1。align <alignment>
内存对齐值,表示分配的空间至少与该边界对齐
例子:
%2 = alloca [10 x i32], align 4
- 分配了一个长度为10个i32的空间
- 内存对齐方式为4Byte
load指令
概述:
“load”指令用于从内存中读取。
语法:
<result> = load <ty>, <ty>* <pointer>[, align <alignment>]
例子:
%7 = load i32, i32* %3, align 4
- 局部变量
%3
是一个指针,表示将%7
赋值为%3
所指的地址的值
store指令
概述:
“store”指令用于写入内存。
语法:
store <ty> <value>, <ty>* <pointer>[, align <alignment>]
例子:
store i32 0, i32* %1, align 4
- 将0存入
%1
所指的地址
getelementptr指令
概述:
“getelementptr”指令用于获取数组的子元素的地址。它只执行地址计算,不访问内存。
语法:
<result> = getelementptr inbounds <ty>, <ty>* <ptrval>{, <ty> <idx>}*
- 第一个
<ty>
是用作计算基础的类型。第二个参数<ty>* <ptrval>
是指针,是开始的基地址。其余参数用于指示聚合对象的哪些元素被索引。每个索引的解释取决于被索引到的类型。
例子:
%110 = getelementptr inbounds [32 x [2 x i32]], [32 x [2 x i32]]* %2, i32 0, i32 30
%10 = getelementptr inbounds [6 x i32], [6 x i32]* @arr, i32 0, i32 %9
- 第一个例子基础类型是[32 x [2 x i32]],第一个索引0表示在
%2
的基地址上没有偏移,第二个索引表示偏移了30 x [2 x i32],返回指向%2
+ 30 x [2 x i32]的 [2 x i32]类型的指针 - 第二个例子基础类型是[6 x i32],第一个索引0表示在
%arr
的基地址上没有偏移,第二个索引表示偏移了%9
x i32,返回指向@arr
+%9
x i32 的 i32类型的指针
8. 转换操作
此类别中的指令是转换指令(强制转换),它们都采用单个操作数和类型。它们对操作数执行各种位转换
ftoi … to指令
概述:
“ftoi”指令将其浮点操作数转换为最接近(向零舍入)的有符号整数值。如果该值不能适合 <ty2>,则结果是poison value。
语法:
<result> = fptosi <ty> <value> to <ty2>
例子:
%35 = fptosi float %34 to i32
itof … to指令
概述:
“itof”指令将其操作数解释为有符号整数,并将其转换为相应的浮点值。如果无法准确表示该值,则使用默认舍入模式对其进行舍入。
语法:
<result> = sitofp <ty> <value> to <ty2>
例子:
%4 = sitofp i32 %3 to float
9. 其他操作
icmp指令
概述:
“icmp”指令根据两个整数或指针的比较返回一个整数(i32)。
语法:
<result> = icmp <cond> <ty> <op1>, <op2>
- 第一个操作数是指示要执行的比较类型的条件代码。它不是一个值,只是一个关键字。可能的条件代码是:
eq: equalne: not equalgt: greater thange: greater or equallt: less thanle: less or equal
例子:
%21 = icmp eq i32* %20, %17
- 若
%20
等于%17
,则%21
为true
,否则为false
fcmp指令
概述:
“fcmp”指令根据浮点数的比较返回一个整数(i32)。
语法:
<result> = fcmp <cond> <ty> <op1>, <op2>
- 第一个操作数是指示要执行的比较类型的条件代码。它不是一个值,只是一个关键字。可能的条件代码是与icmp相同
例子:
%5 = fcmp lt float %4, 0.000000e+00
- 如果变量
%4
小于0.000000e+00,则返回true,否则返回false
phi指令
概述:
“phi”指令用于实现 SSA 图中表示函数的 φ 节点。
在基本块的开头和 PHI 指令之间不能有非 phi 指令,即 PHI 指令必须在基本块中的第一个。
语法:
<result> = phi <ty> [ <val0>, <label0>], ...
- 传入值的类型由
<ty>
指定。 - 在此之后,“phi”指令将一组对作为参数,当前块的每个前置基本块对应一对。
<label0>
代表可能的前置基本块,<val0>
代表该前置基本块带来的值
例子:
%44 = phi i1 [ false, %32 ], [ %42, %36 ]
- 这里的 IR 表明变量
%44
的值可能会来自两个基本块:%32
或者%36
。来自%32
块的变量值是 false,而来自%36
的变量值是%42
。
call指令
概述:
“call”指令代表一个简单的函数调用。“call”指令用于使控制流转移到指定函数,其传入参数绑定到指定值。根据被调用函数中的“ret”指令,控制流继续执行函数调用之后的指令,并且函数的返回值绑定到结果参数。
语法:
<result> = call <fnty> <fnptrval>(<function args>)
例子:
%8 = call i32 @func(i32 %7)
- 函数
@func
的返回值为i32,参数为i32,传递的实参为%7
修改的LLVM IR基本指令相关推荐
- LLVM IR学习记录(1) GetElementPtr指令
GetElementPtr指令是一条指针计算语句,本身并不进行任何数据的访问或修改,只进行指针的计算.使用语法如下: <result> = getelementptr <ty> ...
- LLVM每日谈之三十四 LLVM IR生成和转换的几条指令
本文将罗列几条关于LLVM IR生成和转换的几条指令,并没有技术含量可言,只是让刚接触LLVM IR的同学,有一个检索和参考作用.文中min.c作为输入. min.c int min(int a , ...
- LLVM IR 语法
译者序 目前几乎没有关于LLVM IR(中间语言)的中文资料,因此本人在看英文手册的同时尝试翻译.限于水平和时间,本文只翻译了一小部分英文手册,如果发现理解有冲突之处,请以原文为准. ...
- LLVM极简教程: 第三章 LLVM IR代码生成
第三章 LLVM IR代码生成 原文: Code generation to LLVM IR 本章简介 欢迎进入"用LLVM开发新语言"教程的第三章.本章将介绍如何把第二章中构造的 ...
- LLVM语法语义指令特性
LLVM语法语义指令特性 High Level Structure Module Structure LLVM 程序由Module's组成,每个 's 是输入程序的一个翻译单元.每个模块由函数,全局变 ...
- 简单了解LLVM IR基本语法
可以转载,请注明出处! 以下内容是参照官方文档,对一些代码样例做出的解释,想要彻底掌握IR的语法规则,还是需要仔细熟读IR的官方文档.这里只是对IR的入门介绍,等上道之后,建议再去看官方文档,因为工作 ...
- LLVM每日谈之四十五 LLVM IR TUTORIAL
今年的LLVM欧洲开发者会议上,在Tutorials环节,Vince Bridgers (Intel Corporation), Felipe de Azevedo Piovezan (Intel C ...
- LLVM IR格式的基本介绍
LLVM IR以两种格式存储在磁盘上: 1.位码(.bc文件) 2.汇编文本(.ll文件) 以sum.c源代码为例 int sum(int a, int b){return a+b; } 使用Clan ...
- LLVM IR入门指南(4)——类型系统
我们知道,汇编语言是弱类型的,我们操作汇编语言的时候,实际上考虑的是一些二进制串.但是,LLVM IR却是强类型的,在LLVM IR中所有变量都必须有类型.这是因为,我们在使用高级语言编程的时候,往往 ...
最新文章
- DELETE误操作_oracle
- gitlab访问慢,出现502,特别卡,耗内存cpu解决办法
- jsp文件命名规范_代码规范整理
- HTML img 标签的 border 属性
- css 单位之px , em , rem
- LinkedList 注意事项
- 索罗斯说,我投机了,但我不觉得我做错了什么,我做的都是合法的。
- 基于SSH的宠物管理系统
- 参考文献格式字号字体_论文格式字体字号要求
- Qt开发总结(19)——Qt Charts
- sqlserver数据库18456错误怎么解决?
- 微信app支付服务端开发记录
- “二选一”突袭,暗战“山姆”?
- 2016年智能楼宇趋势展望
- Unity中SLua、Tolua、XLua和ILRuntime效率评测
- Kubernetes和Mesos的区别和优缺点
- 关于VS/VC工程编译不过去这件事
- 【SOAP-WebService系列】历史产物UDDI是什么、长什么样,以及UDDI的发展过程、退出原因
- RTL8211 uboot 模式下4芯网线对接千兆如何协商成百兆
- outlook设置263邮件服务器,win10系统怎么在Outlook中添加263邮箱的操作方法
热门文章
- 正点原子 例程学习记录 实验四 串口实验
- 合天每周CTF学习笔记 — 神奇的磁带
- Windows 10 上安装 3D Studio Max 2016 报错的解决办法
- Playfair加密算法和RSA加密算法介绍
- MySQL 5.7最新版本下载与安装教程
- C语言 宏__builtin_expect的使用
- 前端页面select标签
- Word 2007 下的标尺的位置
- 键盘输入单位不固定员工工资来求平均工资while和do.....while
- C++访问类的私有数据成员的三种方法