已合并
tan算子支持Ascend910b AscendC实现 #2132
wangweidong创建于 4月8日
tan算子支持Ascend910b AscendC实现 #2132
已合并
共 14 个文件变更+1206-0
| @@ -0,0 +1,22 @@ | |||
| 1 | + # ---------------------------------------------------------------------------------------------------------- | ||
| 2 | + # Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + # CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + | ||
| 6 | + # Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | + # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 9 | + # See LICENSE in the root of the software repository for the full text of the License. | ||
| 10 | + # ---------------------------------------------------------------------------------------------------------- | ||
| 11 | + # NOTE: Portions of this code were AI-generated and have been | ||
| 12 | + # technically reviewed for functional accuracy and security | ||
| 13 | + | ||
| 14 | +file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 15 | +if(NOT ENABLE_TEST) | ||
| 16 | + list(REMOVE_ITEM CURRENT_DIRS tests) | ||
| 17 | +endif() | ||
| 18 | +foreach(SUB_DIR ${CURRENT_DIRS}) | ||
| 19 | + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt") | ||
| 20 | + add_subdirectory(${SUB_DIR}) | ||
| 21 | + endif() | ||
| 22 | +endforeach() | ||
| @@ -0,0 +1,242 @@ | |||
| 1 | +# Tan 自定义算子 | ||
| 2 | + | ||
| 3 | +## 功能说明 | ||
| 4 | + | ||
| 5 | +Tan 算子计算输入张量的逐元素正切值: | ||
| 6 | + | ||
| 7 | +``` | ||
| 8 | +tan(x) = sin(x) / cos(x) | ||
| 9 | +``` | ||
| 10 | + | ||
| 11 | +**对标**:PyTorch `torch.tan` | ||
| 12 | + | ||
| 13 | +## 支持规格 | ||
| 14 | + | ||
| 15 | +### 数据类型 | ||
| 16 | + | ||
| 17 | +| 输入 x | 输出 out | | ||
| 18 | +|--------|---------| | ||
| 19 | +| float32 | float32 | | ||
| 20 | +| float16 | float16 | | ||
| 21 | + | ||
| 22 | +注意:输出 out 的数据类型与输入 x 一致。 | ||
| 23 | + | ||
| 24 | +### Shape | ||
| 25 | + | ||
| 26 | +- 支持任意维度(标量、1D ~ 8D 均已验证) | ||
| 27 | +- 输出 shape 与输入 shape 相同 | ||
| 28 | +- 不支持广播(单输入算子) | ||
| 29 | +- 支持空 tensor(元素数为 0) | ||
| 30 | +- 支持动态 shape / 动态 rank | ||
| 31 | + | ||
| 32 | +### 目标芯片 | ||
| 33 | + | ||
| 34 | +- Ascend 910B3(arch32 架构) | ||
| 35 | + | ||
| 36 | +## 使用方法 | ||
| 37 | + | ||
| 38 | +### aclnn API 调用 | ||
| 39 | + | ||
| 40 | +```cpp | ||
| 41 | +#include "acl/acl.h" | ||
| 42 | +#include "aclnn_tan.h" | ||
| 43 | + | ||
| 44 | +// 第一步:获取 workspace 大小和执行器 | ||
| 45 | +uint64_t workspaceSize = 0; | ||
| 46 | +aclOpExecutor* executor = nullptr; | ||
| 47 | +auto ret = aclnnTanGetWorkspaceSize( | ||
| 48 | + x_tensor, // 输入张量 x | ||
| 49 | + output_tensor, // 输出张量 | ||
| 50 | + &workspaceSize, // 输出:workspace 大小 | ||
| 51 | + &executor // 输出:执行器句柄 | ||
| 52 | +); | ||
| 53 | + | ||
| 54 | +// 第二步:分配 workspace 内存 | ||
| 55 | +void* workspace = nullptr; | ||
| 56 | +if (workspaceSize > 0) { | ||
| 57 | + aclrtMalloc(&workspace, workspaceSize, ACL_MEM_MALLOC_NORMAL_ONLY); | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// 第三步:执行算子 | ||
| 61 | +ret = aclnnTan(workspace, workspaceSize, executor, stream); | ||
| 62 | + | ||
| 63 | +// 第四步:同步并释放资源 | ||
| 64 | +aclrtSynchronizeStream(stream); | ||
| 65 | +if (workspace) aclrtFree(workspace); | ||
| 66 | +``` | ||
| 67 | + | ||
| 68 | +### 张量创建示例 | ||
| 69 | + | ||
| 70 | +```cpp | ||
| 71 | +// 创建 float32 张量,shape [2, 4] | ||
| 72 | +std::vector<int64_t> shape = {2, 4}; | ||
| 73 | +std::vector<int64_t> strides = {4, 1}; | ||
| 74 | +aclTensor* tensor = aclCreateTensor( | ||
| 75 | + shape.data(), shape.size(), | ||
| 76 | + ACL_FLOAT, // 数据类型 | ||
| 77 | + strides.data(), 0, // strides + offset | ||
| 78 | + ACL_FORMAT_ND, // 格式 | ||
| 79 | + shape.data(), shape.size(), | ||
| 80 | + device_ptr // 设备内存指针 | ||
| 81 | +); | ||
| 82 | +``` | ||
| 83 | + | ||
| 84 | +### 完整示例参考 | ||
| 85 | + | ||
| 86 | +- **aclnn 调用示例**:`examples/test_aclnn_tan.cpp` | ||
| 87 | +- **GE IR 图模式示例**:`examples/test_geir_tan.cpp` | ||
| 88 | + | ||
| 89 | +运行示例: | ||
| 90 | + | ||
| 91 | +```bash | ||
| 92 | +cd examples | ||
| 93 | +bash run.sh # 运行 aclnn 调用示例(默认) | ||
| 94 | +bash run.sh --graph # 运行图模式 (GE IR) 调用示例 | ||
| 95 | +``` | ||
| 96 | + | ||
| 97 | +## 精度说明 | ||
| 98 | + | ||
| 99 | +| 数据类型 | 精度标准 | 真实 NPU 表现 | 备注 | | ||
| 100 | +|---------|---------|-------------|------| | ||
| 101 | +| float32 | rtol=1e-4, atol=1e-6 | 100% 通过 | 全量 36 条用例 | | ||
| 102 | +| float16 | rtol=1e-3, atol=1e-3 | 100% 通过 | 全量 20 条用例 | | ||
| 103 | + | ||
| 104 | +**说明**:float16 路径内部先 Cast 升至 float32 进行 Sin/Cos/Div 计算,再 Cast 回 float16,保证精度。 | ||
| 105 | + | ||
| 106 | +## 构建方法 | ||
| 107 | + | ||
| 108 | +### 前提条件 | ||
| 109 | + | ||
| 110 | +- CANN Toolkit 已安装(路径:`/home/developer/Ascend/cann-9.0.0` 或其他版本) | ||
| 111 | +- 已设置环境变量:`source /home/developer/Ascend/ascend-toolkit/set_env.sh` | ||
| 112 | + | ||
| 113 | +### 编译自定义算子包 | ||
| 114 | + | ||
| 115 | +```bash | ||
| 116 | +cd ops/tan | ||
| 117 | +bash build.sh --soc=ascend910b --pkg | ||
| 118 | +``` | ||
| 119 | + | ||
| 120 | +编译成功后,算子包位于 `build/custom_opp_ubuntu_aarch64.run`。 | ||
| 121 | + | ||
| 122 | +### 安装算子包 | ||
| 123 | + | ||
| 124 | +```bash | ||
| 125 | +bash build/custom_opp_ubuntu_aarch64.run | ||
| 126 | +``` | ||
| 127 | + | ||
| 128 | +算子安装到:`$ASCEND_HOME_PATH/opp/vendors/tan_custom/` | ||
| 129 | + | ||
| 130 | +## 测试方法 | ||
| 131 | + | ||
| 132 | +### 运行 UT(单元测试) | ||
| 133 | + | ||
| 134 | +```bash | ||
| 135 | +cd tests/ut | ||
| 136 | +bash run.sh | ||
| 137 | +``` | ||
| 138 | + | ||
| 139 | +### 运行 ST(系统测试) | ||
| 140 | + | ||
| 141 | +```bash | ||
| 142 | +cd tests/st | ||
| 143 | +bash run.sh | ||
| 144 | +``` | ||
| 145 | + | ||
| 146 | +全量 56 条测试用例(36 条 float32 + 20 条 float16)。 | ||
| 147 | + | ||
| 148 | +ST 测试支持两种模式: | ||
| 149 | +- **Mock 模式**(CPU Golden):无需 NPU,用于开发验证 | ||
| 150 | +- **真实 NPU 模式**:需要 NPU 设备,验证实际精度 | ||
| 151 | + | ||
| 152 | +### 一键编译 + 测试 | ||
| 153 | + | ||
| 154 | +```bash | ||
| 155 | +bash build.sh --soc=ascend910b --pkg -a # 编译 + UT + ST | ||
| 156 | +bash build.sh --soc=ascend910b --pkg -u # 编译 + 仅 UT | ||
| 157 | +bash build.sh --soc=ascend910b --pkg -s # 编译 + 仅 ST | ||
| 158 | +``` | ||
| 159 | + | ||
| 160 | +## 目录结构 | ||
| 161 | + | ||
| 162 | +``` | ||
| 163 | +ops/tan/ | ||
| 164 | +├── README.md # 本文档 | ||
| 165 | +├── CMakeLists.txt # 顶层构建脚本 | ||
| 166 | +├── build.sh # 编译脚本 | ||
| 167 | +├── op_host/ # Host 侧实现 | ||
| 168 | +│ ├── CMakeLists.txt | ||
| 169 | +│ ├── tan_def.cpp # 算子定义(aclnn API 注册) | ||
| 170 | +│ ├── tan_infershape.cpp # InferShape(输出 shape = 输入 shape) | ||
| 171 | +│ └── arch32/ | ||
| 172 | +│ └── tan_tiling.cpp # Tiling 实现(多核切分 + UB 切分) | ||
| 173 | +├── op_kernel/ # Device 侧实现 | ||
| 174 | +│ ├── CMakeLists.txt | ||
| 175 | +│ ├── tan_arch32.cpp # Kernel 入口(模板分发) | ||
| 176 | +│ └── arch32/ | ||
| 177 | +│ ├── tan.h # Kernel 实现(核心计算逻辑) | ||
| 178 | +│ ├── tan_tiling_data.h # Tiling 数据结构 | ||
| 179 | +│ └── tan_tiling_key.h # Tiling Key 定义 | ||
| 180 | +├── op_graph/ | ||
| 181 | +│ └── tan_proto.h # GE IR 算子原型注册 | ||
| 182 | +├── examples/ # 调用示例 | ||
| 183 | +│ ├── CMakeLists.txt # aclnn 模式构建脚本 | ||
| 184 | +│ ├── CMakeLists_geir.txt # GE IR 模式构建脚本 | ||
| 185 | +│ ├── run.sh # 统一运行脚本(--eager / --graph) | ||
| 186 | +│ ├── test_aclnn_tan.cpp # aclnn 调用示例 | ||
| 187 | +│ └── test_geir_tan.cpp # GE IR 图模式调用示例 | ||
| 188 | +├── tests/ | ||
| 189 | +│ ├── st/ # 系统测试 | ||
| 190 | +│ │ ├── test_aclnn_tan.cpp # ST 测试工程(56 条用例) | ||
| 191 | +│ │ ├── CMakeLists.txt | ||
| 192 | +│ │ └── run.sh # ST 运行脚本 | ||
| 193 | +│ └── ut/ # 单元测试 | ||
| 194 | +│ ├── run.sh # UT 运行脚本 | ||
| 195 | +│ ├── CMakeLists.txt | ||
| 196 | +│ └── op_host/ | ||
| 197 | +│ ├── CMakeLists.txt | ||
| 198 | +│ ├── test_op_host_main.cpp | ||
| 199 | +│ ├── test_tan_infershape.cpp # InferShape UT | ||
| 200 | +│ └── test_tan_tiling.cpp # Tiling UT | ||
| 201 | +├── docs/ | ||
| 202 | +│ ├── aclnnTan.md # aclnn API 接口文档 | ||
| 203 | +│ ├── REQUIREMENT_ANALYSIS.md # 需求分析文档 | ||
| 204 | +│ ├── DETAILED_DESIGN.md # 详细设计文档 | ||
| 205 | +│ ├── TEST_DESIGN.md # 测试设计文档 | ||
| 206 | +│ ├── PRECISION_VERIFICATION_REPORT.md # 精度验收报告 | ||
| 207 | +│ └── DEVELOPMENT_LOG.md # 开发日志 | ||
| 208 | +└── build/ # 编译输出目录 | ||
| 209 | + └── custom_opp_ubuntu_aarch64.run # 算子包 | ||
| 210 | +``` | ||
| 211 | + | ||
| 212 | +## 实现说明 | ||
| 213 | + | ||
| 214 | +### 核心计算步骤 | ||
| 215 | + | ||
| 216 | +#### float32 路径 | ||
| 217 | + | ||
| 218 | +``` | ||
| 219 | +sinVal = Sin(x) // 计算 sin(x) | ||
| 220 | +cosVal = Cos(x) // 计算 cos(x) | ||
| 221 | +y = Div(sinVal, cosVal) // tan(x) = sin(x) / cos(x) | ||
| 222 | +``` | ||
| 223 | + | ||
| 224 | +#### float16 路径(升精度计算) | ||
| 225 | + | ||
| 226 | +``` | ||
| 227 | +x_fp32 = Cast(x, CAST_NONE) // half -> float32 | ||
| 228 | +cosVal = Cos(x_fp32) // 先算 cos(避免输入被覆盖) | ||
| 229 | +sinVal = Sin(x_fp32) // 再算 sin | ||
| 230 | +result = Div(sinVal, cosVal) // tan = sin / cos | ||
| 231 | +y = Cast(result, CAST_ROUND) // float32 -> half | ||
| 232 | +``` | ||
| 233 | + | ||
| 234 | +### Tiling 策略 | ||
| 235 | + | ||
| 236 | +- **多核切分**:总元素数均匀分配到各 AI Core | ||
| 237 | + - `blockFactor = CeilDiv(totalNum, coreNum)` | ||
| 238 | + - `usedCoreNum = CeilDiv(totalNum, blockFactor)` | ||
| 239 | +- **UB 切分**:每个 Core 内按 UB 容量分块处理 | ||
| 240 | + - float32:`ubFactor = FloorAlign(ubCanUse / 4 / 6, ubBlockSize)`(6 块 buffer) | ||
| 241 | + - float16:`ubFactor = FloorAlign(ubCanUse / 4 / 4, ubBlockSize)`(4 块 buffer) | ||
| 242 | +- **流水线**:双 buffer(BUFFER_NUM=2),CopyIn → Compute → CopyOut 三级流水 | ||
| @@ -0,0 +1,149 @@ | |||
| 1 | +# aclnnTan | ||
| 2 | + | ||
| 3 | +## 支持的产品型号 | ||
| 4 | + | ||
| 5 | +| 产品 | 是否支持 | | ||
| 6 | +| :----------------------------------------------------------- | :------: | | ||
| 7 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 8 | + | ||
| 9 | +## 功能描述 | ||
| 10 | + | ||
| 11 | +计算输入张量 `x` 的逐元素正切值,即 $out = \tan(x) = \frac{\sin(x)}{\cos(x)}$。 | ||
| 12 | + | ||
| 13 | +- 不支持广播:`out` 的 shape 与 `x` 相同。 | ||
| 14 | +- 支持数据类型:float32、float16。 | ||
| 15 | + | ||
| 16 | +## 函数原型 | ||
| 17 | + | ||
| 18 | +```cpp | ||
| 19 | +aclnnStatus aclnnTanGetWorkspaceSize( | ||
| 20 | + const aclTensor *x, | ||
| 21 | + const aclTensor *out, | ||
| 22 | + uint64_t *workspaceSize, | ||
| 23 | + aclOpExecutor **executor); | ||
| 24 | + | ||
| 25 | +aclnnStatus aclnnTan( | ||
| 26 | + void *workspace, | ||
| 27 | + uint64_t workspaceSize, | ||
| 28 | + aclOpExecutor *executor, | ||
| 29 | + aclrtStream stream); | ||
| 30 | +``` | ||
| 31 | + | ||
| 32 | +## aclnnTanGetWorkspaceSize | ||
| 33 | + | ||
| 34 | +### 参数说明 | ||
| 35 | + | ||
| 36 | +| 参数名 | 输入/输出 | 描述 | | ||
| 37 | +|-------|---------|------| | ||
| 38 | +| x | 输入 | 数据类型:float32、float16。数据格式:ND。支持非连续 tensor。 | | ||
| 39 | +| out | 输出 | 数据类型与 x 相同。数据格式:ND。shape 须与 x 相同。支持非连续 tensor。 | | ||
| 40 | +| workspaceSize | 输出 | 算子执行所需 workspace 大小,单位为 Byte。由本函数返回,调用方须据此分配 workspace 内存。 | | ||
| 41 | +| executor | 输出 | 算子执行器,包含算子计算流信息,由本函数返回后传入 aclnnTan 执行。 | | ||
| 42 | + | ||
| 43 | +### 返回值说明 | ||
| 44 | + | ||
| 45 | +返回 `aclnnStatus` 错误码,详见 [aclnn 错误码](#错误码)。 | ||
| 46 | + | ||
| 47 | +## aclnnTan | ||
| 48 | + | ||
| 49 | +### 参数说明 | ||
| 50 | + | ||
| 51 | +| 参数名 | 输入/输出 | 描述 | | ||
| 52 | +|-------|---------|------| | ||
| 53 | +| workspace | 输入 | workspace 内存地址。若 workspaceSize 为 0,可传入 nullptr。 | | ||
| 54 | +| workspaceSize | 输入 | workspace 大小,由 aclnnTanGetWorkspaceSize 返回。 | | ||
| 55 | +| executor | 输入 | 算子执行器,由 aclnnTanGetWorkspaceSize 返回。 | | ||
| 56 | +| stream | 输入 | ACL stream,用于异步调度算子执行。 | | ||
| 57 | + | ||
| 58 | +### 返回值说明 | ||
| 59 | + | ||
| 60 | +返回 `aclnnStatus` 错误码,详见 [aclnn 错误码](#错误码)。 | ||
| 61 | + | ||
| 62 | +## 错误码 | ||
| 63 | + | ||
| 64 | +| 错误码 | 描述 | | ||
| 65 | +|-------|------| | ||
| 66 | +| ACLNN_SUCCESS(0) | 执行成功。 | | ||
| 67 | +| ACLNN_ERR_PARAM_NULLPTR | 输入/输出 tensor 指针为空。 | | ||
| 68 | +| ACLNN_ERR_PARAM_INVALID | 参数非法,包括:数据类型不支持、out shape 与 x 不一致等。 | | ||
| 69 | +| ACLNN_ERR_INNER_CREATE_EXECUTOR | 内部创建算子执行器失败。 | | ||
| 70 | +| ACLNN_ERR_INNER_NULLPTR | 内部 tensor 分配失败。 | | ||
| 71 | +| ACLNN_ERR_INNER_INFERSHAPE_ERROR | 内部 InferShape 失败。 | | ||
| 72 | + | ||
| 73 | +## 约束说明 | ||
| 74 | + | ||
| 75 | +- 输入 `x` 支持 float32 和 float16 数据类型。 | ||
| 76 | +- `out` 的数据类型须与 `x` 相同。 | ||
| 77 | +- `out` 的 shape 须与 `x` 相同(不支持广播)。 | ||
| 78 | +- 支持标量输入(内部转为 shape {1} 处理)。 | ||
| 79 | +- 支持空 tensor(元素数为 0),此时 workspaceSize 为 0,直接返回成功。 | ||
| 80 | +- workspace 须在调用 `aclnnTan` 之前分配,在 stream 中算子执行完成后方可释放。 | ||
| 81 | +- 当输入值接近 $\frac{\pi}{2} + k\pi$($k$ 为整数)时,正切函数结果趋向无穷大,可能出现精度下降或溢出。 | ||
| 82 | + | ||
| 83 | +## 调用示例 | ||
| 84 | + | ||
| 85 | +以下示例展示了 Tan 算子的完整调用流程: | ||
| 86 | + | ||
| 87 | +```cpp | ||
| 88 | +#include <cstdio> | ||
| 89 | +#include <vector> | ||
| 90 | +#include "acl/acl.h" | ||
| 91 | +#include "aclnn_tan.h" | ||
| 92 | + | ||
| 93 | +int main() { | ||
| 94 | + // 1. 初始化 ACL 及设备 | ||
| 95 | + aclInit(nullptr); | ||
| 96 | + aclrtSetDevice(0); | ||
| 97 | + aclrtStream stream; | ||
| 98 | + aclrtCreateStream(&stream); | ||
| 99 | + | ||
| 100 | + // 2. 准备输入数据(fp32,shape=[2,4]) | ||
| 101 | + // x = [0.0, 0.5, 1.0, -1.0, 0.25, -0.5, 2.0, -2.0] | ||
| 102 | + // out = tan(x) | ||
| 103 | + int64_t shape[] = {2, 4}; | ||
| 104 | + int64_t strides[] = {4, 1}; | ||
| 105 | + float x_host[] = {0.0f, 0.5f, 1.0f, -1.0f, 0.25f, -0.5f, 2.0f, -2.0f}; | ||
| 106 | + float out_host[8] = {0}; | ||
| 107 | + | ||
| 108 | + void *x_dev = nullptr, *out_dev = nullptr; | ||
| 109 | + size_t nbytes = 8 * sizeof(float); | ||
| 110 | + aclrtMalloc(&x_dev, nbytes, ACL_MEM_MALLOC_NORMAL_ONLY); | ||
| 111 | + aclrtMalloc(&out_dev, nbytes, ACL_MEM_MALLOC_NORMAL_ONLY); | ||
| 112 | + aclrtMemcpy(x_dev, nbytes, x_host, nbytes, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 113 | + | ||
| 114 | + // 3. 创建 aclTensor | ||
| 115 | + aclTensor *x = aclCreateTensor(shape, 2, ACL_FLOAT, strides, 0, | ||
| 116 | + ACL_FORMAT_ND, shape, 2, x_dev); | ||
| 117 | + aclTensor *out = aclCreateTensor(shape, 2, ACL_FLOAT, strides, 0, | ||
| 118 | + ACL_FORMAT_ND, shape, 2, out_dev); | ||
| 119 | + | ||
| 120 | + // 4. 查询 workspace 大小并分配 | ||
| 121 | + uint64_t workspaceSize = 0; | ||
| 122 | + aclOpExecutor *executor = nullptr; | ||
| 123 | + aclnnTanGetWorkspaceSize(x, out, &workspaceSize, &executor); | ||
| 124 | + | ||
| 125 | + void *workspace = nullptr; | ||
| 126 | + if (workspaceSize > 0) | ||
| 127 | + aclrtMalloc(&workspace, workspaceSize, ACL_MEM_MALLOC_NORMAL_ONLY); | ||
| 128 | + | ||
| 129 | + // 5. 执行算子 | ||
| 130 | + aclnnTan(workspace, workspaceSize, executor, stream); | ||
| 131 | + aclrtSynchronizeStream(stream); | ||
| 132 | + | ||
| 133 | + // 6. 取回结果 | ||
| 134 | + aclrtMemcpy(out_host, nbytes, out_dev, nbytes, ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 135 | + printf("out = [%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f]\n", | ||
| 136 | + out_host[0], out_host[1], out_host[2], out_host[3], | ||
| 137 | + out_host[4], out_host[5], out_host[6], out_host[7]); | ||
| 138 | + // 期望: [0.0000, 0.5463, 1.5574, -1.5574, 0.2553, -0.5463, -2.1850, 2.1850] | ||
| 139 | + | ||
| 140 | + // 7. 释放资源 | ||
| 141 | + if (workspace) aclrtFree(workspace); | ||
| 142 | + aclrtFree(x_dev); aclrtFree(out_dev); | ||
| 143 | + aclDestroyTensor(x); aclDestroyTensor(out); | ||
| 144 | + aclrtDestroyStream(stream); | ||
| 145 | + aclrtResetDevice(0); | ||
| 146 | + aclFinalize(); | ||
| 147 | + return 0; | ||
| 148 | +} | ||
| 149 | +``` | ||
| @@ -0,0 +1,167 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * \file test_aclnn_tan.cpp | ||
| 18 | + * \brief Tan 算子 aclnn 调用示例(FP32) | ||
| 19 | + * | ||
| 20 | + * 计算: y = tan(x) = sin(x) / cos(x) | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + do { \ | ||
| 31 | + if (!(cond)) { \ | ||
| 32 | + return_expr; \ | ||
| 33 | + } \ | ||
| 34 | + } while (0) | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + do { \ | ||
| 38 | + printf(message, ##__VA_ARGS__); \ | ||
| 39 | + } while (0) | ||
| 40 | + | ||
| 41 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 42 | +{ | ||
| 43 | + int64_t shapeSize = 1; | ||
| 44 | + for (auto i : shape) { | ||
| 45 | + shapeSize *= i; | ||
| 46 | + } | ||
| 47 | + return shapeSize; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 51 | +{ | ||
| 52 | + auto ret = aclInit(nullptr); | ||
| 53 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 54 | + ret = aclrtSetDevice(deviceId); | ||
| 55 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 56 | + ret = aclrtCreateStream(stream); | ||
| 57 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 58 | + return 0; | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +template <typename T> | ||
| 62 | +int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | ||
| 63 | + aclDataType dataType, aclTensor** tensor) | ||
| 64 | +{ | ||
| 65 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 66 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 67 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 68 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 69 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 70 | + | ||
| 71 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 72 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 73 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, | ||
| 77 | + aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); | ||
| 78 | + return 0; | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +int main() | ||
| 82 | +{ | ||
| 83 | + // 1. 初始化 | ||
| 84 | + int32_t deviceId = 0; | ||
| 85 | + aclrtStream stream; | ||
| 86 | + auto ret = Init(deviceId, &stream); | ||
| 87 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 88 | + | ||
| 89 | + // 2. 构造输入与输出 | ||
| 90 | + std::vector<int64_t> xShape = {2, 4}; | ||
| 91 | + std::vector<int64_t> outShape = {2, 4}; | ||
| 92 | + int64_t totalSize = GetShapeSize(outShape); | ||
| 93 | + | ||
| 94 | + std::vector<float> xHostData = {0.0f, 0.5f, 1.0f, -1.0f, 0.25f, -0.5f, 2.0f, -2.0f}; | ||
| 95 | + std::vector<float> outHostData(totalSize, 0.0f); | ||
| 96 | + | ||
| 97 | + void* xDeviceAddr = nullptr; | ||
| 98 | + void* outDeviceAddr = nullptr; | ||
| 99 | + aclTensor* x = nullptr; | ||
| 100 | + aclTensor* out = nullptr; | ||
| 101 | + | ||
| 102 | + ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT, &x); | ||
| 103 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 104 | + ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); | ||
| 105 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 106 | + | ||
| 107 | + // 3. 调用 aclnnTan | ||
| 108 | + uint64_t workspaceSize = 0; | ||
| 109 | + aclOpExecutor* executor; | ||
| 110 | + ret = aclnnTanGetWorkspaceSize(x, out, &workspaceSize, &executor); | ||
| 111 | + CHECK_RET(ret == ACL_SUCCESS, | ||
| 112 | + LOG_PRINT("aclnnTanGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 113 | + | ||
| 114 | + void* workspaceAddr = nullptr; | ||
| 115 | + if (workspaceSize > 0) { | ||
| 116 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 117 | + CHECK_RET(ret == ACL_SUCCESS, | ||
| 118 | + LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + ret = aclnnTan(workspaceAddr, workspaceSize, executor, stream); | ||
| 122 | + CHECK_RET(ret == ACL_SUCCESS, | ||
| 123 | + LOG_PRINT("aclnnTan failed. ERROR: %d\n", ret); return ret); | ||
| 124 | + | ||
| 125 | + // 4. 同步 | ||
| 126 | + ret = aclrtSynchronizeStream(stream); | ||
| 127 | + CHECK_RET(ret == ACL_SUCCESS, | ||
| 128 | + LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 129 | + | ||
| 130 | + // 5. 拷贝回 host 并比对 | ||
| 131 | + std::vector<float> resultData(totalSize, 0.0f); | ||
| 132 | + ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(float), | ||
| 133 | + outDeviceAddr, totalSize * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 134 | + CHECK_RET(ret == ACL_SUCCESS, | ||
| 135 | + LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 136 | + | ||
| 137 | + int failCount = 0; | ||
| 138 | + const float atol = 1e-4f; | ||
| 139 | + const float rtol = 1e-4f; | ||
| 140 | + LOG_PRINT("=== aclnnTan result vs golden ===\n"); | ||
| 141 | + for (int64_t i = 0; i < totalSize; i++) { | ||
| 142 | + float gold = std::tan(xHostData[i]); | ||
| 143 | + float diff = std::fabs(resultData[i] - gold); | ||
| 144 | + bool ok = diff <= (atol + rtol * std::fabs(gold)); | ||
| 145 | + LOG_PRINT("[%ld] x=%8.4f out=%10.6f gold=%10.6f diff=%.2e %s\n", | ||
| 146 | + i, xHostData[i], resultData[i], gold, diff, ok ? "OK" : "FAIL"); | ||
| 147 | + if (!ok) failCount++; | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + // 6. 释放资源 | ||
| 151 | + aclDestroyTensor(x); | ||
| 152 | + aclDestroyTensor(out); | ||
| 153 | + aclrtFree(xDeviceAddr); | ||
| 154 | + aclrtFree(outDeviceAddr); | ||
| 155 | + if (workspaceSize > 0) aclrtFree(workspaceAddr); | ||
| 156 | + aclrtDestroyStream(stream); | ||
| 157 | + aclrtResetDevice(deviceId); | ||
| 158 | + aclFinalize(); | ||
| 159 | + | ||
| 160 | + if (failCount == 0) { | ||
| 161 | + LOG_PRINT("=== PASS: all %ld elements match golden ===\n", totalSize); | ||
| 162 | + return 0; | ||
| 163 | + } else { | ||
| 164 | + LOG_PRINT("=== FAIL: %d / %ld elements mismatch ===\n", failCount, totalSize); | ||
| 165 | + return 1; | ||
| 166 | + } | ||
| 167 | +} | ||
| @@ -0,0 +1,36 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * \file tan_proto.h | ||
| 19 | + * \brief Tan operator graph-mode (GE IR) proto registration | ||
| 20 | + */ | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +namespace ge { | ||
| 28 | + | ||
| 29 | +REG_OP(Tan) | ||
| 30 | + .INPUT(x, TensorType({DT_FLOAT, DT_FLOAT16})) | ||
S | |||
| 31 | + .OUTPUT(y, TensorType({DT_FLOAT, DT_FLOAT16})) | ||
| 32 | + .OP_END_FACTORY_REG(Tan) | ||
| 33 | + | ||
| 34 | +} // namespace ge | ||
| 35 | + | ||
| 36 | + | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | + # ---------------------------------------------------------------------------------------------------------- | ||
| 2 | + # Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + # This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + # CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + | ||
| 6 | + # Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | + # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | + # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 9 | + # See LICENSE in the root of the software repository for the full text of the License. | ||
| 10 | + # ---------------------------------------------------------------------------------------------------------- | ||
| 11 | + # NOTE: Portions of this code were AI-generated and have been | ||
| 12 | + # technically reviewed for functional accuracy and security | ||
| 13 | + | ||
| 14 | +add_modules_sources(OPTYPE tan ACLNNTYPE aclnn) | ||
| @@ -0,0 +1,52 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * \file tan_def.cpp | ||
| 18 | + * \brief Tan operator definition - declares inputs, outputs, and chip configuration | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +namespace ops { | ||
| 23 | +class Tan : public OpDef { | ||
| 24 | +public: | ||
| 25 | + explicit Tan(const char* name) : OpDef(name) | ||
| 26 | + { | ||
| 27 | + this->Input("x") | ||
| 28 | + .ParamType(REQUIRED) | ||
| 29 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT16}) | ||
| 30 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 31 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 32 | + .AutoContiguous(); | ||
| 33 | + this->Output("y") | ||
| 34 | + .ParamType(REQUIRED) | ||
| 35 | + .DataType({ge::DT_FLOAT, ge::DT_FLOAT16}) | ||
| 36 | + .Format({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 37 | + .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND}) | ||
| 38 | + .AutoContiguous(); | ||
| 39 | + | ||
| 40 | + OpAICoreConfig aicoreConfig910B; | ||
| 41 | + aicoreConfig910B.DynamicCompileStaticFlag(true) | ||
| 42 | + .DynamicFormatFlag(false) | ||
| 43 | + .DynamicRankSupportFlag(true) | ||
| 44 | + .DynamicShapeSupportFlag(true) | ||
| 45 | + .NeedCheckSupportFlag(false) | ||
| 46 | + .PrecisionReduceFlag(true) | ||
| 47 | + .ExtendCfgInfo("opFile.value", "tan"); | ||
| 48 | + this->AICore().AddConfig("ascend910b", aicoreConfig910B); | ||
| 49 | + } | ||
| 50 | +}; | ||
| 51 | +OP_ADD(Tan); | ||
| 52 | +} // namespace ops | ||
| @@ -0,0 +1,47 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * \file tan_infershape.cpp | ||
| 18 | + * \brief Tan shape inference - output shape equals input shape | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +using namespace ge; | ||
| 25 | + | ||
| 26 | +namespace ops { | ||
| 27 | + | ||
| 28 | +static ge::graphStatus InferShape4Tan(gert::InferShapeContext* context) | ||
| 29 | +{ | ||
| 30 | + const gert::Shape* input_shape = context->GetInputShape(0); | ||
| 31 | + if (input_shape == nullptr) { | ||
| 32 | + return ge::GRAPH_FAILED; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + gert::Shape* output_shape = context->GetOutputShape(0); | ||
| 36 | + if (output_shape == nullptr) { | ||
| 37 | + return ge::GRAPH_FAILED; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + *output_shape = *input_shape; | ||
| 41 | + | ||
| 42 | + return ge::GRAPH_SUCCESS; | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +IMPL_OP_INFERSHAPE(Tan).InferShape(InferShape4Tan); | ||
| 46 | + | ||
| 47 | +} // namespace ops | ||
| @@ -0,0 +1,157 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * \file tan_tiling.cpp | ||
| 18 | + * \brief Tan Tiling implementation (arch32 - Ascend910B) | ||
| 19 | + * | ||
| 20 | + * Computes tiling parameters for Tan operator: | ||
| 21 | + * - Multi-core splitting: totalNum divided evenly across AI Cores | ||
| 22 | + * - UB splitting: each core processes data in chunks of ubFactor elements | ||
| 23 | + * - TilingKey selection: based on input dtype (float32 vs float16) | ||
| 24 | + */ | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +namespace optiling { | ||
| 34 | + | ||
| 35 | +using Ops::Base::CeilDiv; | ||
| 36 | +using Ops::Base::FloorDiv; | ||
| 37 | +using Ops::Base::FloorAlign; | ||
| 38 | +using Ops::Base::GetUbBlockSize; | ||
| 39 | + | ||
| 40 | +constexpr uint32_t WS_SYS_SIZE = 0U; | ||
| 41 | +// float32: inputQueue(x2) + outputQueue(x2) + tmpBuf1(x1) + tmpBuf2(x1) = 6 float-sized buffers | ||
| 42 | +// Total bytes = ubFactor * 6 * sizeof(float) | ||
| 43 | +constexpr int64_t BUFFER_NUM_FP32 = 6; | ||
| 44 | +// float16: inputQueue(x2,half) + outputQueue(x2,half) + tmpBuf1(x1,float) + tmpBuf2(x1,float) | ||
| 45 | +// Total bytes = ubFactor * (2*2 + 2*2 + 4 + 4) = ubFactor * 16 = ubFactor * sizeof(float) * 4 | ||
| 46 | +constexpr int64_t BUFFER_NUM_FP16 = 4; | ||
| 47 | + | ||
| 48 | +static const gert::Shape g_vec_1_shape = {1}; | ||
| 49 | + | ||
| 50 | +static inline const gert::Shape EnsureNotScalar(const gert::Shape& in_shape) | ||
| 51 | +{ | ||
| 52 | + if (in_shape.GetDimNum() == 0) { | ||
| 53 | + return g_vec_1_shape; | ||
| 54 | + } | ||
| 55 | + return in_shape; | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +static ge::graphStatus GetPlatformInfo(gert::TilingContext* context, uint64_t& ubSize, int64_t& coreNum) | ||
| 59 | +{ | ||
| 60 | + fe::PlatFormInfos* platformInfoPtr = context->GetPlatformInfo(); | ||
| 61 | + OP_CHECK_NULL_WITH_CONTEXT(context, platformInfoPtr); | ||
| 62 | + auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfoPtr); | ||
| 63 | + coreNum = ascendcPlatform.GetCoreNumAiv(); | ||
| 64 | + OP_CHECK_IF(coreNum == 0, OP_LOGE(context, "coreNum is 0"), return ge::GRAPH_FAILED); | ||
| 65 | + ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ubSize); | ||
| 66 | + OP_CHECK_IF(ubSize == 0, OP_LOGE(context, "ubSize is 0"), return ge::GRAPH_FAILED); | ||
| 67 | + return ge::GRAPH_SUCCESS; | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +static ge::graphStatus GetWorkspaceSize(gert::TilingContext* context) | ||
| 71 | +{ | ||
| 72 | + size_t* currentWorkspace = context->GetWorkspaceSizes(1); | ||
| 73 | + OP_CHECK_NULL_WITH_CONTEXT(context, currentWorkspace); | ||
| 74 | + currentWorkspace[0] = WS_SYS_SIZE; | ||
| 75 | + return ge::GRAPH_SUCCESS; | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +static ge::graphStatus TanTilingFunc(gert::TilingContext* context) | ||
| 79 | +{ | ||
| 80 | + // 1. Get platform info | ||
| 81 | + uint64_t ubSize; | ||
| 82 | + int64_t coreNum; | ||
| 83 | + OP_CHECK_IF( | ||
| 84 | + GetPlatformInfo(context, ubSize, coreNum) != ge::GRAPH_SUCCESS, | ||
| 85 | + OP_LOGE(context, "GetPlatformInfo error"), | ||
| 86 | + return ge::GRAPH_FAILED); | ||
| 87 | + | ||
| 88 | + // 2. Get input shape and dtype | ||
| 89 | + auto inputShape = context->GetInputShape(0); | ||
| 90 | + OP_CHECK_NULL_WITH_CONTEXT(context, inputShape); | ||
| 91 | + auto storageShape = EnsureNotScalar(inputShape->GetStorageShape()); | ||
| 92 | + int64_t totalNum = storageShape.GetShapeSize(); | ||
| 93 | + | ||
| 94 | + auto inputDesc = context->GetInputDesc(0); | ||
| 95 | + OP_CHECK_NULL_WITH_CONTEXT(context, inputDesc); | ||
| 96 | + ge::DataType dtype = inputDesc->GetDataType(); | ||
| 97 | + | ||
| 98 | + // 3. Get workspace size | ||
| 99 | + OP_CHECK_IF( | ||
| 100 | + GetWorkspaceSize(context) != ge::GRAPH_SUCCESS, | ||
| 101 | + OP_LOGE(context, "GetWorkspaceSize error"), | ||
| 102 | + return ge::GRAPH_FAILED); | ||
| 103 | + | ||
| 104 | + // 4. Set TilingData | ||
| 105 | + TanTilingData* tiling = context->GetTilingData<TanTilingData>(); | ||
| 106 | + OP_CHECK_NULL_WITH_CONTEXT(context, tiling); | ||
| 107 | + OP_CHECK_IF( | ||
| 108 | + memset_s(tiling, sizeof(TanTilingData), 0, sizeof(TanTilingData)) != EOK, | ||
| 109 | + OP_LOGE(context, "set tiling data error"), | ||
| 110 | + return ge::GRAPH_FAILED); | ||
| 111 | + | ||
| 112 | + // Handle empty tensor | ||
| 113 | + if (totalNum == 0) { | ||
| 114 | + tiling->totalNum = 0; | ||
| 115 | + tiling->blockFactor = 0; | ||
| 116 | + tiling->ubFactor = 0; | ||
| 117 | + context->SetBlockDim(1); | ||
| 118 | + context->SetTilingKey(GET_TPL_TILING_KEY(TAN_TPL_SCH_MODE_0)); | ||
| 119 | + return ge::GRAPH_SUCCESS; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + // 5. Multi-core splitting | ||
| 123 | + tiling->totalNum = totalNum; | ||
| 124 | + tiling->blockFactor = CeilDiv(totalNum, coreNum); | ||
| 125 | + int64_t usedCoreNum = CeilDiv(totalNum, tiling->blockFactor); | ||
| 126 | + | ||
| 127 | + // 6. UB splitting and TilingKey selection | ||
| 128 | + int64_t ubCanUse = static_cast<int64_t>(ubSize); | ||
| 129 | + int64_t ubBlockSize = GetUbBlockSize(context); | ||
| 130 | + // Both paths compute internally in float32, so typeSize = 4 | ||
| 131 | + constexpr int64_t typeSize = 4; | ||
| 132 | + | ||
| 133 | + if (dtype == ge::DT_FLOAT) { | ||
| 134 | + tiling->ubFactor = FloorAlign(FloorDiv((ubCanUse / typeSize), BUFFER_NUM_FP32), ubBlockSize); | ||
| 135 | + context->SetTilingKey(GET_TPL_TILING_KEY(TAN_TPL_SCH_MODE_0)); | ||
| 136 | + } else if (dtype == ge::DT_FLOAT16) { | ||
| 137 | + tiling->ubFactor = FloorAlign(FloorDiv((ubCanUse / typeSize), BUFFER_NUM_FP16), ubBlockSize); | ||
| 138 | + context->SetTilingKey(GET_TPL_TILING_KEY(TAN_TPL_SCH_MODE_1)); | ||
| 139 | + } else { | ||
| 140 | + OP_LOGE(context, "Tan: unsupported dtype"); | ||
| 141 | + return ge::GRAPH_FAILED; | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + context->SetBlockDim(usedCoreNum); | ||
| 145 | + return ge::GRAPH_SUCCESS; | ||
| 146 | +} | ||
| 147 | + | ||
| 148 | +static ge::graphStatus TilingParseForTan([[maybe_unused]] gert::TilingParseContext* context) | ||
| 149 | +{ | ||
| 150 | + return ge::GRAPH_SUCCESS; | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +struct TanCompileInfo {}; | ||
| 154 | + | ||
| 155 | +IMPL_OP_OPTILING(Tan).Tiling(TanTilingFunc).TilingParse<TanCompileInfo>(TilingParseForTan); | ||
| 156 | + | ||
| 157 | +} // namespace optiling | ||
| @@ -0,0 +1,44 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * \file tan_arch32.cpp | ||
| 18 | + * \brief Tan kernel entry point (arch32 architecture - Ascend910B) | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +enum class TanTilingKey : uint32_t | ||
| 24 | +{ | ||
| 25 | + TILING_KEY_FLOAT32 = 0, | ||
| 26 | + TILING_KEY_FLOAT16 = 1, | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +template <uint32_t schMode> | ||
| 30 | +__global__ __aicore__ void tan(GM_ADDR x, GM_ADDR y, GM_ADDR workspace, GM_ADDR tiling) | ||
| 31 | +{ | ||
| 32 | + REGISTER_TILING_DEFAULT(TanTilingData); | ||
| 33 | + GET_TILING_DATA_WITH_STRUCT(TanTilingData, tilingData, tiling); | ||
| 34 | + if constexpr (schMode == static_cast<uint32_t>(TanTilingKey::TILING_KEY_FLOAT32)) { | ||
| 35 | + NsTan::Tan<float> op; | ||
| 36 | + op.Init(x, y, &tilingData); | ||
| 37 | + op.Process(); | ||
| 38 | + } | ||
| 39 | + if constexpr (schMode == static_cast<uint32_t>(TanTilingKey::TILING_KEY_FLOAT16)) { | ||
| 40 | + NsTan::Tan<half> op; | ||
| 41 | + op.Init(x, y, &tilingData); | ||
| 42 | + op.Process(); | ||
| 43 | + } | ||
| 44 | +} | ||
| @@ -0,0 +1,204 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * \file tan.h | ||
| 18 | + * \brief Tan kernel class definition (arch32 - Ascend910B) | ||
| 19 | + * | ||
| 20 | + * Computes tan(x) = sin(x) / cos(x) for each element. | ||
| 21 | + * - float32 path: direct computation using Sin, Cos, Div | ||
| 22 | + * - float16 path: cast to float32 for computation, then cast back | ||
| 23 | + * | ||
| 24 | + * Uses double buffering (BUFFER_NUM=2) for pipeline parallelism: | ||
| 25 | + * - CopyIn: GM -> UB (input data transfer) | ||
| 26 | + * - Compute: UB vector computation (tan formula) | ||
| 27 | + * - CopyOut: UB -> GM (output data transfer) | ||
| 28 | + */ | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + | ||
| 37 | +namespace NsTan { | ||
| 38 | + | ||
| 39 | +using namespace AscendC; | ||
| 40 | + | ||
| 41 | +constexpr int32_t BUFFER_NUM = 2; | ||
| 42 | + | ||
| 43 | +template <typename T> | ||
| 44 | +class Tan { | ||
| 45 | +public: | ||
| 46 | + __aicore__ inline Tan() {}; | ||
| 47 | + | ||
| 48 | + __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, const TanTilingData* tilingData); | ||
| 49 | + __aicore__ inline void Process(); | ||
| 50 | + | ||
| 51 | +private: | ||
| 52 | + __aicore__ inline void CopyIn(int64_t progress, int64_t currentNum); | ||
| 53 | + __aicore__ inline void CopyOut(int64_t progress, int64_t currentNum); | ||
| 54 | + __aicore__ inline void Compute(int64_t currentNum); | ||
| 55 | + | ||
| 56 | +private: | ||
| 57 | + TPipe pipe; | ||
| 58 | + TQue<QuePosition::VECIN, BUFFER_NUM> inputQueue; | ||
| 59 | + TQue<QuePosition::VECOUT, BUFFER_NUM> outputQueue; | ||
| 60 | + TBuf<QuePosition::VECCALC> tmpBuf1; // stores sin(x) intermediate result | ||
| 61 | + TBuf<QuePosition::VECCALC> tmpBuf2; // stores cos(x) intermediate result | ||
| 62 | + | ||
| 63 | + GlobalTensor<T> inputGM; | ||
| 64 | + GlobalTensor<T> outputGM; | ||
| 65 | + | ||
| 66 | + int64_t blockLength_ = 0; | ||
| 67 | + int64_t ubLength_ = 0; | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +// ============================================================================ | ||
| 71 | +// Init - Initialize GM pointers and allocate UB buffers | ||
| 72 | +// ============================================================================ | ||
| 73 | +template <typename T> | ||
| 74 | +__aicore__ inline void Tan<T>::Init(GM_ADDR x, GM_ADDR y, const TanTilingData* tilingData) | ||
| 75 | +{ | ||
| 76 | + int64_t remainderLength = tilingData->totalNum - tilingData->blockFactor * AscendC::GetBlockIdx(); | ||
| 77 | + blockLength_ = (remainderLength > tilingData->blockFactor) ? tilingData->blockFactor : remainderLength; | ||
| 78 | + // Clamp to 0 for idle cores (when totalNum < coreNum, some cores have no work) | ||
| 79 | + if (blockLength_ < 0) { | ||
| 80 | + blockLength_ = 0; | ||
| 81 | + } | ||
| 82 | + ubLength_ = tilingData->ubFactor; | ||
| 83 | + | ||
| 84 | + // Guard: empty tensor or idle core - skip buffer allocation | ||
| 85 | + if (blockLength_ <= 0 || ubLength_ <= 0) { | ||
| 86 | + return; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + inputGM.SetGlobalBuffer((__gm__ T*)x + tilingData->blockFactor * AscendC::GetBlockIdx(), blockLength_); | ||
| 90 | + outputGM.SetGlobalBuffer((__gm__ T*)y + tilingData->blockFactor * AscendC::GetBlockIdx(), blockLength_); | ||
| 91 | + | ||
| 92 | + pipe.InitBuffer(inputQueue, BUFFER_NUM, ubLength_ * sizeof(T)); | ||
| 93 | + pipe.InitBuffer(outputQueue, BUFFER_NUM, ubLength_ * sizeof(T)); | ||
| 94 | + // Temporary buffers for sin and cos intermediate results | ||
| 95 | + // For float32: used as float buffers directly | ||
| 96 | + // For float16: used as float32 buffers for precision-promoted computation | ||
| 97 | + pipe.InitBuffer(tmpBuf1, ubLength_ * sizeof(float)); | ||
| 98 | + pipe.InitBuffer(tmpBuf2, ubLength_ * sizeof(float)); | ||
| 99 | +} | ||
| 100 | + | ||
| 101 | +// ============================================================================ | ||
| 102 | +// CopyIn - Transfer data from GM to UB | ||
| 103 | +// ============================================================================ | ||
| 104 | +template <typename T> | ||
| 105 | +__aicore__ inline void Tan<T>::CopyIn(int64_t progress, int64_t currentNum) | ||
| 106 | +{ | ||
| 107 | + AscendC::LocalTensor<T> xLocal = inputQueue.AllocTensor<T>(); | ||
| 108 | + AscendC::DataCopyParams copyParams; | ||
| 109 | + copyParams.blockCount = 1; | ||
| 110 | + copyParams.blockLen = currentNum * sizeof(T); | ||
| 111 | + copyParams.srcStride = 0; | ||
| 112 | + copyParams.dstStride = 0; | ||
| 113 | + AscendC::DataCopyPad(xLocal, inputGM[progress * ubLength_], copyParams, {false, 0, 0, 0}); | ||
| 114 | + inputQueue.EnQue(xLocal); | ||
| 115 | +} | ||
| 116 | + | ||
| 117 | +// ============================================================================ | ||
| 118 | +// CopyOut - Transfer data from UB to GM | ||
| 119 | +// ============================================================================ | ||
| 120 | +template <typename T> | ||
| 121 | +__aicore__ inline void Tan<T>::CopyOut(int64_t progress, int64_t currentNum) | ||
| 122 | +{ | ||
| 123 | + AscendC::LocalTensor<T> yLocal = outputQueue.DeQue<T>(); | ||
| 124 | + AscendC::DataCopyParams copyParams; | ||
| 125 | + copyParams.blockCount = 1; | ||
| 126 | + copyParams.blockLen = currentNum * sizeof(T); | ||
| 127 | + copyParams.srcStride = 0; | ||
| 128 | + copyParams.dstStride = 0; | ||
| 129 | + AscendC::DataCopyPad(outputGM[progress * ubLength_], yLocal, copyParams); | ||
| 130 | + outputQueue.FreeTensor(yLocal); | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +// ============================================================================ | ||
| 134 | +// Compute - float32 specialization: direct tan computation | ||
| 135 | +// tan(x) = sin(x) / cos(x) | ||
| 136 | +// ============================================================================ | ||
| 137 | +template <> | ||
| 138 | +__aicore__ inline void Tan<float>::Compute(int64_t currentNum) | ||
| 139 | +{ | ||
| 140 | + AscendC::LocalTensor<float> xLocal = inputQueue.DeQue<float>(); | ||
| 141 | + AscendC::LocalTensor<float> yLocal = outputQueue.AllocTensor<float>(); | ||
| 142 | + AscendC::LocalTensor<float> sinVal = tmpBuf1.Get<float>(); | ||
| 143 | + AscendC::LocalTensor<float> cosVal = tmpBuf2.Get<float>(); | ||
| 144 | + | ||
| 145 | + // Step 1: sin(x) -> sinVal (tmpBuf1) | ||
| 146 | + AscendC::Sin(sinVal, xLocal, currentNum); | ||
| 147 | + // Step 2: cos(x) -> cosVal (tmpBuf2) | ||
| 148 | + AscendC::Cos(cosVal, xLocal, currentNum); | ||
| 149 | + // Step 3: sin(x) / cos(x) -> yLocal | ||
| 150 | + AscendC::Div(yLocal, sinVal, cosVal, currentNum); | ||
| 151 | + | ||
| 152 | + outputQueue.EnQue<float>(yLocal); | ||
| 153 | + inputQueue.FreeTensor(xLocal); | ||
| 154 | +} | ||
| 155 | + | ||
| 156 | +// ============================================================================ | ||
| 157 | +// Compute - float16 specialization: cast to float32, compute, cast back | ||
| 158 | +// Flow: Cast(half->float) -> Cos -> Sin -> Div -> Cast(float->half) | ||
| 159 | +// Key constraint: Cos must be computed before Sin to avoid overwriting input | ||
| 160 | +// ============================================================================ | ||
| 161 | +template <> | ||
| 162 | +__aicore__ inline void Tan<half>::Compute(int64_t currentNum) | ||
| 163 | +{ | ||
| 164 | + AscendC::LocalTensor<half> xLocal = inputQueue.DeQue<half>(); | ||
| 165 | + AscendC::LocalTensor<half> yLocal = outputQueue.AllocTensor<half>(); | ||
| 166 | + AscendC::LocalTensor<float> sinVal = tmpBuf1.Get<float>(); | ||
| 167 | + AscendC::LocalTensor<float> cosVal = tmpBuf2.Get<float>(); | ||
| 168 | + | ||
| 169 | + // Step 1: Cast half -> float (store in sinVal as temp for x_float) | ||
| 170 | + AscendC::Cast(sinVal, xLocal, AscendC::RoundMode::CAST_NONE, currentNum); | ||
| 171 | + // Step 2: cos(x) - must compute before sin overwrites sinVal | ||
| 172 | + AscendC::Cos(cosVal, sinVal, currentNum); | ||
| 173 | + // Step 3: sin(x) - overwrites sinVal (cosVal already saved) | ||
| 174 | + AscendC::Sin(sinVal, sinVal, currentNum); | ||
| 175 | + // Step 4: sin(x) / cos(x) -> sinVal (reuse) | ||
| 176 | + AscendC::Div(sinVal, sinVal, cosVal, currentNum); | ||
| 177 | + // Step 5: Cast float -> half | ||
| 178 | + AscendC::Cast(yLocal, sinVal, AscendC::RoundMode::CAST_ROUND, currentNum); | ||
| 179 | + | ||
| 180 | + outputQueue.EnQue<half>(yLocal); | ||
| 181 | + inputQueue.FreeTensor(xLocal); | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +// ============================================================================ | ||
| 185 | +// Process - Main loop: iterate over tiles | ||
| 186 | +// ============================================================================ | ||
| 187 | +template <typename T> | ||
| 188 | +__aicore__ inline void Tan<T>::Process() | ||
| 189 | +{ | ||
| 190 | + // Guard: empty tensor or idle core - nothing to process | ||
| 191 | + if (blockLength_ <= 0 || ubLength_ <= 0) { | ||
| 192 | + return; | ||
| 193 | + } | ||
| 194 | + int64_t loopCount = (blockLength_ + ubLength_ - 1) / ubLength_; | ||
| 195 | + for (int64_t i = 0; i < loopCount; i++) { | ||
| 196 | + int64_t currentNum = (i == (loopCount - 1)) ? (blockLength_ - ubLength_ * i) : ubLength_; | ||
| 197 | + CopyIn(i, currentNum); | ||
| 198 | + Compute(currentNum); | ||
| 199 | + CopyOut(i, currentNum); | ||
| 200 | + } | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +} // namespace NsTan | ||
| 204 | + | ||
| @@ -0,0 +1,30 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * \file tan_tiling_data.h | ||
| 18 | + * \brief Tan TilingData structure definition | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +struct TanTilingData { | ||
| 25 | + int64_t totalNum = 0; // Total number of elements | ||
| 26 | + int64_t blockFactor = 0; // Number of elements per AI Core | ||
| 27 | + int64_t ubFactor = 0; // Number of elements per UB loop iteration | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | + | ||
| @@ -0,0 +1,42 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * NOTE: Portions of this code were AI-generated and have been | ||
| 13 | + * technically reviewed for functional accuracy and security | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * \file tan_tiling_key.h | ||
| 18 | + * \brief Tan TilingKey definition | ||
| 19 | + * | ||
| 20 | + * TilingKey mapping: | ||
| 21 | + * - TAN_TPL_SCH_MODE_0 (0): FLOAT32 type | ||
| 22 | + * - TAN_TPL_SCH_MODE_1 (1): FLOAT16 type | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +ASCENDC_TPL_ARGS_DECL( | ||
| 34 | + Tan, | ||
| 35 | + ASCENDC_TPL_UINT_DECL(schMode, 1, ASCENDC_TPL_UI_LIST, | ||
| 36 | + TAN_TPL_SCH_MODE_0, TAN_TPL_SCH_MODE_1)); | ||
| 37 | + | ||
| 38 | +ASCENDC_TPL_SEL(ASCENDC_TPL_ARGS_SEL( | ||
| 39 | + ASCENDC_TPL_UINT_SEL(schMode, ASCENDC_TPL_UI_LIST, | ||
| 40 | + TAN_TPL_SCH_MODE_0, TAN_TPL_SCH_MODE_1))); | ||
| 41 | + | ||
| 42 | + | ||
The file is empty
数据类型还是不太对