MLIR笔记(1)

1. 简介

MLIR是Multi-layer IR的缩写,它是基于LLVM IR发展的一个中间语言形式,是Clang/LLVM的发明者Chris Lattner在加盟谷歌后又一个重要的发明。MLIR是较之LLVM IR更为灵活的深度学习编译器架构。

其他编译器,像LLVM(参考Kaleidoscope tutorial),提供一组固定的预定义的类型以及(通常低级/类RISC)指令。在发布LLVM IR之前,由特定语言的前端来执行所有语言特定的类型检查、分析或转换。例如,Clang的AST不仅用来执行静态分析,还用于转换,比如使用AST克隆与重写的C++模板具现。最后,具有比C/C++更高级结构的语言可能要求从它们的AST经过重要的(non-trivial)降级来产生LLVM IR。

因此,多个前端最终重新实现基础架构重要的部分,以支持这些分析与转换。而MLIR通过可扩展性的设计来应对这些情况。因此,只有少数几个预定义指令(MLIR术语里的操作,operation)以及类型。

  1. 命令行选项的解析
    1. 原理

LLVM本身有一整套相当复杂的命令行选项解析机制,通过llvm::cl::AddLiteralOption(),可以向LLVM的命令行解析器注册新的命令行选项,让它为我们提供一整套选项处理功能。这正是MLIR命令行选项着手的地方!注意,它是与LLVM本身的命令行选项解析分开的,LLVM虽然也是调用这个方法,但LLVM组织的方式是不一样的

为了解析与MLIR相关的ODS定义,首先MLIR提供了一个GenRegistration定义,这个结构体提供的唯一方法就是构造函数:

31  mlir::GenRegistration::GenRegistration(StringRef arg, StringRef description,

32                                         GenFunction function) {

33    generatorRegistry->emplace_back(arg, description, function);

34  }

这里generatorRegistry是一个静态变量(由ManagedStatic类提供封装):

29  static llvm::ManagedStatic<std::vector<GenInfo>> generatorRegistry;

其中,GenInfo用于封装各种代码生成器,它只有3个域:arg(选项名,字符串类型),description(选项描述,字符串类型),generator(代码生成器,一个可执行的对象)。

因此在OpDefinitionsGen.cpp里,我们可以看到这样的GenRegistration对象声明:

2255  static mlir::GenRegistration

2256      genOpDecls("gen-op-decls", "Generate op declarations",

2257                 [](const RecordKeeper &records, raw_ostream &os) {

2258                   return emitOpDecls(records, os);

2259                 });

2260 

2261  static mlir::GenRegistration genOpDefs("gen-op-defs", "Generate op definitions",

2262                                         [](const RecordKeeper &records,

2263                                            raw_ostream &os) {

2264                                           return emitOpDefs(records, os);

2265                                         });

这样,程序在初始化时会向generatorRegistry添加这些GenInfo对象。那么generatorRegistry怎么样被调动起来的呢?我们看一下mlri-tblgen.cpp,这是TableGen语言代码生成器的源代码所在:

75  int main(int argc, char **argv) {

76    llvm::InitLLVM y(argc, argv);

77    llvm::cl::opt<const mlir::GenInfo *, false, mlir::GenNameParser> generator(

78        "", llvm::cl::desc("Generator to run"));

79    cl::ParseCommandLineOptions(argc, argv);

80    ::generator = generator.getValue();

81 

82    return TableGenMain(argv[0], &MlirTableGenMain);

83  }

LLVM有一套极其复杂的命令行选项处理机制,这里我们只能简要说一下。

首先,76行的llvm::InitLLVM类型的局部变量y是初始化LLVM的必要模块,与命令行解析的关系不大。77行的generator就是命令行选项解析机制的一部分,它的类型是cl::opt,我们看一下这个类型定义开头的几行(CommandLine.h):

1404  template <class DataType, bool ExternalStorage = false,

1405            class ParserClass = parser<DataType>>

1406  class opt : public Option,

1407              public opt_storage<DataType, ExternalStorage,

1408                                 std::is_class<DataType>::value> {

1409    ParserClass Parser;

 它的构造函数是这样定义的:

1482    template <class... Mods>

1483    explicit opt(const Mods &... Ms)

1484        : Option(Optional, NotHidden), Parser(*this) {

1485      apply(this, Ms...);

1486      done();

1487    }

基类Option描述了选项属性,而opt_storage则保存了命令行上出现选项的具体信息(它是一个模板类,这里的特化以所服务的信息类型为基类,在这个上下文里就是GenInfo的派生类),这里因为在声明opt_storage基类时把ExternalStorage指定为false,因此generator的opt_storage部分将用于保存命令行上出现的选项所对应的GenInfo实例。

同时,构造函数里指定opt使用的Parser是mlir::Gen

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值