mlir-opt不支持动态加载自定义Pass,必须重新编译并静态注册方言和Pass;正确做法是构建树外工具tutorial-opt,在Main.cpp中调用registerMyDialects()和registerMyPasses(),并确保CMake正确链接依赖库。

不能直接用 mlir-opt 加载自定义 Pass,除非你重新编译它并注册你的方言和 Pass。 它不是 opt 那种支持 -load 动态库的工具。默认构建的 mlir-opt 只认 LLVM 项目里已注册的方言(如 std、affine、arith)和内置 Pass(如 --canonicalize),你写的任何新 Pass 都不会出现在它的命令行选项里,也不会被 --pass-pipeline 解析到。
为什么 mlir-opt 不支持 -load 或动态加载
因为 mlir-opt 的设计目标是“轻量 CLI 前端 + 静态注册”,所有方言和 Pass 必须在编译期通过 registerDialects() 和 registerPasses() 注入。它没有运行时符号解析机制,也不链接 dlopen 相关逻辑。这和 LLVM 的 opt 工具完全不同——后者明确支持 -load 加载 .so 并调用 initialize* 系列函数。
-
mlir-opt启动时只扫描已注册的PassRegistry条目,没注册 = 不可见 - 即使你把 Pass 编译进共享库,
mlir-opt --help里也绝不会出现你的 Pass 名字 - 尝试
mlir-opt --my-custom-pass会报错:unknown argument '--my-custom-pass'
正确做法:构建自己的 tutorial-opt
官方推荐路径是创建一个树外(out-of-tree)二进制,名字可以叫 tutorial-opt,它是 mlir-opt 的“克隆体”,但允许你插入自己的方言和 Pass。核心就三步:
- 新建一个
tools/tutorial-opt/目录,放Main.cpp(复制mlir/tools/mlir-opt/MlirOptMain.cpp内容) - 在
CMakeLists.txt中链接你的方言库(如add_mlir_library(MyDialect))和 Pass 库(如add_mlir_library(MyPass)) - 在
Main.cpp的main()入口里显式调用registerMyDialects()和registerMyPasses()
这样编译出的 tutorial-opt 就能识别你的 Pass,比如:tutorial-opt --my-canonicalize input.mlir。
Pass 注册必须匹配方言依赖
如果你的 Pass 操作的是自定义方言(比如 mydialect.foo_op),那它注册时必须确保该方言已注册,否则 runOnOperation() 里调用 getOperation()->getParentOfType<MyDialect>() 会失败,或者 pattern 匹配永远不触发。
- 注册顺序很重要:先
registerMyDialects(),再registerMyPasses() - Pass 类里不要硬编码方言名字符串,而要用
MyDialect::getDialectNamespace()获取 - 如果 Pass 依赖
affine或scf,也要在CMakeLists.txt中显式添加MLIRAffine、MLIRSCF链接项
调试时最容易忽略的点
Pass 在 tutorial-opt 里不生效?90% 是以下两个原因:
-
getOperation()返回的顶层 Operation 不是你期望的 dialect scope —— 比如你写了OperationPass<func::FuncOp>,但输入 IR 根本没func.func,而是裸的module,那就根本不会进入runOnOperation - CMake 没把 Pass 所在的
add_mlir_library()正确加入tutorial-opt的target_link_libraries,导致符号未定义,但链接器不报错(因为 Pass 是弱注册,只是没进 registry)
验证是否注册成功:运行 tutorial-opt --help | grep my,看到你的 Pass 名字;再加 --dry-run 看是否报 “no operation matched” 还是直接跳过——前者说明注册了但没匹配上,后者说明根本没注册。

















