FPGA開発日記

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

LLVMのバックエンドを作るための第一歩 (13. 命令のプリントに関するメソッド群)

命令のプリント、つまりアセンブリ命令をファイルに出力する処理は、基本的にMYRISCVXInstrInfo.tdに記述した命令の定義に基づいて生成される。

LLVMではPrintInstruction()というメソッドがその役割を担います。 このメソッドはMYRISCVXInstPrinterクラスに記述されています。 したがって、PrintInstruction()に関連するメソッドはすべてMYRISCVXInstPrinterに記述することになります。

  • build-myriscvx/lib/Target/MYRISCVX/MYRISCVXGenAsmWriter.inc
/// printInstruction - This method is automatically generated by tablegen
/// from the instruction set description.
void MYRISCVXInstPrinter::printInstruction(const MCInst *MI, raw_ostream &O) {
  static const char AsmStrs[] = {
...
}

ここでサポートメソッドとして追加しなければならないことは、以下の2つ。

  • printOperand() : オペランドを出力する。
  • printMemOperand() : メモリオペランドを出力する。メモリオペランドimm(reg)の形式で出力するので、printOperand()を2回呼び出している。

  • llvm-myriscvx/lib/Target/MYRISCVX/InstPrinter/MYRISCVXInstPrinter.cpp

void MYRISCVXInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
                                       raw_ostream &O) {
  const MCOperand &Op = MI->getOperand(OpNo);
  if (Op.isReg()) {
    printRegName(O, Op.getReg());
    return;
  }

  if (Op.isImm()) {
    O << Op.getImm();
    return;
  }

  assert(Op.isExpr() && "unknown operand kind in printOperand");
  Op.getExpr()->print(O, &MAI, true);
}

void MYRISCVXInstPrinter::
printMemOperand(const MCInst *MI, int opNum, raw_ostream &O) {
  // Load/Store memory operands -- imm($reg)
  // If PIC target the target is loaded as the
  // pattern ld $t9,%call16($gp)
  printOperand(MI, opNum+1, O);
  O << "(";
  printOperand(MI, opNum, O);
  O << ")";
}
f:id:msyksphinz:20190526224919p:plain
printInstruction()により命令がプリントされる仕組み。

このprintInstruction()などの命令プリントメソッドとMYRISCVXTargetMachineとの関連付けは、MCTargetDesc/MYRISCVXMCTargetDesc.cppで行われている。

  • llvm-myriscvx/lib/Target/MYRISCVX/MCTargetDesc/MYRISCVXMCTargetDesc.cpp
// MYRISCVXInstPrinterメソッドを返す。
static MCInstPrinter *createMYRISCVXMCInstPrinter(const Triple &T,
                                                  unsigned SyntaxVariant,
                                                  const MCAsmInfo &MAI,
                                                  const MCInstrInfo &MII,
                                                  const MCRegisterInfo &MRI) {
  return new MYRISCVXInstPrinter(MAI, MII, MRI);
}

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);
    
    // createMYRISCVXMCInstPrinterクラスを通じて、MYRISCVXInstPrintクラスを登録する。
    TargetRegistry::RegisterMCInstPrinter(*T,
                                          createMYRISCVXMCInstPrinter);
  }

}