PTO TPARTADD 指令全解析Ascend CANN 部分有效区域逐元素加法的语义、约束与多平台实现【免费下载链接】pto-isaParallel Tile Operation (PTO) is a virtual instruction set architecture designed by Ascend CANN, focusing on tile-level operations. This repository offers high-performance, cross-platform tile operations across Ascend platforms.项目地址: https://gitcode.com/cann/pto-isaTPARTADD 是 Ascend CANN Parallel Tile OperationPTO虚拟指令集中用于在目标有效区域valid region内执行逐元素加法的核心指令。与普通 TADD 不同TPARTADD 允许两个输入 Tile 的有效区域与目标不一致从而高效支撑 padding、掩码、动态形状等场景下的部分数据叠加。本文将围绕 TPARTADD 指令文档 展开完整讲解其数学语义、汇编语法AS Level 1/2、C 内建接口、各平台实现约束并结合仓库内 CPU 仿真、Atlas A2/A3 与 Ascend 950 系列A5的源码实现与测试用例帮助读者掌握该指令的精确行为边界与实战用法。指令示意图指令概述与核心语义TPARTADD 在目标有效区域上执行逐元素加法其特殊性在于对输入有效区域不做完全一致的强约束当某个元素位置(i, j)上src0与src1同时有效时结果取二者之和当只有其中一个输入有效时结果直接拷贝该输入的值其余有效区域不匹配的组合行为由具体实现定义。对目标有效区域内的每个元素(i, j)其数学语义可以精确表述为如下分段函数$$ \mathrm{dst}{i,j} \begin{cases} \mathrm{src0}{i,j} \mathrm{src1}{i,j} \text{if both inputs are defined at } (i,j) \ \mathrm{src0}{i,j} \text{if only src0 is defined at } (i,j) \ \mathrm{src1}_{i,j} \text{if only src1 is defined at } (i,j) \end{cases} $$理解有效区域valid region在 PTO 的 Tile 模型中每个 Tile 除了声明逻辑形状如16x16外还通过GetValidRow()/GetValidCol()描述当前实际参与计算的有效行数与有效列数。TPARTADD 的计算域完全由dst的有效区域决定The destination valid region defines the result domain而非由 Tile 的物理形状决定。这一设计使得同一份 Tile 形状可以承载动态的有效范围是算子侧实现动态形状、padding、部分写入等逻辑的基础。支持的部分有效区域模式指令文档给出的通用约束明确限定了合法使用模式dst、src0、src1的元素类型必须一致目标有效区域定义结果的计算范围对目标有效区域内的每个元素两个输入都有效则执行逐元素加法仅一个输入有效则结果取该输入值若dst的有效区域为零有效行或有效列为 0指令直接返回不产生任何计算支持的部分有效区域模式要求至少有一个源 Tile 的有效区域与dst完全一致另一个源 Tile 的有效区域在两个维度上都不能超过dst上述范围之外的有效区域组合其行为均由具体实现定义即用户不应依赖未列举模式的结果。这条一源对齐、一源不越界的约束在 Atlas A2/A3 实现 中有对应的运行时断言佐证bool condSrc0EqDst (src0ValidRow dstValidRow src0ValidCol dstValidCol); bool condSrc1EqDst (src1ValidRow dstValidRow src1ValidCol dstValidCol); PTO_ASSERT( condSrc0EqDst || condSrc1EqDst, Fix: TPARTADD At most one entry in the valid-rows and valid-cols of src0 and src1 is smaller than dst.);即 src0 与 src1 中至多一个的有效行有效列可以比 dst 更小另一个必须与 dst 完全相等这与文档描述完全一致。汇编语法TPARTADD 在 PTO 汇编体系中有三种表达形式覆盖从同步伪指令到 SSA、再到 DPSDestination-Operand-Source风格的完整层次。同步形式PTO Assembly Form%dst tpartadd %src0, %src1 : !pto.tile... - !pto.tile...AS Level 1SSA 形式使用pto.前缀与多操作数类型签名显式声明两个输入与一个输出的 Tile 类型%dst pto.tpartadd %src0, %src1 : (!pto.tile..., !pto.tile...) - !pto.tile...AS Level 2DPS 形式采用ins(...)/outs(...)操作数分组输入与输出从 SSA 值细化为具体的!pto.tile_buf...缓冲区pto.tpartadd ins(%src0, %src1 : !pto.tile_buf..., !pto.tile_buf...) outs(%dst : !pto.tile_buf...)C 内建接口TPARTADD 的 C 内建接口声明于 include/pto/common/pto_instr.hpp公共包含头为pto/pto-inst.hpptemplate typename TileDataDst, typename TileDataSrc0, typename TileDataSrc1, typename... WaitEvents PTO_INST RecordEvent TPARTADD(TileDataDst dst, TileDataSrc0 src0, TileDataSrc1 src1, WaitEvents ... events);从源码实现看该接口的行为链是先通过detail::PtoWaitEvents(events...)等待传入的异步事件WaitEvents 变参用于依赖同步再经MAP_INSTR_IMPL(TPARTADD, dst, src0, src1)宏分发到各平台对应的TPARTADD_IMPL实现最终返回一个RecordEvent记录本次发射。在 CPU 仿真模式下MAP_INSTR_IMPL还会通过PTO_INSTR_SCOPE将指令名与操作数写入 trace便于仿真排障参见 include/pto/common/pto_instr.hpp。返回值RecordEvent表示指令发射记录可继续作为后续指令的 WaitEvents 依赖传入从而在用户代码层面构建指令间的流水依赖关系。各平台约束与实现检查通用约束所有平台dst、src0、src1元素类型必须一致各平台实现均以static_assert强制例如 A2/A3 实现中的Fix: TPARTADD src and dst data type is different!结果计算范围由dst有效区域决定dst有效区域为零时指令空转返回支持的部分有效模式见上文。Atlas A2/A3 训练系列产品 / Atlas A2/A3 推理系列产品实现检查支持的元素类型int32_t、int16_t、half、floatdst、src0、src1必须全部为行主序isRowMajor列主序BLayout不被支持源码中以static_assert(TileDataDst::isRowMajor ...)强制。Ascend 950PR / Ascend 950DTA5实现检查支持的元素类型显著更广uint8_t、int8_t、uint16_t、int16_t、uint32_t、int32_t、int64_t、uint64_t、half、float、bfloat16_t从源码看64 位整数类型走专门的Int64PartInt64Op::Add, ...路径见 A5 TPartAdd 实现其余类型走统一的掩码寄存器路径。使用示例Auto自动模式自动模式下 Tile 的放置与调度由编译器/运行时统一管理用户只需声明 Tile 并调用接口#include pto/pto-inst.hpp using namespace pto; void example_auto() { using TileT TileTileType::Vec, float, 16, 16; TileT src0, src1, dst; TPARTADD(dst, src0, src1); }Manual手动模式手动模式下需先用TASSIGN将各 Tile 显式绑定到目标地址如统一缓冲区偏移再发射 TPARTADD#include pto/pto-inst.hpp using namespace pto; void example_manual() { using TileT TileTileType::Vec, float, 16, 16; TileT src0, src1, dst; TASSIGN(src0, 0x1000); TASSIGN(src1, 0x2000); TASSIGN(dst, 0x3000); TPARTADD(dst, src0, src1); }对应汇编形式自动模式资源放置与调度交给编译器/运行时# Auto mode: compiler/runtime-managed placement and scheduling. %dst pto.tpartadd %src0, %src1 : (!pto.tile..., !pto.tile...) - !pto.tile...手动模式先显式绑定资源再发射指令Tile 操作数可选用pto.tassign绑定地址# Manual mode: resources must be bound explicitly before issuing the instruction. # Optional for tile operands: # pto.tassign %arg0, tile(0x1000) # pto.tassign %arg1, tile(0x2000) %dst pto.tpartadd %src0, %src1 : (!pto.tile..., !pto.tile...) - !pto.tile...PTO 汇编完整形式同步 AS Level 2 DPS%dst tpartadd %src0, %src1 : !pto.tile... - !pto.tile... # AS Level 2 (DPS) pto.tpartadd ins(%src0, %src1 : !pto.tile_buf..., !pto.tile_buf...) outs(%dst : !pto.tile_buf...)源码级纵深三个平台的实现原理CPU 仿真实现指令语义的黄金参照CPU 仿真实现位于 include/pto/cpu/TPartAdd.hpp 与 include/pto/cpu/TPartOp.hpp其双层循环精确刻画了文档语义for (int i 0; i DstValidRow; i) { for (int j 0; j DstValidCol; j) { const size_t DstOffset GetTileElementOffsetTileDataDst(i, j); bool InSrc0 i Src0ValidRow j Src0ValidCol; bool InSrc1 i Src1ValidRow j Src1ValidCol; ... if (InSrc0 InSrc1) { InstrOp::PartInstr(dst, src0, src1, DstOffset, Src0Offset, Src1Offset); // dst src0 src1 } else if (InSrc0 !InSrc1) { dst[DstOffset] src0[Src0Offset]; // 仅 src0 有效 → 拷贝 } else if (!InSrc0 InSrc1) { dst[DstOffset] src1[Src1Offset]; // 仅 src1 有效 → 拷贝 } else { dst[DstOffset] 0; // 双方均无效 → 清零实现定义行为 } } }其中PartAddOp::PartInstr仅执行dst[DstOffset] src0[Src0Offset] src1[Src1Offset]这一行加法。值得注意的实现细节文档声明双方都无效等未列举模式行为由实现定义而 CPU 仿真选择写入 0TPartCheck则用static_assert校验数据类型集合并在有效行或有效列为 0 时直接返回TPARTMAX: Invalid data type. 为模板复用遗留的断言文案。CPU 实现支持的数据类型集合与 A5 一致覆盖 8/16/32/64 位整型、half、float、bfloat16。Atlas A2/A3 实现向量 vadd repeat 展开A2/A3 实现位于 include/pto/npu/a2a3/TPartAdd.hpp。其核心思路是将逐元素加法映射到底层向量指令vadd并按 block/repeat 结构展开struct PartAddOp { PTO_INTERNAL static void PartInstr(__ubuf__ T* dst, __ubuf__ T* src0, __ubuf__ T* src1, uint8_t repeats) { vadd(dst, src0, src1, repeats, 1, 1, 1, 8, 8, 8); } };elementsPerRepeat与blockSizeElem由元素类型换算得出BLOCK_BYTE_SIZE / sizeof(T)与REPEAT_BYTE / sizeof(T)见 A2/A3 实现因此不同数据类型会自动适配不同的向量展开参数模板参数dstRowStride / src0RowStride / src1RowStride允许三个 Tile 拥有不同的行跨度支持非连续布局下的部分加法实现会先判断哪个源与 dst 有效区域相等再决定将谁作为全量侧传入TPartInstr从而保证部分模式只出现在一个输入上与文档约束一一对应。Ascend 950PR/950DTA5实现掩码寄存器 zeroing 模式A5 实现位于 include/pto/npu/a5/TPartAdd.hpp基于 RegTensor 与掩码寄存器MaskReg实现struct PartAddOp { PTO_INTERNAL static void BinInstr(RegTensorT dst, RegTensorT src0, RegTensorT src1, MaskReg preg) { vadd(dst, src0, src1, preg, MODE_ZEROING); } };采用MODE_ZEROING模式配合 predication 掩码一次性完成有效区相加、无效区清零的合并语义效率高于逐元素分支判断对int64_t/uint64_t两类 64 位类型走Int64PartInt64Op::Add, ...专用路径其余类型进入统一的TPARTOP_IMPL这解释了 A5 支持类型清单明显长于 A2/A3 的原因通用类型校验以static_assert在编译期完成见 A5 实现非法类型直接编译失败而非运行期报错。测试与验证仓库为 TPARTADD 提供了跨平台、跨架构的完整测试用例可作为指令行为的可执行规范CPU 仿真tests/cpu/st/testcase/tpartadd/main.cpp 使用 64x64 的 Tile、src1 有效区域为 32x32kValidRows1 32、kValidCols1 32的典型部分有效场景从input1.bin/input2.bin读取输入并经设备执行后写出output.bin对照配套 gen_data.py 负责生成 golden 输入数据Atlas A2/A3tests/npu/a2a3/src/st/testcase/tpartadd/main.cppAscend 950A5tests/npu/a5/src/st/testcase/tpartadd/main.cpp 以模板参数dstVR/dstVC/src0VR/src0VC/src1VR/src1VC显式枚举不同有效区域组合并额外声明了LaunchTPartAddInplace用于覆盖**原地in-place**场景——即输出复用某个输入缓冲的情形此外 kirin9030 / kirinDev0000 等架构目录下同样存在 tpartadd 测试集说明该指令在多代 Ascend 架构上均有落地验证。测试框架层面NPU 用例经 ACLaclrtMalloc/aclrtMemcpy/aclrtSynchronizeStream完成主机与设备侧数据搬运与流同步整个用例可经 tests/run_st.sh 脚本统一调度运行。总结TPARTADD 是 PTO 指令集中部分有效区域二元运算族TPARTADD/TPARTMUL 等参见 include/pto/common/pto_instr.hpp 中相邻的TPARTMUL声明的代表指令。它通过目标有效区域定义计算域 至少一个输入与目标区域对齐 另一输入不得越界的约束模型在保证硬件可实现性的同时为算子开发者提供了处理动态形状与掩码叠加的原子能力。无论是理解 PTO-Virtual-ISA-Manual 中的指令体系还是直接在算子内核中落地 partial 数据通路掌握 TPARTADD 的语义边界、汇编三种形态与各平台实现差异都是必要的一步。【免费下载链接】pto-isaParallel Tile Operation (PTO) is a virtual instruction set architecture designed by Ascend CANN, focusing on tile-level operations. This repository offers high-performance, cross-platform tile operations across Ascend platforms.项目地址: https://gitcode.com/cann/pto-isa创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
