FPGA開発日記

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

LLVMのバックエンドを作るための第一歩 (8. Calling Conventionとレジスタ定義)

f:id:msyksphinz:20190425001356p:plain
LLVM Compiler Infrastructure

MYRISCVXCallingConv.td

MYRISCVXのCalling Convention、つまり呼び出し規約について設定するTarget Descriptionファイルだ。MYRISCXVの呼び出し規約は、RISC-Vのものをそのまま使用しようと思う。

ここでは、関数呼び出しの時のCallee Savedレジスタの定義だけを入れておく。この記述は、MYRISCVXRegisterInfoの実装時に使用する。

  • lib/Target/MYRISCVX/MYRISCVXCallingConv.td
  def CSR_LP32 : CalleeSavedRegs<(add SP, FP, S1, (sequence "S%u", 2, 11))>;

MYRISCVXRegisterInfo.{h, cpp}

MYRISCVX.tdレジスタを定義した。MYRISCXVRegisterInfo.{h, cpp}は、定義したレジスタのテンプレートを使った実際の実装を記述することになる。 したがって、MYRISCVXRegisterInfoクラスは、MYRISCVXRegisterInfo.tdから自動生成されたMYRISCVXGenRegisterInfoクラスを継承している。

f:id:msyksphinz:20190518012001p:plain
MYRISCVXRegisterInfoクラスの継承関係。

lib/Target/MYRISCVX/MYRISCVXRegisterInfo.hで定義しなければならないメソッドは以下の通りだ。

  • getCalleeSavedRegs() : Callee Savedなレジスタのリストを返す。これはMYRISCVXRegisterInfo.tdで定義したのでC++に変換されている。

    • lib/Target/MYRISCVX/MYRISCVXCallingConv.td
  def CSR_LP32 : CalleeSavedRegs<(add SP, FP, S1, (sequence "S%u", 2, 11))>;
  const MCPhysReg *
  MYRISCVXRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
    return CSR_LP32_SaveList;
  }
  • getCallPreservedMask() : 役割としてはgetCalleeSavedRegs()と似ている。レジジスタ割り当てに使用しない予約済みのレジスタを示する。ビットマスクとして表現される。
  const uint32_t *
  MYRISCVXRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
                                             CallingConv::ID) const {
    return CSR_LP32_RegMask;
  }
  BitVector MYRISCVXRegisterInfo::
  getReservedRegs(const MachineFunction &MF) const {
    //@getReservedRegs body {
    static const uint16_t ReservedCPURegs[] = {
      MYRISCVX::ZERO, MYRISCVX::RA, MYRISCVX::FP, MYRISCVX::SP, MYRISCVX::GP, MYRISCVX::TP
    };
    BitVector Reserved(getNumRegs());
  
    // ResservedCPURRegsの配列に相当するビットに1を設定していく。
    for (unsigned I = 0; I < array_lengthof(ReservedCPURegs); ++I)
      Reserved.set(ReservedCPURegs[I]);
  
    return Reserved;
  }
  • requiresRegisterScavenging() : レジスタスカベンジャ(レジスタが足りない場合の空きレジスタの探索処理)を実行するかどうかを指定する。今回は単純にtrueを返す。

  • trackLivenessAfterRegAlloc() : レジスタ割り当て後のLiveness(レジスタの生存範囲)を記憶するかどうかを指定する。今回は単純にtrueを返す。

  • eliminateFrameIndex() : 抽象的なフレームインデックスを削除するためのコードを記述する。ここではまだ実装しない。

  void MYRISCVXRegisterInfo::
  eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj,
                      unsigned FIOperandNum, RegScavenger *RS) const {
  }
  • getFrameRegister() : フレームレジスタ(フレームポインタ)を返す。
  unsigned MYRISCVXRegisterInfo::
  getFrameRegister(const MachineFunction &MF) const {
    return MYRISCVX::FP;
  }