Contiguous Non-aligned Data Move-out

Applicability

Product

Supported

Atlas 350 Accelerator Card

Atlas A3 training product/Atlas A3 inference product

x

Atlas A2 training product/Atlas A2 inference product

x

Atlas 200I/500 A2 inference product

x

Atlas inference product AI Core

x

Atlas inference product Vector Core

x

Atlas training product

x

Function Usage

Indicates the Reg vector computation data movement interface, and is used to move non-contiguous aligned data from RegTensor to UB.

Prototype

// Scenario 1: Use uint32_t as the storage offset and use the post mode for data movement. The address of the destination operand in the UB is updated each time the API is called.
template <typename T = DefaultType, PostLiteral postMode = PostLiteral::POST_MODE_UPDATE, typename U>
__simd_callee__ inline void StoreUnAlign(__ubuf__ T*& dstAddr, U& srcReg, UnalignRegForStore& ureg, uint32_t postUpdateStride); 

// Process the tail block of non-aligned data movement. This is applicable to scenario 1.
template <typename T, PostLiteral postMode = PostLiteral::POST_MODE_UPDATE>
__simd_callee__ inline void StoreUnAlignPost(__ubuf__ T*& dstAddr, UnalignRegForStore& ureg, int32_t postUpdateStride);

// Scenario 2: Use AddrReg to store the offset for data movement and use the post mode for data movement. The address of the destination operand in the UB is updated each time the API is called.
template <typename T = DefaultType, PostLiteral postMode = PostLiteral::POST_MODE_UPDATE, typename U>
__simd_callee__ inline void StoreUnAlign(__ubuf__ T*& dstAddr, U& srcReg, UnalignRegForStore& ureg, AddrReg& areg);
// Process the tail block of non-aligned data movement. This is applicable to scenario 2.
template <typename T>
__simd_callee__ inline void StoreUnAlignPost(__ubuf__ T*& dstAddr, UnalignRegForStore& ureg, AddrReg& areg);

// Scenario 3: Use this API together with Squeeze for contiguous non-aligned move-out. The SqueezeReg vector computation API stores the total number of bytes of valid elements to the AR special register. When this API is used, the number of valid elements in the AR register is used as the storage offset.
template <typename T = DefaultType, PostLiteral postMode = PostLiteral::POST_MODE_UPDATE, typename U>
__simd_callee__ inline void StoreUnAlign(__ubuf__ T* dstAddr, U& srcReg, UnalignRegForStore& ureg);

// Process the tail block of non-aligned data movement. This is applicable to scenario 3.
template <typename T>
__simd_callee__ inline void StoreUnAlignPost(__ubuf__ T* dstAddr, UnalignRegForStore& ureg);

Parameters

Table 1 Using int32_t to store the offset in the contiguous non-aligned data move-out mode

Parameter

Input/Output

Description

T

Input

Template parameter. The supported data types are b8, b16, b32, and b64.

postMode

Input

This parameter controls whether to enable post update. The value is of the PostLiteral type.

U

Input

Template parameter. The corresponding RegTensor type for the data types supported by template parameter T.

ureg

Input/Output

UnalignRegForStore: non-aligned register, which is used to store non-aligned data. The length is 32 bytes. It is used as an input/output in the StoreUnAlign function and as an input in the StoreUnAlignPost function.

srcReg

Input

Source operand, which is of the RegTensor type.

dstAddr

Input/Output

Start address of the destination operand in the UB.

postUpdateStride

Input

The meaning of postUpdateStride is different under the POST_MODE_NORMAL and POST_MODE_UPDATE scenarios.

  • POST_MODE_NORMAL scenario: The actual UB start address for the movement is dstAddr, and the number of elements to be moved is postUpdateStride.
  • POST_MODE_UPDATE scenario: The actual UB start address for the movement is dstAddr, and the number of elements to be moved is postUpdateStride. After the movement, the address is updated as follows: dstAddr += postUpdateStride.
Table 2 Using AddrReg to store the offset in the contiguous non-aligned data move-out mode

Parameter

Input/Output

Description

ureg

Input/Output

UnalignRegForStore: non-aligned register, which is used to store non-aligned data. The length is 32 bytes. It is used as an input/output in the StoreUnAlign function and as an input in the StoreUnAlignPost function.

srcReg

Input

Source operand, which is of the RegTensor type.

dstAddr

Input/Output

Start address of the destination operand in the UB.

areg

Input

The actual UB start address for data movement is of the AddrReg data type, which stores the address offset. The actual UB start address for the movement is computed as: srcAddr + offset.

Table 3 Parameters in the scenario where Squeeze is used

Parameter

Input/Output

Description

dstAddr

Input/Output

Start address of the destination operand in the UB.

ureg

Input/Output

UnalignRegForStore: non-aligned register, which is used to store non-aligned data. The length is 32 bytes. It is used as an input/output in the StoreUnAlign function and as an input in the StoreUnAlignPost function.

srcReg

Input

Source operand, which is of the RegTensor type.

Restrictions

  • The dstAddr parameter in this API does not need to be 32-byte aligned.
  • The StoreUnAlign and StoreUnAlignPost interfaces must be used together.

Examples

// Use uint32_t to store the offset in the contiguous non-aligned data move-out mode.
template <typename T>
__simd_vf__ inline void StoreUnAlignVF(__ubuf__ T* dstAddr, __ubuf__ T* srcAddr, uint32_t postUpdateStride, uint16_t repeatTimes)
{
    AscendC::Reg::RegTensor<T> srcReg;
    AscendC::Reg::UnalignRegForLoad ureg0;
    AscendC::Reg::UnalignRegForStore ureg1;
    for (uint16_t i = 0; i < repeatTimes; ++i) {
        AscendC::Reg::LoadUnAlignPre(ureg0, srcAddr + i * postUpdateStride);
        AscendC::Reg::LoadUnAlign(srcReg, ureg0, srcAddr + i * postUpdateStride);
        AscendC::Reg::StoreUnAlign(dstAddr, srcReg, ureg1, postUpdateStride);
    }
    AscendC::Reg::StoreUnAlignPost(dstAddr, ureg1, 0);
}

// Use AddrReg to store the offset in the contiguous non-aligned data move-out mode.
template <typename T>
__simd_vf__ inline void StoreUnAlignVF(__ubuf__ T* dstAddr, __ubuf__ T* srcAddr, uint32_t oneRepeatSize, uint16_t repeatTimes)
{
    AscendC::Reg::RegTensor<T> srcReg;    
    AscendC::Reg::UnalignRegForLoad ureg0;
    AscendC::Reg::UnalignRegForStore ureg1;
    AscendC::Reg::AddrReg aReg;
    for (uint16_t i = 0; i < (uint16_t)repeatTimes; ++i) {
        aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
        AscendC::Reg::LoadUnAlignPre(ureg0, srcAddr, aReg);
        AscendC::Reg::LoadUnAlign(srcReg, ureg0, srcAddr, aReg, 0);
        AscendC::Reg::StoreUnAlign(dstAddr, srcReg, ureg1, aReg);
    }
    AscendC::Reg::StoreUnAlignPost(dstAddr, ureg1, aReg);
}

// Used with Squeeze. For contiguous non-aligned move-out, the SqueezeReg vector computation API stores the total number of bytes of valid elements to the AR register, and uses the number of valid elements in the AR register as the storage offset.
template <typename T>
__aicore__ inline void SqueezeVF(__ubuf__ T* dstAddr, __ubuf__ T* srcAddr, uint32_t oneRepeatSize, uint16_t repeatTimes)
{
    AscendC::Reg::RegTensor<T> srcReg0;
    AscendC::Reg::RegTensor<T> srcReg1;
    AscendC::Reg::UnalignRegForStore ureg;
    AscendC::Reg::MaskReg mask = AscendC::Reg::CreateMask<T, AscendC::Reg::MaskPattern::H>();
    for (uint16_t i = 0; i < repeatTimes; ++i) {
        AscendC::Reg::LoadAlign<T, AscendC::Reg::PostLiteral::POST_MODE_UPDATE>(srcReg0, srcAddr, oneRepeatSize);
        AscendC::Reg::Squeeze<T, AscendC::Reg::GatherMaskMode::STORE_REG>(srcReg1, srcReg0, mask);
        AscendC::Reg::StoreUnAlign<T, AscendC::Reg::PostLiteral::POST_MODE_UPDATE>(dstAddr, srcReg1, ureg);
     }
     AscendC::Reg::StoreUnAlignPost(dstAddr, ureg);
}