修改的LLVM IR基本指令

SysY2022语言定义中不包含无符号整数、结构体、移位操作,整数和浮点数均为32位,比赛测试样例不包含错误。鉴于SysY2022语言的特点,为了IR的简洁,对LLVM IR进行筛选和修改得到如下指令集

目录

1. 终结符指令

2. 一元运算

3. 二元运算

4. 按位二元运算

    • shl
    • lshr
    • ashr
    • and
    • or

5. 向量运算

    • extractelement
    • insertelement
    • shufflevector

6. 聚合操作

    • extractvalue
    • insertvalue

7. 内存访问和寻址操作

8. 转换操作

9. 其他操作

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, %b
  br 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: equal
     ne: not equal
     gt: greater than
     ge: greater or equal
     lt: less than
     le: less or equal
    

例子:

%21 = icmp eq i32* %20, %17
  • %20等于%17,则%21true,否则为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
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值