FPGA開発日記

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

LLVM 8.0ベースのプロジェクトを LLVM 10.0ベースに移行するための作業まとめ

f:id:msyksphinz:20200329231331p:plain:w300
llvm.org

LLVM 10.0がリリースされた。メジャーバージョンアップの頻度が3か月に1回程度となっており追いかけるのも大変だ。 また、メジャーバージョンがアップデートされる度にAPIの仕様が大きく変更されており、プロジェクトを移行させるのも並大抵ではない。

LLVMのバックエンドに自作ターゲットアーキテクチャを追加するプロジェクト、これまではLLVM 8.0ベースで作業していたものを10.0ベースに移行するとどうなるのか、一応作業記録として残しておくことにした。

LLVM 8.0をベースに組み立てた作業コミットを、cherry-pickしながら10.0ベースに移行するだけの話じゃないのか、というとそれだけの簡単な話ではなく、いろいろAPIの修正が必要となる。すべての作業を終えてコンパイルが成功するのを確認するのに丸一日かかってしまったので、作業記録として残しておくことにした。

ちなみに、複数のGitコミットログをまとめてcherry-pickするのは以下の記事が参考になる。

dackdive.hateblo.jp

この記事にある通り、注意点としては始点となるGitコミットの1つ前のコミットを指定すること。


TargetFrameLoweringの仕様変更

  • llvm/lib/Target/MYRISCVX/MYRISCVXFrameLowering.h
In file included from /home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXSubtarget.h:17,
                 from /home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXTargetMachine.h:18,
                 from /home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXTargetMachine.cpp:15:
/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXFrameLowering.h: In constructor 'llvm::MYRISCVXFrameLowering::MYRISCVXFrameLowering(const llvm::MYRISCVXSubtarget&)':
/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXFrameLowering.h:32:18: error: no matching function for call to 'llvm::TargetFrameLowering::TargetFrameLowering(llvm::TargetFrameLowering::StackDirection, int, int)'
           STI(sti) {
                  ^

アライメントを示す引数がint型からAlign型に変更になっている。

  TargetFrameLowering(StackDirection D, Align StackAl, int LAO,
                      Align TransAl = Align::None(), bool StackReal = true)
      : StackDir(D), StackAlignment(StackAl), TransientStackAlignment(TransAl),
        LocalAreaOffset(LAO), StackRealignable(StackReal) {}
  • 解決方法

引数をAlign()型でラップする。

explicit MYRISCVXFrameLowering(const MYRISCVXSubtarget &sti)
    : TargetFrameLowering(StackGrowsDown,
                          /*StackAlignment=*/Align(16),
                          /*LocalAreaOffset=*/0),
      STI(sti) {
}

同様に、setMinFuncitonAlignment()も修正しないとエラーが発生する。

/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXISelLowering.cpp:72:28: error: no matching function for call to 'llvm::MYRISCVXTargetLowering::setMinFunctionAlignment(int)'
   setMinFunctionAlignment(2);
In file included from /home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXISelLowering.h:24,
                 from /home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXISelLowering.cpp:14:
/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/include/llvm/CodeGen/TargetLowering.h:2106:8: note: candidate: 'void llvm::TargetLoweringBase::setMinFunctionAlignment(llvm::Align)'
   void setMinFunctionAlignment(Align Alignment) {
        ^~~~~~~~~~~~~~~~~~~~~~~

修正後:

  //- Set .align 2
  // It will emit .align 2 later
  const Align FunctionAlignment(2);
  setMinFunctionAlignment(FunctionAlignment);

getFrameRegister()

  • getFrameRegister()の仕様変更。戻り値の方の修正など。
/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXRegisterInfo.h:52:14: error: conflicting return type specified for 'virtual unsigned int llvm::MYRISCVXRegisterInfo::getFrameRegister(const llvm::MachineFunction&) const'
     unsigned getFrameRegister(const MachineFunction &MF) const override;
              ^~~~~~~~~~~~~~~~

これまでunsigned intで指定指定たレジスタの情報をRegister型に置き換えることで修正する。

Register MYRISCVXRegisterInfo::
getFrameRegister(const MachineFunction &MF) const {
  const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
  return TFI->hasFP(MF) ? (MYRISCVX::FP) :
      (MYRISCVX::SP);
}

copyPhysReg()の仕様変更

/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXInstrInfo.h:54:8: error: 'void llvm::MYRISCVXInstrInfo::copyPhysReg(llvm::MachineBasicBlock&, llvm::MachineBasicBlock::iterator, const llvm::DebugLoc&, unsigned int, unsigned int, bool) const' marked 'override', but does not override
   void copyPhysReg(MachineBasicBlock &MBB,
        ^~~~~~~~~~~

引数の型がいくつか変更になっており修正する。

  void copyPhysReg(MachineBasicBlock &MBB,
                   MachineBasicBlock::iterator MBBI,
                   const DebugLoc &DL, unsigned DstReg,
                   unsigned SrcReg, bool KillSrc) const override;

修正後:

  void copyPhysReg(MachineBasicBlock &MBB,
                   MachineBasicBlock::iterator MBBI,
                   const DebugLoc &DL, MCRegister DstReg,
                   MCRegister SrcReg, bool KillSrc) const override;

void MYRISCVXInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
                                    MachineBasicBlock::iterator MBBI,
                                    const DebugLoc &DL, MCRegister DstReg,
                                    MCRegister SrcReg, bool KillSrc) const {

make_unique()がこのままでは使えない

/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MYRISCVXTargetMachine.cpp:82:12: error: 'make_unique' was not declared in this scope
       TLOF(make_unique<MYRISCVXTargetObjectFile>()),
            ^~~~~~~~~~~
    //- Default is big endian
    : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options), TT,
                        CPU, FS, Options, getEffectiveRelocModel(JIT, RM),
                        getEffectiveCodeModel(CM, CodeModel::Small), OL),
      TLOF(make_unique<MYRISCVXTargetObjectFile>()),
      ABI(MYRISCVXABIInfo::computeTargetABI(Options.MCOptions.getABIName())),
      DefaultSubtarget(TT, CPU, FS, *this) {
  initAsmInfo();

修正後:

    : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options), TT,
                        CPU, FS, Options, getEffectiveRelocModel(JIT, RM),
                        getEffectiveCodeModel(CM, CodeModel::Small), OL),
      TLOF(std::make_unique<MYRISCVXTargetObjectFile>()),
      ABI(MYRISCVXABIInfo::computeTargetABI(Options.MCOptions.getABIName())),
      DefaultSubtarget(TT, CPU, FS, *this) {
  initAsmInfo();

printInst()の修正

これも仕様が変更となっている。

/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/InstPrinter/MYRISCVXInstPrinter.h:37:10: error: 'void llvm::MYRISCVXInstPrinter::printInst(const llvm::MCInst*, llvm::raw_ostream&, llvm::StringRef, const llvm::MCSubtargetInfo&)' marked 'override', but does not override
     void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
          ^~~~~~~~~
    void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
                   const MCSubtargetInfo &STI) override;

以下のように修正を加える。結構抜本的に変更となっている。

void MYRISCVXInstPrinter::printInst(const MCInst *MI, uint64_t Address,
                                    StringRef Annot, const MCSubtargetInfo &STI,
                                    raw_ostream &O) {
  // Try to print any aliases first.
  if (!printAliasInstr(MI, O))
    //@1 }
    //- printInstruction(MI, O) defined in MYRISCVXGenAsmWriter.inc which came from
    //   MYRISCVX.td indicate.
    printInstruction(MI, Address, O);
  printAnnotation(O, Annot);
}

createMYRISCVXMCAsmInfo()の仕様変更

引数が追加となっている。

/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/MCTargetDesc/MYRISCVXMCTargetDesc.cpp:131:54: error: invalid conversion from 'llvm::MCAsmInfo* (*)(const llvm::MCRegisterInfo&, const llvm::Triple&)' to 'llvm::Target::MCAsmInfoCtorFnTy' {aka 'llvm::MCAsmInfo* (*)(const llvm::MCRegisterInfo&, const llvm::Triple&, const llvm::MCTargetOptions&)'} [-fpermissive]
     RegisterMCAsmInfoFn X(*T, createMYRISCVXMCAsmInfo);
                                                      ^
static MCAsmInfo *createMYRISCVXMCAsmInfo(const MCRegisterInfo &MRI,
                                          const Triple &TT) {
  MCAsmInfo *MAI = new MYRISCVXMCAsmInfo(TT);

  unsigned SP = MRI.getDwarfRegNum(MYRISCVX::SP, true);
  MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, SP, 0);
  MAI->addInitialFrameState(Inst);

  return MAI;
}

変更後。MCTargetOptions &Optionsを引数として追加したが使っていない。これでいいのか?

static MCAsmInfo *createMYRISCVXMCAsmInfo(const MCRegisterInfo &MRI,
                                          const Triple &TT,
                                          const MCTargetOptions &Options) {
  MCAsmInfo *MAI = new MYRISCVXMCAsmInfo(TT);

  unsigned SP = MRI.getDwarfRegNum(MYRISCVX::SP, true);
  MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, SP, 0);
  MAI->addInitialFrameState(Inst);

  return MAI;
}

InstPrinterの廃止とMCTargetDescへの移行

これが一番手こずった。vtableの不足。これがなんだか良く分からない。必要な関数はすべて追加したと思うのだが...

/home/msyksphinz/work/llvm/llvm-myriscvx100/llvm/lib/Target/MYRISCVX/InstPrinter/MYRISCVXInstPrinter.h:30: undefined reference to `vtable for llvm::MYRISCVXInstPrinter'

色々試行した他結果、どうやらInstPrinterディレクトリは廃止されており、その代わりにInstPrinter.{h,cpp}MCTargetDescディレクトリに移動する必要があるらしい。そのための修正を行う。

最終的に、lib/Target/MYRISCVX以下のサブディレクトリはMCTargetDescTargetInfoの2つとなった。

ここまでで、無事にビルドが終了するようになった。

$ tree . -L 1
.
|-- CMakeLists.txt
|-- LLVMBuild.txt
|-- MCTargetDesc
|-- MYRISCVX.h
|-- MYRISCVX.td
|-- MYRISCVXAsmPrinter.cpp
|-- MYRISCVXAsmPrinter.h
|-- MYRISCVXCallingConv.td
|-- MYRISCVXFrameLowering.cpp
|-- MYRISCVXFrameLowering.h
|-- MYRISCVXISelDAGToDAG.cpp
|-- MYRISCVXISelDAGToDAG.h
|-- MYRISCVXISelLowering.cpp
|-- MYRISCVXISelLowering.h
|-- MYRISCVXInstrFormats.td
|-- MYRISCVXInstrInfo.cpp
|-- MYRISCVXInstrInfo.h
|-- MYRISCVXInstrInfo.td
|-- MYRISCVXMCInstLower.cpp
|-- MYRISCVXMCInstLower.h
|-- MYRISCVXMachineFunction.cpp
|-- MYRISCVXMachineFunction.h
|-- MYRISCVXRegisterInfo.cpp
|-- MYRISCVXRegisterInfo.h
|-- MYRISCVXRegisterInfo.td
|-- MYRISCVXSchedule.td
|-- MYRISCVXSubtarget.cpp
|-- MYRISCVXSubtarget.h
|-- MYRISCVXTargetMachine.cpp
|-- MYRISCVXTargetMachine.h
|-- MYRISCVXTargetObjectFile.cpp
|-- MYRISCVXTargetObjectFile.h
`-- TargetInfo