资讯详情

资讯详情

PTO-ISA 逐元素取负指令 TNEG:从数学语义、汇编语法到 C++ 内建接口的完整指南

PTO-ISA 逐元素取负指令 TNEG从数学语义、汇编语法到 C 内建接口的完整指南【免费下载链接】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本文以 CANN pto-isa 仓库中 TNEG 指令文档 为主体结合 A2A3 后端实现 与 A5 后端实现系统讲解 Tile 级逐元素取负negation指令 TNEG 的数学语义、汇编语法、C 内建接口、底层实现原理与约束条件。读完本文你将能够在 pto-isa 编程模型下正确使用TNEG完成向量的逐元素取负并理解其在 Vector 流水线上的实际落地方式。概述与数学语义TNEGTile NEGation是 PTOParallel Tile Operation虚拟指令集中最基础的逐元素一元运算指令之一作用是对一个 tile数据块中的每个元素取相反数。其语义非常简洁输入 src tile输出 dst tile两者形状相同dst 中每个元素等于 src 中对应元素的相反数。对于有效区域valid region内的每个元素(i, j)其数学定义如下$$ \mathrm{dst}{i,j} -\mathrm{src}{i,j} $$其中i、j分别表示 tile 的行、列索引运算仅作用于GetValidRow()/GetValidCol()限定的有效区域而不是整个物理存储空间。这一点与 PTO 中其他 Tile 级指令保持一致tile 的物理尺寸Rows × Cols可能大于有效尺寸ValidRow × ValidCol指令只保证有效区域内的正确性。从使用场景看TNEG 通常出现在需要符号翻转的算子实现中例如减法a - b可等价为a (-b)、归一化前的符号处理、以及某些激活函数/损失函数中的取反步骤。由于它是逐元素操作天然适合与 TADD、TMUL 等同类 Vector 指令组合成更复杂的算子。汇编语法三种表达层级TNEG 与 PTO 其他指令一样根据编程抽象层级的不同存在三种等价汇编形式。理解这三种形式有助于区分虚拟指令集与具体硬件指令的关系。同步形式PTO 汇编这是最接近用户编程意图的指令形式操作数类型为!pto.tile...%dst tneg %src : !pto.tile...AS Level 1SSA 形式SSAStatic Single Assignment形式显式携带pto.前缀与类型转换箭头编译器在后续阶段会做资源分配与指令调度%dst pto.tneg %src : !pto.tile... - !pto.tile...AS Level 2DPS 形式DPSData Parallel Semantics形式使用ins(...) / outs(...)语法直接描述输入缓冲区与输出缓冲区的关系操作数类型为!pto.tile_buf...pto.tneg ins(%src : !pto.tile_buf...) outs(%dst : !pto.tile_buf...)从源码结构看这三种形式是同一操作在不同抽象层级上的投影Level 1 保留 SSA 值语义便于优化Level 2 显式化缓冲区与数据流关系最终统一降级为硬件可执行的 Vector 指令详见下文底层实现原理。C 内建接口TNEG 对外提供 C 内建接口intrinsic用户可直接在 kernel 代码中以函数调用的方式使用无需手写汇编。接口声明TNEG的声明位于 include/pto/common/pto_instr.hpp公共头文件为pto/pto-inst.hpptemplate typename TileDataDst, typename TileDataSrc, typename... WaitEvents PTO_INST RecordEvent TNEG(TileDataDst dst, TileDataSrc src, WaitEvents ... events);接口特征模板参数TileDataDst/TileDataSrc分别为输出/输入 tile 的数据类型WaitEvents...为可选的等待事件集合用于表达跨流水线Pipe依赖返回值RecordEvent允许将本次指令的完成事件与后续指令串联实现事件驱动的异步调度变参事件通过events传入等待事件使调用方能够精细控制 Vector 指令与 MTE搬移引擎、Scalar 等其他单元的同步关系。源码中该声明通过MAP_INSTR_IMPL(TNEG, dst, src)宏映射到平台相关的TNEG_IMPL实现从而在不同昇腾平台A2A3、A5上自动选择对应的底层指令实现。典型调用示例TNEG 指令文档 给出了最小可运行示例#include pto/pto-inst.hpp using namespace pto; void example() { using TileT TileTileType::Vec, float, 16, 16; TileT x, out; TNEG(out, x); }这里TileTileType::Vec, float, 16, 16定义了一个位于 Vector 单元TileType::Vec、元素类型为float、形状为 16×16 的 tile。TNEG(out, x)将x中 16×16 个元素逐一取反写入out。底层实现原理TNEG 是标量乘 -1这是本指令最值得注意的实现细节。查看 A2A3 与 A5 两个后端的源码TNEG_IMPL的实现完全相同——它并不是独立的硬件指令而是复用标量乘指令 TMULS以标量 -1 与 src 逐元素相乘A2A3include/pto/npu/a2a3/TUnaryOp.hppA5include/pto/npu/a5/TUnaryOp.hpp/* TNEG */ template typename DstTile, typename SrcTile PTO_INTERNAL void TNEG_IMPL(DstTile dst, SrcTile src) { TMULS_IMPL(dst, src, -1); }继续追查TMULS_IMPL见 include/pto/npu/a2a3/TMulS.hpp其内部调用TMulST, ...模板函数最终落到TBinSInstrMulSOpT, ...即 Vector 单元的向量×标量vmuls 类硬件指令。这意味着TNEG 的取负在硬件上表现为一次标量乘法标量恒为 -1dst 与 src 的数据类型必须一致TMULS_IMPL中有static_assert强制校验dst 与 src 的有效行列数必须一致且均不得为 0PTO_ASSERT运行时校验。这一用标量乘实现取负的设计体现了指令集在语义完备性与硬件实现成本之间的取舍指令集层面提供语义清晰的tneg原语底层则复用量产已验证的乘法单元减少专用逻辑。调度框架TUnaryOp 的统一循环展开虽然 TNEG 本身委托给 TMULS但 PTO 的 Vector 一元运算族TNOT、TRELU、TABS、TLOG、TRSQRT 等共享同一套 TUnaryOp 调度框架。从源码结构看该框架根据 tile 形状与 repeat 限制pto::REPEAT_MAX在编译期自动选择多种发射策略1L 模式单行/合并处理当 tile 行列可整体合并isCombined且总 repeat 数不超过上限时使用Unary1LNormMode/Unary1LCountMode一条向量指令按连续 repeat 完成全部运算2L 模式按行循环当列方向需要跨 block 处理时进入Unary2LProcess并进一步根据行数、repeat 上限与 stride 约束选择Unary2LCountModecount 模式、Unary2LNormModeColVLAlign列对齐、Unary2LNormModeRowRpt行 repeat或 Head/Tail 拆分策略处理尾部不足一个 repeat 的残余元素配合SetContMaskByDType连续 mask 与SetFullVecMaskByDType恢复全量 mask。因此用户无需关心 tile 形状如何映射到硬件 repeat框架会在编译期自动选择最优展开路径这正是 Tile 级编程模型相对传统手写 Vector 编程的核心优势之一。约束与限制TNEG 的合法使用受以下约束限制违反时会在编译期static_assert或运行期PTO_ASSERT被拦截。数据类型约束平台相关TNEG 迭代dst.GetValidRow()/dst.GetValidCol()且支持的数据类型随平台不同而不同平台支持的数据类型Atlas A2/A3 训练系列产品 / Atlas A2/A3 推理系列产品A2A3int32_t、int16_t、half、floatAscend 950PR / Ascend 950DTA5int32_t、int16_t、uint32_t、uint16_t、half、float、bfloat16_t可见 A5 平台在整数宽度新增uint32_t、uint16_t与低精度浮点新增bfloat16_t上覆盖更广。这些限制来自 TNEG 指令文档 中明确列出的实现检查并在TMULS_IMPL的static_assert中得以印证A2A3 侧支持int32_t/int16_t/half/float。Tile 布局与形状约束从 TunaryCheck 以及TMULS_IMPL的校验逻辑可以归纳出以下约束tile 类型src 与 dst 的Loc必须为TileType::VecVector 单元不支持 Matrix 等其他单元布局tile 必须为行主序isRowMajor形状一致性src.GetValidRow() dst.GetValidRow()且src.GetValidCol() dst.GetValidCol()且有效行列数不得为 0有效区域ValidRow Rows、ValidCol Cols有效区域不得超出物理形状类型一致DstTile::DType与SrcTile::DType必须相同。完整实践从 GlobalTensor 加载到 TNEG 再存回仅调用TNEG本身并不构成一个可运行的 kernel还需要配合全局内存加载TLOAD、存储TSTORE、tile 资源绑定TASSIGN以及跨流水线同步。仓库中的 NPU 测试用例 tests/npu/a2a3/src/st/testcase/tneg/tneg_kernel.cpp 给出了完整流程#include pto/pto-inst.hpp #include pto/common/constants.hpp #include acl/acl.h using namespace pto; template typename T, int kGRows_, int kGCols_, int kTRows_, int kTCols_ __global__ AICORE void runTNeg(__gm__ T __out__* out, __gm__ T __in__* src) { using DynShapeDim5 Shape1, 1, 1, kGRows_, kGCols_; using DynStridDim5 pto::Stride1, 1, 1, kGCols_, 1; using GlobalData GlobalTensorT, DynShapeDim5, DynStridDim5; using TileData TileTileType::Vec, T, kTRows_, kTCols_, BLayout::RowMajor, -1, -1; TileData srcTile(kTRows_, kTCols_); TileData dstTile(kTRows_, kTCols_); TASSIGN(srcTile, 0x0); // 绑定 tile 物理地址 TASSIGN(dstTile, 0x20000); GlobalData srcGlobal(src); GlobalData dstGlobal(out); TLOAD(srcTile, srcGlobal); // MTE2全局内存 - UB #ifndef __PTO_AUTO__ set_flag(PIPE_MTE2, PIPE_V, EVENT_ID0); wait_flag(PIPE_MTE2, PIPE_V, EVENT_ID0); // 等待搬入完成 #endif TNEG(dstTile, srcTile); // Vector逐元素取反 #ifndef __PTO_AUTO__ set_flag(PIPE_V, PIPE_MTE3, EVENT_ID0); wait_flag(PIPE_V, PIPE_MTE3, EVENT_ID0); // 等待取反完成 #endif TSTORE(dstGlobal, dstTile); // MTE3UB - 全局内存 out dstGlobal.data(); }该用例分别实例化了float64×64、int32_t32×32、half32×64、int16_t64×16四种类型组合与文档声明的 A2A3 类型约束完全对应template void LaunchTNegfloat, 64, 64, 64, 64(float* out, float* src, void* stream); template void LaunchTNegint32_t, 32, 32, 32, 32(int32_t* out, int32_t* src, void* stream); template void LaunchTNegaclFloat16, 32, 64, 32, 64(aclFloat16* out, aclFloat16* src, void* stream); template void LaunchTNegint16_t, 64, 16, 64, 16(int16_t* out, int16_t* src, void* stream);自动模式与手动模式的资源管理TNEG 指令文档 还区分了两种编程模式下的资源管理方式自动模式Auto Modetile 的放置与调度由编译器/运行时统一管理指令中无需出现资源绑定信息# Auto mode: compiler/runtime-managed placement and scheduling. %dst pto.tneg %src : !pto.tile... - !pto.tile...手动模式Manual Mode开发者需要先用pto.tassign显式把 tile 操作数绑定到具体的 UB 地址再发射指令# 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.tneg %src : !pto.tile... - !pto.tile...两种模式对应的 C 层差异在前述 kernel 示例中也能看到手动模式需要TASSIGN(srcTile, 0x0)/TASSIGN(dstTile, 0x20000)手动绑定地址并显式使用set_flag/wait_flag做流水线同步而自动模式__PTO_AUTO__下这些操作由框架接管。测试与验证TNEG 在仓库中拥有完整的测试覆盖可作为实现正确性的参照与二次开发的模板NPU 软件测试ST各平台的tneg用例目录均包含 kernel 实现、宿主侧 main 与数据生成脚本tests/npu/a2a3/src/st/testcase/tneg/main.cpp、tneg_kernel.cpp、gen_data.pytests/npu/a5/src/st/testcase/tneg/tests/npu/kirin9030/src/st/testcase/tneg/ 等昇腾其他系列CPU 软件仿真测试tests/cpu/st/testcase/tneg/main.cpp、tneg_kernel.cpp、gen_data.py用于在 CPU 模拟环境下验证指令行为便于无硬件环境下的开发调试Costmodel 性能仿真tests/costmodel/st/testcase/tneg/main.cpp 与 tests/costmodel/st_a5_fit/testcase/tneg_fit/main.cpp 用于在性能模型中校准 TNEG 的周期消耗。上述测试从功能正确性NPU/CPU 对照、多平台一致性A2A3、A5、Kirin 系列与性能建模三个维度共同保证了 TNEG 指令的可靠落地。开发者若需新增平台适配或验证自定义 tile 形状可参照这些用例的目录结构与调用方式。小结TNEG 是 PTO 指令集中语义最简单的一元运算之一但其背后承载了完整的指令集分层设计数学语义 → 汇编三层级表达 → C intrinsic → 硬件 Vector 指令。理解 TNEG 的关键在于把握两点一是它通过TMULS_IMPL(dst, src, -1)复用了标量乘法实现取负二是它的合法性由平台相关的数据类型约束与通用的 tile 形状/布局约束共同限定。结合 TLOAD、TSTORE、TASSIGN 等指令即可在 pto-isa 编程模型下快速搭建出完整的取负算子 kernel。TNEG 指令的 Tile 级逐元素取负操作示意图来自 docs/figures/isa/TNEG.svg【免费下载链接】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),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →