DSP

在llvm中完成if else语句的编译

2019-07-13 15:51发布

说明:我们开发了一款新的DSP芯片,定义了一种新的指令集。现在使用llvm来将c代码编译成我们新定义的汇编指令集。本文是其中对c语言总if else语句的处理。 首先看一段c语言程序: //c代码 void test_main() { int a = 5; int b = 10; if(a == 5) b = 1; else b = 0; } 要想编译这段语句,重点有两个,一个是条件语句的处理,第二个就是跳转。
我们首先看一下llvm把这段语句处理成的IR是什么形式: //经llvm处理后的IR形式 %cmp = icmp eq i32 %0, 5 br i1 %cmp, label %if.then, label %if.else if.then: ; preds = %entry store i32 1, i32* %b, align 4 br label %if.end if.else: ; preds = %entry store i32 0, i32* %b, align 4 br label %if.end if.end: ; preds = %if.else, %if.then ret void } 忽略次要矛盾,主要的语句就是两句: //IR中的关键语句 %cmp = icmp eq i32 %0, 5 br i1 %cmp, label %if.then, label %if.else 一句是比较指令,一句是跳转指令。
根据我们的汇编指令集,我们期望把它处理成这个样子: //期望最终处理成的形式 eq $GR2, $GR3, $GR2 jnc $BB0_2 jmp $BB0_1 $BB0_1: # %if.then movigl $GR2,0 movigh $GR2,0 store32 $GR2, $GR30, 0 jmp $BB0_3 $BB0_2: # %if.else movigl $GR2,0 movigh $GR2,0 store32 $GR2, $GR30, 0 $BB0_3: # %if.end addi $GR30, $GR30, 8 ret 我们做的工作是:

1、添加指令。

我们首先把比较指令EQ和跳转指令JNC添加上:
在llvm-3.5.0.srclibTargetDSPDSPInstrFormats.td文件中添加这种模板: /*================================================ typecode|opcode|rd|rs|rt|inner_op<8> =================================================*/ class R33>typecode, bits<3>opcode, bits<8> inner_op,dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin> :InstDSP{ bits<6> rd; bits<6> rs; bits<6> rt; let Inst{25-20}=rd; let Inst{19-14}=rs; let Inst{13-8}=rt; let Inst{7-0}=inner_op; } 在llvm-3.5.0.srclibTargetDSPDSPInstrInfo.td文件中添加如下代码进行指令描述: class CBranch3> typeop, bits<3> op, bits<5> inner_op, string instr_asm>: R0$rt, brtarget:$addr), !strconcat(instr_asm, " $addr"), [], IIBranch> { let isBranch = 1; let isTerminator = 1; let isBarrier = 1; let hasDelaySlot = 1; } class SetCC_R3> typeop,bits<3> op, bits<8> inner_op, string instr_asm, PatFrag cond_op , RegisterClass RC> :R3$ra), (ins RC:$rb, RC:$rt), !strconcat(instr_asm, " $ra, $rb, $rt"), [(set GPROut:$ra, (cond_op RC:$rb, RC:$rt))],IIAlu>{ let isCommutable = 1; } def JNC : CBranch<0,0,0b01001, "jnc">; def EQ :SetCC_R<0,4,0b000000000,"eq",seteq,CPURegs>; //添加pat,是完成一种替换的功能 // brcond for cmp instruction multiclass BrcondPatsCmp { def : Pat<(brcond (i32 (setne RC:$lhs, RC:$rhs)), bb:$dst), (JNEOp (CMPOp RC:$lhs, RC:$rhs), bb:$dst)>; def : Pat<(brcond (i32 (setune RC:$lhs, RC:$rhs)), bb:$dst), (JNEOp (CMPOp RC:$lhs, RC:$rhs), bb:$dst)>; def : Pat<(brcond RC:$cond, bb:$dst), (JNEOp (CMPOp RC:$cond, ZEROReg), bb:$dst)>; } defm : BrcondPatsCmp;

2、对br_cc节点进行处理

在使用llc时加入-view-isel-dags就可以调用gvedit.exe来查看dag转换图啦。
这里写图片描述
在文件llvm-3.5.0.srclibTargetDSPDSPISelLowering.cpp中 DSPTargetLowering::DSPTargetLowering(DSPTargetMachine &TM, const DSPSubtarget &STI) :TargetLowering(TM, new DSPTargetObjectFile()), Subtarget(STI){ ... setOperationAction(ISD::BR_CC, MVT::i32, Expand);//将BR_CC节点进行Expand操作 } 这样之后会发现还有问题,BasicBlock不识别。。。
接下来修改llvm-3.5.0.srclibTargetDSPDSPMCInstLower.cpp MCOperand DSPMCInstLower::LowerSymbolOperand(const MachineOperand &MO, MachineOperandType MOTy, unsigned Offset) const { MCSymbolRefExpr::VariantKind Kind; const MCSymbol *Symbol; switch (MO.getTargetFlags()) { default:llvm_unreachable("Invalid target flag!"); break; case DSPII::MO_NO_FLAG: Kind = MCSymbolRefExpr::VK_None; break; case DSPII::MO_ABS_HI: Kind = MCSymbolRefExpr::VK_DSP_ABS_HI; break; case DSPII::MO_ABS_LO: Kind = MCSymbolRefExpr::VK_DSP_ABS_LO; break; case DSPII::MO_GPREL: Kind = MCSymbolRefExpr::VK_DSP_GPREL; break; case DSPII::MO_GOT: Kind = MCSymbolRefExpr::VK_DSP_GOT; break; } switch (MOTy){ case MachineOperand::MO_GlobalAddress: Symbol = AsmPrinter.getSymbol(MO.getGlobal()); break; case MachineOperand::MO_ConstantPoolIndex: Symbol = AsmPrinter.GetCPISymbol(MO.getIndex()); break; case MachineOperand::MO_BlockAddress: Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()); Offset += MO.getOffset(); break; case MachineOperand::MO_JumpTableIndex: Symbol = AsmPrinter.GetJTISymbol(MO.getIndex()); break; case MachineOperand::MO_MachineBasicBlock://这一步处理BasicBlock类型 Symbol = MO.getMBB()->getSymbol(); break; default: llvm_unreachable(""); break; } const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, Kind, *Ctx); if (!Offset) return MCOperand::CreateExpr(MCSym); assert(Offset > 0); const MCConstantExpr *OffsetExpr = MCConstantExpr::Create(Offset, *Ctx); const MCBinaryExpr *AddExpr = MCBinaryExpr::CreateAdd(MCSym, OffsetExpr, *Ctx); return MCOperand::CreateExpr(AddExpr); } ok,完工,能够生成我们期望的汇编指令了。
总结:
需要做的工作有:
1、添加指令:
llvm-3.5.0.srclibTargetDSPDSPInstrFormats.td
llvm-3.5.0.srclibTargetDSPDSPInstrInfo.td
2、处理节点:
llvm-3.5.0.srclibTargetDSPDSPISelLowering.cpp
3、添加BasicBlock操作数类型:
llvm-3.5.0.srclibTargetDSPDSPMCInstLower.cpp