FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

オリジナルLLVMバックエンド実装をまとめる(2. llcがターゲットマシンを初期化するまでの流れ)

これまでに示した通り、LLVMにターゲットアーキテクチャを登録するためには様々な機能を追加する必要がある。 llcが呼ばれてから初期化プロセスがどこでどのようにして呼ばれているのか、追いかけてみることにする。

llcllc.cppに定義されてあるmain()から開始される。main()には以下のようにターゲットを初期化するための複数のルーチンが定義されている。

  • llvm-myriscvx80/tools/llc/llc.cpp
int main(int argc, char **argv) {
  InitLLVM X(argc, argv);
...
  // Initialize targets first, so that --version shows registered targets.
  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();

少しわかりにくいが、これらの処理でどのような関数が呼ばれるのか追いかけてまた (図[fig:llc_init_process])

f:id:msyksphinz:20190913171751p:plain
llcのターゲット初期化プロセス
  • llvm-myriscvx80/include/llvm/Support/TargetSelect.h
extern "C" {
  // Declare all of the target-initialization functions that are available.
#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##TargetInfo();
#include "llvm/Config/Targets.def"

#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##Target();
#include "llvm/Config/Targets.def"

  // Declare all of the target-MC-initialization functions that are available.
#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##TargetMC();
#include "llvm/Config/Targets.def"

  // Declare all of the available assembly printer initialization functions.
#define LLVM_ASM_PRINTER(TargetName) void LLVMInitialize##TargetName##AsmPrinter();
#include "llvm/Config/AsmPrinters.def"

  // Declare all of the available assembly parser initialization functions.
#define LLVM_ASM_PARSER(TargetName) void LLVMInitialize##TargetName##AsmParser();
#include "llvm/Config/AsmParsers.def"

  // Declare all of the available disassembler initialization functions.
#define LLVM_DISASSEMBLER(TargetName) \
  void LLVMInitialize##TargetName##Disassembler();
#include "llvm/Config/Disassemblers.def"
}

LLVMInitializeAllTargets()

まずはLLVMInitializeAllTargets()だ。MYRISCVXのターゲットマシンとそのサブターゲットである32ビット版と64ビット版を登録する。LLVMInitializeMYRISCVXTarget()が呼び出される。

  • llvm-myriscvx80/lib/Target/MYRISCVX/MYRISCVXTargetMachine.cpp
extern "C" void LLVMInitializeMYRISCVXTarget() {

  // Register the target.
  //- Little endian Target Machine
  RegisterTargetMachine<MYRISCVX32TargetMachine> X(getTheMYRISCVX32Target());
  RegisterTargetMachine<MYRISCVX64TargetMachine> Y(getTheMYRISCVX64Target());
}

InitializeAllTargetMCs()

サブターゲットのマシンについて、それぞれ必要な情報を登録していく。32ビット版と64ビット版についてレジスタの定義や命令の定義などを登録していく。LLVMInitializeMYRISCVXTargetMC()が呼び出される。

  • llvm-myriscvx80/lib/Target/MYRISCVX/MCTargetDesc/MYRISCVXMCTargetDesc.cpp
extern "C" void LLVMInitializeMYRISCVXTargetMC() {
  for (Target *T : {&getTheMYRISCVX32Target(), &getTheMYRISCVX64Target()}) {
    // Register the MC asm info.
    RegisterMCAsmInfoFn X(*T, createMYRISCVXMCAsmInfo);

    // Register the MC instruction info.
    TargetRegistry::RegisterMCInstrInfo(*T, createMYRISCVXMCInstrInfo);

    // Register the MC register info.
    TargetRegistry::RegisterMCRegInfo(*T, createMYRISCVXMCRegisterInfo);

    // Register the MC subtarget info.
    TargetRegistry::RegisterMCSubtargetInfo(*T,
                                            createMYRISCVXMCSubtargetInfo);
    // Register the MC instruction analyzer.
    TargetRegistry::RegisterMCInstrAnalysis(*T, createMYRISCVXMCInstrAnalysis);
    // Register the MCInstPrinter.
    TargetRegistry::RegisterMCInstPrinter(*T,
                                          createMYRISCVXMCInstPrinter);
  }

}

InitializeAllAsmPrinters()

アセンブリ命令の出力について登録する。LLVMInitializeMYRISCVXAsmPrinter()が呼び出される。

  • llvm-myriscvx80/lib/Target/MYRISCVX/MYRISCVXAsmPrinter.cpp
extern "C" void LLVMInitializeMYRISCVXAsmPrinter() {
  RegisterAsmPrinter<MYRISCVXAsmPrinter> X(getTheMYRISCVX32Target());
  RegisterAsmPrinter<MYRISCVXAsmPrinter> Y(getTheMYRISCVX64Target());
}