LLVMにはすでにRISC-Vのバックエンドサポートが追加されている。しかし、勉強のために独自のRISC-V実装をLLVMに追加している。
32bit環境でのlong longの乗算についての実装を行っている。ISDで言うと所の、SMUL_LOHIとUMUL_LOHIの実装だ。
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2*N], and return the full value as two results, each of type iN.
これを実装したくて、いろいろ調査していたのだが、ビルドして実行してもどうしても正しく命令を生成できない状況が続いていた。 よく考えると、別にMIPSの方式をまねる必要はなく、RISC-VにはHIレジスタもLOレジスタも存在しないのだから、直接レジスタをコピーしてしまえば良いのではなかろうか。
そこで、以下のように実装を行った。
diff --git a/lib/Target/MYRISCVX/MYRISCVXSEInstrInfo.cpp b/lib/Target/MYRISCVX/MYRISCVXSEInstrInfo.cpp index 2a2c7ab1e26..e825e1ce8bc 100644 --- a/lib/Target/MYRISCVX/MYRISCVXSEInstrInfo.cpp +++ b/lib/Target/MYRISCVX/MYRISCVXSEInstrInfo.cpp @@ -162,3 +162,16 @@ loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, BuildMI(MBB, I, DL, get(Opc), DestReg).addFrameIndex(FI).addImm(Offset) .addMemOperand(MMO); } + + +void MYRISCVXSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DstReg, + unsigned SrcReg, bool KillSrc) const { + if (MYRISCVX::GPRRegClass.contains(DstReg, SrcReg)) { + BuildMI(MBB, MBBI, DL, get(MYRISCVX::ADDI), DstReg) + .addReg(SrcReg, getKillRegState(KillSrc)) + .addImm(0); + return; + } +} diff --git a/lib/Target/MYRISCVX/MYRISCVXSEInstrInfo.h b/lib/Target/MYRISCVX/MYRISCVXSEInstrInfo.h index c8df6dafa72..6c0dd18b6c8 100644 --- a/lib/Target/MYRISCVX/MYRISCVXSEInstrInfo.h +++ b/lib/Target/MYRISCVX/MYRISCVXSEInstrInfo.h @@ -55,6 +55,10 @@ namespace llvm { const TargetRegisterInfo *TRI, int64_t Offset) const override; + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DstReg, unsigned SrcReg, + bool KillSrc) const override; + private: void expandRetLR(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const;
要するに単純にcopyPhysRegを使って、必要なレジスタにデータを移すだけだ。通常ならばmuhsで自動的に推論してくれるはずなので、copyPhysRegで自由にレジスタ間を移動できるようにしておくだけである。
これで以下のようなテストプログラムを作成してビルドを行った。
- ch7_1_longlong_mult.cpp
void test_longlong() { int a1 = 0x30001000; int b1 = 0x40001000; long long f = (long long)a1 * (long long)b1; return; }
./bin/clang -c -target mips-unknown-linux-gnu ../lbdex/input/ch7_1_longlong_mult.cpp -emit-llvm ./bin/llc -march=myriscvx32 -relocation-model=pic -filetype=asm ch7_1_longlong_mult.bc -o -
生成されたアセンブリコードは以下のようになった。無事にmulとmulhが生成されている!
addi x2, x2, -16 lui x10, 196609 sw x10, 12(x2) lui x10, 262145 sw x10, 8(x2) lw x10, 12(x2) lw x11, 8(x2) mul x12, x10, x11 mulh x10, x10, x11 addi x11, x2, 0 ori x11, x11, 4 sw x10, 0(x11) sw x12, 0(x2) addi x2, x2, 16 ret