MLIR通过.td定义新Dialect与新Op

您所在的位置:网站首页 mlir是什么意思 MLIR通过.td定义新Dialect与新Op

MLIR通过.td定义新Dialect与新Op

2023-10-03 16:11| 来源: 网络整理| 查看: 265

MLIR通过.td定义新Dialect与新OpMLIR:新建一个Dialect,通过.td定义新DialectMLIR 项目的核心是 Dialect,MLIR 自身就拥有例如linalg,tosa,affine 这些 Dialect。各种不同的 Dialect 使不同类型的优化或转换得以完成。新建一个 Dialect的内容。通过.td定义新 Dialect “Hello”。1复习工具链、总览等等知识请自行翻看历史 MLIR 标签的相关文章前文介绍了mlir-hello[1] 项目的目标就是使用自建的 Dialect 通过 MLIR 生态实现一个 hello world,具体做法为:1. 创建 hello-opt 将原始 print.mlir (可以理解成 hello world 的 main.cpp)转换为 print.ll 文件2. 使用 LLVM 的 lli 解释器直接运行 print.ll 文件2HelloDialect.tdhello.print 作为一个 Op,显而易见,hello Dialect、print Op 都需要被定义。本文来看看如何定义一个新的 Dialect 以及一个 Op。通过声明式的 .td 文件以及 TableGen 工具可以便捷的生成相应的 C++ 代码。代码来自 [mlir-hello]/include/Hello/HelloDialect.td,#ifndef HELLO_DIALECT#define HELLO_DIALECT

// 引入大基类 Dialectinclude "mlir/IR/OpBase.td"

// 定义新 Hello_Dialectdef Hello_Dialect : Dialect { // 定义名字空间 namespace,对应 C++ 的 getDialectNamespace 方法返回值 let name = "hello"; // 一行关于这个 Dialect 的介绍 let summary = "A hello out-of-tree MLIR dialect."; // 更详细的关于这个 Dialect 的介绍 let description = [{ This dialect is minimal example to implement hello-world kind of sample code for MLIR. }]; // 产生一个返回名字空间名称的接口 let cppNamespace = "::hello"; // 该设置用于激活 materializeConstant 方法,这使得可以例如 Canonicalize 优化 let hasConstantMaterializer = 1;}

// 定义一个 Op 作为后续其他具体 Op 的“基类”class Hello_Op : Op;

#endif // HELLO_DIALECT3TableGen来看看这个 .td 能生成什么样子的代码?$MLIR_TBLGEN -gen-dialect-decls HelloDialect.td -I$LOCAL_MLIR/include >> HelloDialect.h/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\|* *||* Dialect Declarations *||* *||* Automatically generated file, do not edit! *||* *|\*===----------------------------------------------------------------------===*/// 名字空间namespace hello {

class HelloDialect : public ::mlir::Dialect { explicit HelloDialect(::mlir::MLIRContext *context); // 用以注册 attributes, operations, types 等等 void initialize(); friend class ::mlir::MLIRContext;public: ~HelloDialect() override; // 定义的名字空间 name static constexpr ::llvm::StringLiteral getDialectNamespace() { return ::llvm::StringLiteral("hello"); }

/// Materialize a single constant operation from a given attribute value with /// the desired resultant type. // 设置的 hasConstantMaterializer 位 ::mlir::Operation *materializeConstant(::mlir::OpBuilder &builder, ::mlir::Attribute value, ::mlir::Type type, ::mlir::Location loc) override;};} // namespace helloMLIR_DECLARE_EXPLICIT_TYPE_ID(::hello::HelloDialect)

对 mlir-hello 项目的源代码文件 HelloDialect.td 进行了学习,通过自定义的 .td 文件声明式的语法可以便捷的定义一个新的 Dialect。MLIR:新建一个Dialect,通过.td定义新OpMulti-Level Intermediate Representation(MLIR)是创建可重用、可扩展编译器基础设施的新途径。介绍一个简单的 MLIR Dialect。MLIR 项目的核心是 Dialect,MLIR 自身就拥有例如linalg,tosa,affine 这些 Dialect。各种不同的 Dialect 使不同类型的优化或转换得以完成。新建一个 Dialect的内容。通过.td定义新 “Hello_Op”。1复习工具链、总览等等知识请自行翻看历史 MLIR 标签的相关文章介绍了mlir-hello项目的目标就是使用自建的 Dialect 通过 MLIR 生态实现一个 hello world,具体做法为:1. 创建 hello-opt 将原始 print.mlir (可以理解成 hello world 的 main.cpp)转换为 print.ll 文件2. 使用 LLVM 的 lli 解释器直接运行 print.ll 文件2HelloOps.tdhello.print 作为一个 Op,显而易见,hello Dialect、print Op 都需要被定义。本文来看看如何定义一个保存变量的ConstantOp和执行打印操作的PrintOp,也就是实际 MLIR 使用中的 hello.constant 和 hello.print。通过声明式的 .td 文件以及 TableGen[2] 工具可以便捷的生成相应的 C++ 代码。更详细的语法可以在 Operation Definition Specification (ODS)[3]找到。代码来自 [mlir-hello]/include/Hello/HelloOps.td,#ifndef HELLO_OPS#define HELLO_OPS

include "HelloDialect.td"// 包含 NoSideEffect 的 trait,不主动做某些消除优化include "mlir/Interfaces/SideEffectInterfaces.td"

// 第一个 Op,用以转换输入为内部使用的 SSA 值// 类似 Dialect 中定义的 class HelloOp (对象)// 实际名字为 constant(CRTP)def ConstantOp : Hello_Op { // 一行关于这个 Op 的介绍 let summary = "constant"; // 更详细的关于这个 Op 的介绍 let description = [{ Constant operation turns a literal into an SSA value. The data is attached to the operation as an attribute. For example:

```mlir %0 = "hello.constant"() { value = dense : tensor } : () -> tensor ``` }];

// 每个 Op 都会有的 builder 方法们 https://mlir.llvm.org/docs/OpDefinitions/#builder-methods let builders = [ // 重载的 build 函数,定义参数。例如下面会生成类似 // `static void build(::mlir::OpBuilder &builder, ::mlir::OperationState &state, mlir::DenseElementsAttr value);` // 样的代码。前面的 ins 指示 dag-type OpBuilder, OpBuilder ];

// let parser = [{ return ::parseConstantOp(parser, result); }]; // 定义输入,类似上面的 builder。可以是 operands 或 attributes,这里是后者。前者意思是由其他 operation 产生的值 let arguments = (ins F64ElementsAttr:$value); // 定义输出 let results = (outs F64Tensor);}

// 第二个 Op,用以表明打印操作def PrintOp : Hello_Op { let summary = "print operation"; let description = [{ The "print" builtin operation prints a given input tensor, and produces no results. }];

// The print operation takes an input tensor to print. let arguments = (ins AnyTypeOf:$input); // 手动写明这个 Op 的输出 let assemblyFormat = "$input attr-dict `:` type($input)";}

#endif // HELLO_OPS3TableGen来看看这个 .td 能生成什么样子的代码?$MLIR_TBLGEN -gen-op-decls include/Hello/HelloOps.td -I$LOCAL_MLIR/include -Iinclude/Hello >> HelloOps.decls.h/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\|* *||* Op Declarations *||* *||* Automatically generated file, do not edit! *||* *|\*===----------------------------------------------------------------------===*/

#if defined(GET_OP_CLASSES) || defined(GET_OP_FWD_DEFINES)#undef GET_OP_FWD_DEFINESnamespace hello {class ConstantOp;} // namespace hellonamespace hello {class PrintOp;} // namespace hello#endif

#ifdef GET_OP_CLASSES#undef GET_OP_CLASSES

//===----------------------------------------------------------------------===//// Local Utility Method Definitions//===----------------------------------------------------------------------===//

namespace hello {

//===----------------------------------------------------------------------===//// ::hello::ConstantOp declarations//===----------------------------------------------------------------------===//

class ConstantOpAdaptor {public: ConstantOpAdaptor(::mlir::ValueRange values, ::mlir::DictionaryAttr attrs = nullptr, ::mlir::RegionRange regions = {});

ConstantOpAdaptor(ConstantOp op);

::mlir::ValueRange getOperands(); std::pair getODSOperandIndexAndLength(unsigned index); ::mlir::ValueRange getODSOperands(unsigned index); ::mlir::DictionaryAttr getAttributes(); ::mlir::DenseElementsAttr getValueAttr(); ::mlir::DenseElementsAttr getValue(); ::mlir::LogicalResult verify(::mlir::Location loc);private: ::mlir::ValueRange odsOperands; ::mlir::DictionaryAttr odsAttrs; ::mlir::RegionRange odsRegions; ::llvm::Optional odsOpName;};class ConstantOp : public ::mlir::Op {public: using Op::Op; using Op::print; using Adaptor = ConstantOpAdaptor;public: static ::llvm::ArrayRef getAttributeNames() { static ::llvm::StringRef attrNames[] = {::llvm::StringRef("value")}; return ::llvm::makeArrayRef(attrNames); }

::mlir::StringAttr getValueAttrName() { return getAttributeNameForIndex(0); }

static ::mlir::StringAttr getValueAttrName(::mlir::OperationName name) { return getAttributeNameForIndex(name, 0); }

static constexpr ::llvm::StringLiteral getOperationName() { return ::llvm::StringLiteral("hello.constant"); }

std::pair getODSOperandIndexAndLength(unsigned index); ::mlir::Operation::operand_range getODSOperands(unsigned index); std::pair getODSResultIndexAndLength(unsigned index); ::mlir::Operation::result_range getODSResults(unsigned index); ::mlir::DenseElementsAttr getValueAttr(); ::mlir::DenseElementsAttr getValue(); void setValueAttr(::mlir::DenseElementsAttr attr); static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, mlir::DenseElementsAttr value); static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, double value); static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::Type resultType0, ::mlir::DenseElementsAttr value); static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::TypeRange resultTypes, ::mlir::DenseElementsAttr value); static void build(::mlir::OpBuilder &, ::mlir::OperationState &odsState, ::mlir::TypeRange resultTypes, ::mlir::ValueRange operands, ::llvm::ArrayRef attributes = {}); ::mlir::LogicalResult verifyInvariantsImpl(); ::mlir::LogicalResult verifyInvariants(); void getEffects(::llvm::SmallVectorImpl &effects);private: ::mlir::StringAttr getAttributeNameForIndex(unsigned index) { return getAttributeNameForIndex((*this)->getName(), index); }

static ::mlir::StringAttr getAttributeNameForIndex(::mlir::OperationName name, unsigned index) { assert(index < 1 && "invalid attribute index"); assert(name.getStringRef() == getOperationName() && "invalid operation name"); return name.getRegisteredInfo()->getAttributeNames()[index]; }

public:};} // namespace helloMLIR_DECLARE_EXPLICIT_TYPE_ID(::hello::ConstantOp)

namespace hello {

//===----------------------------------------------------------------------===//// ::hello::PrintOp declarations//===----------------------------------------------------------------------===//

class PrintOpAdaptor {public: PrintOpAdaptor(::mlir::ValueRange values, ::mlir::DictionaryAttr attrs = nullptr, ::mlir::RegionRange regions = {});

PrintOpAdaptor(PrintOp op);

::mlir::ValueRange getOperands(); std::pair getODSOperandIndexAndLength(unsigned index); ::mlir::ValueRange getODSOperands(unsigned index); ::mlir::Value getInput(); ::mlir::DictionaryAttr getAttributes(); ::mlir::LogicalResult verify(::mlir::Location loc);private: ::mlir::ValueRange odsOperands; ::mlir::DictionaryAttr odsAttrs; ::mlir::RegionRange odsRegions; ::llvm::Optional odsOpName;};class PrintOp : public ::mlir::Op {public: using Op::Op; using Op::print; using Adaptor = PrintOpAdaptor;public: static ::llvm::ArrayRef getAttributeNames() { return {}; }

static constexpr ::llvm::StringLiteral getOperationName() { return ::llvm::StringLiteral("hello.print"); }

std::pair getODSOperandIndexAndLength(unsigned index); ::mlir::Operation::operand_range getODSOperands(unsigned index); ::mlir::Value getInput(); ::mlir::MutableOperandRange getInputMutable(); std::pair getODSResultIndexAndLength(unsigned index); ::mlir::Operation::result_range getODSResults(unsigned index); static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::Value input); static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::TypeRange resultTypes, ::mlir::Value input); static void build(::mlir::OpBuilder &, ::mlir::OperationState &odsState, ::mlir::TypeRange resultTypes, ::mlir::ValueRange operands, ::llvm::ArrayRef attributes = {}); ::mlir::LogicalResult verifyInvariantsImpl(); ::mlir::LogicalResult verifyInvariants(); static ::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result); void print(::mlir::OpAsmPrinter &_odsPrinter); void getEffects(::llvm::SmallVectorImpl &effects);public:};} // namespace helloMLIR_DECLARE_EXPLICIT_TYPE_ID(::hello::PrintOp)#endif // GET_OP_CLASSESTLDR这些只是 Op 的声明,还有定义,太多了就不放这里了。可以通过下面指令生成,$MLIR_TBLGEN -gen-op-defs include/Hello/HelloOps.td -I$LOCAL_MLIR/include -Iinclude/Hello >> HelloOps.defs.h手写这些代码还是写个 .td 自动生成。对 mlir-hello 项目的源代码文件 HelloOps.td,通过自定义的 .td 文件声明式的语法可以在新的 Dialect 中便捷的定义新的 Op。

参考文献链接https://mp.weixin.qq.com/s/IpU6KP6igEgP4mCYUnYTyQhttps://mp.weixin.qq.com/s/8B9A5Pu9mb2ooOOzt3quaQmlir-hello: https://github.com/Lewuathe/mlir-helloTableGen: https://llvm.org/docs/TableGen/ProgRef.htmlmlir-hello: https://github.com/Lewuathe/mlir-helloTableGen: https://llvm.org/docs/TableGen/ProgRef.htmlOperation Definition Specification (ODS): https://mlir.llvm.org/docs/OpDefinitions



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3