news 2026/10/16 2:59:51

Ascend C BitwiseNot 接口全面解析:逐比特取反的高阶数学 API、Tiling 临时空间规划与源码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ascend C BitwiseNot 接口全面解析:逐比特取反的高阶数学 API、Tiling 临时空间规划与源码实现
  • 人工智能
  • 深度学习
  • 算子库
  • CANN
  • Ascend

【免费下载链接】asc-devkit

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

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

本文围绕 CANN asc-devkit 开源仓库中 BitwiseNot 接口文档 及其关联的 BitwiseNot、GetBitwiseNotMaxMinTmpSize、GetBitwiseNotTmpBufferFactorSize 三篇接口说明,完整讲解昇腾 AI 处理器上对 LocalTensor 进行逐比特取反(Bitwise Not)的高阶数学计算接口:包括函数原型、模板与实参配置、支持的数据类型与产品范围、调用示例与结果语义、配套的 Host 侧 Tiling 临时空间规划接口,并结合仓库源码(接口头文件、内核实现、参数校验、Tiling 实现与单元测试)剖析其底层原理。读完本文,你将掌握 BitwiseNot 的正确调用方式、UB 临时空间的规划方法,以及从"文档到源码到测试"的完整证据链。

接口定位:数学计算高阶 API 家族中的按位运算成员

BitwiseNot 属于 asc-devkit 中 SIMD-API 高阶数学计算(math_compute)API 家族。该家族除 BitwiseNot 外,还包含同为按位运算的 BitwiseAnd、BitwiseOr、BitwiseXor,以及逻辑运算 LogicalNot、LogicalAnd、LogicalOr、LogicalXor 等接口。

BitwiseNot 的功能非常直接:逐比特对输入数据进行取反(按位非运算),即对每个元素的二进制表示执行~x操作(0 变 1,1 变 0)。这一操作常用于掩码生成、补码计算、图像处理中的颜色反相、以及各类位操作场景,是典型的单目(单输入)矢量运算。

产品支持情况:目前仅限 Ascend 950 系列

根据 BitwiseNot.md 中的产品支持矩阵,BitwiseNot 接口目前仅支持:

  • Ascend 950PR & 950DT 系列产品:支持

其余产品线均不支持:

  • Atlas A3 系列产品:不支持
  • Atlas A2 系列产品:不支持
  • Atlas 200I/500 A2 推理产品:不支持
  • Atlas 推理系列产品 AI Core / Vector Core:不支持
  • Atlas 训练系列产品:不支持

从源码侧可以得到一致的印证:内核实现头文件 bitwise_not.h 通过编译期宏__NPU_ARCH__判断,仅当架构为3510、9201、5102、5162、3003、3113时才包含并编译 bitwise_not_3510_impl.h 中的实现;同时该头文件还在文件顶部明确禁止了与--enable-simt编译标志混用(#error "bitwise_not.h cannot be used with compile flag --enable-simt enabled."),即 BitwiseNot 只能用于纯 SIMD(矢量)编程场景。

函数原型与参数详解

BitwiseNot 的完整函数原型如下(模板参数在前,普通参数在后):

template <const BitwiseNotConfig& config = DEFAULT_BITWISE_NOT_CONFIG, typename T> __aicore__ inline void BitwiseNot(const LocalTensor<T>& dst, const LocalTensor<T>& src, const uint32_t count)

模板参数说明

表1 模板参数说明

参数名描述
configBitwiseNot 算法的相关配置,可选配,类型为BitwiseNotConfig,具体定义如下方代码所示。其中参数的含义为:

isReuseSource:该参数预留,传入默认值 false 即可。
T源操作数、目的操作数数据类型。支持的数据类型为:int8_t、uint8_t、int16_t、uint16_t、int32_t、uint32_t、int64_t、uint64_t。

BitwiseNotConfig的定义(见 bitwise_not_utils.h 源码):

struct BitwiseNotConfig { bool isReuseSource; }; constexpr BitwiseNotConfig DEFAULT_BITWISE_NOT_CONFIG = {false};

从源码可以看到,仓库提供了编译期常量DEFAULT_BITWISE_NOT_CONFIG = {false},因此模板参数config在绝大多数情况下都可以省略(使用默认值)。isReuseSource字段当前为预留项,用于标识是否复用源操作数的输入空间,目前必须传入false——内核参数校验(见下文"参数校验"小节)会对该字段做强校验。

实参(普通参数)说明

表2 参数说明

参数名称类型说明
dst输出目的操作数。类型为 LocalTensor,支持的 TPosition 为 VECIN/VECCALC/VECOUT。
src输入源操作数。类型为 LocalTensor,支持的 TPosition 为 VECIN/VECCALC/VECOUT。数据类型需要与目的操作数保持一致。
count输入参与计算的元素个数。

需要说明的是,TPosition::VECIN/VECCALC/VECOUT三个逻辑位置在物理上都映射到Unified Buffer(UB)(参见 通用说明和约束 中的 TPosition 与物理内存映射关系表)。也就是说,参与 BitwiseNot 计算的 src 与 dst 都必须位于 AI Core 的 UB 上,计算前通常需要先用DataCopy将 Global Memory(GM)中的输入搬入 UB,计算完成后再将结果搬回 GM(完整流程见下文"Kernel 侧完整调用流程")。

返回值说明

无返回值(void),计算结果直接写入dst。

约束说明

使用 BitwiseNot 时必须遵守以下约束:

  • 不支持源操作数与目的操作数地址重叠。即src与dst不能指向 UB 中的同一段地址空间,这与基础 API 中"单次迭代内支持源目的 100% 完全重叠"的通用约定不同(通用说明和约束),属于该接口的额外限制,需要开发者额外注意。
  • 操作数地址偏移对齐要求请参见通用说明和约束。其中与 BitwiseNot 直接相关的是:UB 存储单元的起始地址要求 32 Byte 对齐(L1 Buffer 同样为 32 Byte 对齐,L0A/L0B 为 512 Byte 对齐,L0C 为 64 Byte 对齐)。

调用示例与结果语义

接口文档给出了最简调用示例:

AscendC::LocalTensor<uint32_t> dst, src; uint32_t count = 512; // 参与计算的元素个数 AscendC::BitwiseNot(dst, src, count);

示例运行结果(接口文档原样摘录):

输入数据(src): [ 91, 48, -71, 112, 64, -107, 74, -121, -103, -50, 112, -23, 15, ... -74] 输出数据(dst): [-92, -49, 70, -113, -65, 106, -75, 120, 102, 49, -113, 22, -16, ... 73]

结果的二进制语义解读

注意示例中src的数据类型是uint32_t,但输入值以带符号形式书写(如-71、-107)。逐比特取反的结果需要结合二进制的补码表示来理解:

  • 对于无符号数,~x等价于2^N - 1 - x(N 为位宽,如uint32_t的 N=32)。例如91(0x0000005B)取反后为0xFFFFFFA4,按有符号int32_t解读即为-92,与示例输出一致。
  • 对于有符号负数,其二进制即补码,逐比特取反后等价于-x - 1。例如-71(0xFFFFFFB9)取反为0x00000046,即70,与示例输出一致。

因此,BitwiseNot 对源数据的每一位(含符号位)统一翻转,不区分符号,这正是"逐比特取反"与"数值取负(Neg)"的本质区别。

Kernel 侧完整调用流程

在实际算子开发中,BitwiseNot 需要与数据搬运、队列管理配合使用。仓库测试用例 test_operator_bitwise_not.cpp 给出了一个完整的可参考模板:使用TQue<TPosition::VECIN, 1>输入队列和TQue<TPosition::VECOUT, 1>输出队列,CopyIn阶段用DataCopy把 GlobalTensor 数据搬入 UB,Compute阶段调用BitwiseNot(dstLocal, srcLocal, this->dataSize),CopyOut阶段把结果搬回 GM,并对count不能按32/sizeof(T)整除的尾数部分做逐元素SetValue/GetValue回写:

__aicore__ inline void Compute() { PipeBarrier<PIPE_ALL>(); LocalTensor<T> dstLocal = outQueue.AllocTensor<T>(); LocalTensor<T> srcLocal = inQueue.DeQue<T>(); BitwiseNot(dstLocal, srcLocal, this->dataSize); outQueue.EnQue<T>(dstLocal); inQueue.FreeTensor(srcLocal); }

源码级实现原理

接口入口与编译期分派

公开接口声明位于 include/adv_api/math/bitwise_not.h。该头文件通过__NPU_ARCH__编译期宏判断目标架构,仅对支持的架构(3510、9201、5102、5162、3003、3113)引入内核实现 bitwise_not_3510_impl.h,并把真正的计算逻辑转发给BitwiseNotImpl<config, T>(dst, src, count)。

内核实现:类型分派与矢量寄存器运算

bitwise_not_3510_impl.h 中的BitwiseNotImpl首先通过static_assert+SupportType<T, uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t>()在编译期强制校验数据类型必须是文档声明的 8 种类型之一,随后按数据类型字节数做两条计算路径的分派:

  • sizeof(T) == 8(int64_t/uint64_t):使用双寄存器特性Reg::RegTraitNumTwo,单次repeat处理GetVecLen() / sizeof(T) * 2个元素;
  • 其他类型:使用单寄存器Reg::RegTensor<T>,单次repeat处理GetVecLen() / sizeof(T)个元素。

真正的计算在BitwiseNotCompute中完成,核心调用链为寄存器级的Reg::Not(dstVreg, srcVreg, mask)矢量取反指令,配合Reg::LoadAlign/Reg::StoreAlign完成 UB 数据的加载与回存,并用Reg::UpdateMask<T, Trait>(count)生成尾数掩码来处理不能被单次 repeat 整除的剩余元素:

Reg::LoadAlign(srcVreg, src + i * oneRepElm); Reg::Not(dstVreg, srcVreg, mask); Reg::StoreAlign(dst + i * oneRepElm, dstVreg, mask);

可以看到,整条计算被划分为repeatTime次循环(每次双份处理)加一次尾部处理,以充分利用矢量单元的计算宽度。

参数校验(API Check)

在ASCENDC_CPU_DEBUG等调试路径下,bitwise_not_check_c310.h 中的CheckFuncClassBitwiseNot会组合多组基础校验类完成运行期检查:

  • CalCountVerifyingParameters:校验count(参与计算元素个数)的合法性;
  • TensorVerifyingParameters:校验 dst/src 的 TPosition 必须是VECIN/VECOUT/VECCALC(即必须位于 UB);
  • TensorReuseVerifyingParameters:校验 dst 与 src 不得地址重叠(对应上文"不支持源操作数与目的操作数地址重叠"约束);
  • IsReuseSourceVerifyingParameters<false>:校验isReuseSource必须为 false(预留参数强约束)。

Tiling 配套接口(一):GetBitwiseNotMaxMinTmpSize

BitwiseNot 的核函数(Kernel)侧计算需要开发者预留/申请临时空间。GetBitwiseNotMaxMinTmpSize 用于在 Host 侧获取预留/申请的最大和最小临时空间大小,开发者基于此范围选择合适的空间大小作为 Tiling 参数传递到核函数侧使用。

使用要点:

  • 为保证功能正确,预留/申请的临时空间大小不能小于最小临时空间大小;
  • 在最小临时空间~最大临时空间范围内,随着临时空间增大,核函数侧接口计算性能会有一定程度的优化提升。为了达到更好的性能,开发者可以根据实际的内存使用情况进行空间预留/申请。

函数原型

void GetBitwiseNotMaxMinTmpSize(const platform_ascendc::PlatformAscendC& ascendcPlatform, const AscendC::TensorShape& srcShape, const uint32_t typeSize, const bool isReuseSource, uint32_t& maxValue, uint32_t& minValue)

参数说明

表1 接口参数列表

参数名输入/输出功能
ascendcPlatform输入输入的平台信息。PlatformAscendC 的定义请参见构造及析构函数。
srcShape输入输入的 shape 信息,参数类型为 AscendC::TensorShape(ge::Shape的类型别名)。
typeSize输入输入的数据类型大小,单位为字节。比如输入的数据类型为 uint16_t,此处应传入 2。
isReuseSource输入该参数预留,传入默认值 false 即可。
maxValue输出BitwiseNot 接口能完成计算所需的最大临时空间大小,超出该值的空间不会被该接口使用。最大空间大小为 0 表示计算不需要临时空间。请注意,maxValue 仅作为参考值,有可能大于 Unified Buffer(UB)剩余空间的大小,该场景下,开发者需要根据 UB 剩余空间的大小来选取合适的临时空间大小。
minValue输出BitwiseNot 接口能完成计算所需最小临时空间大小。最小空间大小为 0 表示计算不需要临时空间。

调用示例

std::vector<int64_t> shape_vec = {1024}; AscendC::TensorShape shape(shape_vec); uint32_t maxValue = 0; uint32_t minValue = 0; auto plat = platform_ascendc::PlatformAscendC(context->GetPlatformInfo()); AscendC::GetBitwiseNotMaxMinTmpSize(plat, shape, 2, false, maxValue, minValue);

Tiling 实现侧的证据

Host 侧实现位于 bitwise_not_tiling_impl.cpp:

  • 内部维护SUPPORT_TYPESIZE = {1, 2, 4, 8},与 BitwiseNot 支持的 8 种整数类型(1/2/4/8 字节)一一对应,typeSize不在该集合时会触发TypeSizeVerifyingParameters校验失败;
  • 通过ASCENDC_HOST_ASSERT((npuArch == NpuArch::DAV_3510 || npuArch == NpuArch::DAV_9201), ...)校验 NPU 架构,与接口文档"仅 Ascend 950 系列支持"的产品矩阵一致;
  • GetBitwiseNotMaxTmpSize与GetBitwiseNotMinTmpSize当前均返回 0,即该接口当前版本的 BitwiseNot 计算不需要额外临时空间,与测试用例的断言一致(见下文"测试用例验证")。

Tiling 配套接口(二):GetBitwiseNotTmpBufferFactorSize

GetBitwiseNotTmpBufferFactorSize 用于获取maxLivedNodeCount和extraBuf,在固定空间大小的情况下,通过这两个输出值可以推算算子单次最大计算元素数量:

  • maxLivedNodeCount:最大存活节点数,表示临时空间是单次计算数据量所占空间的多少倍;
  • extraBuf:使用的额外临时空间大小,单位为字节。

单接口推算公式

算子实现需要调用 BitwiseNot 接口,开发者为其预留currBuff大小的空间,利用 GetBitwiseNotTmpBufferFactorSize 接口得到maxLivedNodeCount、extraBuf输出值,可推导算子单次最大计算元素数量为:

currentShapeSize = (currBuff - extraBuf) / maxLivedNodeCount / typeSize

多接口组合推算公式

算子实现需要调用两个核函数侧 API(如 KernelIntf1、KernelIntf2),利用两个 GetXxxTmpBufferFactorSize(其中 Xxx 为需要调用的两个高阶 API)接口的两组输出值(maxLivedNodeCount、extraBuf)以及当前现有的临时空间,分别推导单次最大计算元素数量,再取较小值作为最终的单次计算规模:

currentShapeSize1 = (currBuff - extraBuf1) / maxLivedNodeCount1 / typeSize currentShapeSize2 = (currBuff - extraBuf2) / maxLivedNodeCount2 / typeSize currentShapeSize = min(currentShapeSize1, currentShapeSize2)

注意:上文中的currBuff表示接口计算可用的空间,需要去除用户输入输出等空间;另外,接口获取的maxLivedNodeCount值可能为 0,计算时需要判断该值非 0,避免除零错误。

函数原型

void GetBitwiseNotTmpBufferFactorSize(const platform_ascendc::PlatformAscendC& ascendcPlatform, const uint32_t typeSize, uint32_t& maxLivedNodeCount, uint32_t& extraBuf)

参数说明

表1 参数列表

参数名输入/输出功能
ascendcPlatform输入输入的平台信息。PlatformAscendC 的定义请参见构造及析构函数。
typeSize输入输入的数据类型大小,单位为字节。
maxLivedNodeCount输出最大存活节点数,表示临时空间是单次计算数据量所占空间的多少倍。
extraBuf输出使用的额外临时空间大小,单位为字节。

约束说明

当利用 maxLivedNodeCount、extraBuf 反推出的currentShapeSize * typeSize < 256B时,currentShapeSize 按照256B / typeSize的值向上取整。这一约束与矢量计算以 256 Byte 为基本处理粒度的硬件特性相吻合。

调用示例

uint32_t maxLivedNodeCount = 0; uint32_t extraBuf = 0; auto plat = platform_ascendc::PlatformAscendC(context->GetPlatformInfo()); AscendC::GetBitwiseNotTmpBufferFactorSize(plat, typeSize, maxLivedNodeCount, extraBuf);

Host 侧 Tiling 与 Kernel 侧的配套使用流程

GetXxxMaxMinTmpSize 系列 Tiling 接口的完整配套使用方法,可参考更多样例(该文档以同类数学接口 Asin 为例说明通用流程,同样适用于 BitwiseNot 系列接口):

  1. Host 侧:在 Tiling 函数中构造AscendC::TensorShape shape(srcDims)描述输入形状,调用GetBitwiseNotMaxMinTmpSize获取maxValue/minValue;再通过platform_ascendc::PlatformAscendC(platformInfo).GetCoreMemSize(platform_ascendc::CoreMemType::UB, tailSize)获取 UB 剩余空间(实际场景需减去已使用的 UB 空间),并以tailSize >= maxValue ? maxValue : tailSize确定最终临时空间大小tmpSize,写入 TilingData(如srcSize、tmpBufferSize字段)传给 Kernel;
  2. Kernel 侧:通过GET_TILING_DATA读取 TilingData,用pipe.InitBuffer(tmpBuf, tmpBufferSize)按计算出的空间大小申请临时 Buffer,之后即可安全调用 BitwiseNot 完成计算。

这种"Host 侧算空间、Kernel 侧按空间计算"的配合方式,能够避免临时空间申请不足导致的错误,也能在 UB 空间允许的范围内最大化单次计算规模。

测试用例验证

仓库为 BitwiseNot 提供了两层测试验证:

  1. 内核功能测试test_operator_bitwise_not.cpp:以BitwiseNotTestParams{dataTypeSize, inDataSize, calFunc}参数化方式覆盖8 种数据类型 × 3 种数据规模(32 / 256 / 1024 元素),即 uint8_t、int8_t、uint16_t、int16_t、uint32_t、int32_t、uint64_t、int64_t 全类型组合。测试将输入初始化为1(二进制最低位为 1,其余位为 0),调用 BitwiseNot 后校验输出字节全为0x00,精确验证了"逐比特取反"的语义(~0x01 = 0xFE,取uint8_t首字节即0x00)。

  2. Tiling 接口测试test_tiling_v310.cpp 中的TestBitwiseNotTiling:构造shapeDims = {128}的 shape 与sizeof(float)(4 字节)的 typeSize,断言GetBitwiseNotMaxMinTmpSize返回的maxVal、minVal均为 0,GetBitwiseNotTmpBufferFactorSize返回的extraBuf、maxLivedNodesCnt均为 0——印证了当前版本 BitwiseNot 计算无需额外临时空间,开发者调用这两个 Tiling 接口时可直接将返回值作为 0 处理,或按通用流程将其作为"空间下限/上限"参考继续参与 UB 规划。

关键源码路径速览

内容仓库相对路径
公开接口声明include/adv_api/math/bitwise_not.h
配置结构体定义include/adv_api/math/bitwise_not_utils.h
Tiling 接口声明include/adv_api/math/bitwise_not_tiling.h
内核实现(Reg::Not 矢量取反)impl/adv_api/detail/math/bitwise_not/bitwise_not_3510_impl.h
Tiling 实现(临时空间计算)impl/adv_api/tiling/math/bitwise_not_tiling_impl.cpp
参数校验实现impl/adv_api/detail/api_check/kernel_check/math/bitwise_not/bitwise_not_check_c310.h
内核功能测试tests/api/adv_api/math/bitwise_not/test_operator_bitwise_not.cpp
Tiling 接口测试tests/api/adv_api/tiling/test_tiling_v310.cpp

继续阅读

  • BitwiseNot 接口页(接口索引入口)
  • BitwiseAnd、BitwiseOr、BitwiseXor 等同类按位运算接口
  • 数学计算接口总览
  • 通用说明和约束(TPosition 映射、地址对齐)
  • LocalTensor 数据结构
  • 人工智能
  • 深度学习
  • 算子库
  • CANN
  • Ascend

【免费下载链接】asc-devkit

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

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

相关推荐

上一篇:Apache Pulsar 主题统计指标全解读:从 partitioned-stats 到 stats-internal 的运维实战指南
下一篇:ai-marketing-skills eval 技能:如何为任意AI功能自动搭建评估套件并检测回归

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 2:58:56

大模型基础与 Ollama 本地部署

本篇主要记录大模型学习第一阶段的内容&#xff0c;包括大模型基础概念、私有化部署、Ollama 的安装与使用、常用命令、HTTP/API 基础&#xff0c;以及使用 ChatBox 快速搭建本地 ChatBot。一、大模型与聊天机器人基础1.1 什么是聊天机器人聊天机器人&#xff08;ChatBot&#…

作者头像 李华
网站建设 2026/10/16 2:58:22

【uni-app项目实战】心理健康服务平台(六)

目录 十一、极速问诊 11.1 选择患者 11.1.1 布局模板 11.1.2 患者列表 11.2.3 选择患者 11.2 预付订单 11.2.1 布局模板 11.2.2 跳转页面 11.2.3 订单信息 11.2.4 患者信息 11.3 待付订单 11.4 支付渠道 11.4.1 custom-payment 11.4.2 支付流程 11.4.3 支付宝支…

作者头像 李华
网站建设 2026/10/16 2:57:11

仓颉 ArkUI Badge 信息标记组件开发指南:用法、样式与实战示例

文档知识库教程OpenHarmony 【免费下载链接】CangjieCorpus 本仓库为仓颉编程语言语料库&#xff0c;聚焦 仓颉编程语言 核心知识体系&#xff0c;整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源&#xff0c;经结构化处理与专业标注&#xff0c;构建为支持 R…

作者头像 李华