☰
asc-devkit 寄存器向量基础算术 API 完全指南:Abs/Add/Div 等 25 个 SIMD 接口的原型、数据类型、精度与 Subnormal 详解
2026/10/15 2:22:29 网站建设 项目流程
  • 人工智能
  • 深度学习
  • 算子库
  • CANN
  • Ascend

【免费下载链接】asc-devkit

本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C++标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。

项目地址:https://gitcode.com/cann/asc-devkit
点击查看免费下载

本文以 asc-devkit 开源仓库 SIMD-API 文档中「基础算术」(basic_arithmetic)专题为核心,系统讲解昇腾 AI 处理器寄存器向量计算(Reg Compute)模式下 25 个基础算术接口的功能语义、函数原型、模板参数、数据类型约束、调用示例,并深入剖析进位(carry)机制、精度模式与 Subnormal(FTZ)处理等关键特性。读者阅读后可掌握 AscendC 寄存器级 SIMD 算术运算的完整使用方法,并能在算子开发中正确选择算法模式、规避精度陷阱。

一、基础算术 API 全貌

「基础算术」是 asc-devkit SIMD-API 中寄存器向量计算(reg_vector_compute)的重要组成部分,全部接口作用于RegTensor寄存器操作数,通过MaskReg掩码控制元素的有效性,按元素(element-wise)完成数学运算。专题由 概述 与 25 个接口子文档组成,按运算元数可分为三类:单目运算、双目运算、标量双目运算。

1.1 单目运算(一元接口)

接口描述
Abs对实数类型:对 srcReg 中的有效元素逐个取绝对值,$dstReg_i = \lvert srcReg_i \rvert$;对复数类型:逐个取模,$dstReg_i = \lvert srcReg_i \rvert = (\alpha^2 + \beta^2)^{1/2}$($srcReg_i = \alpha + \beta i$,α 为实部,β 为虚部)
Exp$dstReg_i = e^{srcReg_i}$
Ln$dstReg_i = \ln(srcReg_i)$
Log$dstReg_i = \log(srcReg_i)$(以 e 为底,与 Ln 等价)
Log2$dstReg_i = \log_2(srcReg_i)$
Log10$dstReg_i = \log_{10}(srcReg_i)$
Neg$dstReg_i = -srcReg_i$
Relu$dstReg_i = \max(0, srcReg_i)$
Sqrt$dstReg_i = (srcReg_i)^{1/2}$

1.2 双目运算(二元接口)

接口描述
Add$dstReg_i = srcReg0_i + srcReg1_i$;或保留进位 ${carry_i, dstReg_i} = srcReg0_i + srcReg1_i$
AddC${carry_i, dstReg_i} = srcReg0_i + srcReg1_i + carrySrc_i$(带输入进位的加法)
Div$dstReg_i = srcReg0_i / srcReg1_i$
Max$dstReg_i = \max(srcReg0_i, srcReg1_i)$
Min$dstReg_i = \min(srcReg0_i, srcReg1_i)$
Mul$dstReg_i = srcReg0_i \times srcReg1_i$
Mull$dstReg0_i = (srcReg0_i \times srcReg1_i) \bmod 2^{bit}$,$dstReg1_i = (srcReg0_i \times srcReg1_i) / 2^{bit}$(bit 为操作数位宽,低/高位分别输出)
Prelu$dstReg_i = \begin{cases} srcReg0_i & srcReg0_i > 0 \ srcReg0_i \times srcReg1_i & srcReg0_i \leq 0 \end{cases}$
Sub$dstReg_i = srcReg0_i - srcReg1_i$;或保留进位 ${carry_i, dstReg_i} = {1'b0, srcReg0_i} + {1'b0, \sim srcReg1_i} + 33'b1$
SubC${carry_i, dstReg_i} = {1'b0, srcReg0_i} + {1'b0, \sim srcReg1_i} + {32'b0, carrySrc_i}$(带输入进位的减法)

1.3 标量双目运算(矢量 + 标量接口)

接口描述
Adds$dstReg_i = srcReg_i + scalarValue$
LeakyRelu$dstReg_i = \begin{cases} srcReg_i & srcReg_i > 0 \ srcReg_i \times scalarValue & srcReg_i \leq 0 \end{cases}$
Maxs$dstReg_i = \max(srcReg_i, scalarValue)$
Mins$dstReg_i = \min(srcReg_i, scalarValue)$
Muls$dstReg_i = srcReg_i \times scalarValue$

二、产品支持情况与头文件位置

基础算术接口目前仅在特定处理器系列上受支持。以 Abs 为代表,各接口的产品支持情况一致,可直接对照:

产品系列支持情况
Ascend 950PR & 950DT 系列产品支持
Kirin 9050 处理器系列产品支持
KirinDev0001 处理器系列产品支持
KirinDev0002 处理器系列产品支持
KirinDev0003 处理器系列产品支持
Atlas A3 系列产品不支持
Atlas A2 系列产品不支持
Atlas 200I/500 A2 推理产品不支持
Atlas 推理系列产品 AI Core / Vector Core不支持
Atlas 训练系列产品不支持

不同类别接口对应不同头文件(均为include/basic_api/reg_compute/下的公开接口头文件):

  • 单目运算:basic_api/reg_compute/kernel_reg_compute_vec_unary_intf.h
  • 双目运算:basic_api/reg_compute/kernel_reg_compute_vec_binary_intf.h
  • 标量双目运算:basic_api/reg_compute/kernel_reg_compute_vec_binary_scalar_intf.h

仓库源码中,接口声明与实现分离:声明位于 kernel_reg_compute_vec_unary_intf.h、kernel_reg_compute_vec_binary_intf.h、kernel_reg_compute_vec_binary_scalar_intf.h,实现则按芯片架构(如 dav_3510、dav_5161、dav_9201 等)分布在impl/basic_api/reg_compute/与impl/basic_api/dav_*目录中。头文件末尾会根据__NPU_ARCH__宏自动包含对应架构的实现头文件(如kernel_reg_compute_vec_binary_scalar_intf_impl.h),这也是接口具有架构差异化的底层原因。

三、通用模板参数与 MaskMergeMode 机制

所有基础算术接口均遵循统一的模板参数约定。以 Add 为典型原型:

template <typename T = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Add(U& dstReg, U& srcReg0, U& srcReg1, MaskReg& mask)

模板参数通用语义

参数名描述
T操作数数据类型(不同接口支持范围不同,见各接口「数据类型」小节)
modeMaskMergeMode 枚举,选择 MERGING 或 ZEROING 模式
U / S / V操作数的 RegTensor 类型,例如RegTensor<half>,由编译器自动推导,用户无需填写;U 通常还兼作标量源操作数类型

MaskMergeMode 定义如下:

enum class MaskMergeMode { UNKNOWN, // 转换类型不支持 MaskMergeMode 时选择 MERGING, // mask 未选择的元素保留 dst 原值 ZEROING // mask 未选择的元素在 dst 中置零 };

需要特别注意的是:当前绝大多数基础算术接口仅支持 ZEROING 模式(如 Abs、Exp、Sqrt、Ln、Log、Log2、Log10、Neg、Relu、Prelu、Adds、Maxs、Mins、Muls、LeakyRelu、Div 默认、Mul、Sub、Add),而Add、Sub、Max、Min 同时支持 ZEROING 与 MERGING 两种模式。MERGING 模式下,mask 未筛选的元素在 dstReg 中保留原值,可用于累积式写入场景。

参数级语义方面,dstReg为输出目的操作数,srcReg/srcReg0/srcReg1为输入源操作数,mask为元素操作的有效指示(详见 MaskReg),carry/carrySrc为进位相关 MaskReg。所有接口均无返回值(void)。

四、单目运算接口详解

单目接口统一声明在 kernel_reg_compute_vec_unary_intf.h 中。

4.1 Abs:绝对值(实数)/ 模(复数)

// 实数计算 template <typename T = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Abs(U& dstReg, U& srcReg, MaskReg& mask) // 复数计算(S、V 由编译器推导) template <typename T = DefaultType, typename U = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename S, typename V> __simd_callee__ inline void Abs(S& dstReg, V& srcReg, MaskReg& mask)

数据类型组合(srcReg → dstReg):

srcRegdstReg
int8_tint8_t
int16_tint16_t
halfhalf
int32_tint32_t
floatfloat
complex32half
int64_tint64_t
complex64float

约束:

  • 当目的操作数与源操作数数据类型不一致时(复数场景),两者不可重叠;
  • 整型计算超出表示范围时采用非饱和截断:例如 int8_t 类型,srcReg 为 -128 时,其绝对值 128 会被截断为 -128;
  • 针对 Ascend 950PR & 950DT 系列产品,仅 complex32 和 complex64 类型的内部计算涉及 Subnormal,处理方式受编译选项--cce-ftz控制(默认值为 true):--cce-ftz=false时保留 Subnormal 并按实际数值参与运算;--cce-ftz=true时启用 FTZ(Flush-To-Zero)模式,Subnormal 按 0 处理,可能造成精度差异。

调用示例(实数,循环处理多 repeat):

template<typename T> __simd_vf__ inline void AbsVF(__ubuf__ T* dstAddr, __ubuf__ T* srcAddr, uint32_t count, uint16_t oneRepeatSize, uint16_t repeatTimes) { AscendC::Reg::RegTensor<T> srcReg; AscendC::Reg::RegTensor<T> dstReg; AscendC::Reg::MaskReg mask; for (uint16_t i = 0; i < repeatTimes; i++) { mask = AscendC::Reg::UpdateMask<T>(count); AscendC::Reg::LoadAlign(srcReg, srcAddr + i * oneRepeatSize); AscendC::Reg::Abs(dstReg, srcReg, mask); AscendC::Reg::StoreAlign(dstAddr + i * oneRepeatSize, dstReg, mask); } }

4.2 Exp:指数运算

原型为template <typename T = DefaultType, auto mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Exp(U& dstReg, U& srcReg, MaskReg& mask)。注意此处mode为auto类型,可配置为 MaskMergeMode 枚举值,或指向ExpSpecificMode结构体的指针:

enum class ExpAlgo { INTRINSIC = 0, PRECISION_1ULP_FTZ_TRUE, PRECISION_1ULP_FTZ_FALSE, }; struct ExpSpecificMode { MaskMergeMode mrgMode = MaskMergeMode::ZEROING; ExpAlgo algo = ExpAlgo::INTRINSIC; };

支持的数据类型仅为half、float。三种算法的最大精度误差均为 1ulp:

  • ExpAlgo::INTRINSIC(默认):对于 half、float,Subnormal 处理受--cce-ftz控制(默认 true,即默认采用 FTZ 模式);
  • ExpAlgo::PRECISION_1ULP_FTZ_TRUE:单指令计算,始终采用 FTZ 模式;
  • ExpAlgo::PRECISION_1ULP_FTZ_FALSE:通过软件仿真实现,支持 Subnormal 数据计算。

由于保留 Subnormal 需要软件仿真,在默认--cce-ftz=true下一般场景建议使用默认 INTRINSIC 或显式选择PRECISION_1ULP_FTZ_TRUE以获取更优性能;需要精确输出 Subnormal 时才使用PRECISION_1ULP_FTZ_FALSE。文档给出了 half/float 下的 Subnormal 示例(如 half 输入 -9.703125 输出 6.0975551605e-05,二进制尾数0 00000 1111111111)。

使用高精度/Subnormal 模式时通过模板参数传入结构体指针:

// 1ulp精度及Subnormal模式 // static constexpr AscendC::Reg::ExpSpecificMode mode = { // AscendC::Reg::MaskMergeMode::ZEROING, AscendC::ExpAlgo::PRECISION_1ULP_FTZ_FALSE}; // AscendC::Reg::Exp<T, &mode>(dstReg, srcReg, mask);

4.3 Sqrt:平方根运算

template <typename T = DefaultType, auto mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Sqrt(U& dstReg, U& srcReg, MaskReg& mask)

SqrtSpecificMode定义:

enum class SqrtAlgo { INTRINSIC = 0, FAST_INVERSE, PRECISION_1ULP_FTZ_TRUE, PRECISION_0ULP_FTZ_FALSE, PRECISION_1ULP_FTZ_FALSE, }; struct SqrtSpecificMode { MaskMergeMode mrgMode = MaskMergeMode::ZEROING; bool precisionMode = false; SqrtAlgo algo = SqrtAlgo::INTRINSIC; };

关键点:

  • 数据类型仅 half、float;
  • precisionMode=true时使能更高精度计算(快速求逆算法,仅对 float 生效),最大精度误差 0ulp;
  • SqrtAlgo::INTRINSIC为默认算法(1ulp),--cce-ftz=false保留 Subnormal,true(默认)采用 FTZ;
  • SqrtAlgo::FAST_INVERSE与SqrtAlgo::PRECISION_0ULP_FTZ_FALSE使用快速求逆算法,仅支持 float 并支持 Subnormal 计算(0ulp);
  • SqrtAlgo::PRECISION_1ULP_FTZ_FALSE支持 half 类型的 Subnormal 数据计算(1ulp);
  • 约束:输入为负数时结果为 nan;输入为 -0 时结果为 -0。

4.4 Ln / Log / Log2 / Log10:对数运算族

四者原型一致:template <typename T = DefaultType, auto mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Ln|Log|Log2|Log10(U& dstReg, U& srcReg, MaskReg& mask),均仅支持 half、float。

  • Ln:自然对数,$dstReg_i = \ln(srcReg_i)$;
  • Log:与 Ln 功能等价,命名遵循 C/C++ 标准库中log()表示自然对数的约定(文档明确说明);
  • Log2:$dstReg_i = \log_2(srcReg_i)$;
  • Log10:$dstReg_i = \log_{10}(srcReg_i)$。

各接口的 SpecificMode 结构体模式完全同构(LnSpecificMode/LogSpecificMode/Log2SpecificMode/Log10SpecificMode),均含mrgMode与algo两个字段,枚举均为INTRINSIC、PRECISION_1ULP_FTZ_TRUE、PRECISION_1ULP_FTZ_FALSE三值,最大精度误差均为 1ulp。此外Log2 与 Log10 具有精度提升特性:当源操作数为 half 时,会先将 half 提升精度到 float 后计算,再将结果转回 half 输出。

4.5 Neg:取相反数

template <typename T = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Neg(U& dstReg, U& srcReg, MaskReg& mask)

支持数据类型:int8_t、int16_t、half、int32_t、float、int64_t。仅支持 ZEROING 模式。无额外约束。

4.6 Relu:线性整流

template <typename T = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Relu(U& dstReg, U& srcReg, MaskReg& mask)

支持数据类型:half、int32_t、float、int64_t。仅支持 ZEROING 模式。

五、双目运算接口详解:含进位算术与高精度除法

双目接口统一声明在 kernel_reg_compute_vec_binary_intf.h 中。

5.1 Add / AddC / Sub / SubC:进位(carry)算术

这四个接口构成一组完整的带进位加减法体系,通过 MaskReg 类型的 carry 寄存器实现多精度(宽位宽)整数算术。Carry flag(进位/借位标志)用于表示加法进位或减法无借位。

Add有两种原型:

// 不保留进位 template <typename T = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Add(U& dstReg, U& srcReg0, U& srcReg1, MaskReg& mask) // 保留进位 template <typename T = DefaultType, typename U> __simd_callee__ inline void Add(MaskReg& carry, U& dstReg, U& srcReg0, U& srcReg1, MaskReg& mask)
  • 不保留进位:支持 int8_t、uint8_t、int16_t、uint16_t、half、bfloat16_t、int32_t、uint32_t、float、complex32、int64_t、uint64_t、complex64;
  • 保留进位:仅支持 int32_t、uint32_t,且计算结果不保留进位。
  • 进位写入规则:若 srcReg0、srcReg1 按位相加后最高位有进位,则在 carry(MaskReg 寄存器)对应位置每 4bit 的最低位写 1,否则写 0。

Sub同理,减法在硬件底层通过补码加法实现:${carry_i, dstReg_i} = {1'b0, srcReg0_i} + {1'b0, \sim srcReg1_i} + 33'b1$。保留进位时仅支持 int32_t、uint32_t。

AddC(带输入进位加法)与SubC(带输入进位减法)将前序运算产生的 carry 作为carrySrc输入继续参与运算:

template <typename T = DefaultType, typename U> __simd_callee__ inline void AddC(MaskReg& carry, U& dstReg, U& srcReg0, U& srcReg1, MaskReg& carrySrc, MaskReg& mask) // SubC 原型同上,函数名替换为 SubC

${carry_i, dstReg_i} = srcReg0_i + srcReg1_i + carrySrc_i$(SubC 为 ${1'b0, srcReg0_i} + {1'b0, \sim srcReg1_i} + {32'b0, carrySrc_i}$),支持数据类型同样为 int32_t、uint32_t。Add 输出的 carry 适用场景参考 AddC 功能说明,Sub 输出的 carry 适用场景参考 SubC 功能说明——典型应用即 64 位整数的分段加减:32 位加法产生进位后,通过 AddC 将进位传递到高 32 位段。

带进位的完整调用示例(AddC,carry 以 8×4B=32B 对齐存储):

template <typename T> static __simd_vf__ inline void AddVF(__ubuf__ T* dst0Addr, __ubuf__ T* dst1Addr, __ubuf__ T* src0Addr, __ubuf__ T* src1Addr, uint32_t count, uint16_t repeatTimes, uint16_t oneRepeatSize){ AscendC::Reg::RegTensor<T> srcReg0; AscendC::Reg::RegTensor<T> srcReg1; AscendC::Reg::RegTensor<T> dstReg0; AscendC::Reg::MaskReg mask; AscendC::Reg::MaskReg maskZero = AscendC::Reg::CreateMask<T, AscendC::Reg::MaskPattern::ALLF>(); AscendC::Reg::MaskReg carry = AscendC::Reg::CreateMask<uint8_t>(); for (uint16_t i = 0; i < repeatTimes; i++) { mask = AscendC::Reg::UpdateMask<T>(count); AscendC::Reg::LoadAlign(srcReg0, src0Addr + i * oneRepeatSize); AscendC::Reg::LoadAlign(srcReg1, src1Addr + i * oneRepeatSize); AscendC::Reg::AddC(carry, dstReg0, srcReg0, srcReg1, maskZero, mask); // 8*4B=32B align AscendC::Reg::StoreAlign<uint32_t, AscendC::Reg::MaskDist::DIST_NORM>((__ubuf__ uint32_t*)dst1Addr + i * 8, carry); AscendC::Reg::StoreAlign(dst0Addr + i * oneRepeatSize, dstReg0, mask); } }

5.2 Mul / Mull:乘法与高低位分离

Mul:template <typename T = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Mul(U& dstReg, U& srcReg0, U& srcReg1, MaskReg& mask),支持 int16_t、uint16_t、half、bfloat16_t、int32_t、uint32_t、float、complex32、int64_t、uint64_t、complex64,输出为不饱和模式(溢出直接截断)。

Mull:将乘法结果的低位部分写入 dstReg0、溢出(高位)部分写入 dstReg1,适合 64 位乘法分解等场景:

template <typename T = DefaultType, typename U> __simd_callee__ inline void Mull(U& dstReg0, U& dstReg1, U& srcReg0, U& srcReg1, MaskReg& mask)

$dstReg0_i = (srcReg0_i \times srcReg1_i) \bmod 2^{bit}$,$dstReg1_i = (srcReg0_i \times srcReg1_i) / 2^{bit}$,其中 bit 表示操作数位宽。仅支持 int32_t、uint32_t。

5.3 Div:多种算法与 Subnormal 模式

Div 是基础算术中模式最丰富的接口,mode为auto类型,可配置 MaskMergeMode 枚举或指向DivSpecificMode结构体的指针:

enum class DivAlgo { INTRINSIC = 0, DIFF_COMPENSATION, PRECISION_1ULP_FTZ_TRUE, PRECISION_0ULP_FTZ_TRUE, PRECISION_0ULP_FTZ_FALSE, PRECISION_1ULP_FTZ_FALSE }; struct DivSpecificMode { MaskMergeMode mrgMode = MaskMergeMode::ZEROING; bool precisionMode = false; DivAlgo algo = DivAlgo::INTRINSIC; };

各模式的数据类型与精度:

模式支持数据类型最大精度误差
DivAlgo::INTRINSIC(默认)int16_t、uint16_t、half、int32_t、uint32_t、float、complex32、int64_t、uint64_t、complex641ulp(half/float 受--cce-ftz控制)
DivAlgo::PRECISION_1ULP_FTZ_TRUE同上1ulp(始终 FTZ)
DivAlgo::DIFF_COMPENSATIONfloat、complex640ulp(差值补偿算法,受--cce-ftz控制)
DivAlgo::PRECISION_0ULP_FTZ_TRUEfloat、complex640ulp(始终 FTZ)
DivAlgo::PRECISION_0ULP_FTZ_FALSEfloat0ulp(保留 Subnormal)
DivAlgo::PRECISION_1ULP_FTZ_FALSEhalf、float1ulp(保留 Subnormal)

补充说明:

  • precisionMode=true时使用差值补偿算法,最大精度误差 0ulp,支持 float、complex64;
  • 默认算法 INTRINSIC 下,--cce-ftz=false等效于PRECISION_1ULP_FTZ_FALSE,--cce-ftz=true(默认)等效于PRECISION_1ULP_FTZ_TRUE;整数类型不涉及 Subnormal;complex32/complex64 的实部与虚部分别为 half/float,Subnormal 处理遵循对应元素类型的--cce-ftz配置;
  • 名称含FTZ_FALSE的算法始终保留 Subnormal,名称含FTZ_TRUE的算法始终采用 FTZ。

文档给出了 FTZ 差异的数值示例:

被除数输入除数输入输出(配置 Subnormal 模式)输出(不配置 Subnormal 模式)
1(0x3F80 0000)-5.01923249665106e-39(0x8036 A794)-1.9923364304124947e+38(0xFF15 E301)-inf(0xFF80 0000)
1.8611191411098982e-39(0x0014 440B)7.70406850625423e-39(0x0053 E3CF)0.24157613515853882(0x3E77 5FBC)NaN(0x7FFF FFFF)

可见不配置 Subnormal 时,微小量相除可能产生 -inf 或 NaN,而保留 Subnormal 可得到正确有限结果——这正是算法对数据精度有特殊要求或需避免除零错误时的关键取舍。使用建议:一般场景使用性能更优的PRECISION_1ULP_FTZ_TRUE或PRECISION_0ULP_FTZ_TRUE;需要精确输出 Subnormal 时使用PRECISION_0ULP_FTZ_FALSE或PRECISION_1ULP_FTZ_FALSE。

高精度模式调用方式:

// 高精度模式 // static constexpr AscendC::Reg::DivSpecificMode mode = {AscendC::Reg::MaskMergeMode::ZEROING, true}; // 0ulp精度及Subnormal模式 // static constexpr AscendC::Reg::DivSpecificMode mode = { // AscendC::Reg::MaskMergeMode::ZEROING, true, AscendC::DivAlgo::PRECISION_0ULP_FTZ_FALSE}; // AscendC::Reg::Div<T, &mode>(dstReg, srcReg0, srcReg1, mask);

5.4 Max / Min:按元素取最值

template <typename T = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Max(U& dstReg, U& srcReg0, U& srcReg1, MaskReg& mask) // Min 同理

两者均支持 ZEROING 与 MERGING 模式,数据类型支持 int8_t、uint8_t、int16_t、uint16_t、half、bfloat16_t、int32_t、uint32_t、float、int64_t、uint64_t。约束差异体现在符号零处理上:

  • Max:srcReg0 为 -0、srcReg1 为 +0 时,输出 +0;
  • Min:srcReg0 为 -0、srcReg1 为 +0 时,输出 -0。

MERGING 模式调用方式(Min 示例):

// Merging Mode模式 // AscendC::Reg::Min<T, MaskMergeMode::MERGING>(dstReg, srcReg0, srcReg1, mask); AscendC::Reg::Min(dstReg, srcReg0, srcReg1, mask);

5.5 Prelu:参数化 ReLU

template <typename T = DefaultType, MaskMergeMode mode = MaskMergeMode::ZEROING, typename U> __simd_callee__ inline void Prelu(U &dstReg, U &srcReg0, U &srcReg1, MaskReg &mask)

当 srcReg0 元素 > 0 时直接输出该元素,否则输出 srcReg0 与 srcReg1 对应元素之积。支持 half、float,仅 ZEROING 模式。注意它与标量版 LeakyRelu 的区别:Prelu 的负半轴斜率来自矢量 srcReg1(每个元素可不同),LeakyRelu 的斜率是统一标量。

六、标量双目运算接口详解

标量双目接口统一声明在 kernel_reg_compute_vec_binary_scalar_intf.h,原型模式统一为:

template <typename T = DefaultType, typename U, MaskMergeMode mode = MaskMergeMode::ZEROING, typename S> __simd_callee__ inline void Adds(S& dstReg, S& srcReg, U scalarValue, MaskReg& mask) // Muls / Maxs / Mins / LeakyRelu 原型同构,函数名替换即可

其中 T 为矢量目的/源操作数数据类型,U 为标量源操作数数据类型,S 为 RegTensor 类型(编译器推导)。此类接口当前均仅支持 ZEROING 模式。

各接口要点:

接口支持数据类型约束
Adds(+ 标量)int8_t、uint8_t、int16_t、uint16_t、half、bfloat16_t、int32_t、uint32_t、float、complex32、int64_t、uint64_t、complex64无
Maxs(取与标量较大者)int8_t、uint8_t、int16_t、uint16_t、half、bfloat16_t、int32_t、uint32_t、float、int64_t、uint64_tsrcReg 为 -0、scalarValue 为 +0 时输出 +0
Mins(取与标量较小者)同 MaxssrcReg 为 -0、scalarValue 为 +0 时输出 -0
Muls(× 标量)int16_t、uint16_t、half、int32_t、uint32_t、float、complex32、int64_t、uint64_t、complex64无
LeakyRelu(负半轴 × 标量斜率)half、float无

标量接口典型调用示例(Adds):

template<typename T> __simd_vf__ inline void AddsVF(__ubuf__ T* dstAddr, __ubuf__ T* srcAddr, T scalarValue, uint32_t count, uint16_t oneRepeatSize, uint16_t repeatTimes) { AscendC::Reg::RegTensor<T> srcReg; AscendC::Reg::RegTensor<T> dstReg; AscendC::Reg::MaskReg mask; for (uint16_t i = 0; i < repeatTimes; i++) { mask = AscendC::Reg::UpdateMask<T>(count); AscendC::Reg::LoadAlign(srcReg, srcAddr + i * oneRepeatSize); AscendC::Reg::Adds(dstReg, srcReg, scalarValue, mask); AscendC::Reg::StoreAlign(dstAddr + i * oneRepeatSize, dstReg, mask); } }

七、关键特性专题:精度误差与 Subnormal(FTZ)处理

7.1 精度误差(ulp)

基础算术接口文档统一以ulp(Unit in the Last Place)量化最大精度误差:

  • 1ulp 级:Abs、Exp、Ln、Log、Log2、Log10、Neg、Relu、Mul、Div(INTRINSIC 与 1ULP 系列)、Sqrt(INTRINSIC 与 1ULP 系列)、Adds/Muls/Maxs/Mins/LeakyRelu 等;
  • 0ulp 级:Div 的 DIFF_COMPENSATION、PRECISION_0ULP_FTZ_TRUE、PRECISION_0ULP_FTZ_FALSE,Sqrt 的 FAST_INVERSE、PRECISION_0ULP_FTZ_FALSE(以及对应接口precisionMode=true时),它们分别通过差值补偿算法与快速求逆算法实现高精度计算;
  • Log2、Log10 还具备 half 提升 float 计算的精度提升特性。

7.2 Subnormal 与 FTZ

Subnormal(次正规数)是浮点格式中接近零的极小数值。FTZ(Flush-To-Zero)模式下,结果或参与运算的 Subnormal 被直接清零(近似为 0),而非保留精确微小数值。两种控制途径:

  1. 编译选项--cce-ftz(默认 true):影响默认算法(INTRINSIC)及 DIFF_COMPENSATION 等对 half/float 类型的行为;false时保留 Subnormal;
  2. 显式算法选择:*_FTZ_FALSE后缀算法始终保留 Subnormal(通过软件仿真实现),*_FTZ_TRUE后缀算法始终采用 FTZ(单指令计算,性能更优)。

使用建议总结:默认--cce-ftz=true下,一般场景建议使用默认 INTRINSIC 或显式选择*_FTZ_TRUE算法以获得更好性能;仅当算法对数据精度有特殊要求(如需要精确输出 Subnormal、避免微小量相除产生 -inf/NaN)时,才选择*_FTZ_FALSE系列算法。

八、源码实现与测试佐证

接口声明与各架构实现可在仓库中直接追溯:

  • 接口声明:单目接口、双目接口、标量双目接口,均在AscendC::Reg命名空间下以__simd_callee__ inline模板函数形式对外提供;
  • 架构实现:impl/basic_api/reg_compute/下按 dav_3510、dav_5161、dav_9201 等目录组织kernel_reg_compute_vec_unary_impl.h、kernel_reg_compute_vec_binary_impl.h、kernel_reg_compute_vec_binary_scalar_impl.h;impl/basic_api/dav_*下kernel_operator_vec_unary_impl.h、kernel_operator_vec_binary_impl.h、kernel_operator_vec_binary_continuous_impl.h等文件中可检索到DivSpecificMode、ExpSpecificMode等模式结构体的落地实现;
  • 头文件自检测试:测试用例 host_header_kernel_reg_compute_intf_checker.cpp 通过using AscendC::Reg::Add;等语句逐一校验 Add、AddC、Div、Max、Min、Mul、Mull、Prelu、Sub、SubC 以及 Adds、LeakyRelu、Maxs、Mins、Muls 等接口在主机侧头文件中的可声明性,可作为接口名称与命名空间用法的直接参考;
  • 接口头文件会对--enable-simt编译标志与内部头文件包含守卫(__ASCENDC_INCLUDE_INTERNAL_HEADERS__)进行约束检查,提醒开发者基础算术接口面向 SIMD 编译模式,且应通过公开头文件使用。

九、总结

asc-devkit 的寄存器向量基础算术 API 以RegTensor+MaskReg为操作模型,覆盖绝对值、指数、对数、开方、取反、激活(Relu/Prelu/LeakyRelu)、加减乘除、最值与标量运算共 25 个接口。使用时可遵循以下要点:按运算类别选择 单目/双目/标量双目 头文件;通过模板参数 T 指定数据类型、mode 指定掩码合并模式;利用 Add/AddC/Sub/SubC 的 carry 机制实现宽位宽整数运算;对 Div/Exp/Sqrt/Ln/Log/Log2/Log10 通过 SpecificMode 结构体在精度与性能之间权衡;关注--cce-ftz编译选项对 Subnormal 结果的语义影响。所有接口均需结合 MaskReg 掩码与 RegTensor 寄存器操作数配套使用,并注意当前仅在 Ascend 950 系列与 Kirin 系列产品上受支持。

  • 人工智能
  • 深度学习
  • 算子库
  • CANN
  • Ascend

【免费下载链接】asc-devkit

本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C++标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。

项目地址:https://gitcode.com/cann/asc-devkit
点击查看免费下载

相关推荐

上一篇:为什么Gurobi modeling-examples是优化建模的黄金标准?5大优势深度剖析
下一篇:快速跑通大麦自动抢票:基于 API 直连的毫秒级下单方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询