FPGA開発日記

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

オリジナルLLVMバックエンド実装をまとめる(30. llvm-litによるテストの追加)

f:id:msyksphinz:20191007020939p:plain:w200

前回の続き。MYRISCVXのテストを追加する。

simple_main.cppをclangでコンパイルすると、以下のようなLLVM中間コードが生成される。

./bin/clang --target=riscv64-unknown-elf -c  ../myriscvx-tests/tests/simple_main.cpp -emit-llvm -o - | ./bin/llvm-dis -o -
...
; Function Attrs: noinline norecurse nounwind optnone
define dso_local signext i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  ret i32 0
}
...

この中間表現をllcで処理してアセンブリ命令を出力するわけだが、上記のコードは以下のように変換されるはずだ。

...
main:                                   # @main

# %bb.0:                                # %entry
        addi    x2, x2, -4
        addi    x10, zero, 0
        sw      x10, 0(x2)
        addi    x2, x2, 4
        ret
...

入力としての中間コードと、出力としての想定するアセンブリ命令を1つにまとめて、テストを作る。

  • llvm-myriscvx80/test/CodeGen/MYRISCVX/simple_main.ll
; 32ビット MYRISCVXでllcを実行。clangで生成したIRは、-O3を指定してある。
; RUN: llc -mtriple=myriscvx32 < %s \
; RUN:   | FileCheck %s -check-prefix=MY32I

define dso_local i32 @main32_O3() local_unnamed_addr #0 {
; MY32I-LABEL: main32_O3:
; MY32I:       # %bb.0:
; MY32I-NEXT:    addi x10, zero, 0
; MY32I-NEXT:    ret
entry:
  ret i32 0
}
  • llvm-myriscvx80/test/CodeGen/MYRISCVX/simple_main.ll
; 64ビット MYRISCVXでllcを実行。clangで生成したIRは、-O3を指定してある。
; RUN: llc -mtriple=myriscvx64 < %s \
; RUN:   | FileCheck %s -check-prefix=MY64I

define dso_local i32 @main64_O3() local_unnamed_addr #0 {
; MY64I-LABEL: main64_O3:
; MY64I:       # %bb.0:
; MY64I-NEXT:    addi x10, zero, 0
; MY64I-NEXT:    ret
entry:
  ret i32 0
}
  • llvm-myriscvx80/test/CodeGen/MYRISCVX/simple_main.ll
; 64ビット MYRISCVXでllcを実行。clangで生成したIRは、-O0を指定してある。
; RUN: llc -mtriple=myriscvx32 < %s \
; RUN:   | FileCheck %s -check-prefix=MY32I

define dso_local signext i32 @main32() #0 {
; MY32I-LABEL: main32:
; MY32I:        addi    x2, x2, -4
; MY32I:        addi    x10, zero, 0
; MY32I:        sw      x10, 0(x2)
; MY32I:        addi    x2, x2, 4
; MY32I:        ret
entry:
  %retval = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  ret i32 0
}
  • llvm-myriscvx80/test/CodeGen/MYRISCVX/simple_main.ll
; 64ビット MYRISCVXでllcを実行。clangで生成したIRは、-O0を指定してある。
; RUN: llc -mtriple=myriscvx64 < %s \
; RUN:   | FileCheck %s -check-prefix=MY64I

define dso_local signext i32 @main64() #0 {
; MY64I-LABEL: main64:
; MY64I:        addi    x2, x2, -4
; MY64I:        addi    x10, zero, 0
; MY64I:        sw      x10, 0(x2)
; MY64I:        addi    x2, x2, 4
; MY64I:        ret
entry:
  %retval = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  ret i32 0
}

-check-prefix=で指定したラベルを元に生成されたコードとの比較を行っていく。上記の4つのテストが実行され、最終結果が表示される仕組みだ。実行してみる。

$ ./bin/llvm-lit -v ../llvm-myriscvx80/test/CodeGen/MYRISCVX/simple_main.ll
-- Testing: 1 tests, 1 threads --
PASS: LLVM :: CodeGen/MYRISCVX/simple_main.ll (1 of 1)
Testing Time: 0.45s
  Expected Passes    : 1

なんだかあまり変わり映えののない結果になったが、Passしているので良しとする。万が一テストに失敗した場合は以下のようにエラーログが表示される。

  • llvm-myriscvx80/test/CodeGen/MYRISCVX/simple_main.ll
; 32ビット MYRISCVXでllcを実行。clangで生成したIRは、-O3を指定してある。
; RUN: llc -mtriple=myriscvx32 < %s \
; RUN:   | FileCheck %s -check-prefix=MY32I

define dso_local i32 @main32_O3() local_unnamed_addr #0 {
; MY32I-LABEL: main32_O3:
; MY32I:       # %bb.0:
; MY32I-NEXT:    addi x10, zero, 0
; MY32I-NEXT:    rett   # 間違えてretをrettとしてしまった。
entry:
  ret i32 0
}

実行すると以下のようにエラーが表示された。故意に間違えたエラーではあるが、正しく指摘されている。

Exit Code: 1

Command Output (stderr):
--
/home/msyksphinz/work/llvm/llvm-myriscvx80/test/CodeGen/MYRISCVX/simple_main.ll:51:10: error: MY64I: expected string not found in input
; MY64I: rett
         ^
<stdin>:60:2: note: scanning from here
 ret
 ^