首发于LLVM每日谈

LLVM每日谈之五十二 创建LLVM后端的第一步校正(target machine)

根据LLVM文档《Writing an LLVM Backend 》可知道,LLVM新建一个后端需要七大步骤。前文对七大步骤和文档中其他的结构的关系也做了简单的分析。后续会逐步分析新建后端的七大步骤,并以RISC-V为目标平台,结合RISC-V的LLVM后端代码进行分析。另外,由于《Writing an LLVM Backend 》中有一部分内容已经和代码完全脱钩,所以我通常会列出文档的要求,然后再给出实际代码的情况,这样既可以最大限度的利用文档,也给出了最新的代码的情况。

本文从七大步骤的第一步开始。第一步要做的内容:Create a subclass of the TargetMachine class that describes characteristics of your target machine.

文档内容:

根据《Writing an LLVM Backend 》的内容,可知在第一步需要在lib/Target/目录之下新建RISCV目录,然后在该目录下新建XXXXTargetMachine.h和XXXXTargetMachine.cpp。同时,还对新建的XXXXTargetMachine.h文件要求具有以下的方法:

  • getInstrInfo();
  • getRegisterInfo();
  • getFrameInfo();
  • getDataLayout();
  • getSubtargetImpl();

对于某些平台,还需要有:

  • getTargetLowering();
  • getJITInfo();

另外,文档要求XXXXTargetMachine的构造函数应该具体规定一个TargetDescription字符串用来描述目标机器的DataLayout。

实际代码的情况则和这个有很大的不同。以RISC-V目标平台为例,确实是在lib/Target/目录之下新建了RISCV目录,并且该目录之下有RISCVTargetMachine.h和RISCVTargetMachine.cpp文档。但是,RISCVTargetMachine.h中所包含的内容,则和文档《Writing an LLVM Backend 》要求的有很大的区别。

实际代码内容:

RISCVTargetMachine.h

RISCVTargetMachine.h中声明了RISCVTargetMachine类:

class RISCVTargetMachine : public LLVMTargetMachine {

该类是LLVMTargetMachine的子类,它包含了以下几个成员函数(除构造函数和解析函数之外):

const RISCVSubtarget *getSubtargetImpl(const Function &) const override {

TargetPassConfig *createPassConfig(PassManagerBase &PM) override;

TargetLoweringObjectFile *getObjFileLowering() const override {

RISCVTargetMachine.cpp

RISCVTargetMachine.cpp中则实现了computeDataLayout函数,用于计算DataLayout(也指明DataLayout的字符串只有两种情况):

static StringRef computeDataLayout(const Triple &TT) {
  if (TT.isArch64Bit()) {
    return "e-m:e-p:64:64-i64:64-i128:128-n64-S128";
  } else {
    assert(TT.isArch32Bit() && "only RV32 and RV64 are currently supported");
    return "e-m:e-p:32:32-i64:64-n32-S128";
  }
}

同时,RISCVTargetMachine.cpp中还实现了类RISCVPassConfig:

class RISCVPassConfig : public TargetPassConfig {

RISCVPassConfig类是TargetPassConfig类的子类,TargetPassConfig类的声明位于include/llvm/CodeGen/TargetPassConfig.h 之中。

通过实现RISCVTargetMachine::createPassConfig成员函数(该函数在RISCVTargetMachine.h中有声明):

TargetPassConfig *RISCVTargetMachine::createPassConfig(PassManagerBase &PM) {
  return new RISCVPassConfig(*this, PM);
}

将RISCVPassConfig和RISCVTargetMachine联系了起来。

这时候比较文档内容和源码内容,必要的接口只有getSubtargetImpl()在RISCVTargetMachine.h中有了声明。考虑到RISCVTargetMachine是LLVMTargetMachine的子类,LLVMTargetMachine又是TargetMachine,我们查看LLVMTargetMachine和TargetMachine的源码,这两个类都位于include/llvm/Target/TargetMachine.h

TargetMachine.h

TargetMachine.h中有TargetMachine类和其子类LLVMTargetMachine。TargetMachine类中有createDataLayout():

const DataLayout createDataLayout() const { return DL; }

createDataLayout()和文档中提到的getDataLayout()其实是同样作用,只是名字差异而已。

文档内容和代码的差异:

所以,新建后端的七大步骤的第一步,文档和实际代码的差距已经很明显了。文档中要求有的,而指定位置源码中没有的接口有:

  • getInstrInfo();
  • getRegisterInfo();
  • getFrameInfo();

注:

1、因为文档与代码的差异较大,预计在后续的步骤中还会出现类似的情况。所以计划按照文档的七大步骤走完之后,根据各个步骤和代码的差别,总体写一个符合代码的七个步骤。

2、本系列文档参照的文档《Writing an LLVM Backend 》是LLVM8.0.0系列文档。代码为主干代码。目前可见的8.0.0的文档与主干文档一直,主干文档并未更新。


相关内容:

小乖他爹:LLVM每日谈之三十七 LLVM后端简介(杭州分享PPT)

小乖他爹:LLVM每日谈之四十七 LLVM后端文档解析

小乖他爹:LLVM每日谈之四十八 LLVM后端文档解析1

小乖他爹:LLVM每日谈之四十九 LLVM后端文档解析2

小乖他爹:LLVM每日谈之五十 LLVM 后端文档解析3 —目标描述类

小乖他爹:LLVM每日谈之五十一 TargetMachine

编辑于 2019-06-03

文章被以下专栏收录