mlir(google/heir)dialect
方言:
https://mlir.llvm.org/docs/DefiningDialects/
LangRef Refresher
Before diving into how to define these constructs, below is a quick refresher from the MLIR LangRef.
Dialects are the mechanism by which to engage with and extend the MLIR ecosystem. They allow for defining new attributes, operations, and types. Dialects are used to model a variety of different abstractions; from traditional arithmetic to pattern rewrites; and is one of the most fundamental aspects of MLIR.
理解:定义了dialect之后,就可以为方言增加attributes、operations和types。
Defining a Dialect
// Include the definition of the necessary tablegen constructs for defining // our dialect. include "mlir/IR/DialectBase.td" // Here is a simple definition of a dialect. def MyDialect : Dialect { let summary = "A short one line description of my dialect."; let description = [{ My dialect is a very important dialect. This section contains a much more detailed description that documents all of the important pieces of information to know about the document. }]; /// This is the namespace of the dialect. It is used to encapsulate the sub-components /// of the dialect, such as operations ("my_dialect.foo"). let name = "my_dialect"; /// The C++ namespace that the dialect, and its sub-components, get placed in. let cppNamespace = "::my_dialect"; }
Initialization
Every dialect must implement an initialization hook to add attributes, operations, types, attach any desired interfaces, or perform any other necessary initialization for the dialect that should happen on construction. This hook is declared for every dialect to define, and has the form:
void MyDialect::initialize() { // Dialect initialization logic should be defined in here. }
理解:每一个方言(dialect)都必须实现hook函数initialization,在函数initialization中注册方言的子组件,比如attributes、operations、types及其他任何在构造时需要做的初始化动作。
例子:
#include "mlir/IR/DialectBase.td" def LWE_Dialect : Dialect { let name = "lwe"; let description = [{ The `lwe` dialect is a dialect for concepts related to cryptosystems in the Learning With Errors (LWE) family. }]; let cppNamespace = "::mlir::heir::lwe"; let useDefaultTypePrinterParser = 1; let useDefaultAttributePrinterParser = 1; };
namespace mlir { namespace heir { namespace lwe { class LWEDialect : public ::mlir::Dialect { explicit LWEDialect(::mlir::MLIRContext *context); void initialize(); friend class ::mlir::MLIRContext; public: ... }; } // namespace lwe } // namespace heir } // namespace mlir
namespace mlir { namespace heir { namespace lwe { LWEDialect::LWEDialect(::mlir::MLIRContext *context) : ::mlir::Dialect(getDialectNamespace(), context, ::mlir::TypeID::get<LWEDialect>()) { initialize(); } LWEDialect::~LWEDialect() = default; } // namespace lwe } // namespace heir } // namespace mlir
#include "lib/Dialect/LWE/IR/LWEDialect.cpp.inc" namespace mlir { namespace heir { namespace lwe { void LWEDialect::initialize() { addAttributes< #define GET_ATTRDEF_LIST #include "lib/Dialect/LWE/IR/LWEAttributes.cpp.inc" >(); addTypes< #define GET_TYPEDEF_LIST #include "lib/Dialect/LWE/IR/LWETypes.cpp.inc" >(); addOperations< #define GET_OP_LIST #include "lib/Dialect/LWE/IR/LWEOps.cpp.inc" >(); } } // namespace lwe } // namespace heir } // namespace mlir
Documentation
The summary and description fields allow for providing user documentation for the dialect. The summary field expects a simple single-line string, with the description field used for long and extensive documentation. This documentation can be used to generate markdown documentation for the dialect and is used by upstream MLIR dialects.
理解:在td中定义新的dialect,需要是Dialect的继承类,在定义中使用的字段summary的值应该是一行子串,字段description的值应该是多行子串。这两个子串是对新定义的dialect的介绍信息,利用tblgen工具把td源码转成技术参考手册(md文件)时候用到的主要就是这两个字段值。
Class Name
The name of the C++ class which gets generated is the same as the name of our TableGen dialect definition, but with any _ characters stripped out. This means that if you name your dialect Foo_Dialect, the generated C++ class would be FooDialect. In the example above, we would get a C++ dialect named MyDialect.
理解:td源码中通过关键字def定义了dialect名字,将dialect名字中的字符“_”全部去除,就是该方言在C++源码中的类名。比如在“lib\Dialect\LWE\IR\LWEDialect.td”中通过def定义的方言LWE_Dialect在C++源码中对应的类名是LWEDialect。
C++ Namespace
The namespace that the C++ class for our dialect, and all of its sub-components, is placed under is specified by the cppNamespace field. By default, uses the name of the dialect as the only namespace. To avoid placing in any namespace, use "". To specify nested namespaces, use "::" as the delimiter between namespace, e.g., given "A::B", C++ classes will be placed within: namespace A { namespace B { <classes> } }.
理解:在定义dialect的td源码中,字段cppNamespace指定方言及其所有子组件(attribute、type和operation等)的名字空间。如果let cppNamespace=”” ,那么tblgen生成的C++源码文件不会为该dialect设置任何名字空间。
举例:在lib\Dialect\LWE\IR\LWEDialect.td中,为LWE_Dialect设置了let cppNamespace = "::mlir::heir::lwe"。所以自动生成的C++源码文件LWEDialect.h.inc和LWEDialect.cpp.inc中,将所有LWE_Dialect的实现代码的名字空间是“namespace mlir {namespace heir {namespace lwe { ... } } }”
Default Attribute/Type Parsers and Printers
When a dialect registers an Attribute or Type, it must also override the respective Dialect::parseAttribute/Dialect::printAttribute or Dialect::parseType/Dialect::printType methods. In these cases, the dialect must explicitly handle the parsing and printing of each individual attribute or type within the dialect. If all of the attributes and types of the dialect provide a mnemonic, however, these methods may be autogenerated by using the useDefaultAttributePrinterParser and useDefaultTypePrinterParser fields. By default, these fields are set to 1(enabled), meaning that if a dialect needs to explicitly handle the parser and printer of its Attributes and Types it should set these to 0 as necessary.
理解:如果注册进方言中的所有attribute和type都提供了助记符(字段mnemonic),那么在定义dialect的td源码中设置let useDefaultAttributePrinterParser=1可以为注册到此dialect的每一个attribute自动生成解析函数比如LWEDialect::parseAttribute和打印函数LWEDialect::printAttribute,设置let useDefaultTypePrinterParser=1也可以为注册到此dialect的每一个type自动生成解析函数比如LWEDialect::parseType和打印函数LWEDialect::printType。另外,这两个字段的默认值也是1,所以如果希望自定义attribute或者type的解析函数和打印函数,需要显式地将这两个字段值置0.
https://mlir.llvm.org/docs/DefiningDialects/AttributesAndTypes/
Registering with the Dialect ¶
Once the attributes and types have been defined, they must then be registered with the parent Dialect. This is done via the addAttributes and addTypes methods. Note that when registering, the full definition of the storage classes must be visible.
理解:新定义了attribute和type之后,还必须把它们注册到相应的方言中。这是在方言的钩子函数initialize中通过调用函数addAttribute和函数addTypes来实现的。
例子:
void MyDialect::initialize() { /// Add the defined attributes to the dialect. addAttributes< #define GET_ATTRDEF_LIST #include "MyDialect/Attributes.cpp.inc" >(); /// Add the defined types to the dialect. addTypes< #define GET_TYPEDEF_LIST #include "MyDialect/Types.cpp.inc" >(); }
posted on 2025-04-21 14:06 LiveWithACat 阅读(45) 评论(0) 收藏 举报
浙公网安备 33010602011771号