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

说明:我们开发了一款新的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.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;

2、对br_cc节点进行处理

在使用llc时加入-view-isel-dags就可以调用gvedit.exe来查看dag转换图啦。
在llvm中完成if else语句的编译_第1张图片
在文件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

你可能感兴趣的:(llvm)