
PTO-ISA TMULS 指令详解Tile 与标量逐元素乘法的语义、内建接口与实现原理【免费下载链接】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 仓库中 docs/isa/TMULS_zh.md 展开并辅以include/pto下的 NPU/CPU 实现与tests下的测试用例进行源码级佐证。TMULSTile Mul by Scalar是 PTOParallel Tile Operation虚拟指令集中最常用的向量标量运算指令之一用于将 Tile 中的每个元素与一个标量相乘。本文从数学语义、汇编语法、C 内建接口、平台约束到底层实现与测试验证完整讲解该指令的用法与原理帮助你快速在 Atlas A2/A3 与 Ascend 950 系列产品上编写正确的向量缩放scaling代码并理解其与vmuls等底层向量指令的对应关系。指令概览与数学语义TMULS 执行Tile 与标量的逐元素乘法是向量化的标量乘scalar multiply操作将源 Tilesrc中有效区域内的每一个元素与标量scalar相乘结果写入目标 Tiledst的对应位置。对有效区域内的每个元素(i, j)数学语义为$$\mathrm{dst}{i,j} \mathrm{src}{i,j} \cdot \mathrm{scalar}$$需要说明的是TMULS 的“有效区域”Valid Region以dst的GetValidRow()与GetValidCol()作为迭代域即目标 Tile 的有效行列决定了实际参与运算的元素范围详见下文“约束与校验”。从指令族角度看TMULS 属于“标量二元运算”族与 TADDS、TSUBS、TDIVS 等并列它与逐元素二元运算 TMUL 的区别在于TMUL 的第二个操作数是另一个 Tile而 TMULS 的第二个操作数是单个标量值因此只需一次标量加载即可完成整块数据的缩放指令开销更低。汇编语法TMULS 在 PTO 汇编中同时提供同步形式与两级抽象层级AS Level 1 / AS Level 2的表示。同步形式%dst tmuls %src, %scalar : !pto.tile..., f32其中%scalar为标量值!pto.tile...表示 Tile 类型省略号处为具体形状、布局等类型参数f32为标量数据类型示例。AS Level 1SSA 形式Level 1 使用 SSA静态单赋值形式指令名带pto.前缀显式给出输入与输出的类型签名%dst pto.tmuls %src, %scalar : (!pto.tile..., dtype) - !pto.tile...AS Level 2DPS 形式Level 2 采用 DPS数据并行语义形式将操作数区分为ins(...)输入与outs(...)输出并显式标注tile_buf缓冲类型pto.tmuls ins(%src, %scalar : !pto.tile_buf..., dtype) outs(%dst : !pto.tile_buf...)C 内建接口TMULS 的 C 内建接口声明位于 include/pto/common/pto_instr.hpptemplate typename TileDataDst, typename TileDataSrc, typename... WaitEvents PTO_INST RecordEvent TMULS(TileDataDst dst, TileDataSrc src0, typename TileDataSrc::DType scalar, WaitEvents ... events);接口要点如下公共头文件pto/pto-inst.hpp为统一入口内部声明位于pto/common/pto_instr.hpp。参数说明dst目标 TileTileDataDst结果写入其中src0源 TileTileDataSrc其数据类型TileDataSrc::DType同时决定了标量scalar的类型scalar标量乘数类型为源 Tile 的元素类型events可变参数事件等待集合WaitEvents。返回值PTO_INST RecordEvent。接口会先执行detail::PtoWaitEvents(events...)等待前置事件再通过MAP_INSTR_IMPL(TMULS, dst, src0, scalar)映射到平台实现并返回一个RecordEvent供后续指令如TSTORE依赖同步。从 tests/npu/a5/src/st/testcase/tmuls/tmuls_kernel.cpp 可以看到典型的链式用法EventOp::TLOAD, Op::TMULS event0; EventOp::TMULS, Op::TSTORE_VEC event1; event0 TLOAD(srcTile, srcGlobal); event1 TMULS(dstTile, srcTile, scalar, event0); TSTORE(dstGlobal, dstTile, event1);与TMULS签名结构相同的指令还有TADDS、TSUBS、TDIVS等见 include/pto/common/pto_instr.hpp它们统一采用“目标 Tile、源 Tile、标量、事件列表”的参数次序便于记忆与迁移。约束与校验TMULS 在不同硬件平台上具有不同的数据类型支持与校验规则二者由编译期static_assert静态检查与运行期PTO_ASSERT动态检查共同保障。实现检查Atlas A2/A3 训练系列产品 / Atlas A2/A3 推理系列产品对应实现位于 include/pto/npu/a2a3/TMulS.hppTileData::DType必须是以下之一int32_t、int16_t、half、floatTile 位置必须是向量TileData::Loc TileType::Vec静态有效边界TileData::ValidRow TileData::Rows且TileData::ValidCol TileData::Cols运行时src0.GetValidRow() dst.GetValidRow()且src0.GetValidCol() dst.GetValidCol()Tile 布局必须是行主序TileData::isRowMajor。源码中对应的静态断言包括TileDataSrc::Loc TileType::Vec、TileDataDst::Loc TileType::Vec以及dst与src数据类型一致性的static_assert(std::is_same_vT, typename TileDataDst::DType, ...)运行期还会检查dstTile的validRow/validCol与src一致且均不为 0。实现检查Ascend 950PR / Ascend 950DT对应实现位于 include/pto/npu/a5/TMulS.hppTileData::DType必须是以下之一uint16_t、int16_t、uint32_t、int32_t、int64_t、uint64_t、half、float、bfloat16_tTile 位置必须是向量TileData::Loc TileType::Vec静态有效边界TileData::ValidRow TileData::Rows且TileData::ValidCol TileData::Cols运行时src0.GetValidCol() dst.GetValidCol()Tile 布局必须是行主序TileData::isRowMajor。对比可见Ascend 950 系列在数据类型上比 A2/A3 更宽额外支持uint16_t、uint32_t、int64_t、uint64_t、bfloat16_t且运行时仅要求ValidCol一致PTO_ASSERT(src0.GetValidCol() dst.GetValidCol(), ...)对ValidRow的一致性要求放宽。有效区域该操作使用dst.GetValidRow()/dst.GetValidCol()作为迭代域即有效行数与有效列数取自目标 Tile运算只作用于该范围内的元素超出部分不参与计算。使用示例自动模式Auto自动模式下Tile 的存储位置由编译器/运行时自动分配开发者只需声明 Tile 并调用指令#include pto/pto-inst.hpp using namespace pto; void example_auto() { using TileT TileTileType::Vec, float, 16, 16; TileT src, dst; TMULS(dst, src, 2.0f); }这里TileTileType::Vec, float, 16, 16声明了一个 16 行 16 列的 float 向量 TileTMULS(dst, src, 2.0f)将src每个元素乘以 2.0 写入dst。手动模式Manual手动模式下需要先用TASSIGN将 Tile 显式绑定到具体的地址如 Unified Buffer 地址再发射指令#include pto/pto-inst.hpp using namespace pto; void example_manual() { using TileT TileTileType::Vec, float, 16, 16; TileT src, dst; TASSIGN(src, 0x1000); TASSIGN(dst, 0x2000); TMULS(dst, src, 2.0f); }汇编示例ASM自动模式# 自动模式由编译器/运行时负责资源放置与调度。 %dst pto.tmuls %src, %scalar : (!pto.tile..., dtype) - !pto.tile...手动模式# 手动模式先显式绑定资源再发射指令。 # 可选当该指令包含 tile 操作数时 # pto.tassign %arg0, tile(0x1000) # pto.tassign %arg1, tile(0x2000) %dst pto.tmuls %src, %scalar : (!pto.tile..., dtype) - !pto.tile...PTO 汇编形式%dst tmuls %src, %scalar : !pto.tile..., f32 # AS Level 2 (DPS) pto.tmuls ins(%src, %scalar : !pto.tile_buf..., dtype) outs(%dst : !pto.tile_buf...)源码级实现原理A2/A3 平台实现include/pto/npu/a2a3/TMulS.hpp 中MulSOpT::BinSInstr直接封装底层向量标量乘法指令vmuls(dst, src0, src1, repeats, 1, 1, 8, 8); // 或带行步长版本 vmuls(dst, src0, src1, repeats, 1, 1, dstRepeatStride, srcRepeatStride);其中repeats表示重复次数dstRepeatStride/srcRepeatStride为行间步长以 repeat 为单位。TMulS函数通过__cce_get_tile_ptr获取 Tile 的 UB 地址按REPEAT_BYTE / sizeof(T)计算每 repeat 元素数、按BLOCK_BYTE_SIZE / sizeof(T)计算块大小再交给模板TBinSInstr按行/列遍历执行。Ascend 950 平台实现include/pto/npu/a5/TMulS.hpp 的实现更为精细常规类型非 64 位整数走BinaryInstrMulSOpT, ...路径MulSOpT::BinSInstr使用带谓词寄存器的向量指令vmuls(reg_dst, reg_src0, src1, preg, MODE_ZEROING);preg为掩码predicate寄存器MODE_ZEROING表示掩码外元素清零int64_t/uint64_t走独立的Int64Scalar路径见 include/pto/npu/a5/TBinSOp.hpp先将 64 位标量拆成高低两个 32 位vector_s32再用vmull低位乘 两次vmula交叉乘加组合实现 64 位乘法最后vintlv交错回 64 位数据并通过vsts写回。BinaryInstr见 include/pto/npu/a5/TBinSOp.hpp会依据 Tile 形状自动选择实现策略当ValidCol Cols整列有效或行数为 1 时走 1D 循环TBinOp1DSwitch否则走 2D 循环TBinOp2DSwitch同时支持VFImplKind指定的多种实现版本VFIMPL_1D/2D×POST_UPDATE/NO_POST_UPDATE默认版本为VFIMPL_DEFAULT。CPU 仿真实现include/pto/cpu/TBinSOps.hpp 提供了TMULS_IMPL的 CPU 仿真实现供 CPU 模拟器docs/coding/cpu_sim_zh.md与单元测试使用保证了同一份 kernel 代码可在无 NPU 环境下验证逻辑正确性。测试验证仓库为 TMULS 提供了跨平台、跨数据类型的测试覆盖CPU 测试tests/cpu/st/testcase/tmuls/tmuls_kernel.cpp 定义了 11 个 kernel 用例覆盖float、half、int32_t、int16_t、uint8_t、uint16_t、uint32_t、int64_t、uint64_tTile 形状从 7×448 到 256×16 不等tests/cpu/st/testcase/tmuls/main.cpp 使用 gtest 框架执行 kernel 并与 golden 数据比对ResultCmpT(golden, devFinal, 0.001f)。测试流程tests/cpu/st/testcase/tmuls/gen_data.py体现了完整的验证闭环以固定随机种子np.random.seed(23)生成随机输入input.bin生成随机标量并写入divider.bin以struct.pack(f, ...)保存为 float按output_arr[i, j] input_arr[i, j] * divider[0, 0]逐元素计算得到golden.binkernel 端通过TLOAD载入输入与标量 →TMULS计算 →TSTORE写出host 端读取output.bin与golden.bin比对。NPU 测试NPU 侧测试分布于各平台目录下例如 tests/npu/a5/src/st/testcase/tmuls/、tests/npu/a2a3/src/st/testcase/tmuls/、tests/npu/kirin9030/src/st/testcase/tmuls/ 等均包含tmuls_kernel.cpp、main.cpp与gen_data.py。A5 测试中还展示了“按列切块”by-col tile处理超宽矩阵的写法见 tests/npu/a5/src/st/testcase/tmuls/tmuls_kernel.cpp并演示了通过Event与set_flag/wait_flag在PIPE_MTE2搬入、PIPE_V向量计算、PIPE_MTE3搬出之间建立同步的正确流水模式。此外还有与 TROWSUM 组合的复合用例如tests/npu/a5/src/st/testcase/tmuls_trowsum/。小结TMULS 是 PTO 向量标量运算的核心指令本文从语义、语法、接口、约束、示例、实现与测试六个维度对其进行了完整剖析。实际编写 kernel 时请重点确认三点目标平台支持的数据类型A2/A3 与 950 系列不同、Tile 类型必须为TileType::Vec且行主序、以及dst/src有效区域的一致性要求。相关指令可进一步阅读 TMULTile 与 Tile 逐元素乘、TADDS、TSUBS 与 TDIVS 的文档它们在接口形态与实现模式上高度一致。【免费下载链接】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),仅供参考