FPGA開発日記

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

オリジナルLLVM Backendを追加しよう (15. int型以外の変数への対応)

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

jonathan2251.github.io

第7章は、int型以外の各種変数型に対応させる。

github.com

diff --git a/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td b/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
index 41f009b0d11..b7da82ae9f7 100644
--- a/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
+++ b/lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
@@ -127,6 +133,12 @@ def store_a : AlignedStore<store>;
 // Instructions specific format
 //===----------------------------------------------------------------------===//

+class EffectiveAddress<string instr_asm, RegisterClass RC, Operand Mem> :
+  FI<0b0000011, 0b010, (outs RC:$ra), (ins Mem:$addr),
+     instr_asm, [(set RC:$ra, addr:$addr)], IIAlu> {
+}
+
+

EffectiveAddressクラスを定義している。これは良く分からないがaddi命令に対応させるようにしておけばよいのかな?

以下のプログラムでテストする。これはプログラムとしては意味のないもの、というか動かないだろうけど、とりあえずポインタの動きを見るためには良さそう。

/// start
int test_local_pointer()
{
  int b = 3;

  int* p = &b;

  return *p;
}
./bin/clang -c -target mips-unknown-linux-gnu ../lbdex/input/ch7_1_localpointer.cpp -emit-llvm
./bin/llc -march=myriscvx32 -filetype=asm ch7_1_localpointer.bc -o -
        addi    x10, x0, 3
        sw      x10, 4(x2)
        addi    x10, x2, 4
        sw      x10, 0(x2)
        lw      x10, 0(x2)
        lw      x10, 0(x10)

3という実体を作ってから、メモリに格納してから、アドレスを生成してまた実体をメモリからロードする。 一応動作としては合っているようだ。

次に、以下のコードをコンパイルしてアセンブリを生成できるようにする。charとshortが混在している環境だ。

/// start
struct Date
{
  short year;
  char month;
  char day;
  char hour;
  char minute;
  char second;
};

unsigned int b[4] = {'a', 'b', 'c', '\0'};

int test_char()
{
  unsigned char a = b[1];
  char c = (char)b[1];
  Date date1 = {2012, (char)11, (char)25, (char)9, (char)40, (char)15};
  char m = date1.month;
  char s = date1.second;

  return 0;
}

Tutorialの通りに、単純に以下のコードを追加すれば動作するのかと思った。

  • lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
defm LB  : LoadM32<0b0000011, 0b000, "lb" , sextloadi8_a >;
defm LH  : LoadM32<0b0000011, 0b001, "lh" , sextloadi16_a>;
defm LW  : LoadM32<0b0000011, 0b010, "lw" , load_a       >;
defm LBU : LoadM32<0b0000011, 0b100, "lbu", zextloadi8_a >;
defm LHU : LoadM32<0b0000011, 0b101, "lhu", zextloadi16_a>;

defm SB  : StoreM32<0b0100011, 0b000, "sb", truncstorei8_a >;
defm SH  : StoreM32<0b0100011, 0b001, "sh", truncstorei16_a>;
defm SW  : StoreM32<0b0100011, 0b010, "sw", store_a        >;

LLVMをビルドしてアセンブリをはいてみると、どうもうまくいかずにエラーとなってしまった。

LLVM ERROR: Cannot select: t45: i32,ch = load<(dereferenceable load 1 from %ir.second, align 2), anyext from i8> t44, t36, undef:i32
  t36: i32 = or FrameIndex:i32<2>, Constant:i32<6>
    t12: i32 = FrameIndex<2>
    t28: i32 = Constant<6>
  t5: i32 = undef

これらのエラーは、MIPSと比較したり、charとshortを全部intに変えてみたりして確認してみるとわかりやすい気がする。 原因を絞り込んだ結果、charとshortのメモリアクセス命令を定義しただけではだめ、ちゃんとIRから推論されるように追加する必要があった。

  • lib/Target/MYRISCVX/MYRISCVXInstrInfo.td
@@ -413,3 +414,9 @@ class WrapperPat<SDNode node, Instruction ORiOp, RegisterClass RC>:
           (ORiOp RC:$gp, node:$in)>;

 def : WrapperPat<tglobaladdr, ORI, GPR>;
+
+def : Pat<(i32 (extloadi1  addr:$src)), (LBU addr:$src)>;
+def : Pat<(i32 (extloadi8  addr:$src)), (LBU addr:$src)>;
+def : Pat<(i32 (extloadi16 addr:$src)), (LHU addr:$src)>;
+// peepholes
+def : Pat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>;

これにより、上記のC言語のコードは正しく出力されるようになった。

./bin/clang -c -target mips-unknown-linux-gnu ../lbdex/input/ch7_1_char_in_struct.cpp -emit-llvm
./bin/llc -march=mips -relocation-model=pic -filetype=asm ch7_1_char_in_struct.bc -o -
# %bb.0:                                # %entry
        addi    x2, x2, -24
        lui     x10, %got_hi(b)
        add     x10, x10, x3
        lw      x10, %got_lo(b)(x10)
        addi    x10, x10, 4
        lw      x11, 0(x10)
        sb      x11, 20(x2)
        lw      x10, 0(x10)
        sb      x10, 16(x2)
        lw      x10, %got($_ZZ9test_charvE5date1)(x3)
        ori     x10, x10, %lo($_ZZ9test_charvE5date1)
        addi    x11, x10, 4
        lhu     x11, 0(x11)
        addi    x12, x10, 6
        lhu     x12, 0(x12)
        slli    x12, x12, 16
        or      x11, x12, x11
        addi    x12, x2, 8
        ori     x13, x12, 4
        sw      x11, 0(x13)
        lhu     x11, 0(x10)
        addi    x10, x10, 2
        lhu     x10, 0(x10)
        slli    x10, x10, 16
        or      x10, x10, x11
        sw      x10, 8(x2)
        ori     x10, x12, 2
        lbu     x10, 0(x10)
        sb      x10, 4(x2)
        ori     x10, x12, 6
        lbu     x10, 0(x10)
        sb      x10, 0(x2)
        addi    x10, x0, 0
        addi    x2, x2, 24
        ret