* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
* NOTE: Portions of this code were AI-generated and have been
* technically reviewed for functional accuracy and security
*/
#ifndef ACTS_ULQ_KERNEL_H_
#define ACTS_ULQ_KERNEL_H_
#include "kernel_operator.h"
#include "acts_ulq_tiling_struct.h"
#include "acts_ulq_struct.h"
__aicore__ inline void GetCoreRange(int64_t core_id, int64_t tiles_main, int64_t cores_tail, int64_t& start,
int64_t& end)
{
if (core_id < cores_tail) {
start = core_id * (tiles_main + 1);
end = start + tiles_main + 1;
} else {
start = cores_tail * (tiles_main + 1) + (core_id - cores_tail) * tiles_main;
end = start + tiles_main;
}
}
__aicore__ inline int64_t GetUBSplitRange(int64_t a_o_off, int64_t a_o, int64_t a_i, int64_t a_i_tail)
{
return (a_o_off == a_o - 1) ? a_i_tail : a_i;
}
__aicore__ inline bool FlatToEffectiveCoord(int64_t flat, const int64_t* max_bro_shape, int64_t rank,
int64_t split_axis, int64_t a_i, int64_t a_o, int64_t* eff_coord)
{
for (int64_t d = 0; d < rank; d++)
eff_coord[d] = 0;
int64_t a_o_off = flat % a_o;
int64_t outer = flat / a_o;
for (int64_t d = split_axis - 1; d >= 0; d--) {
eff_coord[d] = outer % max_bro_shape[d];
outer /= max_bro_shape[d];
}
eff_coord[split_axis] = a_o_off * a_i;
return true;
}
__aicore__ inline int64_t CalcInputOffset(const int64_t* eff_coord, const int64_t* strides, int64_t rank)
{
int64_t offset = 0;
for (int64_t d = 0; d < rank; d++)
offset += eff_coord[d] * strides[d];
return offset;
}
__aicore__ inline int64_t CalcOutputOffset(const int64_t* eff_coord, const int64_t* strides, int64_t rank)
{
int64_t offset = 0;
for (int64_t d = 0; d < rank; d++)
offset += eff_coord[d] * strides[d];
return offset;
}
__aicore__ inline int64_t CalcOutputTransferCount(const int64_t* normal_shape, int64_t rank, int64_t split_axis,
int64_t a_i_seg)
{
int64_t split_elems = (normal_shape[split_axis] == 1) ? 1 : a_i_seg;
int64_t inner_elems = 1;
for (int64_t d = split_axis + 1; d < rank; d++)
inner_elems *= normal_shape[d];
return split_elems * inner_elems;
}
template <typename T>
__simd_vf__ inline void MinsVF(__ubuf__ T* dstAddr, T scalar, uint32_t count, uint32_t oneRepeatSize,
uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void MaxsVF(__ubuf__ T* dstAddr, T scalar, uint32_t count, uint32_t oneRepeatSize,
uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void ScaleVF(__ubuf__ T* dstAddr, __ubuf__ T* srcMinAddr, __ubuf__ T* srcMaxAddr, T invStep,
uint32_t count, uint32_t oneRepeatSize, uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void ClipBoundsVF(__ubuf__ T* clipMinAddr, __ubuf__ T* clipMaxAddr, __ubuf__ T* oriClipMinAddr,
__ubuf__ T* scaleAddr, T step, uint32_t count, uint32_t oneRepeatSize,
uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void LossMVF(__ubuf__ T* dstAddr, __ubuf__ T* oriClipMinAddr, __ubuf__ T* scaleAddr, T invStep,
uint32_t count, uint32_t oneRepeatSize, uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void ClampVF(__ubuf__ T* dstAddr, __ubuf__ T* dataAddr, __ubuf__ T* clipMinAddr,
__ubuf__ T* clipMaxAddr, uint32_t count, uint32_t oneRepeatSize, uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void MaskMinVF(__ubuf__ T* dstAddr, __ubuf__ T* dataAddr, __ubuf__ T* clipMinAddr, uint32_t count,
uint32_t oneRepeatSize, uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void MaskMaxVF(__ubuf__ T* dstAddr, __ubuf__ T* dataAddr, __ubuf__ T* clipMaxAddr, uint32_t count,
uint32_t oneRepeatSize, uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void QuantVF(__ubuf__ T* roundXAddr, __ubuf__ T* clampedLossAddr, __ubuf__ T* clampedXAddr,
__ubuf__ T* scaleAddr, T invStep, uint32_t count, uint32_t oneRepeatSize,
uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void SelectLossVF(__ubuf__ T* dstAddr, __ubuf__ T* clampMinMaskAddr, __ubuf__ T* clampMaxMaskAddr,
__ubuf__ T* clampedLossAddr, __ubuf__ T* lossMAddr, uint32_t count,
uint32_t oneRepeatSize, uint16_t repeatTimes);
template <typename T>
__simd_vf__ inline void OutputVF(__ubuf__ T* dstAddr, __ubuf__ T* roundXAddr, __ubuf__ T* scaleAddr, uint32_t count,
uint32_t oneRepeatSize, uint16_t repeatTimes);
template <typename T, int64_t RANK>
class ActsUlqKernel {
static constexpr int64_t ND = (RANK <= 5) ? RANK : 5;
static constexpr uint32_t VL = AscendC::GetVecLen() / sizeof(float);
static constexpr int64_t kNumBufs = std::is_same_v<T, half> ? (kPhysNodes + kCastBufs) : kPhysNodes;
AscendC::TPipe pipe_;
const ActsUlqTilingData<RANK>* td_;
AscendC::GlobalTensor<T> gmIn_[kMaxInputSlots];
AscendC::GlobalTensor<T> gmOut_[kMaxOutputSlots];
AscendC::TBuf<AscendC::TPosition::VECCALC> buf_[kNumBufs];
AscendC::MultiCopyParams<T, ND> nddmaParams_[kMaxInputSlots];
int64_t nddmaOuterIters_[kMaxInputSlots];
int64_t nddma_dims_;
public:
__aicore__ inline void Init(GM_ADDR inputs[kMaxInputSlots], GM_ADDR outputs[kMaxOutputSlots],
const ActsUlqTilingData<RANK>* td)
{
td_ = td;
for (int i = 0; i < kMaxInputSlots; i++)
gmIn_[i].SetGlobalBuffer((__gm__ T*)inputs[i]);
for (int i = 0; i < kMaxOutputSlots; i++)
gmOut_[i].SetGlobalBuffer((__gm__ T*)outputs[i]);
for (int i = 0; i < kNumBufs; i++)
pipe_.InitBuffer(buf_[i], td_->per_buf_bytes);
const int64_t* dstShape = td_->max_bro_shape;
int64_t k = td_->split.axis;
nddma_dims_ = (RANK - k <= ND) ? (RANK - k) : ND;
for (int inp = 0; inp < kMaxInputSlots; inp++) {
int64_t inner = 1;
int64_t nd = 0;
for (int64_t d = RANK - 1; d >= k && nd < ND; d--) {
nddmaParams_[inp].loopInfo.loopSize[nd] = (d == k) ? 0 : dstShape[d];
nddmaParams_[inp].loopInfo.loopSrcStride[nd] = td_->input_strides[inp][d];
nddmaParams_[inp].loopInfo.loopDstStride[nd] = inner;
nddmaParams_[inp].loopInfo.loopLpSize[nd] = 0;
nddmaParams_[inp].loopInfo.loopRpSize[nd] = 0;
inner *= (d == k) ? td_->split.a_i : dstShape[d];
nd++;
}
for (; nd < ND; nd++) {
nddmaParams_[inp].loopInfo.loopSize[nd] = 1;
nddmaParams_[inp].loopInfo.loopSrcStride[nd] = 0;
nddmaParams_[inp].loopInfo.loopDstStride[nd] = inner;
nddmaParams_[inp].loopInfo.loopLpSize[nd] = 0;
nddmaParams_[inp].loopInfo.loopRpSize[nd] = 0;
}
nddmaOuterIters_[inp] = 1;
for (int64_t d = k; d < RANK - nddma_dims_; d++)
nddmaOuterIters_[inp] *= (d == k) ? td_->split.a_i : dstShape[d];
}
}
__aicore__ inline void Process()
{
int32_t evMTE2toV = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::MTE2_V));
int32_t evVtoMTE2 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE2));
int32_t evVtoMTE3 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE3));
int32_t evMTE3toMTE2 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::MTE3_MTE2));
int32_t evCast0 = 0, evCast1 = 0, evCast2 = 0, evCast3 = 0;
if constexpr (std::is_same_v<T, half>) {
evCast0 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE3));
evCast1 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE3));
evCast2 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE3));
evCast3 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE3));
}
int64_t start, end;
GetCoreRange(AscendC::GetBlockIdx(), td_->multicore.tiles_main, td_->multicore.cores_tail, start, end);
constexpr int B0 = 0, B1 = 1, B2 = 2, B3 = 3, B4 = 4, B5 = 5;
constexpr int BC = kPhysNodes;
constexpr int IN_DATA = 0, IN_CLAMP_MIN = 1, IN_CLAMP_MAX = 2;
constexpr int OUT_OUTPUT = 0, OUT_MIN_MASK = 1, OUT_MAX_MASK = 2, OUT_LOSS = 3;
constexpr float eps = 1.192092896e-07f;
constexpr float step = 255.0f;
constexpr float inv_step = 1.0f / 255.0f;
int64_t inner_count = 1;
for (int64_t d = td_->split.axis + 1; d < RANK; d++)
inner_count *= td_->max_bro_shape[d];
int64_t coord[8] = {};
for (int64_t flat = start; flat < end; flat++) {
int64_t a_i_seg = GetUBSplitRange(flat % td_->split.a_o, td_->split.a_o, td_->split.a_i,
td_->split.a_i_tail);
int64_t count = a_i_seg * inner_count;
FlatToEffectiveCoord(flat, td_->max_bro_shape, RANK, td_->split.axis, td_->split.a_i, td_->split.a_o,
coord);
uint16_t repeatTimes = (uint16_t)AscendC::CeilDivision(count, (int64_t)VL);
if (flat != start)
AscendC::WaitFlag<AscendC::HardEvent::MTE3_MTE2>(evMTE3toMTE2);
if constexpr (std::is_same_v<T, half>) {
CopyInBrc(coord, IN_CLAMP_MIN, BC, a_i_seg);
AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::Cast<float, half>(buf_[B0].template Get<float>(), buf_[BC].template Get<half>(),
AscendC::RoundMode::CAST_NONE, (uint32_t)count);
} else {
CopyInBrc(coord, IN_CLAMP_MIN, B0, a_i_seg);
AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
}
if (td_->fixed_min != 0) {
AscendC::Duplicate(buf_[B0].template Get<float>(), 0.0f, count);
} else {
asc_vf_call<MinsVF<float>>((__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(), 0.0f, count,
VL, repeatTimes);
}
if constexpr (std::is_same_v<T, half>) {
CopyInBrc(coord, IN_CLAMP_MAX, BC, a_i_seg);
AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::Cast<float, half>(buf_[B1].template Get<float>(), buf_[BC].template Get<half>(),
AscendC::RoundMode::CAST_NONE, (uint32_t)count);
} else {
CopyInBrc(coord, IN_CLAMP_MAX, B1, a_i_seg);
AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
}
AscendC::Duplicate(buf_[B2].template Get<float>(), step * eps, count);
AscendC::Max(buf_[B1].template Get<float>(), buf_[B1].template Get<float>(), buf_[B2].template Get<float>(),
count);
asc_vf_call<ScaleVF<float>>((__ubuf__ float*)buf_[B2].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B1].template Get<float>().GetPhyAddr(), inv_step, count,
VL, repeatTimes);
asc_vf_call<ClipBoundsVF<float>>((__ubuf__ float*)buf_[B3].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B4].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B2].template Get<float>().GetPhyAddr(), step, count,
VL, repeatTimes);
asc_vf_call<LossMVF<float>>((__ubuf__ float*)buf_[B1].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B2].template Get<float>().GetPhyAddr(), inv_step, count,
VL, repeatTimes);
AscendC::SetFlag<AscendC::HardEvent::V_MTE2>(evVtoMTE2);
AscendC::WaitFlag<AscendC::HardEvent::V_MTE2>(evVtoMTE2);
if constexpr (std::is_same_v<T, half>) {
CopyInBrc(coord, IN_DATA, BC, a_i_seg);
AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::Cast<float, half>(buf_[B0].template Get<float>(), buf_[BC].template Get<half>(),
AscendC::RoundMode::CAST_NONE, (uint32_t)count);
} else {
CopyInBrc(coord, IN_DATA, B0, a_i_seg);
AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(evMTE2toV);
}
asc_vf_call<ClampVF<float>>((__ubuf__ float*)buf_[B5].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B3].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B4].template Get<float>().GetPhyAddr(), count, VL,
repeatTimes);
asc_vf_call<MaskMinVF<float>>((__ubuf__ float*)buf_[B3].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B3].template Get<float>().GetPhyAddr(), count, VL,
repeatTimes);
asc_vf_call<MaskMaxVF<float>>((__ubuf__ float*)buf_[B4].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B4].template Get<float>().GetPhyAddr(), count, VL,
repeatTimes);
asc_vf_call<QuantVF<float>>((__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B5].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B5].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B2].template Get<float>().GetPhyAddr(), inv_step, count,
VL, repeatTimes);
asc_vf_call<SelectLossVF<float>>((__ubuf__ float*)buf_[B5].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B3].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B4].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B5].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B1].template Get<float>().GetPhyAddr(), count, VL,
repeatTimes);
asc_vf_call<OutputVF<float>>((__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B0].template Get<float>().GetPhyAddr(),
(__ubuf__ float*)buf_[B2].template Get<float>().GetPhyAddr(), count, VL,
repeatTimes);
AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(evVtoMTE3);
AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(evVtoMTE3);
if constexpr (std::is_same_v<T, half>) {
AscendC::Cast<half, float>(buf_[BC].template Get<half>(), buf_[B0].template Get<float>(),
AscendC::RoundMode::CAST_RINT, (uint32_t)count);
AscendC::Cast<half, float>(buf_[B1].template Get<half>(), buf_[B3].template Get<float>(),
AscendC::RoundMode::CAST_RINT, (uint32_t)count);
AscendC::Cast<half, float>(buf_[B2].template Get<half>(), buf_[B4].template Get<float>(),
AscendC::RoundMode::CAST_RINT, (uint32_t)count);
AscendC::Cast<half, float>(buf_[B3].template Get<half>(), buf_[B5].template Get<float>(),
AscendC::RoundMode::CAST_RINT, (uint32_t)count);
AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(evCast0);
AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(evCast0);
CopyOutCast(coord, OUT_OUTPUT, BC, a_i_seg);
CopyOutCast(coord, OUT_MIN_MASK, B1, a_i_seg);
CopyOutCast(coord, OUT_MAX_MASK, B2, a_i_seg);
CopyOutCast(coord, OUT_LOSS, B3, a_i_seg);
} else {
CopyOutOne(coord, OUT_OUTPUT, B0, a_i_seg);
CopyOutOne(coord, OUT_MIN_MASK, B3, a_i_seg);
CopyOutOne(coord, OUT_MAX_MASK, B4, a_i_seg);
CopyOutOne(coord, OUT_LOSS, B5, a_i_seg);
}
if (flat != end - 1)
AscendC::SetFlag<AscendC::HardEvent::MTE3_MTE2>(evMTE3toMTE2);
}
}
private:
__aicore__ inline void CopyInBrc(const int64_t* coord, int inputIdx, int slot, int64_t a_i_seg)
{
int64_t k = td_->split.axis;
int64_t off = CalcInputOffset(coord, td_->input_strides[inputIdx], RANK);
const int64_t* dstShape = td_->max_bro_shape;
auto params = nddmaParams_[inputIdx];
int64_t k_nd = RANK - 1 - k;
int64_t inner = 1;
for (int64_t nd = 0; nd < ND; nd++) {
if (nd == k_nd)
params.loopInfo.loopSize[nd] = a_i_seg;
params.loopInfo.loopDstStride[nd] = inner;
inner *= params.loopInfo.loopSize[nd];
}
static constexpr AscendC::NdDmaConfig cfg = {false, AscendC::NdDmaConfig::unsetPad,
AscendC::NdDmaConfig::unsetPad, false};
if constexpr (RANK <= 5) {
AscendC::DataCopy<T, ND, cfg>(buf_[slot].template Get<T>(), gmIn_[inputIdx][off], params);
} else {
AscendC::LocalTensor<T> buf = buf_[slot].template Get<T>();
int64_t elem_base = off;
for (int64_t oi = 0; oi < nddmaOuterIters_[inputIdx]; oi++) {
int64_t elem_adj = 0, tmp = oi;
for (int64_t d = RANK - nddma_dims_ - 1; d >= k; d--) {
int64_t sz = (d == k) ? a_i_seg : dstShape[d];
elem_adj += (tmp % sz) * td_->input_strides[inputIdx][d];
tmp /= sz;
}
AscendC::DataCopy<T, ND, cfg>(buf[oi * inner], gmIn_[inputIdx][elem_base + elem_adj], params);
}
}
}
__aicore__ inline void CopyOutOne(const int64_t* coord, int outputIdx, int slot, int64_t a_i_seg)
{
int64_t off = CalcOutputOffset(coord, td_->output_strides[outputIdx], RANK);
int64_t cnt = CalcOutputTransferCount(td_->output_shapes[outputIdx], RANK, td_->split.axis, a_i_seg);
AscendC::DataCopyExtParams extParams;
extParams.blockCount = 1;
extParams.blockLen = cnt * sizeof(T);
extParams.srcStride = 0;
extParams.dstStride = 0;
AscendC::DataCopyPad(gmOut_[outputIdx][off], buf_[slot].template Get<T>(), extParams);
}
__aicore__ inline void CopyOutCast(const int64_t* coord, int outputIdx, int slot, int64_t a_i_seg)
{
int64_t off = CalcOutputOffset(coord, td_->output_strides[outputIdx], RANK);
int64_t cnt = CalcOutputTransferCount(td_->output_shapes[outputIdx], RANK, td_->split.axis, a_i_seg);
AscendC::DataCopyExtParams extParams;
extParams.blockCount = 1;
extParams.blockLen = cnt * sizeof(half);
extParams.srcStride = 0;
extParams.dstStride = 0;
AscendC::DataCopyPad(gmOut_[outputIdx][off], buf_[slot].template Get<half>(), extParams);
}
};
template <typename T>
__simd_vf__ inline void MinsVF(__ubuf__ T* dstAddr, T scalar, uint32_t count, uint32_t oneRepeatSize,
uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> srcReg, dstReg;
AscendC::Reg::MaskReg mask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(srcReg, dstAddr, aReg);
AscendC::Reg::Mins<T>(dstReg, srcReg, scalar, mask);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void MaxsVF(__ubuf__ T* dstAddr, T scalar, uint32_t count, uint32_t oneRepeatSize,
uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> srcReg, dstReg, scalarReg;
AscendC::Reg::MaskReg mask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(srcReg, dstAddr, aReg);
AscendC::Reg::Duplicate(scalarReg, scalar, mask);
AscendC::Reg::Max<T>(dstReg, srcReg, scalarReg, mask);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void ScaleVF(__ubuf__ T* dstAddr, __ubuf__ T* srcMinAddr, __ubuf__ T* srcMaxAddr, T invStep,
uint32_t count, uint32_t oneRepeatSize, uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> minReg, maxReg, diffReg, dstReg;
AscendC::Reg::MaskReg mask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(minReg, srcMinAddr, aReg);
AscendC::Reg::LoadAlign(maxReg, srcMaxAddr, aReg);
AscendC::Reg::Sub<T>(diffReg, maxReg, minReg, mask);
AscendC::Reg::Muls<T>(dstReg, diffReg, invStep, mask);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void ClipBoundsVF(__ubuf__ T* clipMinAddr, __ubuf__ T* clipMaxAddr, __ubuf__ T* oriClipMinAddr,
__ubuf__ T* scaleAddr, T step, uint32_t count, uint32_t oneRepeatSize,
uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> minReg, scaleReg, divReg, roundReg, cmReg, cxReg;
AscendC::Reg::MaskReg mask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(minReg, oriClipMinAddr, aReg);
AscendC::Reg::LoadAlign(scaleReg, scaleAddr, aReg);
AscendC::Reg::Div<T>(divReg, minReg, scaleReg, mask);
AscendC::Reg::Truncate<float, AscendC::RoundMode::CAST_RINT>(roundReg, divReg, mask);
AscendC::Reg::Mul<T>(cmReg, scaleReg, roundReg, mask);
AscendC::Reg::StoreAlign(clipMinAddr, cmReg, aReg, mask);
AscendC::Reg::Adds<T>(cxReg, roundReg, step, mask);
AscendC::Reg::Mul<T>(cxReg, scaleReg, cxReg, mask);
AscendC::Reg::StoreAlign(clipMaxAddr, cxReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void LossMVF(__ubuf__ T* dstAddr, __ubuf__ T* oriClipMinAddr, __ubuf__ T* scaleAddr, T invStep,
uint32_t count, uint32_t oneRepeatSize, uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> minReg, scaleReg, divReg, roundReg, diffReg, dstReg;
AscendC::Reg::MaskReg mask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(minReg, oriClipMinAddr, aReg);
AscendC::Reg::LoadAlign(scaleReg, scaleAddr, aReg);
AscendC::Reg::Div<T>(divReg, minReg, scaleReg, mask);
AscendC::Reg::Truncate<float, AscendC::RoundMode::CAST_RINT>(roundReg, divReg, mask);
AscendC::Reg::Sub<T>(diffReg, roundReg, divReg, mask);
AscendC::Reg::Muls<T>(dstReg, diffReg, invStep, mask);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void ClampVF(__ubuf__ T* dstAddr, __ubuf__ T* dataAddr, __ubuf__ T* clipMinAddr,
__ubuf__ T* clipMaxAddr, uint32_t count, uint32_t oneRepeatSize, uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> dataReg, cmReg, cxReg, tmpReg, dstReg;
AscendC::Reg::MaskReg mask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(dataReg, dataAddr, aReg);
AscendC::Reg::LoadAlign(cmReg, clipMinAddr, aReg);
AscendC::Reg::LoadAlign(cxReg, clipMaxAddr, aReg);
AscendC::Reg::Max<T>(tmpReg, dataReg, cmReg, mask);
AscendC::Reg::Min<T>(dstReg, tmpReg, cxReg, mask);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void MaskMinVF(__ubuf__ T* dstAddr, __ubuf__ T* dataAddr, __ubuf__ T* clipMinAddr, uint32_t count,
uint32_t oneRepeatSize, uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> dataReg, cmReg, dstReg;
AscendC::Reg::RegTensor<T> oneReg, zeroReg;
AscendC::Reg::MaskReg mask, cmpMask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(dataReg, dataAddr, aReg);
AscendC::Reg::LoadAlign(cmReg, clipMinAddr, aReg);
AscendC::Reg::Compare<T, AscendC::CMPMODE::GE>(cmpMask, dataReg, cmReg, mask);
AscendC::Reg::Duplicate(oneReg, T(1.0));
AscendC::Reg::Duplicate(zeroReg, T(0.0));
AscendC::Reg::Select<T>(dstReg, oneReg, zeroReg, cmpMask);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void MaskMaxVF(__ubuf__ T* dstAddr, __ubuf__ T* dataAddr, __ubuf__ T* clipMaxAddr, uint32_t count,
uint32_t oneRepeatSize, uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> dataReg, cxReg, dstReg;
AscendC::Reg::RegTensor<T> oneReg, zeroReg;
AscendC::Reg::MaskReg mask, cmpMask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(dataReg, dataAddr, aReg);
AscendC::Reg::LoadAlign(cxReg, clipMaxAddr, aReg);
AscendC::Reg::Compare<T, AscendC::CMPMODE::LE>(cmpMask, dataReg, cxReg, mask);
AscendC::Reg::Duplicate(oneReg, T(1.0));
AscendC::Reg::Duplicate(zeroReg, T(0.0));
AscendC::Reg::Select<T>(dstReg, oneReg, zeroReg, cmpMask);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void QuantVF(__ubuf__ T* roundXAddr, __ubuf__ T* clampedLossAddr, __ubuf__ T* clampedXAddr,
__ubuf__ T* scaleAddr, T invStep, uint32_t count, uint32_t oneRepeatSize,
uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> cxReg, scaleReg, rawReg, roundReg, diffReg, lossReg;
AscendC::Reg::MaskReg mask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(cxReg, clampedXAddr, aReg);
AscendC::Reg::LoadAlign(scaleReg, scaleAddr, aReg);
AscendC::Reg::Div<T>(rawReg, cxReg, scaleReg, mask);
AscendC::Reg::Truncate<float, AscendC::RoundMode::CAST_RINT>(roundReg, rawReg, mask);
AscendC::Reg::StoreAlign(roundXAddr, roundReg, aReg, mask);
AscendC::Reg::Sub<T>(diffReg, roundReg, rawReg, mask);
AscendC::Reg::Muls<T>(lossReg, diffReg, invStep, mask);
AscendC::Reg::StoreAlign(clampedLossAddr, lossReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void SelectLossVF(__ubuf__ T* dstAddr, __ubuf__ T* clampMinMaskAddr, __ubuf__ T* clampMaxMaskAddr,
__ubuf__ T* clampedLossAddr, __ubuf__ T* lossMAddr, uint32_t count,
uint32_t oneRepeatSize, uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> minMaskReg, maxMaskReg, clReg, lmReg, dstReg;
AscendC::Reg::RegTensor<T> halfReg;
AscendC::Reg::MaskReg mask, cmpMask1, cmpMask2;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(minMaskReg, clampMinMaskAddr, aReg);
AscendC::Reg::LoadAlign(maxMaskReg, clampMaxMaskAddr, aReg);
AscendC::Reg::LoadAlign(clReg, clampedLossAddr, aReg);
AscendC::Reg::LoadAlign(lmReg, lossMAddr, aReg);
AscendC::Reg::Duplicate(halfReg, T(0.5));
AscendC::Reg::Compare<T, AscendC::CMPMODE::GT>(cmpMask1, minMaskReg, halfReg, mask);
AscendC::Reg::Select<T>(dstReg, clReg, lmReg, cmpMask1);
AscendC::Reg::Compare<T, AscendC::CMPMODE::GT>(cmpMask2, maxMaskReg, halfReg, mask);
AscendC::Reg::Select<T>(dstReg, dstReg, lmReg, cmpMask2);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
template <typename T>
__simd_vf__ inline void OutputVF(__ubuf__ T* dstAddr, __ubuf__ T* roundXAddr, __ubuf__ T* scaleAddr, uint32_t count,
uint32_t oneRepeatSize, uint16_t repeatTimes)
{
AscendC::Reg::RegTensor<T> rxReg, scaleReg, dstReg;
AscendC::Reg::MaskReg mask;
AscendC::Reg::AddrReg aReg;
for (uint16_t i = 0; i < repeatTimes; ++i) {
aReg = AscendC::Reg::CreateAddrReg<T>(i, oneRepeatSize);
mask = AscendC::Reg::UpdateMask<T>(count);
AscendC::Reg::LoadAlign(rxReg, roundXAddr, aReg);
AscendC::Reg::LoadAlign(scaleReg, scaleAddr, aReg);
AscendC::Reg::Mul<T>(dstReg, rxReg, scaleReg, mask);
AscendC::Reg::StoreAlign(dstAddr, dstReg, aReg, mask);
}
}
#endif