LLVMにはすでにRISC-Vのバックエンドサポートが追加されている。しかし、勉強のために独自のRISC-V実装をLLVMに追加している。
関数コールに対応するためには、EmitPrologueおよびEmitEpilogueを実装しなければならない。 このためには、ロードストア命令・アドレス計算に必要な命令を定義しなければならない。
LUI命令は、Load Immediate Upperに相当する命令だが、これはRISC-V命令セットのうちでU-Typeに相当する。
U-Typeを命令フォーマットで定義した。
lib/Target/MYRISCVX/MYRISCVXInstrFormats.td
class FU<bits<7> opcode, dag outs, dag ins, string asmstr, list<dag> pattern, InstrItinClass itin>: MYRISCVXInst<outs, ins, asmstr, pattern, itin, FrmI> { bits<5> rd; bits<20> imm20; let Opcode = opcode; let Inst{31-12} = imm20; let Inst{11-7} = rd; }
これに基づいて、LUI命令をはじめとする命令群を定義していく。
def ORI : ArithLogicI<0b0010011, 0b110, "ori", or, uimm12, immZExt12, GPR>; def LUI : ArithLogicU<0b0110111, "lui", simm20, immSExt12>; def ADD : ArithLogicR<0b0110011, 0b000, "add", add, GPR>; def SRLI : shift_rotate_imm32<0b0010011, 0b101, 0x00, "shli", shl>;
定数を扱うためのパターンも定義してゆく。
// Small immediates def : Pat<(i32 immSExt12:$in), (ADDI ZERO, imm:$in)>; def : Pat<(i32 immZExt12:$in), (ORI ZERO, imm:$in)>; def : Pat<(i32 immLow12Zero:$in), (LUI (HI20 imm:$in))>; // Arbitrary immediates def : Pat<(i32 imm:$imm), (ORI (LUI (HI20 imm:$imm)), (LO12 imm:$imm))>;
この中で登場するLO12とか、HI20は以下のように定義される。
// Transformation Function - get the lower 12 bits. def LO12 : SDNodeXForm<imm, [{ return getImm(N, N->getZExtValue() & 0xfff); }]>; // Transformation Function - get the higher 20 bits. def HI20 : SDNodeXForm<imm, [{ return getImm(N, (N->getZExtValue() >> 12) & 0xfffff); }]>;
EmitPrologue, EmitEpilogue, さらにloadImmediate()関数を追加してビルドを実行した。
一応ビルドに成功し、命令の選択はできるようになったが途中で固まってしまう。どこかで無限ループしているか?解析する必要がありそうだ。
$ ./bin/llc -march=myriscvx64 -mcpu=myriscvx64 -relocation-model=pic -filetype=asm ch3.bc -o - ... '-noabicalls' is not a recognized feature for this target (ignoring feature) Selecting: t7: ch = MYRISCVXISD::Ret t6, Register:i32 $a0, t6:1 Selecting: t6: ch,glue = CopyToReg t4, Register:i32 $a0, Constant:i32<0> Selecting: t4: ch = store<(store 4 into %ir.retval)> t0, Constant:i32<0>, FrameIndex:i32<0>, undef:i32 Selecting: t5: i32 = Register $a0 Selecting: t1: i32 = Constant<0> Selecting: t0: ch = EntryToken