ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

PyPTO vf.move 寄存器搬运指令详解:reg_tensor 与 mask_reg 双模式语义、参数与实战示例

PyPTO vf.move 寄存器搬运指令详解:reg_tensor 与 mask_reg 双模式语义、参数与实战示例 人工智能编译器模型编译高性能计算深度学习CANN【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址https://gitcode.com/cann/pypto点击查看免费下载vf.move 是 PyPTO 向量函数Vector FunctionVF体系中用于寄存器间数据搬运的核心指令负责将源操作数 src 中的元素或比特位复制到目标操作数 dst 的对应位置是 VF 数据流中承接vf.load_align与vf.store_align的关键中间操作。本文基于当前仓库 move.md 文档结合 vf 接口源码 与 VF 测试用例完整讲解vf.move在 reg_tensorvmov与 mask_regpmov两种模式下的语义、参数、约束与可复制的完整调用示例帮助开发者正确地在 Vector 流水线中编排寄存器复制逻辑。功能说明两种寄存器类型的搬运语义vf.move将源操作数src中的元素复制到目标操作数dst的对应位置。它同时支持 reg_tensor 和 mask_reg 两种寄存器类型二者语义差异显著reg_tensor 模式对应底层 vmov 指令对src中的有效元素逐个复制写入dst中对应位置无效位置保留dst原值。等价于纯寄存器拷贝dstReg_i srcReg_i。mask_reg 模式对应底层 pmov 指令将src中的 bit 复制到dst中对应位置。如果有输入 maskpreg则仅复制被 mask 选定的有效 bit无效位置填 0。mask_reg 模式的位复制机制如上图所示其展开粒度与数据类型强相关16 位宽类型DT_INT16、DT_UINT16、DT_FP16、DT_BF16读取完整 128 bit 的{MASK1, MASK0}将每个 bit 复制为 2 bitb16 粒度32 位宽类型DT_INT32、DT_UINT32、DT_FP32读取 64 bit 的MASK0将每个 bit 复制为 4 bitb32 粒度。这一粒度差异与 mask_reg 文档中总位宽固定为 256 bit、由 dtype 决定每个元素对应多少掩码位的机制完全一致b16 粒度下 128 个元素 × 2 bit 256 bitb32 粒度下 64 个元素 × 4 bit 256 bit。产品支持情况vf.move的产品支持矩阵如下与当前仓库文档一致产品支持情况Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品不支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品不支持即当前vf.move以及整个 VF 寄存器计算体系仅面向 Ascend 950 系列架构提供支持在使用前需确认目标设备属于该产品线。函数原型与参数说明函数原型move(src, preg, mode: Optional[MergeMode] None) - dst参数说明参数输入/输出说明src输入源操作数reg_tensor 或者 mask_reg 类型源操作数 src 与目的操作数 dst 的数据类型保持一致。支持的数据类型为DT_BOOL、DT_INT8、DT_UINT8、DT_INT16、DT_UINT16、DT_FP16、DT_BF16、DT_INT32、DT_UINT32、DT_FP32、DT_INT64、DT_UINT64。preg输入mask_reg。控制哪些元素/bit 参与操作-reg_tensor 模式preg 为元素操作的有效指示。preg 选中的位置将 src 中对应元素复制写入 dstpreg 未选中的位置dst 保留原值。-mask_reg 模式preg 控制哪些 bit 有效。preg 选中的 bit将 src 中对应 bit 复制到 dstpreg 未选中的 bitdst 对应位置填 0。mode输入可选对应 MergeMode 类型。-pypto_pro.language.MergeMode.MERGING默认preg 未选中的元素在 dst 中保留原值。-pypto_pro.language.MergeMode.ZEROING当前不支持。返回值说明返回dst目的操作数reg_tensor 或者 mask_reg 类型支持的数据类型与src中的说明一致即 src 与 dst 类型保持一致。约束说明无额外约束。需要说明的是src与dst数据类型必须一致在 reg_tensor 模式下若创建寄存器后未通过vf.load_align或vf.full初始化内容为未定义值该约束来自 reg_tensor 文档。关于 MergeMode 的进一步说明vf.move的 mode 参数取值定义在 MergeMode 枚举中。从仓库中该枚举文档可以看到MergeMode 是 VF 计算指令族通用的掩码处理策略ZEROING表示 mask 未选中位置置零MERGING表示 mask 未选中位置保留目标寄存器原值。注意与vf.add、vf.sub、vf.mul、vf.div等计算指令默认采用ZEROING不同vf.move的默认值是MERGING未选中位置保留 dst 原值且当前仅支持MERGINGZEROING模式在vf.move上暂未开放。从源码理解 vf.move 的底层实现接口声明python 侧vf.move的 Python 接口声明位于 python/pypto_pro/language/_vf_api.py 的vf类中约 L1931 起。其 docstring 明确写明了底层指令与语义RegTensor 场景对应vmov指令将 src 的有效元素复制到 dst被 mask 遮掉的位置保留 dst 原值MODE_MERGINGMaskReg 场景对应pmov指令将 src 的 bit 复制到 dst带 mask 时仅复制被选中的 bit。语义表达式为dstReg_i srcReg_i并支持 b8/b16/b32/b64 四种元素位宽。四种调用形式在 docstring 中均有说明# RegTensor with mask dst vf.move(src_reg, preg) # RegTensor without mask dst vf.move(src_reg) # MaskReg with mask dst vf.move(src_mask, preg) # MaskReg without mask dst vf.move(src_mask)可见preg参数是可省略的不传 mask 时执行全量复制传 mask 时按 mask 语义执行reg_tensor 保留原值 / mask_reg 未选中位填 0。与 Tile 级 pl.move 的区分仓库中还存在一个Tile 级的pl.move声明于 python/pypto_pro/language/_api.py L243 起二者易混淆但作用域完全不同vf.move(src, preg, mode)寄存器级搬运作用于 VF 函数内的 reg_tensor / mask_reg运行在 Vector 流水线V 流水线上pl.move(dst_tile, src_tile, offset, ...)Tile 级搬运作用于片上 Tile如 Acc(L0C)→Vec(UB)、Mat(L1)→Left(L0A)、Vec(UB)→Mat(L1) 等路径支持acc_to_vec_mode、relu_pre_mode、scale等融合选项。编写 kernel 时若在pl.vector_function内部处理寄存器数据应使用vf.move若在pl.jit主函数中做 Tile 间搬移则使用pl.move。位宽展开与寄存器容量vf.move支持的 b8/b16/b32/b64 位宽与 reg_tensor 的容量表对应寄存器总大小固定为 256 字节DT_INT8/DT_UINT8 等 8 bit 类型容纳 256 个元素16 bit 类型容纳 128 个元素32 bit 类型容纳 64 个元素64 bit 类型容纳 32 个元素。这也是 mask_reg 模式每 bit 展开为 2 bit/4 bit的硬件基础。完整调用示例以下四个示例均可在 Ascend 950 系列设备上直接运行并给出了完整的 host 侧测试与 golden 校验逻辑。示例一reg_tensor 模式将 FP32 数据从 src Tile 加载到寄存器经vf.move全量复制preg 为MaskPattern.ALL即所有元素有效同时演示 mask_reg 的vf.move将ALL掩码搬运为ALLF掩码最后 store 回 dst Tileimport os import pypto_pro.language as pl import torch import torch_npu pl.vector_function def example_vf(src_tile, dst_tile): preg vf.create_mask(patternpl.MaskPattern.ALL, dtypepl.DT_FP32) reg_a vf.load_align(src_tile, 0) reg_b vf.move(reg_a, preg) src_mask vf.create_mask(patternpl.MaskPattern.ALL, dtypepl.DT_FP32) dst_mask vf.create_mask(patternpl.MaskPattern.ALLF, dtypepl.DT_FP32) dst_mask vf.move(src_mask) vf.store_align(dst_tile, reg_b, dst_mask) pl.jit() def example_kernel( a: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], out: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], ): tf pl.TileType(shape[1, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec) in_a_grp pl.make_tile_group(typetf, addrs0x0, mutex_ids[0]) in_a in_a_grp.current() t_out_grp pl.make_tile_group(typetf, addrs0x100, mutex_ids[1]) t_out t_out_grp.current() with pl.section_vector(): pl.load(in_a, a, [0, 0]) example_vf(in_a, t_out) pl.store(out, t_out, [0, 0]) def test_example(): device_id int(os.environ.get(TILE_FWK_DEVICE_ID, 0)) device fnpu:{device_id} core_nums 1 torch.npu.set_device(device) a torch.randn([1, 64], devicedevice, dtypetorch.float32) out torch.empty([1, 64], devicedevice, dtypetorch.float32) example_kernelNone, core_nums torch.npu.synchronize() torch.testing.assert_close(out, a, rtol1e-5, atol1e-5) if __name__ __main__: test_example() print(PASSED)关键点vf.create_mask(patternpl.MaskPattern.ALL, ...)创建全有效 maskvf.move(reg_a, preg)将寄存器内容整体复制vf.move(src_mask)省略 preg 参数直接对 mask_reg 做 bit 搬运。host 侧通过torch.testing.assert_close(out, a)验证输入输出完全一致。示例二mask_reg 模式条件掩码搬运先通过vf.ge生成元素 ≥ 0的 mask再用vf.move将 mask 复制随后以复制出的 mask 作为vf.abs的有效性控制——等价于对非负元素取绝对值、负元素置 0 的 ReLU 语义import os import pypto_pro.language as pl import torch import torch_npu pl.vector_function def example_vf(src_tile, dst_tile): preg vf.create_mask(patternpl.MaskPattern.ALL, dtypepl.DT_FP32) reg vf.load_align(src_tile, 0) mask_a vf.ge(reg, 0.0, preg) dst_mask vf.move(mask_a) reg_dst vf.abs(reg, dst_mask) vf.store_align(dst_tile, reg_dst, preg) pl.jit() def example_kernel( a: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], out: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], ): tf pl.TileType(shape[1, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec) in_a_grp pl.make_tile_group(typetf, addrs0x0, mutex_ids[0]) in_a in_a_grp.current() t_out_grp pl.make_tile_group(typetf, addrs0x100, mutex_ids[1]) t_out t_out_grp.current() with pl.section_vector(): pl.load(in_a, a, [0, 0]) example_vf(in_a, t_out) pl.store(out, t_out, [0, 0]) def test_example(): device_id int(os.environ.get(TILE_FWK_DEVICE_ID, 0)) device fnpu:{device_id} core_nums 1 torch.npu.set_device(device) a torch.randn([1, 64], devicedevice, dtypetorch.float32) out torch.empty([1, 64], devicedevice, dtypetorch.float32) example_kernelNone, core_nums torch.npu.synchronize() expected torch.where(a 0, a, torch.zeros_like(a)) torch.testing.assert_close(out, expected, rtol1e-5, atol1e-5) if __name__ __main__: test_example() print(PASSED)该示例在仓库测试 test_vf_basic_ops.py 中有同类实现_vf_kernel_67_mask_mov_sel_0mask_a vf.ge(reg_a, 0.0, preg)→preg_mov vf.move(mask_a, preg)→reg_dst vf.abs(reg_a, preg_mov)可对照验证 mask 搬运后再参与计算的标准写法。示例三reg_tensor 模式 FP8 数据类型演示 FP8 → FP32 的转换链vf.load_align以DT_FP8E4M3FN类型加载vf.astype转 FP32再经vf.move复制。注意此处 FP8 Tile 形状为[1, 256]8 bit 类型每寄存器容纳 256 个元素而 FP32 输出 Tile 为[1, 64]转换后元素数收缩为 1/4golden 校验需对期望值做[:, ::4]步进采样import os import pypto_pro.language as pl import torch import torch_npu pl.vector_function def example_vf_fp8(src_tile, dst_tile): preg vf.create_mask(patternpl.MaskPattern.ALL, dtypepl.DT_FP32) reg_f8 vf.load_align(src_tile, 0, dtypepl.DT_FP8E4M3FN) reg_f32 vf.astype(reg_f8, preg, dtypepl.DT_FP32) reg_dst vf.move(reg_f32, preg) vf.store_align(dst_tile, reg_dst, preg) pl.jit() def example_kernel_fp8( a: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP8E4M3FN], out: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_FP32], ): tf_in pl.TileType(shape[1, 256], dtypepl.DT_FP8E4M3FN, target_memorypl.MemorySpace.Vec) tf_out pl.TileType(shape[1, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec) in_a_grp pl.make_tile_group(typetf_in, addrs0x0, mutex_ids[0]) in_a in_a_grp.current() t_out_grp pl.make_tile_group(typetf_out, addrs0x100, mutex_ids[1]) t_out t_out_grp.current() with pl.section_vector(): pl.load(in_a, a, [0, 0]) example_vf_fp8(in_a, t_out) pl.store(out, t_out, [0, 0]) def test_example_fp8(): device_id int(os.environ.get(TILE_FWK_DEVICE_ID, 0)) device fnpu:{device_id} core_nums 1 torch.npu.set_device(device) a torch.randn([1, 256], devicedevice, dtypetorch.float32).to(torch.float8_e4m3fn) out torch.empty([1, 64], devicedevice, dtypetorch.float32) example_kernel_fp8None, core_nums torch.npu.synchronize() expected a.to(torch.float32) torch.testing.assert_close(out, expected[:, ::4], rtol1e-2, atol1e-2) if __name__ __main__: test_example_fp8() print(PASSED)结合 reg_tensor 文档的约束可知FP8 属于仅支持搬运、填充和类型转换的存储型数据不能直接参与算术运算必须先vf.astype转成 FP32/BF16/FP16 再计算——这正是本示例的技术背景。示例四INT64 数据类型示例vf.move对 64 bit 整数类型的直接搬运。INT64 Tile 形状[1, 32]每寄存器 32 个元素golden 用rtol0, atol0精确比对import os import pypto_pro.language as pl import torch import torch_npu pl.vector_function def example_vf_int64(src_tile, dst_tile): preg vf.create_mask(patternpl.MaskPattern.ALL, dtypepl.DT_INT64) reg_a vf.load_align(src_tile, 0) reg_out vf.move(reg_a, preg) vf.store_align(dst_tile, reg_out, preg) pl.jit() def example_kernel_int64( a: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_INT64], out: pl.Tensor[[pl.DYNAMIC, pl.DYNAMIC], pl.DT_INT64], ): tf pl.TileType(shape[1, 32], dtypepl.DT_INT64, target_memorypl.MemorySpace.Vec) in_a_grp pl.make_tile_group(typetf, addrs0, mutex_ids[0]) in_a in_a_grp.current() t_out_grp pl.make_tile_group(typetf, addrs256, mutex_ids[1]) t_out t_out_grp.current() with pl.section_vector(): pl.load(in_a, a, [0, 0]) example_vf_int64(in_a, t_out) pl.store(out, t_out, [0, 0]) def test_example_int64(): device_id int(os.environ.get(TILE_FWK_DEVICE_ID, 0)) device fnpu:{device_id} core_nums 1 torch.npu.set_device(device) a torch.randint(-100, 100, [1, 32], devicedevice, dtypetorch.int64) out torch.empty([1, 32], devicedevice, dtypetorch.int64) example_kernel_int64None, core_nums torch.npu.synchronize() torch.testing.assert_close(out, a, rtol0, atol0) if __name__ __main__: test_example_int64() print(PASSED)测试用例佐证仓库的 VF 前端测试 python/tests/st/pypto_pro/frontend/vf_api/test_vf_basic_ops.py 中覆盖了vf.move的多种组合场景可作为理解与验证的参考纯 copy 场景约 L525-L534_vf_kernel_11_copy_madd_0中reg_dst vf.move(reg_a, preg)后直接vf.store_align验证 reg_tensor 全量复制mask 搬运后参与计算约 L2584-L2595_vf_kernel_67_mask_mov_sel_0中preg_mov vf.move(mask_a, preg)后用vf.abs(reg_a, preg_mov)与本文示例二逻辑一致其余多处如 L1457、L1504、L1647、L2589、L2913-L2917分别覆盖vf.move在mul_add_dst、mask 逻辑运算and/or/xor/not等复合 VF 流程中的用法验证了该指令在真实算子流水中的可组合性。使用建议与注意事项确认硬件平台vf.move仅支持 Ascend 950PR/Ascend 950DTA2/A3 系列产品不支持编写 kernel 前先确认部署设备。src 与 dst 类型必须一致文档明确要求源操作数与目的操作数数据类型保持一致混用类型需先vf.astype转换。mode 参数当前仅支持 MERGINGreg_tensor 模式下未选中的 dst 位置保留原值这是默认也是唯一受支持的行为ZEROING暂不可用。若需要未选中位置置 0应显式构造全有效 mask 或改用vf.select/vf.abs等计算指令配合 mask 实现。mask_reg 模式的位展开规律16 位类型每 bit 展开为 2 bit读取{MASK1, MASK0}共 128 bit32 位类型每 bit 展开为 4 bit读取MASK0共 64 bit搬运前后 mask 的有效元素密度会随 dtype 变化理解这一机制有助于推导 mask 运算的期望结果。区分 vf.move 与 pl.moveVF 函数内寄存器搬运用vf.moveTile 级跨存储空间的搬移用pl.move支持 fix/mte1/mte3 等多流水路径与量化融合二者接口签名与作用域均不同。寄存器资源reg_tensor 数量上限 32、mask_reg 数量上限 16超出上限的数据会落入预留的 8K UB 内存并可能引起性能劣化编译器会自动复用生命周期结束的寄存器编写长 VF 函数时注意及时结束寄存器生命周期。总结vf.move是 PyPTO VF 编程模型中最基础也是最高频的寄存器数据搬运原语reg_tensor 模式下以vmov实现带掩码的元素复制未选中保留原值mask_reg 模式下以pmov实现带掩码的 bit 复制未选中填 0并支持 b8/b16/b32/b64 四种位宽粒度。本文结合接口源码与仓库测试完整还原了其参数语义、位展开机制与四种典型调用范式FP32 全量复制、条件 mask 搬运、FP8 转换搬运、INT64 精确搬运开发者可直接将示例作为模板集成到自己的 Vector 算子流水线中并通过仓库测试用例进一步验证组合用法。赞分享人工智能编译器模型编译高性能计算深度学习CANN【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址https://gitcode.com/cann/pypto点击查看免费下载相关推荐PyPTO vf.xor 寄存器按位异或接口详解函数原型、MergeMode 语义与 reg_tensor/mask_reg 双形态实战PyPTO vf.xor 寄存器按位异或接口详解函数原型、MergeMode 语义与 reg_tensor/mask_reg 双形态实战 导读 vf.xor人工智能编译器模型编译高性能计算深度学习CANNPyPTO SIMD-API 数据压缩指令 vf.pack 详解reg_tensor 与 mask_reg 双模式实现与实战PyPTO SIMD API 数据压缩指令 vf.pack 详解reg_tensor 与 mask_reg 双模式实现与实战 导读 vf.pack 是 PyP人工智能编译器模型编译高性能计算深度学习CANNPyPTO vf.mul_add_dst 寄存器级乘加融合FMA指令详解语义、参数与实战PyPTO vf.mul_add_dst 寄存器级乘加融合FMA指令详解语义、参数与实战 导读 vf.mul_add_dst 是 CANN PyPTO 向人工智能编译器模型编译高性能计算深度学习CANN上一篇Obsidian.nvim模板系统完全指南自定义变量与动态内容替换终极教程下一篇如何快速配置Jellyfin字幕管理新手完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

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