LLVMについて理解するために、RISC-Vをネタにしていろいろ勉強してみたい。 Release 7.0では一応RISC-Vの32-bitと64-bit版がサポートされているようなので、ビルドに追加して様子を見てみる。
ここで追加するのは、新しい"RISCV_msyksphinz"というアーキテクチャ。基本的にRISC-Vと同じなのだが、Cpu0のサンプルをベースに作るので実装はLLVMの本体に登録されているものとは異なる。
とりあえず実装は以下のリポジトリで進める。ブランチはriscv_msyksphinzを作成した。
アーキテクチャの定義
アーキテクチャの定義は、CMakeLists.txtに追加する。
CMakeLists.txt
# List of all targets to be built by default: set(LLVM_ALL_TARGETS AArch64 ... RISCV_msyksphinz )
cmake/config-ix.cmake
... elseif (LLVM_NATIVE_ARCH MATCHES "riscv64-msyksphinz") set(LLVM_NATIVE_ARCH RISCV_msyksphinz) ...
include/llvm/BinaryFormat/ELFRelocs/RISCV.def
はRISC-VのABIで定義されているリロケーションテーブルを追加している。リロケーションについては以下のブログが非常に詳しかった。
riscv-gnu-toolchain/riscv-binutils-gdb/include/elf/riscv.h
/* Relocation types. */ START_RELOC_NUMBERS (elf_riscv_reloc_type) /* Relocation types used by the dynamic linker. */ RELOC_NUMBER (R_RISCV_NONE, 0) RELOC_NUMBER (R_RISCV_32, 1) RELOC_NUMBER (R_RISCV_64, 2) RELOC_NUMBER (R_RISCV_RELATIVE, 3) ... /* Relocation types not used by the dynamic linker. */ RELOC_NUMBER (R_RISCV_BRANCH, 16) RELOC_NUMBER (R_RISCV_JAL, 17) RELOC_NUMBER (R_RISCV_CALL, 18) RELOC_NUMBER (R_RISCV_CALL_PLT, 19) RELOC_NUMBER (R_RISCV_GOT_HI20, 20)
E_Flagsの設定。これは各アーキテクチャのプロセッサ固有のフラグについて示している。
include/llvm/BinaryFormat/ELF.h
// RISCV Specific e_flags enum : unsigned { EF_RISCV_RVC = 0x0001, EF_RISCV_FLOAT_ABI = 0x0006, EF_RISCV_FLOAT_ABI_SOFT = 0x0000, EF_RISCV_FLOAT_ABI_SINGLE = 0x0002, EF_RISCV_FLOAT_ABI_DOUBLE = 0x0004, EF_RISCV_FLOAT_ABI_QUAD = 0x0006, EF_RISCV_RVE = 0x0008 };
riscv-gnu-toolchain/riscv-binutils-gdb/include/elf/riscv.h
/* Processor specific flags for the ELF header e_flags field. */ /* File may contain compressed instructions. */ #define EF_RISCV_RVC 0x0001 /* Which floating-point ABI a file uses. */ #define EF_RISCV_FLOAT_ABI 0x0006 /* File uses the soft-float ABI. */ #define EF_RISCV_FLOAT_ABI_SOFT 0x0000 /* File uses the single-float ABI. */ #define EF_RISCV_FLOAT_ABI_SINGLE 0x0002 /* File uses the double-float ABI. */ #define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004 /* File uses the quad-float ABI. */ #define EF_RISCV_FLOAT_ABI_QUAD 0x0006 /* The name of the global pointer symbol. */ #define RISCV_GP_SYMBOL "__global_pointer$"
RISC-Vレジスタの定義
Encのビット数が5だったり、16だったり、32だったりする。これの理由は分からないが、5-bitあればよい気がするので5に削ってみる。
// We have banks of 32 registers each. class RISCVReg<bits<5> Enc, string n> : Register<n> { let HWEncoding = Enc; }
さらに、32個分のレジスタに対して名前を定義した。これはdefで行う。
lib/Target/RISCV_msysksphinz/RISCVRegisterInfo.td
def ZERO : RISCVGPRReg<0, "x0">, DwarfRegNum<[0]>; def RA : RISCVGPRReg<1, "x1">, DwarfRegNum<[1]>; def SP : RISCVGPRReg<2, "x2">, DwarfRegNum<[2]>; def GP : RISCVGPRReg<3, "x3">, DwarfRegNum<[3]>; ...
LLVMBuild.txt と CMakeLists.txt
lib/Target/RISCV_msyksphinz
には、CMakeLists.txtとLLVMBuild.txtが配置されている。
さらに、サブディレクトリとしてMCTargetDesc
とTargetInfo
を作成したのだが、そのどちらにもCMakeLists.txtとLLVMBuild.txtを配置した。
LLVMBuild.txtはどうやらそのディレクトリがどのコンポーネントについてのディレクトリなのかを示しているらしい。
一方で、CMakeLists.txtはそのディレクトリのビルド対象となるファイルと、どのようなライブラリを作成するのかが記述される。
RISCV_msyksphinz/MCTargetDesc/LLVMBuild.txt
[component_0] type = Library name = RISCV_msyksphinzDesc parent = RISCV_msyksphinz required_libraries = MC RISCV_msyksphinzInfo Support add_to_library_groups = RISCV_msyksphinz
RISCV_msyksphinz/MCTargetDesc/CMakeLists.txt
# MCTargetDesc/CMakeLists.txt add_llvm_library(LLVMRISCV_msyskphinzDesc RISCV_msyksphinz_MCTargetDesc.cpp )
ビルドできなくて猛烈に迷ったのだが、どうやらMCTargetDescとTargetInfoレジスタは必須で作らなければならないようだ。
そして定義するライブラリの名前も、${ターゲット名}Desc
とか、${ターゲット名}Info
などにしなければならない。つまり、今回の場合はRISCV_msyksphinzDesc
とか、RISCV_msyksphinzInfo
というちょっと格好悪い名前になる。
これで、ビルドを試行した。というか、まずはCMakeで最低限エラーが発生しないところまで進めよう。
cmake -G Ninja -DCMAKE_BUILD_TYPE="Debug" -DLLVM_TARGETS_TO_BUILD="RISCV_msyksphinz" ../llvm-riscv-msyksphinz
... CMake Error in lib/Target/RISCV_msyksphinz/MCTargetDesc/CMakeLists.txt: Exporting the target "LLVMRISCV_msyskphinzDesc" is not allowed since its linker language cannot be determined CMake Error in lib/Target/RISCV_msyksphinz/MCTargetDesc/CMakeLists.txt: Exporting the target "LLVMRISCV_msyskphinzDesc" is not allowed since its linker language cannot be determined
とりあえずエラーは大量に出ているのだが、「ファイルがねえよ」とか、「そんなライブラリねえよ」という問題外のエラーは出なくなったので良しとする。