LLVM编译器后端比较功能的添加

news/2024/11/28 10:47:50/

1.动机

从机器层面上来看,控制流类的跳转指令分为无条件跳转和有条件跳转,无条件跳转 JMP,有条件跳转 JEQ、JNE、JLT、JGT、JLE、JGE,这部分指令是需要通过检查 condition code (SW 寄存器)来决定跳转条件;J 类型指令依赖的 condition code 是通过比较指令(比如 CMP)的结果来设置的。如下图所示,JNE跳转指令通过检查SW寄存器的状态以决定是否发生跳转。因此,为了支持控制流功能,首先要打通比较功能。

e21b97084ddb77003b37c90b29701367.png


2.LLVM IR 中的比较指令

LLVM IR提供的 int 类型比较指令为 icmp。其接受三个参数:比较方案以及两个比较参数。

%result = icmp ule i32 %a, %b

ule是比较方案,其中 u 为 unsigned int,le 为 lower than or equal,%a和%b就是用来比较的两个数,而icmp则返回一个i1类型的值,用来表示结果是否为真。

与ule类似的比较方案有多种,如:

  • 等于与不等于:eq、ne;

  • 无符号比较:ugt、uge、ult、ule, 分别对应无符号的大于、大于等于、小于、小于等于;

  • 有符号比较:sgt、sge、slt、sle, 分别对应有符号的大于、大于等于、小于、小于等于。

3.实现比较功能的添加

3.1 定义format

class FA<bits<8> op, dag outs, dag ins, string asmStr,list<dag> pattern, InstrItinClass itin>: Cpu0Inst<outs, ins, asmStr, pattern, itin, FrmA>
{bits<4>  ra;bits<4>  rb;bits<4>  rc;bits<12> shamt;let Opcode = op;let Inst{23-20} = ra;let Inst{19-16} = rb;let Inst{15-12} = rc;let Inst{11-0}  = shamt;
}

rbrc为两个寄存器类型源操作数,用于存放比较的数据,ra为寄存器类型目的操作数,用来存放比较的结果。

class FL<bits<8> op, dag outs, dag ins, string asmStr,list<dag> pattern, InstrItinClass itin>: Cpu0Inst<outs, ins, asmStr, pattern, itin, FrmL>
{bits<4>  ra;bits<4>  rb;bits<16> imm16;let Opcode = op;let Inst{23-20} = ra;let Inst{19-16} = rb;let Inst{15-0}  = imm16;
}

rb为寄存器类型源操作数,用于存放比较的数据,imm16是用于比较的16位立即数,ra为寄存器类型目的操作数,用来存放比较的结果。

3.2 定义指令

class SetCC_R<bits<8> op, string instrAsm, PatFrag condOp,RegisterClass RC>: FA<op, (outs GPROut:$ra), (ins RC:$rb, RC:$rc),!strconcat(instrAsm, "\t$ra, $rb, $rc"),[(set GPROut:$ra, (condOp RC:$rb, RC:$rc))],IIAlu>, Requires<[HasSlt]> {let shamt = 0;
}
def SLT      : SetCC_R<0x28, "slt", setlt, CPURegs>;
def SLTu     : SetCC_R<0x29, "sltu", setult, CPURegs>;

SetCC_R继承自上面定义的FASLTSLTu对应着小于、无符号小于两种比较方案

class SetCC_I<bits<8> op, string instrAsm, PatFrag condOp, Operand Od,PatLeaf immType, RegisterClass RC>: FL<op, (outs GPROut:$ra), (ins RC:$rb, Od:$imm16),!strconcat(instrAsm, "\t$ra, $rb, $imm16"),[(set GPROut:$ra, (condOp RC:$rb, immType:$imm16))],IIAlu>, Requires<[HasSlt]>;class FMem<bits<8> op, dag outs, dag ins, string asmStr, list<dag> pattern,InstrItinClass itin>: FL<op, outs, ins, asmStr, pattern, itin> {bits<20> addr;let Inst{19-16}   = addr{19-16};let Inst{15-0}    = addr{15-0};let DecoderMethod = "DecodeMem";
}
def SLTi     : SetCC_I<0x26, "slti", setlt, simm16, immSExt16, CPURegs>;
def SLTiu    : SetCC_I<0x27, "sltiu", setult, simm16, immSExt16, CPURegs>;

SetCC_I继承自上面定义的FLSLTiSLTiu对应着立即数小于、立即数无符号小于两种比较方案。

3.3 定义Pattern

上述四条指令只提到了小于、无符号小于两种比较方案,另外的比较方案没有定义。针对这种指令集中没有定义的比较方案需要借助Pattern定义。

指令选择过程就是DAG的模式匹配过程,模式的定义其主要在td文件中进行描述。当一个匹配找到后,将其DAG中的Node替换为具体的机器指令或伪指令。所以td文件中的Pattern的定义对于指令选择起到至关重要的作用。

每一个Pattern记录继承自 Pat class,其有两个参数,第一个参数DAG图中待匹配的模式,第二个参数是一个由机器指令组成DAG,当一个 Pattern 匹配后,将使用第二个参数替换第一个参数。以大于和大于等于为例,比较方案的模式定义如下:

  • 大于(setgt、setugt)

multiclass SetgtPatsSlt<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> {def : Pat<(setgt RC:$lhs, RC:$rhs),// a > b is equal to b < a is equal to setlt(b, a)(SLTOp RC:$rhs, RC:$lhs)>;def : Pat<(setugt RC:$lhs, RC:$rhs),(SLTuOp RC:$rhs, RC:$lhs)>;
}defm : SetgtPatsSlt<CPURegs, SLT, SLTu>;
  • 大于等于(setge、setuge)

multiclass SetgePatsSlt<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> {def : Pat<(setge RC:$lhs, RC:$rhs),// a >= b is equal to b <= a(XORi (SLTOp RC:$lhs, RC:$rhs), 1)>;def : Pat<(setuge RC:$lhs, RC:$rhs),(XORi (SLTuOp RC:$lhs, RC:$rhs), 1)>;
}defm : SetgePatsSlt<CPURegs, SLT, SLTu>;

4.测试 (以大于为例)

  • 测试用例

int test_setxx()
{int a = 5;int b = 3;int c;c = (a > b);   // sgt, c = 1return (c);
}
  • LLVM IR

%a = alloca i32, align 4%b = alloca i32, align 4%c = alloca i32, align 4store i32 5, i32* %a, align 4store i32 3, i32* %b, align 4%0 = load i32, i32* %a, align 4%1 = load i32, i32* %b, align 4%cmp = icmp sgt i32 %0, %1%conv = zext i1 %cmp to i32store i32 %conv, i32* %c, align 4%2 = load i32, i32* %c, align 4ret i32 %2
}
  • 指令选择前后的DAG

041d51d97620a0e8683a70c055a40eee.png

5d1c094ca695c3bde4eb71dd6ba71bb8.png


  • 汇编

test_setxx:.frame $fp,16,$lr.mask  0x00000000,0.set noreorder.set nomacro
# %bb.0:                                # %entryaddiu $sp, $sp, -16addiu $2, $zero, 5st $2, 12($sp)addiu $2, $zero, 3st $2, 8($sp)ld $2, 12($sp)ld $3, 8($sp)cmp $sw, $3, $2andi $2, $sw, 1st $2, 4($sp)ld $2, 4($sp)addiu $sp, $sp, 16ret $lrnop.set macro.set reorder.end test_setxx
$func_end0:.size test_setxx, ($func_end0)-test_setxx# -- End function

5.总结

LLVM编译器后端的主要工作是将LLVM中间端表达式(IR)转换成汇编文件,Cpu0 是一个非常简单的 RISC 架构处理器,本文以Cpu0作为硬件的例子,来构建能适配它的编译器后端,主要讲述了比较指令在整个控制流当中的作用并梳理了在LLVM后端中添加比较功能的过程。在编译器后端的开发过程中有一定的参考作用。可能存在认知上的偏差,也请大佬多多指教,笔者也会在学习中一步步改正错误,欢迎交流技术心得。

c537289a22c4d76a1fca60a12a9615e7.png


参考文献

  • https://llvm.org/docs/WritingAnLLVMBackend.html

  • https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.html

  • https://zhuanlan.zhihu.com/p/386457923

  • https://zhuanlan.zhihu.com/p/163328574


http://www.ppmy.cn/news/48803.html

相关文章

中断嵌套实验

使用汇编语言&#xff0c;要求&#xff1a; 外部中断1可以嵌套外部中断0 没有中断时&#xff0c;8个LED发光二极管以0.1s的速度闪烁。 有外部中断0时&#xff0c;8个LED发光二极管以0.1s的速度流水点亮。&#xff08;中断子程序0&#xff09; 有外部中断1时&#xff0c;会打断外…

JavaWeb——UDP的报文结构和注意事项

目录 一、UDP特点 1、无连接 2、不可靠 3、面向数据报 4、全双工通信 二、UDP报文结构 1、报头 2、载荷 三、端口 四、报文长度 五、校验和 1、定义 六、注意事项 1、UDP只有接收缓冲区、没有发送缓冲区 2、UDP大小受限 3、基于UDP的应用层协议 4、MTU对UDP协议…

Scala中的Map 集合详解

目录 一、不可变长Map集合 1.map的声明与遍历 2.map的常用方法&#xff1a;get、getOrElse、keys、values、、&#xff1a; 二、可变长Map集合 三、Map的其他方法 key -> value 的语法形式实际上是用库中的隐式转换实现的&#xff0c;实际调用了 Map.apply 方法。Map.a…

燃气管道定位83KHZ地下电子标识器探测仪ED-8000操作指南

1、电子标识器探测工作 燃气管道定位83KHZ地下电子标识器探测仪ED-8000&#xff0c;探测时周边 3 米范围内不能有其他探测仪&#xff0c;保持探测仪垂直向 下&#xff0c;探测仪的末端距离地面 5~10cm 左右&#xff0c;延估计的埋地管线走向水平移动探测仪。当发现持续信号且信…

Doo Prime 德璞资本:股指期货交易如何管理好个人情绪

在股指期货交易中&#xff0c;我们可以感觉到心态随着交易的成败而变化。有时心态对交易影响不大&#xff0c;但有时影响很大&#xff0c;一个好的心态&#xff0c;能够应对各种变化&#xff0c;各种损益和市场判断的正确和错误&#xff0c;不会对心态产生很大的影响&#xff0…

GPT对SaaS领域有什么影响?

GPT火了&#xff0c;Chat GPT真的火了。 突然之间&#xff0c;所有人都在讨论AI&#xff0c;最初的访客是程序员、工程师、AI从业者&#xff0c;从早高峰写字楼电梯里讨论声&#xff0c;到村里大爷们的饭后谈资&#xff0c;路过的狗子都要和它讨论两句GPT的程度。 革命的前夜…

理解什么是DTO?什么是AutoMapper?

什么是DTO? .Net DTO是一个对象&#xff0c;它定义了数据如何在网络上发送。它只用于发送和接收数据&#xff0c;不包含任何业务逻辑。使用DTO的原因有以下几个&#xff1a; 将服务层与数据库层分离隐藏客户端不需要查看的特定属性省略一些属性以减少有效负载大小处理嵌套对象…

银行数字化转型导师坚鹏:商业银行数字化风控(1天)

商业银行数字化风控 课程背景&#xff1a; 数字化背景下&#xff0c;很多银行存在以下问题&#xff1a; 不清楚商业银行数字化风控发展现状&#xff1f; 不清楚对公业务数字化风控工作如何开展&#xff1f; 不知道零售业务数字化风控工作如何开展&#xff1f; 课程特色…