说明:我们开发了一款新的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
我们做的工作是:
我们首先把比较指令EQ和跳转指令JNC添加上:
在llvm-3.5.0.src\lib\Target\DSP\DSPInstrFormats.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.src\lib\Target\DSP\DSPInstrInfo.td文件中添加如下代码进行指令描述:
class CBranch3> typeop, bits<3> op, bits<5> inner_op, string instr_asm>:
R0$rt, brtarget:$addr),
!strconcat(instr_asm, "\t$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, "\t$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;
在使用llc时加入-view-isel-dags就可以调用gvedit.exe来查看dag转换图啦。
在文件llvm-3.5.0.src\lib\Target\DSP\DSPISelLowering.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.src\lib\Target\DSP\DSPMCInstLower.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.src\lib\Target\DSP\DSPInstrFormats.td
llvm-3.5.0.src\lib\Target\DSP\DSPInstrInfo.td
2、处理节点:
llvm-3.5.0.src\lib\Target\DSP\DSPISelLowering.cpp
3、添加BasicBlock操作数类型:
llvm-3.5.0.src\lib\Target\DSP\DSPMCInstLower.cpp