FPGA開発日記

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

オリジナルLLVM Backendを追加しよう (21. Function Callの実装)

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

jonathan2251.github.io

第9章は、関数コールの実装だ。関数コールの実装は量が多すぎてまだ理解が及んでいないが、とりあえずJumpLinkの実装が難しい。

  • lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
/// Arithmetic Instructions (3-Operand, R-Type)
def JALR : JumpFR<0b1100111, 0b000, "jalr", GPR>;
// def : InstAlias<"jr $rs1", (JALR ZERO, GPR:$rs1, 0)>;
def RET  : RetBase<GPR>;

関数コールには基本的にJALR命令を使うことになると思うので、MYRISCVXJmpLinkを定義して、この上で命令を組み立てていくことにする。

  • lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
def SDT_MYRISCVXJmpLink : SDTypeProfile<0, 2, [SDTCisVT<1, iPTR>]>;
...
// Call
def MYRISCVXJmpLink : SDNode<"MYRISCVXISD::JmpLink",SDT_MYRISCVXJmpLink,
                         [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
                         SDNPVariadic]>;
...
def : Pat<(MYRISCVXJmpLink GPR:$rd, (i32 tglobaladdr:$dst)),
          (JALR GPR:$rd, tglobaladdr:$dst)>;
def : Pat<(MYRISCVXJmpLink GPR:$rd, (i32 texternalsym:$dst)),
          (JALR GPR:$rd, texternalsym:$dst)>;

ここでテスト中に悩んでしまっているのだが、ch9_1.cppを実行すると以下のようにエラーが発生した。

./bin/llc -march=myriscvx32 -relocation-model=pic -filetype=asm ch9_1.bc -o -
Selecting: t48: ch = MYRISCVXISD::Ret t47, Register:i32 $a0, t47:1
Selecting: t47: ch,glue = CopyToReg t45, Register:i32 $a0, t46
Selecting: t46: i32,ch = load<(dereferenceable load 4 from %ir.a)> t45, FrameIndex:i32<1>, undef:i32
Selecting: t45: ch = store<(store 4 into %ir.a)> t43:1, t43, FrameIndex:i32<1>, undef:i32
Selecting: t43: i32,ch,glue = CopyFromReg t42, Register:i32 $a0, t42:1
Selecting: t42: ch,glue = callseq_end t41, TargetConstant:i32<24>, TargetConstant:i32<0>, t41:1
Selecting: t41: ch,glue = MYRISCVXISD::JmpLink t29, Register:i32 $gp, Register:i32 $a0, Register:i32 $a1, Register:i32 $gp, RegisterMask:Untyped, t39:1
LLVM ERROR: Cannot select: t41: ch,glue = MYRISCVXISD::JmpLink t29, Register:i32 $gp, Register:i32 $a0, Register:i32 $a1, Register:i32 $gp, RegisterMask:Untyped, t39:1
  t31: i32 = Register $gp
  t35: i32 = Register $a0
...

どうもMYRISCVXISD::JmpLinkの命令が作れないのか?

        addi    x2, x2, -8
        sw      x0, 4(x2)
opcode = 126
Pseudo opcode found in EmitInstruction()
UNREACHABLE executed at /home/masayuki/others/riscv/llvm/llvm-myriscvx/lib/Target/MYRISCVX/MYRISCVXAsmPrinter.cpp:120!
Stack dump:

以下のようにスタックダンプが出て、Pseudo命令をプリントしてしまいそうな場合は、以下の生成されたファイルをチェックする。

  • build-myriscvx/lib/Target/MYRISCVX/MYRISCVXGenInstrInfo.inc.tmp
namespace MYRISCVX {
  enum {
    PHI = 0,
...
    G_BLOCK_ADDR    = 125,
    ADJCALLSTACKDOWN    = 126,
    ADJCALLSTACKUP  = 127,
    CPRESTORE   = 128,
...

この場合は、ADJCALLSTACKDOWN, ADJCALLSTACKUPが疑似命令であるので、これを削除しなければならない。このためには、eliminateCallFramePseudoInstrを追加する。

diff --git a/lib/Target/MYRISCVX/MYRISCVXFrameLowering.cpp b/lib/Target/MYRISCVX/MYRISCVXFrameLowering.cpp
index e6f64bfb642..78cdaed47d5 100644
--- a/lib/Target/MYRISCVX/MYRISCVXFrameLowering.cpp
+++ b/lib/Target/MYRISCVX/MYRISCVXFrameLowering.cpp
@@ -95,3 +95,11 @@ bool MYRISCVXFrameLowering::hasFP(const MachineFunction &MF) const {
       MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() ||
       TRI->needsStackRealignment(MF);
 }
+
+
+// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions
+MachineBasicBlock::iterator MYRISCVXFrameLowering::
+eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
+                              MachineBasicBlock::iterator I) const {
+  return MBB.erase(I);
+}
diff --git a/lib/Target/MYRISCVX/MYRISCVXFrameLowering.h b/lib/Target/MYRISCVX/MYRISCVXFrameLowering.h
index 8e605a1c204..14fd90f6544 100644
--- a/lib/Target/MYRISCVX/MYRISCVXFrameLowering.h
+++ b/lib/Target/MYRISCVX/MYRISCVXFrameLowering.h
@@ -31,6 +31,11 @@ namespace llvm {
     static const MYRISCVXFrameLowering *create(const MYRISCVXSubtarget &ST);

     bool hasFP(const MachineFunction &MF) const override;
+
+    MachineBasicBlock::iterator
+    eliminateCallFramePseudoInstr(MachineFunction &MF,
+                                  MachineBasicBlock &MBB,
+                                  MachineBasicBlock::iterator I) const override;
   };

   /// Create MYRISCVXFrameLowering objects.
diff --git a/lib/Target/MYRISCVX/MYRISCVXInstrInfo.cpp b/lib/Target/MYRISCVX/MYRISCVXInstrInfo.cpp
index 0b7b40ec6ed..f86d5780f00 100644
--- a/lib/Target/MYRISCVX/MYRISCVXInstrInfo.cpp
+++ b/lib/Target/MYRISCVX/MYRISCVXInstrInfo.cpp
@@ -29,7 +29,9 @@ void MYRISCVXInstrInfo::anchor() {}

 //@MYRISCVXInstrInfo {
 MYRISCVXInstrInfo::MYRISCVXInstrInfo(const MYRISCVXSubtarget &STI)
-    : Subtarget(STI) {}
+    :
+    MYRISCVXGenInstrInfo(MYRISCVX::ADJCALLSTACKDOWN, MYRISCVX::ADJCALLSTACKUP),
+    Subtarget(STI) {}

 const MYRISCVXInstrInfo *MYRISCVXInstrInfo::create(MYRISCVXSubtarget &STI) {
   return llvm::createMYRISCVXSEInstrInfo(STI);

これでch9_1.cppコンパイルして実行した。無事に命令が生成できたようだ。

./bin/clang -c -target mips ../lbdex/input/ch9_1.cpp -emit-llvm
./bin/llc -march=myriscvx32 -relocation-model=pic -filetype=asm ch9_1.bc -o -
_Z5sum_iiiiiii:
        .frame  $x8,16,$x1
        .mask   0x00000000,0
        .set    noreorder
        .cpload $t9
        .set    nomacro
# %bb.0:                                # %entry
        lui     x10, %hi(_gp_disp)
        addi    x10, x10, %lo(_gp_disp)
        addi    x2, x2, -16
        lw      x12, 36(x2)
        lw      x12, 32(x2)
        lw      x12, 28(x2)
        lw      x12, 24(x2)
        sw      x10, 12(x2)
        sw      x11, 8(x2)
        lui     x10, %got_hi(gI)
        add     x10, x10, x3
        lw      x10, %got_lo(gI)(x10)
        lw      x10, 0(x10)
        lw      x11, 12(x2)
        add     x10, x10, x11
        lw      x11, 8(x2)
        add     x10, x10, x11
        lw      x11, 24(x2)
        add     x10, x10, x11
        lw      x11, 28(x2)
        add     x10, x10, x11
        lw      x11, 32(x2)
        add     x10, x10, x11
        lw      x11, 36(x2)
        add     x10, x10, x11
        sw      x10, 4(x2)
        lw      x10, 4(x2)
        addi    x1, x10, 0
        addi    x2, x2, 16
        jalr    x1
        .set    macro
        .set    reorder
        .end    _Z5sum_iiiiiii
...
main:
        .frame  $x8,32,$x1
        .mask   0x00000000,0
        .set    noreorder
        .cpload $t9
        .set    nomacro
# %bb.0:                                # %entry
        lui     x10, %hi(_gp_disp)
        addi    x10, x10, %lo(_gp_disp)
        addi    x2, x2, -32
        sw      x0, 28(x2)
        addi    x10, x0, 6
        sw      x10, 20(x2)
        addi    x10, x0, 5
        sw      x10, 16(x2)
        addi    x10, x0, 4
        sw      x10, 12(x2)
        addi    x10, x0, 3
        sw      x10, 8(x2)
        lw      x3, %call16(_Z5sum_iiiiiii)(x3)
        addi    x10, x0, 1
        addi    x11, x0, 2
        jalr    x3
        sw      x10, 24(x2)
        lw      x10, 24(x2)
        addi    x1, x10, 0
        addi    x2, x2, 32
        jalr    x1
        .set    macro
        .set    reorder
        .end    main
$func_end1:
f:id:msyksphinz:20190324150547j:plain