FPGA開発日記

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

RISC-V 64-bit LLVM Backendを試す (6. Subtargetの確認とllcの動作確認)

LLVMにはすでにRISC-Vのバックエンドサポートが追加されている。しかし、勉強のために独自のRISC-V実装をLLVMに追加している。 まだ現時点ではビルドにすら成功していないが、徐々に修正しながら必要なものを追加してビルドしている。

前回までのビルドしたバイナリで、動作を確認してみる。

./bin/clang -target riscv64-unknown-linux-gnu -c ../lbdex/input/ch3.cpp -emit-llvm -o ch3.riscv64.bc
./bin/llc -march=myriscvx64 -relocation-model=pic -filetype=asm ch3.riscv64.bc -o -

llc: /home/msyksphinz/work/riscv/llvm-myriscvx64/tools/llc/llc.cpp:462: int compileModule(char**, llvm::LLVMContext&): Assertion `Target && "Could not allocate target machine!"' failed.
Stack dump:

アサーションで落ちてしまった。ターゲットマシンは登録してあるはずだから、この動作は少し想定外だ。

GDBで動作を確認しながらおかしいところを追いかけていく。

./tools/llc/llc.cppアサーションが落ちていた。

  • ./tools/llc/llc.cpp
  std::unique_ptr<TargetMachine> Target(TheTarget->createTargetMachine(
      TheTriple.getTriple(), CPUStr, FeaturesStr, Options, getRelocModel(),
      getCodeModel(), OLvl));

  assert(Target && "Could not allocate target machine!");

ここの動作を追いかけていくと、TargetMachineを登録するルーチンにたどり着いた。

  • ./include/llvm/Support/TargetRegistry.h
  TargetMachine *createTargetMachine(StringRef TT, StringRef CPU,
                                     StringRef Features,
                                     const TargetOptions &Options,
                                     Optional<Reloc::Model> RM,
                                     Optional<CodeModel::Model> CM = None,
                                     CodeGenOpt::Level OL = CodeGenOpt::Default,
                                     bool JIT = false) const {
    if (!TargetMachineCtorFn)
      return nullptr;
    return TargetMachineCtorFn(*this, Triple(TT), CPU, Features, Options, RM,
                               CM, OL, JIT);
  }

ここでMYRISCVXの実装を確認してみると、よく見たらBigEndianのアーキテクチャのみを有効にして、LittleEndianの実装を作っていなかった。BigEndianの実装は登録してもいないので、Little Endiianの実装を登録した。

diff --git a/lib/Target/MYRISCVX/MCTargetDesc/MYRISCVXMCTargetDesc.h b/lib/Target/MYRISCVX/MCTargetDesc/MYRISCVXMCTargetDesc.h
index 24f8dbea..c89e6030 100644
--- a/lib/Target/MYRISCVX/MCTargetDesc/MYRISCVXMCTargetDesc.h
+++ b/lib/Target/MYRISCVX/MCTargetDesc/MYRISCVXMCTargetDesc.h
@@ -20,7 +20,6 @@ namespace llvm {
 class Target;
 class Triple;

-extern Target TheMYRISCVXTarget;
 extern Target TheMYRISCVXelTarget;

 } // End llvm namespace
diff --git a/lib/Target/MYRISCVX/TargetInfo/MYRISCVXTargetInfo.cpp b/lib/Target/MYRISCVX/TargetInfo/MYRISCVXTargetInfo.cpp
index b6efdf2a..4505588e 100644
--- a/lib/Target/MYRISCVX/TargetInfo/MYRISCVXTargetInfo.cpp
+++ b/lib/Target/MYRISCVX/TargetInfo/MYRISCVXTargetInfo.cpp
@@ -12,9 +12,9 @@
 #include "llvm/Support/TargetRegistry.h"
 using namespace llvm;

-Target llvm::TheMYRISCVXTarget, llvm::TheMYRISCVXelTarget;
+Target llvm::TheMYRISCVXelTarget;

 extern "C" void LLVMInitializeMYRISCVXTargetInfo() {
   RegisterTarget<Triple::myriscvx,
-                 /*HasJIT=*/true> Y(TheMYRISCVXTarget, "myriscvx", "MYRISCVX", "MYRISCVX");
+                 /*HasJIT=*/true> Y(TheMYRISCVXelTarget, "myriscvx", "MYRISCVX", "MYRISCVX");
 }

これで再度ビルドして確認してみる。

./bin/llc -march=myriscvx -relocation-model=pic -filetype=asm ch3.riscv64.bc

llc: /home/msyksphinz/work/riscv/llvm-riscv-msyksphinz/lib/CodeGen/LLVMTargetMachine.cpp:60: void llvm::LLVMTargetMachine::initAsmInfo(): Assertion `TmpAsmInfo && "MCAsmInfo not initialized. " "Make sure you include the correct TargetSelect.h" "and that InitializeAllTargetMCs() is being invoked!"' failed.
Stack dump:
0.      Program arguments: ./bin/llc -march=myriscvx -relocation-model=pic -filetype=asm ch3.riscv64.bc
#0 0x00007f7786f6e6b3 llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/msyksphinz/work/riscv/llvm-riscv-msyksphinz/lib/Support/Unix/Signals.inc:490:0
#1 0x00007f7786f6e746 PrintStackTraceSignalHandler(void*) /home/msyksphinz/work/riscv/llvm-riscv-msyksphinz/lib/Support/Unix/Signals.inc:554:0

エラーが出なくなった。AsmInfoはまだ実装していないので、この動作は想定通りだ。さて、次に進むぞ。

一応、-mcpu=helpで動作を確認しておく。

$ ./bin/llc -march=myriscvx -mcpu=help
Available CPUs for this target:

  myriscvx64_impl - Select the myriscvx64_impl processor.

Available features for this target:

  myriscvx64      - MYRISCVX64 ISA Support.
  myriscvx64_impl - MYRISCVX64 ISA Support.

ちゃんと登録したアーキテクチャが表示されている。どうやらうまくいったようだ。 この"Available CPUs for this target"と"Available features for this target"で"myriscvx64_impl"が被っているのは、"Available features for this target"の方が範囲が広いからだと思う。

ここで追加されたアーキテクチャは、lib/Target/MYRISCVX.tdで追加していたものだ。SubtargetFeatureとしてプロセッサモデルはmyriscvx64_impl, アーキテクチャモデルとしてはmyriscvxを追加している。

def FeatureMYRISCVX64 : SubtargetFeature<"myriscvx64", "HasArchX64", "true", "MYRISCVX64 ISA Support">;

def FeatureMYRISCVX64_CPU : SubtargetFeature<"myriscvx64_impl", "MYRISCVXArchVersion",
                                "MYRISCVX64", "MYRISCVX64 ISA Support",
                                [FeatureMYRISCVX64]>;

def : ProcessorModel<"myriscvx64_impl", NoSchedModel, [FeatureMYRISCVX64_CPU]>;

f:id:msyksphinz:20190109233324p:plain
llcのオプションとして独自アーキテクチャ実装myriscvxが追加された。