LLVMにはすでにRISC-Vのバックエンドサポートが追加されている。しかし、勉強のために独自のRISC-V実装をLLVMに追加している。
LLVMには独自のIRを定義できる仕組みがあり、それを使って命令を変換したりして最終的に命令を生成する。 例えば、Return命令をどのようにして最終的にllcが命令として出力するのかについてまとめる。
例えば、MYRISCVXRet
という関数から戻る命令のためのIRを定義する。
ISDというのは、SelectionDAGノードの型を示すものらしい。
lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
// Return def MYRISCVXRet : SDNode<"MYRISCVXISD::Ret", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
これはLLVMの実装からは、MYRISCVXISD::Ret
として参照できるようになる。
DAGは、以下の定義によって使用される。
lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
let isReturn=1, isTerminator=1, hasDelaySlot=0, isBarrier=1, hasCtrlDep=1 in def RetRA : MYRISCVXPseudo<(outs), (ins), "", [(MYRISCVXRet)]>;
RetRAノードを定義する。isReturnとisTerminatorはリターン命令であり、BasicBlockの最後のノードである、ということを示していると思う。
このMYRSCVXISD::Ret
ノードはC言語のreturn命令などで使用されるのだが、Instruction Selectionの段階でMYRISCVX::RetRA
に変換される。これは同等なので変換しても良い。
ISEL: Starting selection on root node: t62: ch = MYRISCVXISD::Ret t61 Selecting: t62: ch = MYRISCVXISD::Ret t61 ISEL: Starting pattern match Morphed node: t62: ch = RetRA t61 ISEL: Match complete!
このMYRISCVX::RetRA
は、以下のMYRISCVXSEISelLowering.cpp
の実装によってMYRISCVX::JALR
に変換される。
これが最終的にjalr ra
という命令に変換されるわけだ。
This function is called for all pseudo instructions that remain after register allocation. Many pseudo instructions are created to help register allocation. This is the place to convert them into real instructions. The target can edit MI in place, or it can insert new instructions and erase MI. The function should return true if anything was changed.
//@expandPostRAPseudo /// Expand Pseudo instructions into real backend instructions bool MYRISCVXSEInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { //@expandPostRAPseudo-body MachineBasicBlock &MBB = *MI.getParent(); switch (MI.getDesc().getOpcode()) { default: return false; case MYRISCVX::RetRA: expandRetLR(MBB, MI); break; } MBB.erase(MI); return true; } void MYRISCVXSEInstrInfo::expandRetLR(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { BuildMI(MBB, I, I->getDebugLoc(), get(MYRISCVX::JALR)).addReg(MYRISCVX::RA); }
Cpu0の命令変換の説明では、以下のように書いてある。