FPGA開発日記

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

RISC-V 64-bit LLVM Backendを試す (2. 独自RISC-V実装を追加する。アーキテクチャの追加とレジスタ)

LLVMについて理解するために、RISC-Vをネタにしていろいろ勉強してみたい。 Release 7.0では一応RISC-Vの32-bitと64-bit版がサポートされているようなので、ビルドに追加して様子を見てみる。

ここで追加するのは、新しい"RISCV_msyksphinz"というアーキテクチャ。基本的にRISC-Vと同じなのだが、Cpu0のサンプルをベースに作るので実装はLLVMの本体に登録されているものとは異なる。

とりあえず実装は以下のリポジトリで進める。ブランチはriscv_msyksphinzを作成した。

github.com

アーキテクチャの定義

アーキテクチャの定義は、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.defRISC-VのABIで定義されているリロケーションテーブルを追加している。リロケーションについては以下のブログが非常に詳しかった。

intothevoid.hatenablog.com

この定義はRISC-V GCCにも同じような定義がある。

  • 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

f:id:msyksphinz:20190103014852p:plain
LLVMディレクトリ構造と追加したファイル群

lib/Target/RISCV_msyksphinz には、CMakeLists.txtとLLVMBuild.txtが配置されている。 さらに、サブディレクトリとしてMCTargetDescTargetInfoを作成したのだが、そのどちらにも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

とりあえずエラーは大量に出ているのだが、「ファイルがねえよ」とか、「そんなライブラリねえよ」という問題外のエラーは出なくなったので良しとする。