ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

custom_macro 跨 Pipe 宏操作完全指南:从原理到 IR 写法

custom_macro 跨 Pipe 宏操作完全指南:从原理到 IR 写法 custom_macro 跨 Pipe 宏操作完全指南从原理到 IR 写法【免费下载链接】BiliBiliToolProB 站bilibili自动任务工具支持docker、青龙、k8s等多种部署方式。全面拥抱AI。敏感肌也能用。项目地址: https://gitcode.com/GitHub_Trending/bi/BiliBiliToolPro如果你的融合算子需要同时动用多条 Pipeline——例如 MTE2 负责把数据从 GM 搬进来Vector Core 接着完成计算——HIVM 方言里的hir.custom_macro跨 Pipe 宏操作就是为这类场景准备的。它是hir.custom的多 Pipeline 版本用hivm.pipe_in和hivm.pipe_out两个属性声明数据从哪里流入、从哪个 Pipeline 流出而跨 Pipe 同步则交给编译器自动补齐。先说场景单 Pipe 的 custom 为什么不够hir.custom的设计假设是算子从头到尾待在一条 Pipeline 里一个hivm.pipe属性足以交代它的位置。可实际的融合操作往往横跨多条流水线——数据先从 GM 经 MTE2 加载进来在 Vector Core 上做主计算随后还要走一遍后处理。这种数据流单 Pipe 操作描述不了Pipeline 之间先后关系的表达更是无从谈起。hir.custom_macro正是为此开辟的入口。 机制两条流水线之间的交接可以把它理解成两条流水线之间的一次交接上游 Pipelinepipe_in比如PIPE_MTE2语义是数据从 GM 加载进入把数据递出去下游 Pipelinepipe_out比如PIPE_V语义是交给 Vector Core 处理再接手。承担这个语义标记的是MacroOpTrait。被该 trait 标记的操作会在编译器的同步分析阶段被区别对待InjectSync/GraphSyncSolverPass 读取pipe_in与pipe_out的取值后替你补上set_flag/wait_flag跨 Pipe 同步操作使两条 Pipeline 的先后次序得到保证。换句话说你只需把进出两条 Pipe 指对同步 flag 由编译器负责生成。长什么样TableGen 定义与字段速览定义本身相当紧凑摘自HIVMOps.tddef CustomMacroOp : HIVM_CustomOpcustom_macro, [MacroOpTrait] { let arguments (ins StrAttr:$name, VariadicAnyType:$inputs, VariadicAnyType:$outputs); let results (outs VariadicAnyType:$results); }字段逐一拆解字段类型必选角色$nameStrAttr是操作名称$inputsVariadicAnyType是输入参数$outputsVariadicAnyType是输出/初始化参数DPS init$resultsVariadicAnyType—结果值属性一侧四个必填项共同刻画跑在哪、数据怎么走hivm.tcore_typeTCoreTypeAttr执行的 Core 类型、hivm.pipe_inPipeAttr输入 Pipeline、hivm.pipe_outPipeAttr输出 Pipeline、hivm.vf_modeVFModeAttrVector 运行模式。此外还有一个可选属性gm_addr_args_indicesDenseI32ArrayAttr用于指明哪些参数位置上是 GM 地址。动手写 IR自定义与内置的写法差异自定义宏操作需要把四个属性显式写全数据流向在 IR 上一目了然%empty tensor.empty() : tensor3x3xf32 %0 hivm.hir.custom_macro { hivm.tcore_type #hivm.tcore_typeVECTOR, hivm.vf_mode #hivm.vf_modeSIMD, hivm.pipe_in #hivm.pipePIPE_MTE2, hivm.pipe_out #hivm.pipePIPE_V } my_custom_op ins(%arg0, %arg1, %c4_i64, %c0_i32, %c2_i64, %c1_i64, %c2_i32, %c2_i32, %c0_i32, %c0_i32 : memref?xf32, tensor3x3xi64, i64, i32, i64, i64, i32, i32, i32, i32) outs(%empty : tensor3x3xf32) - tensor3x3xf32一旦操作命中 Builtin写法就可以收敛到只留名字和操作数属性块整体省略%empty tensor.empty() : tensor3x3xf32 %0 hivm.hir.custom_macro __builtin_gather_load ins(%arg0, %arg1, %c4_i64, %c0_i32, %c2_i64, %c1_i64, %c2_i32, %c2_i32, %c0_i32, %c0_i32 : memref?xf32, tensor3x3xi64, i64, i32, i64, i64, i32, i32, i32, i32) outs(%empty : tensor3x3xf32) - tensor3x3xf32两段 IR 的操作数布局完全一致分岔点只在属性声明前者显式告诉编译器从 MTE2 进入、从 V 流出VECTOR core、SIMD 模式后者的这些信息由 Builtin 名称隐含编译器按内置定义自行解析。选型custom 还是 custom_macro判断标准只有一条——数据流是否落在同一条 Pipeline 内维度CustomOpCustomMacroOpTraitSinglePipeOpTraitMacroOpTraitPipe 属性hivm.pipe单个hivm.pipe_inhivm.pipe_out两个覆盖 Pipeline单个跨多个同步方式Pipe 内同步跨 Pipe 同步一句话总结单 Pipeline 内的操作继续用hir.custom只要涉及数据加载 计算 后处理这类跨流水线协作就切换到hir.custom_macro。⚡ 编译器替你做了哪些事同步注入MacroOpTrait让InjectSync/GraphSyncSolverPass 识别出跨 Pipe 操作并自动在操作前后生成set_flag/wait_flag。你不需要手写任何同步指令前提是pipe_in、pipe_out如实反映真实的数据流向——编译器完全依据这两个属性生成同步。DPS 语义操作实现了DestinationStyleOpInterface$outputs作为 DPS 的 init 操作数参与执行结果写入$results。这意味着输出侧张量要由你先构造好示例里那个tensor.empty() : tensor3x3xf32就是为此准备的。Builtin 校验命中内置操作时编译器会按内置定义检查参数是否正确参数与定义不符会在验证阶段被拦下。快速参考C API 与属性常量Pipe 相关方法getInPipe()/setInPipe(PIPE)、getOutPipe()/setOutPipe(PIPE)返回与参数类型均为PIPE。执行配置相关getCoreType()→optionalTCoreType、setCoreType(TCoreType)、getVFMode()→optionalVFMode、setVFMode(VFMode)。另可用isBuiltin()判断操作是否为内置。Pipe 属性名常量static constexpr StringLiteral inPipeName hivm.pipe_in; static constexpr StringLiteral outPipeName hivm.pipe_out;延伸资料源码定义bishengir/include/bishengir/Dialect/HIVM/IR/HIVMOps.tdL1105–L1167测试用例bishengir/test/Dialect/HIVM/IR/custom-op.mlir相关文档CustomOp 说明01-custom-op.md【免费下载链接】BiliBiliToolProB 站bilibili自动任务工具支持docker、青龙、k8s等多种部署方式。全面拥抱AI。敏感肌也能用。项目地址: https://gitcode.com/GitHub_Trending/bi/BiliBiliToolPro创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进