- 模型编译
- 深度学习
- 推理引擎
【免费下载链接】tvm
Open Machine Learning Compiler Framework
tvm.script.ir_builder是 TVM 中一套"方言无关"(dialect-agnostic)的编程式 IR 构造框架:它以线程局部的帧栈(frame stack)为核心,让开发者用 Pythonwith上下文以命令式风格直接构建 IRModule、Relax 函数与 TIR 块,而无需先书写 TVMScript 文本再解析。本文将以该模块的 API 文档为骨架,深入仓库源码与测试用例,系统讲解IRBuilder/IRBuilderFrame的核心机制、IR 层(ir)、Relax 层(relax)、分布式扩展(relax.distributed)与 TIRx 层(tirx)的完整编程接口,以及它在实际代码生成与测试场景中的典型用法。
本文对应的官方 API 参考文档为 docs/reference/api/python/script/ir_builder.rst,该文档通过 Sphinx
automodule指令聚合了五个公开子模块的成员签名与 docstring,本文在此基础上结合源码(python/tvm/script/ir_builder/、include/tvm/script/ir_builder/)与测试用例逐层展开。
一、理解核心抽象:IRBuilder 与 IRBuilderFrame 的框架栈模型
tvm.script.ir_builder的顶层命名空间导出了两个基础对象:IRBuilder(方言无关的构建器)与IRBuilderFrame(构建器栈帧)。二者在 python/tvm/script/ir_builder/base.py 中定义为tvm.runtime.Object的注册子类,底层对应 C++ 端 include/tvm/script/ir_builder/base.h 中的IRBuilderNode与IRBuilderFrameNode。
1.1 IRBuilder:线程局部的作用域管理器
IRBuilder的惯用方式是"放进with作用域,在其中调用各方言的方法,退出时取出构建结果"。其关键成员如下:
| 方法 | 作用 | 底层 FFI |
|---|---|---|
IRBuilder() | 构造一个构建器实例 | _ffi_api.IRBuilder |
__enter__/__exit__ | 进入/退出with作用域,使构建器可被IRBuilder.current()获取 | IRBuilderEnter/IRBuilderExit |
IRBuilder.current()(静态) | 获取当前线程局部作用域中的构建器 | IRBuilderCurrent |
IRBuilder.is_in_scope()(静态) | 查询当前线程局部作用域是否存在构建器 | IRBuilderIsInScope |
get() | 取出构建完成的 IR 对象 | IRBuilderGet |
with_source_span(span) | 为嵌套作用域内构造的 IR 节点附加前端源码span | IRBuilderPushSourceSpan/IRBuilderPopSourceSpan |
IRBuilder.name(s, v)(静态) | 给对象命名,返回同一对象 | IRBuilderName |
IRBuilder.name_many(s, vs)(静态) | 批量命名,要求名称列表与对象列表等长 | 逐项调用name |
从 include/tvm/script/ir_builder/base.h 的节点定义可以看出,每个IRBuilderNode内部维护了三块状态:
ffi::Array<IRBuilderFrame> frames:上下文帧栈,从栈顶向下查找最近的指定类型帧;ffi::Optional<ffi::ObjectRef> result:IR 构造的最终产出;std::vector<Span> source_spans:活动的前端源码跨度(从外到内)。
C++ 端提供模板方法FindFrame<TFrame>()(自栈顶向下查找指定类型帧,见 base.h)、GetLastFrame<TFrame>()(仅检查栈顶是否为指定类型,见 base.h)以及Get<TObjectRef>()(取出结果并做类型校验,见 base.h)。这些机制正是"上下文相关 IR 构造"的基础:例如同一个match_buffer调用,在PrimFuncFrame下是函数签名中的 buffer 声明,而在SBlockFrame下则生成MatchBufferRegion(参见IRBuilderFrame的 docstring 示例与 base.h 中的 C++ 注释)。
with_source_span的嵌套语义值得注意:当多个不同的源码区间发生嵌套(如 TVMScript 内联展开)时,会被保留为SequentialSpan,用于前端报错定位。
1.2 IRBuilderFrame:携带回调的栈帧
IRBuilderFrame是构建器帧的基类。它同样支持with作用域:
__enter__调用IRBuilderFrameEnter将自身压入当前构建器的帧栈;__exit__在没有异常发生时才调用IRBuilderFrameExit出栈——从 base.py 可以看到,若with作用域因异常退出,出栈逻辑会被跳过,避免污染栈状态;add_callback(callback)注册一个在退出with作用域时被调用的回调,底层对应 base.h 中IRBuilderFrameNode的std::vector<ffi::TypedFunction<void()>> callbacks成员(该字段刻意未注册进反射,因为它不应被遍历访问)。
各方言的帧(如IRModuleFrame、Relax 的FunctionFrame/BindingBlockFrame、TIRx 的PrimFuncFrame/SBlockFrame)都是IRBuilderFrame的子类,python/tvm/script/ir_builder/ir/frame.py 中IRModuleFrame的注册即是例证。
二、包结构与方言懒加载机制
python/tvm/script/ir_builder/init.py 说明了该包的模块组织原则:
- IR 层是基础层,不注册为方言:它的 builder 是真实子模块
tvm.script.ir_builder.ir,始终可以直接导入; - 其余方言 builder 按需懒加载:
tvm.script.ir_builder.relax、tvm.script.ir_builder.relax.distributed、tvm.script.ir_builder.tirx等通过__getattr__在tvm.script._DIALECT_REGISTRY中查找方言名,再动态导入<dialect_module_path>.builder(例如tvm.tirx.script.builder),结果缓存到模块全局变量,后续访问不再走__getattr__。
这意味着你既可以用from tvm.script.ir_builder import relax as relax_builder显式导入,也可以直接import tvm.script.ir_builder后通过属性访问触发懒加载。该机制由 python/tvm/script/init.py 中的_DIALECT_REGISTRY与_DialectRedirectFinder配合实现,负责处理深层语句式导入。
三、IR 层(tvm.script.ir_builder.ir):面向 IRModule 的基础构建器
IR 层暴露为I命名空间(在 TVMScript 中常写作from tvm.script import ir as I)。其全部 API 集中在 python/tvm/script/ir_builder/ir/ir.py,入口均转发至_ffi_api:
3.1 IRModule 帧与模块级操作
| 函数 | 作用 | 参数说明 |
|---|---|---|
ir_module() | 开启一个IRModuleFrame,返回帧对象 | 无参数 |
module_attrs(attrs, allow_overwrite=False) | 设置模块级 attrs | attrs: Dict[str, Object];allow_overwrite控制是否允许覆盖已有 attr |
module_get_attr(attr_key) | 读取指定 attr | 返回Optional[Object],不存在时返回None |
module_set_attr(attr_key, attr_value, allow_overwrite=False) | 设置/覆盖指定 attr | attr_value可为None |
module_global_infos(global_infos) | 设置模块级 global infos | global_infos: Dict[str, List[GlobalInfo]] |
3.2 函数声明与定义
decl_function(func_name, func_signature) -> GlobalVar:声明一个尚未给出实现体、仅指定签名(参数与返回类型/形状)的函数,常用于跨函数调用场景。若func_signature不是BaseFunc实例,会抛出ValueError;def_function(func_name, func):为之前声明过的函数补全实现体。
二者配合可以在一个 IRModule 中先声明后定义,从而支持相互递归或前向引用。
3.3 GlobalInfo 相关工具
| 函数 | 作用 |
|---|---|
dummy_global_info() | 创建DummyGlobalInfo表达式(常用于尚未确定设备信息的占位) |
vdevice(target=None, vdevice_id=0, memory_scope="global") | 创建虚拟设备VDeviceglobal info;vdevice_id默认 0,memory_scope默认"global" |
lookup_vdevice(target_kind=None, device_index=-1) | 从模块 globalinfo 的 vdevice 列表中按 target 类型(如"llvm"、"cuda")与设备索引检索VDevice |
lookup_name(name) -> bool | 检查是否存在指定名字的全局变量 |
3.4meta_var:解析期元编程标记
meta_var(value)是 TVMScript 解析期(parser-time)专用的元编程值包装器:对它的赋值会被解包而不产生 IR binding,且支持迭代解包(__iter__将列表元素逐个包装)。在 python/tvm/script/ir_builder/ir/ir.py 中,它被定义为运行时类meta_var(类型检查环境下则是同名函数),其 docstring 明确说明:在 Relax 方言中,它是"默认原始绑定发射(primitive binding emission)"的显式退出开关。各方言命名空间会提供指向同一实现的兼容别名。
四、Relax 层(tvm.script.ir_builder.relax):构建 Relax 函数的完整 API
Relax 方言 builder 位于 python/tvm/relax/script/builder/ir.py(约 990 行),是实际使用最频繁的构建器。它复导出tvm.relax.op下大量算子(add、matmul、nn.conv2d、nn.batch_norm、nn.relu等),并提供了函数级与绑定块级 API。
4.1 函数帧 API
| 函数 | 作用 | 关键参数 |
|---|---|---|
function(is_pure=True, is_private=False) | 开启函数帧,返回FunctionFrame | is_pure标注函数纯性;is_private标注私有性 |
arg(name, ty) | 向最近函数帧添加参数,返回Var | ty为 Relax 类型(如R.Tensor) |
func_name(name) | 指定最近函数帧的名字 | — |
func_attr(attrs) | 指定函数 attrs(Dict[str, Object]) | — |
func_ret_type(ret_ty) | 指定函数返回类型;func_ret_ty为向后兼容别名 | — |
func_ret_value(value) | 指定函数返回值表达式 | — |
4.2 绑定块(BindingBlock)API
| 函数 | 作用 |
|---|---|
dataflow() | 开启 dataflow 绑定块帧,返回BindingBlockFrame |
output(*vars) | 将 dataflow 块内的变量暴露为块外全局可见的变量 |
emit(value, annotate_ty=None) | 发射一条绑定(生成Var),可选显式标注类型 |
emit_te(func, *args, **kwargs) | 通过 TE(张量表达式)算子生成Call |
emit_match_cast(value, ty) | 发射MatchCast绑定,返回Var |
emit_var_binding(binding) | 直接发射一条VarBinding |
emit_with_type(...)/emit_with_ty(...) | 带类型信息发射 |
tuple(*fields)/shape(value) | 构造 Relax 元组与形状表达式 |
此外,to_vdevice(data, dst_vdevice)支持将dst_vdevice以字符串形式(如"cuda:0",或"llvm"形式)解析为VDevice后调用tvm.relax.op.to_vdevice;rewriter(rewriter_mod)则可以从一个定义了pattern/replacement两个同名签名函数的 IRModule 或 TVMScript 类构造PatternMatchingRewriter,用于声明式改写规则。
4.3 实战示例:用构建器生成一个卷积网络 IRModule
python/tvm/relax/backend/adreno/mod_utils.py 中的get_relax_conv2d_mod展示了标准三步法(IRBuilder→ 方言帧 →builder.get()):
from tvm.script.ir_builder import IRBuilder from tvm.script.ir_builder import relax as relax_builder from tvm.script import relax as R with IRBuilder() as builder: with relax_builder.function(): R.func_name("main") data = R.arg("data", R.Tensor(data_shape, dtype)) weight = R.arg("weight", R.Tensor(weight_shape, dtype)) with R.dataflow() as frame: output = R.emit(R.nn.conv2d(data, weight, out_dtype=dtype, strides=stride, dilation=dilation, padding=padding, groups=groups)) if has_bias: output = R.emit(output + bias) R.output(output) R.func_ret_value(frame.output_vars[0]) func = builder.get() return tvm.IRModule({"main": func})关键点:
with IRBuilder() as builder使构建器进入线程局部作用域;with relax_builder.function()压入函数帧,随后R.arg注册参数、R.func_name命名;with R.dataflow()压入 dataflow 绑定块帧,块内R.emit逐个发射算子绑定,R.output声明块输出;- 退出所有作用域后
builder.get()返回构造好的relax.Function,再手工包成tvm.IRModule。
在 tests/python/relax/test_codegen_cutlass.py 中还有IRBuilder与relax_builder.function()组合构造 CUTLASS codegen 测试输入的更复杂示例(函数内嵌套R.dataflow()、T.prim_func(s_tir=True)的 TIR 内核等),说明该方法可与 TIRx 层混合使用,覆盖端到端 codegen 场景。
五、分布式扩展(tvm.script.ir_builder.relax.distributed)
relax.distributed是 Relax 构建器的分布式扩展,对应 python/tvm/relax/script/builder/distributed/ir.py,用于构造带设备网格(device mesh)、分布式张量与分布式算子绑定的 Relax IR。它与主relax构建器共享IRBuilder/帧栈机制:以with D.DeviceMesh(...)、with D.Tensor(...)等分布式专用帧/表达式配合relax_builder.function()使用,构造出的 IR 可直接交给 Relax 的分布式 pass 管线(如DistributedNormalize)继续处理。该模块的 API 文档通过automodule自动收集,其分布式类型(DTensorStructInfo等)与全局信息(如DeviceMesh)在 python/tvm/relax/distributed/ 中有完整定义。
六、TIRx 层(tvm.script.ir_builder.tirx):底层的 TIR 构建能力
TIRx 方言 builder 位于 python/tvm/tirx/script/builder/ir.py,提供面向底层 TIR 的帧与语句构建接口。核心入口包括:
prim_func(...)(见 ir.py):开启PrimFuncFrame,是 TIR 函数级作用域;sblock(name="", no_realize=False, exec_scope="")(见 ir.py):开启SBlockFrame,no_realize控制是否自动 realize buffer,exec_scope指定执行作用域;func_name(name)/func_attr(attrs)/func_ret(ret_type)(见 ir.py):函数命名、属性与返回类型设置;sblock_attr(attrs)(ir.py)与sblock_alloc_buffer(...)(ir.py):块级属性与 buffer 分配;block_name_suffix_context(block_suffix)(ir.py):为块名追加后缀的上下文管理器;func_gen(name)(ir.py):函数生成器辅助。
结合 python/tvm/tirx/script/builder/utils.py 的frame_scope(frames)辅助函数,可以批量压入多个帧。TIRx builder 与 parser(python/tvm/tirx/script/parser/entry.py 的prim_func)共享同一套帧模型,因此 TVMScript 的@T.prim_func语法与编程式T.prim_func(...)构造在语义上等价。
七、综合实战:混合使用 IR 层与方言构建器
IR 层的I.ir_module()帧可以与任何方言帧组合,实现"先开模块、再填函数"的完整流程。结合 python/tvm/script/ir_builder/ir/ir.py 的 API,一个通用模式如下:
from tvm.script.ir_builder import IRBuilder from tvm.script.ir_builder import ir as I from tvm.script.ir_builder import relax as relax_builder from tvm.script import relax as R with IRBuilder() as builder: with I.ir_module() as mod_frame: # 模块级信息(可选) I.module_attrs({"tir.noalias": True}) with relax_builder.function(is_pure=True): R.func_name("main") x = R.arg("x", R.Tensor((16, 16), "float32")) y = R.emit(x * 2.0) R.func_ret_value(y) mod = builder.get() # 返回 IRModule要点回顾:
I.ir_module()与relax_builder.function()形成嵌套帧栈,出栈顺序严格反向;I.module_attrs在IRModuleFrame存活期内生效;- 若要构造跨函数调用,可先用
I.decl_function("helper", signature)声明,再在后续用I.def_function("helper", func)补全实现; - 最终
builder.get()的返回类型由栈顶帧决定:RelaxFunctionFrame出栈后得到relax.Function,IRModuleFrame出栈后得到IRModule(C++ 端Get<TObjectRef>()会校验结果类型,见 base.h)。
八、源码阅读索引
若希望深入理解tvm.script.ir_builder的实现,建议按以下路径阅读:
- Python 绑定层:python/tvm/script/ir_builder/base.py(
IRBuilder/IRBuilderFrame)、python/tvm/script/ir_builder/ir/ir.py(IR 层 API)、python/tvm/script/ir_builder/init.py(方言懒加载); - C++ 实现层:include/tvm/script/ir_builder/base.h(帧栈与
Get/FindFrame模板)、src/script/ir_builder/base.cc(线程局部作用域与 FFI 注册); - Relax 方言:python/tvm/relax/script/builder/ir.py、python/tvm/relax/script/builder/distributed/ir.py;
- TIRx 方言:python/tvm/tirx/script/builder/ir.py、python/tvm/tirx/script/builder/utils.py;
- 测试用例:tests/python/relax/backend/adreno/mod_utils.py、tests/python/relax/test_codegen_cutlass.py。
结语
tvm.script.ir_builder是 TVM 中"程序化构造 IR"的统一入口:IRBuilder提供线程局部作用域,IRBuilderFrame提供带回调的上下文帧栈,ir层管理 IRModule 与全局信息,relax、relax.distributed与tirx层分别覆盖高层函数构建、分布式扩展与底层 TIR 语句构造。掌握了帧栈模型与各层的函数签名,你便可以在不依赖 TVMScript 文本解析的前提下,以纯命令式 Python 精确生成任意结构的 IR——这正是自动化 codegen、测试输入生成与编译器前端集成的核心能力所在。
- 模型编译
- 深度学习
- 推理引擎
【免费下载链接】tvm
Open Machine Learning Compiler Framework
相关推荐
TVM Relax BlockBuilder 完全指南:用 Python 构建 Relax IR 的开发者 API
TVM Relax BlockBuilder 完全指南:用 Python 构建 Relax IR 的开发者 API 本指南基于 Apache TVM 开源仓库中
模型编译深度学习推理引擎TVM TIRx 核心脚本 API 指南:从 `tvm.script.tirx` 解析器到 IR Builder 的完整解析
TVM TIRx 核心脚本 API 指南:从 tvm.script.tirx 解析器到 IR Builder 的完整解析 导读 TIRx 是 Apache TV
模型编译深度学习推理引擎TVM TIRx Python API 参考指南:从内核编写、IR 检查到编译器扩展的完整实践
TVM TIRx Python API 参考指南:从内核编写、IR 检查到编译器扩展的完整实践 TIRx 是 Apache TVM 中面向现代加速器(CUDA、
模型编译深度学习推理引擎
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考