PTO TPARTADD 指令全解析:Ascend CANN 部分有效区域逐元素加法的语义、约束与多平台实现
2026/9/19 9:30:29 网站建设 项目流程

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-isa

TPARTADD 是 Ascend CANN Parallel Tile Operation(PTO)虚拟指令集中用于在目标有效区域(valid region)内执行逐元素加法的核心指令。与普通 TADD 不同,TPARTADD 允许两个输入 Tile 的有效区域与目标不一致,从而高效支撑 padding、掩码、动态形状等场景下的部分数据叠加。本文将围绕 TPARTADD 指令文档 展开,完整讲解其数学语义、汇编语法(AS Level 1/2)、C++ 内建接口、各平台实现约束,并结合仓库内 CPU 仿真、Atlas A2/A3 与 Ascend 950 系列(A5)的源码实现与测试用例,帮助读者掌握该指令的精确行为边界与实战用法。

指令示意图

指令概述与核心语义

TPARTADD 在目标有效区域上执行逐元素加法,其特殊性在于对输入有效区域不做"完全一致"的强约束:当某个元素位置(i, j)src0src1同时有效时,结果取二者之和;当只有其中一个输入有效时,结果直接拷贝该输入的值;其余有效区域不匹配的组合行为由具体实现定义。

对目标有效区域内的每个元素(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、部分写入等逻辑的基础。

支持的"部分有效区域"模式

指令文档给出的通用约束明确限定了合法使用模式:

  • dstsrc0src1的元素类型必须一致;
  • 目标有效区域定义结果的计算范围;
  • 对目标有效区域内的每个元素:两个输入都有效则执行逐元素加法;仅一个输入有效则结果取该输入值;
  • 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、再到 DPS(Destination-Operand-Source)风格的完整层次。

同步形式(PTO Assembly Form):

%dst = tpartadd %src0, %src1 : !pto.tile<...> -> !pto.tile<...>

AS Level 1(SSA 形式):使用pto.前缀与多操作数类型签名,显式声明两个输入与一个输出的 Tile 类型:

%dst = pto.tpartadd %src0, %src1 : (!pto.tile<...>, !pto.tile<...>) -> !pto.tile<...>

AS Level 2(DPS 形式):采用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.hpp>

template <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 依赖传入,从而在用户代码层面构建指令间的流水依赖关系。

各平台约束与实现检查

通用约束(所有平台)

  • dstsrc0src1元素类型必须一致(各平台实现均以static_assert强制,例如 A2/A3 实现中的"Fix: TPARTADD src and dst data type is different!");
  • 结果计算范围由dst有效区域决定;
  • dst有效区域为零时指令空转返回;
  • 支持的部分有效模式见上文。

Atlas A2/A3 训练系列产品 / Atlas A2/A3 推理系列产品实现检查

  • 支持的元素类型:int32_tint16_thalffloat
  • dstsrc0src1必须全部为行主序(isRowMajor),列主序(BLayout)不被支持,源码中以static_assert(TileDataDst::isRowMajor && ...)强制。

Ascend 950PR / Ascend 950DT(A5)实现检查

  • 支持的元素类型显著更广:uint8_tint8_tuint16_tint16_tuint32_tint32_tint64_tuint64_thalffloatbfloat16_t
  • 从源码看,64 位整数类型走专门的Int64Part<Int64Op::Add, ...>路径(见 A5 TPartAdd 实现),其余类型走统一的掩码寄存器路径。

使用示例

Auto(自动)模式

自动模式下 Tile 的放置与调度由编译器/运行时统一管理,用户只需声明 Tile 并调用接口:

#include <pto/pto-inst.hpp> using namespace pto; void example_auto() { using TileT = Tile<TileType::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 = Tile<TileType::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 = GetTileElementOffset<TileDataDst>(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 仿真选择写入 0;TPartCheck则用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); } };
  • elementsPerRepeatblockSizeElem由元素类型换算得出:BLOCK_BYTE_SIZE / sizeof(T)REPEAT_BYTE / sizeof(T)(见 A2/A3 实现),因此不同数据类型会自动适配不同的向量展开参数;
  • 模板参数dstRowStride / src0RowStride / src1RowStride允许三个 Tile 拥有不同的行跨度,支持非连续布局下的部分加法;
  • 实现会先判断哪个源与 dst 有效区域相等,再决定将谁作为"全量"侧传入TPartInstr,从而保证部分模式只出现在一个输入上,与文档约束一一对应。

Ascend 950PR/950DT(A5)实现(掩码寄存器 + zeroing 模式)

A5 实现位于 include/pto/npu/a5/TPartAdd.hpp,基于 RegTensor 与掩码寄存器(MaskReg)实现:

struct PartAddOp { PTO_INTERNAL static void BinInstr(RegTensor<T>& dst, RegTensor<T>& src0, RegTensor<T>& src1, MaskReg preg) { vadd(dst, src0, src1, preg, MODE_ZEROING); } };
  • 采用MODE_ZEROING模式,配合 predication 掩码一次性完成"有效区相加、无效区清零"的合并语义,效率高于逐元素分支判断;
  • int64_t/uint64_t两类 64 位类型,走Int64Part<Int64Op::Add, ...>专用路径,其余类型进入统一的TPARTOP_IMPL,这解释了 A5 支持类型清单明显长于 A2/A3 的原因;
  • 通用类型校验以static_assert在编译期完成(见 A5 实现),非法类型直接编译失败而非运行期报错。

测试与验证

仓库为 TPARTADD 提供了跨平台、跨架构的完整测试用例,可作为指令行为的可执行规范:

  • CPU 仿真:tests/cpu/st/testcase/tpartadd/main.cpp 使用 64x64 的 Tile、src1 有效区域为 32x32(kValidRows1 = 32kValidCols1 = 32)的典型部分有效场景,从input1.bin/input2.bin读取输入并经设备执行后写出output.bin对照;配套 gen_data.py 负责生成 golden 输入数据;
  • Atlas A2/A3:tests/npu/a2a3/src/st/testcase/tpartadd/main.cpp;
  • Ascend 950(A5):tests/npu/a5/src/st/testcase/tpartadd/main.cpp 以模板参数dstVR/dstVC/src0VR/src0VC/src1VR/src1VC显式枚举不同有效区域组合,并额外声明了LaunchTPartAddInplace用于覆盖**原地(in-place)**场景——即输出复用某个输入缓冲的情形;
  • 此外 kirin9030 / kirinDev0000 等架构目录下同样存在 tpartadd 测试集,说明该指令在多代 Ascend 架构上均有落地验证。

测试框架层面,NPU 用例经 ACL(aclrtMalloc/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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询