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]>;