最稳妥路径是用TableGen+.td文件定义Dialect:需继承Dialect基类,填全name(须与IR前缀一致)、cppNamespace(如"::toy")、summary、description四字段,并include "mlir/IR/OpBase.td";生成需用mlir-tblgen -gen-dialect-decls/-defs,且必须显式调用registerDialect<ToyDialect>()完成注册。

直接用 TableGen + .td 文件定义是最稳妥的路径,手写 C++ Dialect 类容易漏注册、错命名、不兼容后续 MLIR 版本的接口变更。
怎么写一个合法的 Dialect .td 文件
核心是继承 Dialect 基类并填好四个必填字段:命名空间、C++ 命名空间、简介、描述。注意 let name 必须和你在 MLIR IR 中写 Op 时用的前缀完全一致(比如 toy.print 对应 let name = "toy")。
常见错误现象:
-
mlir-tblgen报错说unknown type 'Dialect':没加include "mlir/IR/OpBase.td" - 生成的 C++ 编译失败,提示
getDialectNamespace未定义:漏了let cppNamespace,或值写成"toy"却没加双冒号前缀(应为"::toy") - 运行期报
dialect 'xxx' is not registered:生成的 C++ 没在initialize()里调用registerDialect<XXXDialect>()
最小可用模板:
include "mlir/IR/OpBase.td"
def Toy_Dialect : Dialect {
let name = "toy";
let summary = "Toy dialect for tutorial";
let description = [{ Toy language dialect }];
let cppNamespace = "::toy";
}
如何用 mlir-tblgen 生成 C++ 声明和定义
mlir-tblgen 是唯一受支持的生成器,不能用系统自带的 llvm-tblgen —— 后者缺少 MLIR 特定的后端。
两个命令必须都执行:
-
mlir-tblgen -gen-dialect-decls Ops.td -I $MLIR_INCLUDE_DIR > ToyDialect.h:生成头文件,含class ToyDialect声明和getDialectNamespace() -
mlir-tblgen -gen-dialect-defs Ops.td -I $MLIR_INCLUDE_DIR > ToyDialect.cpp:生成实现,含initialize()和注册逻辑
关键点:
-
-I路径必须指向mlir/include,不是llvm/include - 生成的
ToyDialect.cpp里默认不含registerDialect<ToyDialect>()调用——你得手动在initialize()函数末尾加上这行 - 生成的头文件会依赖
mlir/IR/Dialect.h,确保你的 CMakeLists.txt 正确 linkMLIRIR
为什么 registerDialect 必须显式调用
MLIR 不靠静态构造函数自动注册 Dialect,而是要求你在某个初始化入口(通常是 registerAllDialects() 或自定义初始化函数)中显式调用 registerDialect<XXXDialect>()。
否则即使编译通过,MLIRContext 也完全不知道这个 Dialect 存在,任何尝试解析 toy.print 的操作都会失败。
典型集成方式:
void registerToyDialect(mlir::DialectRegistry ®istry) {
registry.insert<toy::ToyDialect>();
}
然后在创建 MLIRContext 前传入:
mlir::DialectRegistry registry; registerToyDialect(registry); auto context = std::make_unique<mlir::MLIRContext>(registry);
手写 C++ Dialect 类的风险点
虽然可行,但极易出错:
-
getDialectNamespace()返回值类型必须是llvm::StringRef,返回局部字符串字面量(如return "toy")会导致悬垂引用 -
initialize()里若忘记调用addOperations<...>()注册 Op,后续所有 Op 解析都会失败,错误信息极不直观(常表现为unknown op) - MLIR 15+ 版本开始要求 Dialect 类必须提供
materializeConstant方法(哪怕空实现),否则canonicalizepass 会崩溃 - 没有 ODS 支持,Op 的 verify、parse、print 全得手写,且必须严格匹配
OperationState内存布局,稍有偏差就触发断言或越界读
除非你正在调试 TableGen 本身,否则不要碰纯手写路径。

















