FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

オリジナルLLVM Backendを追加しよう (17. 32-bitコアでの64bit整数演算の命令出力実装)

LLVMにはすでにRISC-Vのバックエンドサポートが追加されている。しかし、勉強のために独自のRISC-V実装をLLVMに追加している。

jonathan2251.github.io

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

f:id:msyksphinz:20190307010859p:plain