应手动递归遍历:从 module.body.operations 开始,对每个 op 检查 regions,有则递归进入 region.blocks[i].operations;需单独处理 block.arguments 和 terminator op,因 Python 绑定未暴露 op.walk()。

怎么用 Python 遍历 MLIR 函数里的所有 Operation
MLIR 的 Python 绑定(mlir.ir)不提供类似 TVM 的 post_order_visit 那样开箱即用的递归遍历函数,必须手动按 Region → Block → Operation 逐层展开。最直接的方式是拿到函数体(通常是第一个 Region),再遍历其唯一 Block 中的所有 Operation。
常见错误是只调用 func.body.operations 就以为完事——但这是错的:func 对象本身没有 body 属性;正确路径是 func.regions[0].blocks[0].operations(假设是单 region、单 block 的标准函数)。
- 确保你解析的是含函数定义的模块,比如用
ir.Module.parse(...) - 用
func = module.body.operations[0]拿到第一个 op(通常是func.func),再确认它的name是"func.func" - 访问
func.regions[0].blocks[0].operations才能得到函数体内的所有操作 - 如果函数有控制流(如
scf.if),那些嵌套在子 region 里的 op 不会出现在顶层 block 中,需递归遍历每个region
怎么递归遍历所有嵌套 Operation(含 if/for 等)
仅遍历顶层 block 会漏掉 scf.for、scf.if、cf.cond_br 等带 region 的操作内部的指令。必须对每个 Operation 检查它是否有 regions,有就递归进每个 region 的每个 block 再取 operations。
注意:不是所有 op 都有 regions,比如 arith.addi 就没有;但 scf.for、func.func、cf.cond_br 都有。调用前务必用 hasattr(op, 'regions') 或 len(op.regions) > 0 判断,否则会抛 AttributeError。
- 递归函数入口建议从
module.body.operations开始,而非某个特定 func —— 模块可能含多个函数或全局 op - 每个
region是ir.Region对象,需遍历其blocks;每个block是ir.Block,再遍历其operations - 避免无限递归:MLIR Python API 中 region 和 block 不构成循环引用,但你自己写的递归函数要确保 base case(比如空 region 或无子 region 的 op)
为什么不能直接用 C++ 的 op.walk()?
MLIR C++ API 提供了 op.walk([](Operation *nestedOp) { ... }) 这种简洁遍历方式,但当前(2026 年)Python 绑定 尚未暴露 这个方法。调用 op.walk 会报 AttributeError: 'Operation' object has no attribute 'walk'。
这不是你环境没装对,而是官方 Python binding 明确未封装该接口。所以别搜 “mlir python walk”,那只会带你绕远路。老实用三层嵌套 for 循环 + 显式 region 检查,反而稳定可靠。
- 替代方案只有自己写递归函数,或用
mlir.execution_engine加载后通过 C++ 扩展桥接(不推荐,增加部署复杂度) - 如果你真需要 walk 行为,可临时用 C++ 写个 minimal wrapper 导出一个
walk_operations函数,再用 pybind11 编译成 .so 调用 - 目前 GitHub 上已有几个社区 PR 在推动 Python
walk支持,但尚未合入主线(截至 2026-09)
遍历时容易忽略的“隐形”操作
有些 op 看似没内容,实则携带关键信息,比如 func.return、arith.constant、memref.alloc,它们不会自动展开子结构,但属于函数逻辑一部分。更隐蔽的是 block argument —— 它们不是 op,但出现在 block.arguments 里,代表函数参数或 loop index,在做数据流分析时必须纳入。
-
block.arguments是ir.Value列表,类型为ir.BlockArgument,需单独处理(比如打印arg.type和arg.owner) -
func.func自身的参数在func.attributes["function_type"].value.results和.inputs里,和 block arguments 是两套东西 - region 的 terminator(如
func.return、scf.yield)是 op,但常被当成“结束符”跳过,其实它参与值传递,漏掉会导致数据流断链

















