第三部分:数据搬入/搬出 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 选择。


Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐