[AI][昇腾950]Simd-VF 编程(2)
·
第三部分:数据搬入/搬出 API
3.1 LoadAlign —— 对齐搬入(vld)
原型(kernel_reg_compute_datacopy_intf.h):
// 基本形式:地址固定
template <typename T, LoadDist dist = DIST_NORM, typename U>
void LoadAlign(U& dstReg, __ubuf__ T* srcAddr);
// post-update:搬入后 srcAddr += postUpdateStride(单位:元素数)
template <typename T, PostLiteral postMode, LoadDist dist, typename U>
void LoadAlign(U& dstReg, __ubuf__ T*& srcAddr, int32_t postUpdateStride);
// AddrReg 偏移:从 srcAddr + areg 偏移处加载
template <typename T, LoadDist dist, typename U>
void LoadAlign(U& dstReg, __ubuf__ T* srcAddr, AddrReg offset);
// 双寄存器同时加载(dual issue,提升吞吐)
template <typename T, LoadDist dist, typename U>
void LoadAlign(U& dstReg0, U& dstReg1, __ubuf__ T* srcAddr);
最常用模式对比:
// 模式 A: 显式地址计算(最直观)
for (uint16_t i = 0; i < repeatTimes; ++i) {
AscendC::Reg::LoadAlign(xReg, xAddr + i * oneRepeatSize);
AscendC::Reg::StoreAlign(zAddr + i * oneRepeatSize, zReg, mask);
}
// 模式 B: post-update(推荐,硬件自动累加地址)
__ubuf__ T* xPtr = xAddr; // 注意必须用引用传递
__ubuf__ T* zPtr = zAddr;
for (uint16_t i = 0; i < repeatTimes; ++i) {
AscendC::Reg::LoadAlign<T, AscendC::Reg::PostLiteral::POST_MODE_UPDATE>(xReg, xPtr, oneRepeatSize);
AscendC::Reg::StoreAlign<T, AscendC::Reg::PostLiteral::POST_MODE_UPDATE>(zPtr, zReg, oneRepeatSize, mask);
}
// 循环结束后 xPtr 已自动累加到 xAddr + repeatTimes * oneRepeatSize
// 模式 C: AddrReg(地址复杂偏移)
for (uint16_t i = 0; i < repeatTimes; ++i) {
areg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
AscendC::Reg::LoadAlign(xReg, xAddr, areg);
AscendC::Reg::StoreAlign(zAddr, zReg, areg, mask);
}
LoadDist —— 数据分布模式(来自 kernel_reg_compute_utils.h):
| 模式 | 含义 | 典型用途 |
|---|---|---|
DIST_NORM(默认) |
连续加载 | 普通向量 |
DIST_BRC_B8/B16/B32 |
广播加载(每 8/16/32B 重复) | 标量广播到 lane |
DIST_US_B8/B16 |
上采样(每元素重复 2 次) | Upsample |
DIST_DS_B8/B16 |
下采样(取每隔 1 个元素) | Downsample |
DIST_BDINTLV / DIST_DINTLV_B8/B16/B32 |
解交织 | 双通道数据分离 |
DIST_UNPACK_B8/B16/B32 |
解压缩(窄位宽→宽位宽) | Cast 时小转大 |
DIST_SPLT4CHN_B8 / DIST_SPLT2CHN_B8/B16 |
通道分离 | NCHW → 分通道 |
DIST_BLK |
按 Block 加载 | 特殊对齐场景 |
DIST_E2B_B16/B32 |
2 字节扩展为 4/8 字节 | int16 → int32/int64 |
样例:Broadcast 加载(ld_st_reg_align.asc 场景 5):
AscendC::Reg::LoadAlign<T, AscendC::Reg::LoadDist::DIST_BRC_B16>(xReg, xAddr + i * oneRepeatSize);
// 等价于把 xAddr 处一个 16B 数据广播 16 次填满 256B 寄存器
样例:Upsample 加载(场景 6):
AscendC::Reg::LoadAlign<T, AscendC::Reg::LoadDist::DIST_US_B16>(xReg, xAddr + i * oneRepeatSize / 2);
// 加载 VL/2 数据,每个元素重复 2 次,得到 VL 长度结果
3.2 StoreAlign —— 对齐搬出(vst)
原型:
// 基本形式
template <typename T, StoreDist dist = DIST_NORM_B16, typename U>
void StoreAlign(__ubuf__ T* dstAddr, U& srcReg, MaskReg& mask);
// post-update
template <typename T, PostLiteral postMode, StoreDist dist, typename U>
void StoreAlign(__ubuf__ T*& dstAddr, U& srcReg, int32_t postUpdateStride, MaskReg& mask);
// AddrReg 偏移
template <typename T, StoreDist dist, typename U>
void StoreAlign(__ubuf__ T* dstAddr, U& srcReg, AddrReg offset, MaskReg& mask);
// Block strided(vsstb):跨步按 32B DataBlock 写
template <typename T, DataCopyMode dataMode, PostLiteral postMode, typename U>
void StoreAlign(__ubuf__ T*& dstAddr, U& srcReg, uint32_t dataBlockStride, uint32_t repeatStride, MaskReg& mask);
// 双寄存器同时写
template <typename T, StoreDist dist, typename U>
void StoreAlign(__ubuf__ T* dstAddr, U& srcReg0, U& srcReg1, MaskReg& mask);
StoreDist —— 写出分布模式:
| 模式 | 含义 |
|---|---|
DIST_NORM_B8/B16/B32 |
普通写出(按元素位宽) |
DIST_FIRST_ELEMENT_B8/B16/B32 |
只写第一个元素 |
DIST_PACK_B16/B32/B64 |
压缩写出(宽位宽→窄位宽,配合 Cast 大转小) |
DIST_INTLV_B8/B16/B32 |
交织写出(双通道合并) |
DIST_PACK4_B32 |
4 元素压缩为 1 个 32B |
DIST_MRG4CHN_B8 / DIST_MRG2CHN_B8/B16 |
4/2 通道合并写出 |
样例:Cast 时压缩写出(cast.asc 场景 2,float→int16_t):
AscendC::Reg::Cast<int16_t, float, castTrait>(yReg, xReg, mask);
AscendC::Reg::StoreAlign<int16_t, AscendC::Reg::PostLiteral::POST_MODE_UPDATE,
AscendC::Reg::StoreDist::DIST_PACK_B32>(yAddr, yReg, oneRepeatSize, mask);
// 64 个 float → 64 个 int16_t,每个 32B Block 只用低 16B,StoreDist PACK 让相邻 Block 数据紧凑存放
3.3 Block Strided 搬移(vsldb / vsstb)
当数据在 UB 中按 32B DataBlock 跨步排列时使用:
// 加载:从 srcAddr 开始,每 srcBlockStride 个 Block 取一个 Block,共取 8 个 Block 拼成 256B
AscendC::Reg::LoadAlign<T, AscendC::Reg::DataCopyMode::DATA_BLOCK_COPY,
AscendC::Reg::PostLiteral::POST_MODE_UPDATE>(
xReg, xAddr, srcBlockStride, srcBlockStride * oneRepeatDataBlock, mask);
// 写出:每 dstBlockStride 个 Block 写一个 Block
AscendC::Reg::StoreAlign<T, AscendC::Reg::DataCopyMode::DATA_BLOCK_COPY,
AscendC::Reg::PostLiteral::POST_MODE_UPDATE>(
zAddr, zReg, dstBlockStride, dstBlockStride * oneRepeatDataBlock, mask);
oneRepeatDataBlock = VL / 32B = 8(950PR 都是 8 个 Block 拼成 256B)。
3.4 Load / Store —— 简化形式
不依赖 MaskReg 的轻量搬移,适合编译期已知对齐且全量的场景:
template <typename T, typename U> void Load(U& dstReg, __ubuf__ T* srcAddr);
template <typename T, typename U> void Store(__ubuf__ T* dstAddr, U& srcReg);
template <typename T, typename U> void Store(__ubuf__ T* dstAddr, U& srcReg, uint32_t count);
3.5 LoadUnAlign / StoreUnAlign —— 非对齐搬移
用于输出长度非对齐或需要紧凑存储的场景,必须配 UnalignRegForLoad/Store:
AscendC::Reg::UnalignRegForLoad uregL;
AscendC::Reg::LoadUnAlignPre<T>(uregL, srcAddr); // 预取跨边界数据
AscendC::Reg::LoadUnAlign<T, AscendC::Reg::PostLiteral::POST_MODE_UPDATE>(
dstReg, uregL, srcAddr, postUpdateStride); // 拼接加载
AscendC::Reg::UnalignRegForStore uregS;
AscendC::Reg::StoreUnAlign<T, AscendC::Reg::PostLiteral::POST_MODE_UPDATE>(
dstAddr, srcReg, uregS, postUpdateStride); // 非对齐写(缓存尾部)
AscendC::Reg::StoreUnAlignPost(dstAddr, uregS); // 循环结束后刷出残留
3.6 MaskReg 搬入/搬出(pld/plds/pst/psts/pstu)
Mask 寄存器本身也可在 UB 中保存/恢复:
AscendC::Reg::LoadAlign(mask, maskAddr, aregOffset); // pld
AscendC::Reg::LoadAlign(mask, maskAddr); // plds
AscendC::Reg::StoreAlign(maskAddr, mask, aregOffset); // pst
AscendC::Reg::StoreAlign(maskAddr, mask); // psts
AscendC::Reg::StoreUnAlign(maskAddr, mask, ureg); // pstu
3.7 Gather / Scatter —— 离散访问
Gather 按寄存器中的 index 从 UB 取散列数据,Scatter 反向写:
// vgather2: dstReg[i] = baseAddr[indexReg[i]], mask 控制哪些 lane 参与
template <typename T0, typename T1, typename T2, typename T3, typename T4>
void Gather(T3& dstReg, __ubuf__ T1* baseAddr, T4& index, MaskReg& mask);
// vgatherb: 类似但 index 按 Block 单位
template <typename T, typename U, typename S>
void GatherB(U& dstReg, __ubuf__ T* baseAddr, S& index, MaskReg& mask);
// vscatter: baseAddr[indexReg[i]] = srcReg[i]
template <typename T, typename U, typename S, typename V>
void Scatter(__ubuf__ T* baseAddr, S& srcReg, V& index, MaskReg& mask);
适用场景:Embedding 查表、稀疏 attention、ROI Align 等不规则访问。
3.8 Move —— 寄存器间搬移
template <typename T, typename U> void Move(U& dstReg, U& srcReg, MaskReg& mask);
寄存器之间的数据拷贝,配合 mask 可做 lane 选择。
更多推荐



所有评论(0)