FPGA開発日記

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

オリジナルLLVM Backendを追加しよう (22. 論理・比較バリエーションの拡充)

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

Chapter-4.2のあたりを進めている。論理演算命令と比較命令だ。

比較命令をテストしようとすると、MYRISCVXの実装では命令の生成に失敗してしまった。

./bin/clang -target mips-unknown-linux-gnu -c ../lbdex/input/ch4_2_logic.cpp -emit-llvm
./bin/llc -march=myriscvx32 -relocation-model=pic -filetype=asm ch4_2_logic.bc -o -
Selecting: t36: ch = store<(store 4 into %ir.b)> t30:1, t52, FrameIndex:i32<1>, undef:i32

Selecting: t52: i32 = and t50, Constant:i32<1>

Selecting: t50: i32 = setcc t30, Constant:i32<0>, seteq:ch

LLVM ERROR: Cannot select: t50: i32 = setcc t30, Constant:i32<0>, seteq:ch
  t30: i32,ch = load<(dereferenceable load 4 from %ir.a)> t29, FrameIndex:i32<0>, undef:i32
    t2: i32 = FrameIndex<0>
    t4: i32 = undef
  t3: i32 = Constant<0>
In function: _Z16test_andorxornotv

どうも、RISC-Vでは比較命令のバリエーションが少ないため、SLT/SLTIUをうまく使いまわして命令を生成する必要があるらしい。 RISC-V本体の実装から引っ張ってきた。 パタンルールを追加する。

diff --git a/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td b/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
index 41a47ff6ff3..2c0424c98d4 100644
--- a/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
+++ b/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
@@ -296,6 +296,17 @@ def SLTIU : SetCC_I<0b0010011, 0b011, "sltiu", setult, simm12, immSExt12, GPR>;
 def SLT   : SetCC_R<0b0110011, 0b010, "slt",  setlt,  GPR>;
 def SLTU  : SetCC_R<0b0110011, 0b011, "sltu", setult, GPR>;

+// Define pattern expansions for setcc operations that aren't directly
+// handled by a RISC-V instruction.
+def : Pat<(seteq  GPR:$rs1, GPR:$rs2), (SLTIU (XOR GPR:$rs1, GPR:$rs2), 1)>;
+def : Pat<(setne  GPR:$rs1, GPR:$rs2), (SLTU ZERO, (XOR GPR:$rs1, GPR:$rs2))>;
+def : Pat<(setugt GPR:$rs1, GPR:$rs2), (SLTU GPR:$rs2, GPR:$rs1)>;
+def : Pat<(setuge GPR:$rs1, GPR:$rs2), (XORI (SLTU GPR:$rs1, GPR:$rs2), 1)>;
+def : Pat<(setule GPR:$rs1, GPR:$rs2), (XORI (SLTU GPR:$rs2, GPR:$rs1), 1)>;
+def : Pat<(setgt  GPR:$rs1, GPR:$rs2), (SLT GPR:$rs2, GPR:$rs1)>;
+def : Pat<(setge  GPR:$rs1, GPR:$rs2), (XORI (SLT GPR:$rs1, GPR:$rs2), 1)>;
+def : Pat<(setle  GPR:$rs1, GPR:$rs2), (XORI (SLT GPR:$rs2, GPR:$rs1), 1)>;
+
 // Only op DAG can be disabled by ch4_1, data DAG cannot.
 def SDT_MYRISCVXDivRem : SDTypeProfile<0, 2,
                                   [SDTCisInt<0>,

これで、比較命令が生成できるようになる。

        lw      x10, 28(x2)
        lw      x11, 24(x2)
        xor     x10, x10, x11
        sltiu   x10, x10, 1
        andi    x10, x10, 1
        sw      x10, 20(x2)

次にテストするのは、ch4_2_slt_explain.cppだ。 これは本来比較フラグをレジスタに引っ張ってきて演算をするのだが、RISC-Vでは比較命令の結果も汎用レジスタに格納するので特に考えることは無い。

  int a = 3, b = 1;
  int d = 0, e = 0, f = 0;

  d = (a < 1);
  e = (b < 2);
  f = d + e;

  return (f);

生成結果は以下となった。

        slti    x10, x10, 1
        andi    x10, x10, 1
        sw      x10, 12(x2)
        lw      x10, 16(x2)
        slti    x10, x10, 2
        andi    x10, x10, 1
        sw      x10, 8(x2)
        lw      x10, 12(x2)
        lw      x11, 8(x2)
        add     x10, x10, x11
        sw      x10, 4(x2)

f:id:msyksphinz:20190217002302p:plain