已合并
[CANNBot]Acosh适配Ascend950 #2884
Nerddddddddddd创建于 5月21日
[CANNBot]Acosh适配Ascend950 #2884
已合并
Nerddddddddddd创建于 5月21日
21 个文件变更+1482-51
Mmath/acosh/CMakeLists.txt+13-14
@@ -1,19 +1,18 @@
1-# ----------------------------------------------------------------------------1+# ---------------------------------------------------------------------------------------------------------
2-# This program is free software, you can redistribute it and/or modify it.2+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
3-# Copyright (c) 2025 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-# This file is a part of the CANN Open Software.4+# CANN Open Software License Agreement Version 2.0 (the "License").
5-# Licensed under CANN Open Software License Agreement Version 2.0 (the "License").
6# Please refer to the License for details. You may not use this file except in compliance with the License.5# 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, INCLUDING6+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
8-# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.7+# 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.8# See LICENSE in the root of the software repository for the full text of the License.
10-# ----------------------------------------------------------------------------9+# ---------------------------------------------------------------------------------------------------------
11-file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)10+ 
12-foreach(SUB_DIR ${CURRENT_DIRS})11+# Generated By CANNBot
13- if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt")12+ 
14- add_subdirectory(${SUB_DIR})13+set(SUPPORT_COMPUTE_UNIT "ascend950")
15- endif()14+set(SUPPORT_TILING_DIR "arch35")
16-endforeach()15+add_all_modules_sources(OPTYPE acosh ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE)
17 16 
18if(ENABLE_TEST AND (UT_TEST_ALL OR OP_KERNEL_AICPU_UT))17if(ENABLE_TEST AND (UT_TEST_ALL OR OP_KERNEL_AICPU_UT))
19 list(FIND ASCEND_OP_NAME acosh ACOSH_INDEX)18 list(FIND ASCEND_OP_NAME acosh ACOSH_INDEX)
Mmath/acosh/README.md+91-1
@@ -1,3 +1,93 @@
1# Acosh1# Acosh
2 2 
3-本目录仅包含Acosh算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)3+> 反双曲余弦(Inverse Hyperbolic Cosine)算子对应 PyTorch `torch.acosh` / `torch.acosh_`
4+> 在线 aclnn API 文档:[docs/aclnnAcosh&aclnnInplaceAcosh.md](docs/aclnnAcosh&aclnnInplaceAcosh.md)
5+ 
6+## 产品支持情况
7+ 
8+|产品 | 是否支持 |
9+|:-------------------------|:----------:|
10+| <term>Ascend 950PR/Ascend 950DT</term> | √ |
11+| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ |
12+| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ |
13+| <term>Atlas 200I/500 A2 推理产品</term> | × |
14+| <term>Atlas 推理系列产品</term> | √ |
15+| <term>Atlas 训练系列产品</term> | √ |
16+ 
17+## 功能说明
18+ 
19+- 接口功能:对输入Tensor中的每个元素进行反双曲余弦操作后输出。
20+ 
21+- 计算公式:
22+ 
23+ $$
24+ out=cosh^{-1}(self)
25+ $$
26+ 
27+## 参数说明
28+ 
29+<table style="table-layout: fixed; width: 1000px"><colgroup>
30+<col style="width: 50px">
31+<col style="width: 70px">
32+<col style="width: 200px">
33+<col style="width: 100px">
34+<col style="width: 50px">
35+</colgroup>
36+<thead>
37+ <tr>
38+ <th>参数名</th>
39+ <th>输入/输出/属性</th>
40+ <th>描述</th>
41+ <th>数据类型</th>
42+ <th>数据格式</th>
43+ </tr></thead>
44+<tbody>
45+ <tr>
46+ <td>self</td>
47+ <td>输入</td>
48+ <td>公式中的输入 self,dtype 与 out 一致,shape 任意(0~8 维),支持空 Tensor,支持非连续 Tensor。</td>
49+ <td>FLOAT、FLOAT16、BFLOAT16</td>
50+ <td>ND</td>
51+ </tr>
52+ <tr>
53+ <td>out</td>
54+ <td>输出</td>
55+ <td>公式中的输出 out,shape 与 self 完全一致;非原地接口专有。</td>
56+ <td>FLOAT、FLOAT16、BFLOAT16</td>
57+ <td>ND</td>
58+ </tr>
59+ <tr>
60+ <td>selfRef</td>
61+ <td>输入/输出</td>
62+ <td>原地接口专有,既作输入又作输出的张量,计算结果原地写回。</td>
63+ <td>FLOAT、FLOAT16、BFLOAT16</td>
64+ <td>ND</td>
65+ </tr>
66+</tbody></table>
67+ 
68+- 参数 `self``out` 的 dtype 必须完全一致;shape 维度数 ∈ [0, 8]。
69+- 仅支持 ND 数据格式;不支持 NCHW / NHWC / 5HD 等私有格式。
70+ 
71+## 约束说明
72+ 
73+ 
74+## 调用说明
75+ 
76+<table><thead>
77+ <tr>
78+ <th>调用方式</th>
79+ <th>调用样例</th>
80+ <th>说明</th>
81+ </tr></thead>
82+<tbody>
83+ <tr>
84+ <td>aclnn 调用(非原地)</td>
85+ <td><a href="./examples/test_aclnn_acosh.cpp">examples/test_aclnn_acosh.cpp</a></td>
86+ <td rowspan="2">参考 ops-math 仓库根 build.sh 完成算子编译与算子包安装,再用 examples 验证(NPU 真机)。</td>
87+ </tr>
88+ <tr>
89+ <td>aclnn 调用(原地)</td>
90+ <td><a href="./examples/test_aclnn_inplace_acosh.cpp">examples/test_aclnn_inplace_acosh.cpp</a></td>
91+ </tr>
92+</tbody></table>
93+ 
Mmath/acosh/docs/aclnnAcosh&aclnnInplaceAcosh.md+25-23
@@ -4,14 +4,14 @@
4 4 
5## 产品支持情况5## 产品支持情况
6 6 
7-| 产品 | 是否支持 |7+|产品 | 是否支持 |
8-| :----------------------------------------------------------- | :------: |8+|:-------------------------|:----------:|
9-| <term>Ascend 950PR/Ascend 950DT</term> | × |9+| <term>Ascend 950PR/Ascend 950DT</term> | |
10-| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | |10+| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | |
11-| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | |11+| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | |
12-| <term>Atlas 200I/500 A2 推理产品</term> | × |12+| <term>Atlas 200I/500 A2 推理产品</term> | × |
13-| <term>Atlas 推理系列产品</term> | |13+| <term>Atlas 推理系列产品</term> | |
14-| <term>Atlas 训练系列产品</term> | |14+| <term>Atlas 训练系列产品</term> | |
15 15 
16## 功能说明16## 功能说明
17 17 
@@ -32,33 +32,33 @@
32 32 
33```cpp33```cpp
34aclnnStatus aclnnAcoshGetWorkspaceSize(34aclnnStatus aclnnAcoshGetWorkspaceSize(
35- const aclTensor* self, 35+ const aclTensor *self,
36- aclTensor* out, 36+ aclTensor *out,
37- uint64_t* workspaceSize, 37+ uint64_t *workspaceSize,
38- aclOpExecutor** executor)38+ aclOpExecutor **executor)
39```39```
40 40 
41```cpp41```cpp
42aclnnStatus aclnnAcosh(42aclnnStatus aclnnAcosh(
43- void* workspace,43+ void *workspace,
44- uint64_t workspaceSize,44+ uint64_t workspaceSize,
45- aclOpExecutor* executor,45+ aclOpExecutor *executor,
46- aclrtStream stream)46+ aclrtStream stream)
47```47```
48 48 
49```cpp49```cpp
50aclnnStatus aclnnInplaceAcoshGetWorkspaceSize(50aclnnStatus aclnnInplaceAcoshGetWorkspaceSize(
51- aclTensor* selfRef, 51+ aclTensor *selfRef,
52- uint64_t* workspaceSize, 52+ uint64_t *workspaceSize,
53- aclOpExecutor** executor)53+ aclOpExecutor **executor)
54```54```
55 55 
56```cpp56```cpp
57aclnnStatus aclnnInplaceAcosh(57aclnnStatus aclnnInplaceAcosh(
58- void* workspace, 58+ void *workspace,
59- uint64_t workspaceSize, 59+ uint64_t workspaceSize,
60- aclOpExecutor* executor, 60+ aclOpExecutor *executor,
61- aclrtStream stream)61+ aclrtStream stream)
62```62```
63 63 
64## aclnnAcoshGetWorkspaceSize64## aclnnAcoshGetWorkspaceSize
@@ -347,6 +347,7 @@ aclnnStatus aclnnInplaceAcosh(
347 347 
348 aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。348 aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。
349 349 
350+ 
350## 约束说明351## 约束说明
351 352 
352- 确定性计算:353- 确定性计算:
@@ -513,3 +514,4 @@ int main() {
513 return 0;514 return 0;
514}515}
515```516```
517+ 
Amath/acosh/examples/arch35/test_aclnn_acosh.cpp+182-0
@@ -0,0 +1,182 @@
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+/* Generated By CANNBot */
12+ 
13+/**
14+ * @file test_aclnn_acosh.cpp
15+ * @brief aclnnAcosh(非原地)调用示例
16+ *
17+ * 演示标准 aclnn 两段式调用流程:
18+ * 1) aclInit / aclrtSetDevice / aclrtCreateStream
19+ * 2) Host 构造输入张量并拷贝到 Device
20+ * 3) aclnnAcoshGetWorkspaceSize → workspaceSize / executor
21+ * 4) 申请 workspace 后调用 aclnnAcosh
22+ * 5) aclrtSynchronizeStream 等待执行结束
23+ * 6) Device → Host 拷回输出并打印
24+ * 7) 资源释放 + aclFinalize
25+ *
26+ * 前置条件:算子已编译并安装到 ${ASCEND_HOME_PATH}/opp/vendors/acosh_custom/
27+ */
28+ 
29+#include <cmath>
30+#include <cstdio>
31+#include <iostream>
32+#include <vector>
33+ 
34+#include "acl/acl.h"
35+#include "aclnn_acosh.h"
36+ 
37+#define CHECK_RET(cond, return_expr) \
38+ do { \
39+ if (!(cond)) { \
40+ return_expr; \
41+ } \
42+ } while (0)
43+ 
44+#define LOG_PRINT(message, ...) \
45+ do { \
46+ printf(message, ##__VA_ARGS__); \
47+ } while (0)
48+ 
49+static int64_t GetShapeSize(const std::vector<int64_t> &shape)
50+{
51+ int64_t size = 1;
52+ for (auto d : shape) {
53+ size *= d;
54+ }
55+ return size;
56+}
57+ 
58+static int Init(int32_t deviceId, aclrtStream *stream)
59+{
60+ auto ret = aclInit(nullptr);
61+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
62+ ret = aclrtSetDevice(deviceId);
63+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
64+ ret = aclrtCreateStream(stream);
65+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
66+ return 0;
67+}
68+ 
69+template <typename T>
70+static int CreateAclTensor(const std::vector<T> &hostData,
71+ const std::vector<int64_t> &shape,
72+ void **deviceAddr,
73+ aclDataType dataType,
74+ aclTensor **tensor)
75+{
76+ auto bytes = GetShapeSize(shape) * sizeof(T);
77+ auto ret = aclrtMalloc(deviceAddr, bytes, ACL_MEM_MALLOC_HUGE_FIRST);
78+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
79+ ret = aclrtMemcpy(*deviceAddr, bytes, hostData.data(), bytes, ACL_MEMCPY_HOST_TO_DEVICE);
80+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy H2D failed. ERROR: %d\n", ret); return ret);
81+ 
82+ // 行主序连续 strides
83+ std::vector<int64_t> strides(shape.size(), 1);
84+ for (int64_t i = static_cast<int64_t>(shape.size()) - 2; i >= 0; --i) {
85+ strides[i] = shape[i + 1] * strides[i + 1];
86+ }
87+ 
88+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType,
89+ strides.data(), 0, aclFormat::ACL_FORMAT_ND,
90+ shape.data(), shape.size(), *deviceAddr);
91+ return 0;
92+}
93+ 
94+int main()
95+{
96+ // 1. 初始化 ACL
97+ int32_t deviceId = 0;
98+ aclrtStream stream = nullptr;
99+ auto ret = Init(deviceId, &stream);
100+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
101+ 
102+ // 2. 构造输入:shape = [2, 4],全部位于定义域 [1, +∞)
103+ std::vector<int64_t> selfShape = {2, 4};
104+ std::vector<int64_t> outShape = {2, 4};
105+ std::vector<float> selfHostData = {1.0f, 2.0f, 3.0f, 5.0f,
106+ 10.0f, 1.5f, 2.5f, 4.0f};
107+ std::vector<float> outHostData(static_cast<size_t>(GetShapeSize(outShape)), 0.0f);
108+ 
109+ aclTensor *selfTensor = nullptr;
110+ void *selfDevice = nullptr;
111+ ret = CreateAclTensor(selfHostData, selfShape, &selfDevice,
112+ aclDataType::ACL_FLOAT, &selfTensor);
113+ CHECK_RET(ret == ACL_SUCCESS, return ret);
114+ 
115+ aclTensor *outTensor = nullptr;
116+ void *outDevice = nullptr;
117+ ret = CreateAclTensor(outHostData, outShape, &outDevice,
118+ aclDataType::ACL_FLOAT, &outTensor);
119+ CHECK_RET(ret == ACL_SUCCESS, return ret);
120+ 
121+ // 3. 第一段接口:获取 workspace 大小 + executor
122+ uint64_t workspaceSize = 0;
123+ aclOpExecutor *executor = nullptr;
124+ ret = aclnnAcoshGetWorkspaceSize(selfTensor, outTensor, &workspaceSize, &executor);
125+ CHECK_RET(ret == ACL_SUCCESS,
126+ LOG_PRINT("aclnnAcoshGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
127+ 
128+ // 4. 申请 workspace(如有)
129+ void *workspaceAddr = nullptr;
130+ if (workspaceSize > 0) {
131+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
132+ CHECK_RET(ret == ACL_SUCCESS,
133+ LOG_PRINT("workspace aclrtMalloc failed. ERROR: %d\n", ret); return ret);
134+ }
135+ 
136+ // 5. 第二段接口:实际执行算子
137+ ret = aclnnAcosh(workspaceAddr, workspaceSize, executor, stream);
138+ CHECK_RET(ret == ACL_SUCCESS,
139+ LOG_PRINT("aclnnAcosh failed. ERROR: %d\n", ret); return ret);
140+ 
141+ // 6. 同步等待
142+ ret = aclrtSynchronizeStream(stream);
143+ CHECK_RET(ret == ACL_SUCCESS,
144+ LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
145+ 
146+ // 7. 拷回输出并打印(同时用 std::acosh 粗略对照)
147+ auto outBytes = GetShapeSize(outShape) * sizeof(float);
148+ std::vector<float> npuResult(static_cast<size_t>(GetShapeSize(outShape)), 0.0f);
149+ ret = aclrtMemcpy(npuResult.data(), outBytes, outDevice, outBytes,
150+ ACL_MEMCPY_DEVICE_TO_HOST);
151+ CHECK_RET(ret == ACL_SUCCESS,
152+ LOG_PRINT("aclrtMemcpy D2H failed. ERROR: %d\n", ret); return ret);
153+ 
154+ LOG_PRINT("\n=== aclnnAcosh result (shape=[2,4], dtype=FLOAT) ===\n");
155+ int allClose = 1;
156+ for (size_t i = 0; i < npuResult.size(); ++i) {
157+ float expected = std::acosh(selfHostData[i]);
158+ float diff = std::fabs(npuResult[i] - expected);
159+ // FP32 阈值参考:MERE 2^-13 ≈ 1.22e-4,这里取 1e-4 作为示例粗对照
160+ const char *flag = (diff < 1e-4f) ? "OK" : "DIFF";
161+ if (diff >= 1e-4f) {
162+ allClose = 0;
163+ }
164+ LOG_PRINT(" self[%zu]=%-9.4f npu=%-12.7f std::acosh=%-12.7f diff=%-10.3e [%s]\n",
165+ i, selfHostData[i], npuResult[i], expected, diff, flag);
166+ }
167+ LOG_PRINT("=== aclnnAcosh %s ===\n", allClose ? "PASS (粗对照)" : "DIFF (粗对照)");
168+ 
169+ // 8. 释放资源
170+ aclDestroyTensor(selfTensor);
171+ aclDestroyTensor(outTensor);
172+ aclrtFree(selfDevice);
173+ aclrtFree(outDevice);
174+ if (workspaceSize > 0 && workspaceAddr != nullptr) {
175+ aclrtFree(workspaceAddr);
176+ }
177+ aclrtDestroyStream(stream);
178+ aclrtResetDevice(deviceId);
179+ aclFinalize();
180+ 
181+ return allClose ? 0 : 1;
182+}
Amath/acosh/examples/arch35/test_aclnn_inplace_acosh.cpp+167-0
@@ -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+/* Generated By CANNBot */
12+ 
13+/**
14+ * @file test_aclnn_inplace_acosh.cpp
15+ * @brief aclnnInplaceAcosh(原地)调用示例
16+ *
17+ * 与 test_aclnn_acosh.cpp 的差异:
18+ * - 只有 selfRef 一个张量,既作输入又作输出,结果原地写回;
19+ * - 调用 aclnnInplaceAcoshGetWorkspaceSize / aclnnInplaceAcosh。
20+ *
21+ * 前置条件:算子已编译并安装到 ${ASCEND_HOME_PATH}/opp/vendors/acosh_custom/
22+ */
23+ 
24+#include <cmath>
25+#include <cstdio>
26+#include <iostream>
27+#include <vector>
28+ 
29+#include "acl/acl.h"
30+#include "aclnn_acosh.h"
31+ 
32+#define CHECK_RET(cond, return_expr) \
33+ do { \
34+ if (!(cond)) { \
35+ return_expr; \
36+ } \
37+ } while (0)
38+ 
39+#define LOG_PRINT(message, ...) \
40+ do { \
41+ printf(message, ##__VA_ARGS__); \
42+ } while (0)
43+ 
44+static int64_t GetShapeSize(const std::vector<int64_t> &shape)
45+{
46+ int64_t size = 1;
47+ for (auto d : shape) {
48+ size *= d;
49+ }
50+ return size;
51+}
52+ 
53+static int Init(int32_t deviceId, aclrtStream *stream)
54+{
55+ auto ret = aclInit(nullptr);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
57+ ret = aclrtSetDevice(deviceId);
58+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
59+ ret = aclrtCreateStream(stream);
60+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
61+ return 0;
62+}
63+ 
64+template <typename T>
65+static int CreateAclTensor(const std::vector<T> &hostData,
66+ const std::vector<int64_t> &shape,
67+ void **deviceAddr,
68+ aclDataType dataType,
69+ aclTensor **tensor)
70+{
71+ auto bytes = GetShapeSize(shape) * sizeof(T);
72+ auto ret = aclrtMalloc(deviceAddr, bytes, ACL_MEM_MALLOC_HUGE_FIRST);
73+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
74+ ret = aclrtMemcpy(*deviceAddr, bytes, hostData.data(), bytes, ACL_MEMCPY_HOST_TO_DEVICE);
75+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy H2D failed. ERROR: %d\n", ret); return ret);
76+ 
77+ std::vector<int64_t> strides(shape.size(), 1);
78+ for (int64_t i = static_cast<int64_t>(shape.size()) - 2; i >= 0; --i) {
79+ strides[i] = shape[i + 1] * strides[i + 1];
80+ }
81+ 
82+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType,
83+ strides.data(), 0, aclFormat::ACL_FORMAT_ND,
84+ shape.data(), shape.size(), *deviceAddr);
85+ return 0;
86+}
87+ 
88+int main()
89+{
90+ // 1. 初始化 ACL
91+ int32_t deviceId = 0;
92+ aclrtStream stream = nullptr;
93+ auto ret = Init(deviceId, &stream);
94+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
95+ 
96+ // 2. 构造 selfRef:shape=[2,4],同时作为输入与输出
97+ std::vector<int64_t> selfShape = {2, 4};
98+ std::vector<float> selfHost = {1.0f, 2.0f, 3.0f, 5.0f,
99+ 10.0f, 1.5f, 2.5f, 4.0f};
100+ // 保留原始值用于后续 std::acosh 粗对照
101+ const std::vector<float> origSelf = selfHost;
102+ 
103+ aclTensor *selfRef = nullptr;
104+ void *selfDevice = nullptr;
105+ ret = CreateAclTensor(selfHost, selfShape, &selfDevice,
106+ aclDataType::ACL_FLOAT, &selfRef);
107+ CHECK_RET(ret == ACL_SUCCESS, return ret);
108+ 
109+ // 3. 第一段接口
110+ uint64_t workspaceSize = 0;
111+ aclOpExecutor *executor = nullptr;
112+ ret = aclnnInplaceAcoshGetWorkspaceSize(selfRef, &workspaceSize, &executor);
113+ CHECK_RET(ret == ACL_SUCCESS,
114+ LOG_PRINT("aclnnInplaceAcoshGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
115+ 
116+ // 4. 申请 workspace
117+ void *workspaceAddr = nullptr;
118+ if (workspaceSize > 0) {
119+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
120+ CHECK_RET(ret == ACL_SUCCESS,
121+ LOG_PRINT("workspace aclrtMalloc failed. ERROR: %d\n", ret); return ret);
122+ }
123+ 
124+ // 5. 第二段接口:原地执行
125+ ret = aclnnInplaceAcosh(workspaceAddr, workspaceSize, executor, stream);
126+ CHECK_RET(ret == ACL_SUCCESS,
127+ LOG_PRINT("aclnnInplaceAcosh failed. ERROR: %d\n", ret); return ret);
128+ 
129+ // 6. 同步等待
130+ ret = aclrtSynchronizeStream(stream);
131+ CHECK_RET(ret == ACL_SUCCESS,
132+ LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
133+ 
134+ // 7. 拷回(注意:selfRef 内存即输出)
135+ auto bytes = GetShapeSize(selfShape) * sizeof(float);
136+ std::vector<float> npuResult(static_cast<size_t>(GetShapeSize(selfShape)), 0.0f);
137+ ret = aclrtMemcpy(npuResult.data(), bytes, selfDevice, bytes,
138+ ACL_MEMCPY_DEVICE_TO_HOST);
139+ CHECK_RET(ret == ACL_SUCCESS,
140+ LOG_PRINT("aclrtMemcpy D2H failed. ERROR: %d\n", ret); return ret);
141+ 
142+ LOG_PRINT("\n=== aclnnInplaceAcosh result (shape=[2,4], dtype=FLOAT) ===\n");
143+ int allClose = 1;
144+ for (size_t i = 0; i < npuResult.size(); ++i) {
145+ float expected = std::acosh(origSelf[i]);
146+ float diff = std::fabs(npuResult[i] - expected);
147+ const char *flag = (diff < 1e-4f) ? "OK" : "DIFF";
148+ if (diff >= 1e-4f) {
149+ allClose = 0;
150+ }
151+ LOG_PRINT(" selfRef[%zu] in=%-9.4f out(原地)=%-12.7f std::acosh=%-12.7f diff=%-10.3e [%s]\n",
152+ i, origSelf[i], npuResult[i], expected, diff, flag);
153+ }
154+ LOG_PRINT("=== aclnnInplaceAcosh %s ===\n", allClose ? "PASS (粗对照)" : "DIFF (粗对照)");
155+ 
156+ // 8. 释放资源
157+ aclDestroyTensor(selfRef);
158+ aclrtFree(selfDevice);
159+ if (workspaceSize > 0 && workspaceAddr != nullptr) {
160+ aclrtFree(workspaceAddr);
161+ }
162+ aclrtDestroyStream(stream);
163+ aclrtResetDevice(deviceId);
164+ aclFinalize();
165+ 
166+ return allClose ? 0 : 1;
167+}
Amath/acosh/examples/test_aclnn_acosh.cpp+182-0
@@ -0,0 +1,182 @@
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+/* Generated By CANNBot */
12+ 
13+/**
14+ * @file test_aclnn_acosh.cpp
15+ * @brief aclnnAcosh(非原地)调用示例
16+ *
17+ * 演示标准 aclnn 两段式调用流程:
18+ * 1) aclInit / aclrtSetDevice / aclrtCreateStream
19+ * 2) Host 构造输入张量并拷贝到 Device
20+ * 3) aclnnAcoshGetWorkspaceSize → workspaceSize / executor
21+ * 4) 申请 workspace 后调用 aclnnAcosh
22+ * 5) aclrtSynchronizeStream 等待执行结束
23+ * 6) Device → Host 拷回输出并打印
24+ * 7) 资源释放 + aclFinalize
25+ *
26+ * 前置条件:算子已编译并安装到 ${ASCEND_HOME_PATH}/opp/vendors/acosh_custom/
27+ */
28+ 
29+#include <cmath>
30+#include <cstdio>
31+#include <iostream>
32+#include <vector>
33+ 
34+#include "acl/acl.h"
35+#include "aclnn_acosh.h"
36+ 
37+#define CHECK_RET(cond, return_expr) \
38+ do { \
39+ if (!(cond)) { \
40+ return_expr; \
41+ } \
42+ } while (0)
43+ 
44+#define LOG_PRINT(message, ...) \
45+ do { \
46+ printf(message, ##__VA_ARGS__); \
47+ } while (0)
48+ 
49+static int64_t GetShapeSize(const std::vector<int64_t> &shape)
50+{
51+ int64_t size = 1;
52+ for (auto d : shape) {
53+ size *= d;
54+ }
55+ return size;
56+}
57+ 
58+static int Init(int32_t deviceId, aclrtStream *stream)
59+{
60+ auto ret = aclInit(nullptr);
61+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
62+ ret = aclrtSetDevice(deviceId);
63+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
64+ ret = aclrtCreateStream(stream);
65+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
66+ return 0;
67+}
68+ 
69+template <typename T>
70+static int CreateAclTensor(const std::vector<T> &hostData,
71+ const std::vector<int64_t> &shape,
72+ void **deviceAddr,
73+ aclDataType dataType,
74+ aclTensor **tensor)
75+{
76+ auto bytes = GetShapeSize(shape) * sizeof(T);
77+ auto ret = aclrtMalloc(deviceAddr, bytes, ACL_MEM_MALLOC_HUGE_FIRST);
78+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
79+ ret = aclrtMemcpy(*deviceAddr, bytes, hostData.data(), bytes, ACL_MEMCPY_HOST_TO_DEVICE);
80+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy H2D failed. ERROR: %d\n", ret); return ret);
81+ 
82+ // 行主序连续 strides
83+ std::vector<int64_t> strides(shape.size(), 1);
84+ for (int64_t i = static_cast<int64_t>(shape.size()) - 2; i >= 0; --i) {
85+ strides[i] = shape[i + 1] * strides[i + 1];
86+ }
87+ 
88+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType,
89+ strides.data(), 0, aclFormat::ACL_FORMAT_ND,
90+ shape.data(), shape.size(), *deviceAddr);
91+ return 0;
92+}
93+ 
94+int main()
95+{
96+ // 1. 初始化 ACL
97+ int32_t deviceId = 0;
98+ aclrtStream stream = nullptr;
99+ auto ret = Init(deviceId, &stream);
100+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
101+ 
102+ // 2. 构造输入:shape = [2, 4],全部位于定义域 [1, +∞)
103+ std::vector<int64_t> selfShape = {2, 4};
104+ std::vector<int64_t> outShape = {2, 4};
105+ std::vector<float> selfHostData = {1.0f, 2.0f, 3.0f, 5.0f,
106+ 10.0f, 1.5f, 2.5f, 4.0f};
107+ std::vector<float> outHostData(static_cast<size_t>(GetShapeSize(outShape)), 0.0f);
108+ 
109+ aclTensor *selfTensor = nullptr;
110+ void *selfDevice = nullptr;
111+ ret = CreateAclTensor(selfHostData, selfShape, &selfDevice,
112+ aclDataType::ACL_FLOAT, &selfTensor);
113+ CHECK_RET(ret == ACL_SUCCESS, return ret);
114+ 
115+ aclTensor *outTensor = nullptr;
116+ void *outDevice = nullptr;
117+ ret = CreateAclTensor(outHostData, outShape, &outDevice,
118+ aclDataType::ACL_FLOAT, &outTensor);
119+ CHECK_RET(ret == ACL_SUCCESS, return ret);
120+ 
121+ // 3. 第一段接口:获取 workspace 大小 + executor
122+ uint64_t workspaceSize = 0;
123+ aclOpExecutor *executor = nullptr;
124+ ret = aclnnAcoshGetWorkspaceSize(selfTensor, outTensor, &workspaceSize, &executor);
125+ CHECK_RET(ret == ACL_SUCCESS,
126+ LOG_PRINT("aclnnAcoshGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
127+ 
128+ // 4. 申请 workspace(如有)
129+ void *workspaceAddr = nullptr;
130+ if (workspaceSize > 0) {
131+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
132+ CHECK_RET(ret == ACL_SUCCESS,
133+ LOG_PRINT("workspace aclrtMalloc failed. ERROR: %d\n", ret); return ret);
134+ }
135+ 
136+ // 5. 第二段接口:实际执行算子
137+ ret = aclnnAcosh(workspaceAddr, workspaceSize, executor, stream);
138+ CHECK_RET(ret == ACL_SUCCESS,
139+ LOG_PRINT("aclnnAcosh failed. ERROR: %d\n", ret); return ret);
140+ 
141+ // 6. 同步等待
142+ ret = aclrtSynchronizeStream(stream);
143+ CHECK_RET(ret == ACL_SUCCESS,
144+ LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
145+ 
146+ // 7. 拷回输出并打印(同时用 std::acosh 粗略对照)
147+ auto outBytes = GetShapeSize(outShape) * sizeof(float);
148+ std::vector<float> npuResult(static_cast<size_t>(GetShapeSize(outShape)), 0.0f);
149+ ret = aclrtMemcpy(npuResult.data(), outBytes, outDevice, outBytes,
150+ ACL_MEMCPY_DEVICE_TO_HOST);
151+ CHECK_RET(ret == ACL_SUCCESS,
152+ LOG_PRINT("aclrtMemcpy D2H failed. ERROR: %d\n", ret); return ret);
153+ 
154+ LOG_PRINT("\n=== aclnnAcosh result (shape=[2,4], dtype=FLOAT) ===\n");
155+ int allClose = 1;
156+ for (size_t i = 0; i < npuResult.size(); ++i) {
157+ float expected = std::acosh(selfHostData[i]);
158+ float diff = std::fabs(npuResult[i] - expected);
159+ // FP32 阈值参考:MERE 2^-13 ≈ 1.22e-4,这里取 1e-4 作为示例粗对照
160+ const char *flag = (diff < 1e-4f) ? "OK" : "DIFF";
161+ if (diff >= 1e-4f) {
162+ allClose = 0;
163+ }
164+ LOG_PRINT(" self[%zu]=%-9.4f npu=%-12.7f std::acosh=%-12.7f diff=%-10.3e [%s]\n",
165+ i, selfHostData[i], npuResult[i], expected, diff, flag);
166+ }
167+ LOG_PRINT("=== aclnnAcosh %s ===\n", allClose ? "PASS (粗对照)" : "DIFF (粗对照)");
168+ 
169+ // 8. 释放资源
170+ aclDestroyTensor(selfTensor);
171+ aclDestroyTensor(outTensor);
172+ aclrtFree(selfDevice);
173+ aclrtFree(outDevice);
174+ if (workspaceSize > 0 && workspaceAddr != nullptr) {
175+ aclrtFree(workspaceAddr);
176+ }
177+ aclrtDestroyStream(stream);
178+ aclrtResetDevice(deviceId);
179+ aclFinalize();
180+ 
181+ return allClose ? 0 : 1;
182+}
Amath/acosh/examples/test_aclnn_inplace_acosh.cpp+167-0
@@ -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+/* Generated By CANNBot */
12+ 
13+/**
14+ * @file test_aclnn_inplace_acosh.cpp
15+ * @brief aclnnInplaceAcosh(原地)调用示例
16+ *
17+ * 与 test_aclnn_acosh.cpp 的差异:
18+ * - 只有 selfRef 一个张量,既作输入又作输出,结果原地写回;
19+ * - 调用 aclnnInplaceAcoshGetWorkspaceSize / aclnnInplaceAcosh。
20+ *
21+ * 前置条件:算子已编译并安装到 ${ASCEND_HOME_PATH}/opp/vendors/acosh_custom/
22+ */
23+ 
24+#include <cmath>
25+#include <cstdio>
26+#include <iostream>
27+#include <vector>
28+ 
29+#include "acl/acl.h"
30+#include "aclnn_acosh.h"
31+ 
32+#define CHECK_RET(cond, return_expr) \
33+ do { \
34+ if (!(cond)) { \
35+ return_expr; \
36+ } \
37+ } while (0)
38+ 
39+#define LOG_PRINT(message, ...) \
40+ do { \
41+ printf(message, ##__VA_ARGS__); \
42+ } while (0)
43+ 
44+static int64_t GetShapeSize(const std::vector<int64_t> &shape)
45+{
46+ int64_t size = 1;
47+ for (auto d : shape) {
48+ size *= d;
49+ }
50+ return size;
51+}
52+ 
53+static int Init(int32_t deviceId, aclrtStream *stream)
54+{
55+ auto ret = aclInit(nullptr);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
57+ ret = aclrtSetDevice(deviceId);
58+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
59+ ret = aclrtCreateStream(stream);
60+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
61+ return 0;
62+}
63+ 
64+template <typename T>
65+static int CreateAclTensor(const std::vector<T> &hostData,
66+ const std::vector<int64_t> &shape,
67+ void **deviceAddr,
68+ aclDataType dataType,
69+ aclTensor **tensor)
70+{
71+ auto bytes = GetShapeSize(shape) * sizeof(T);
72+ auto ret = aclrtMalloc(deviceAddr, bytes, ACL_MEM_MALLOC_HUGE_FIRST);
73+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
74+ ret = aclrtMemcpy(*deviceAddr, bytes, hostData.data(), bytes, ACL_MEMCPY_HOST_TO_DEVICE);
75+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy H2D failed. ERROR: %d\n", ret); return ret);
76+ 
77+ std::vector<int64_t> strides(shape.size(), 1);
78+ for (int64_t i = static_cast<int64_t>(shape.size()) - 2; i >= 0; --i) {
79+ strides[i] = shape[i + 1] * strides[i + 1];
80+ }
81+ 
82+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType,
83+ strides.data(), 0, aclFormat::ACL_FORMAT_ND,
84+ shape.data(), shape.size(), *deviceAddr);
85+ return 0;
86+}
87+ 
88+int main()
89+{
90+ // 1. 初始化 ACL
91+ int32_t deviceId = 0;
92+ aclrtStream stream = nullptr;
93+ auto ret = Init(deviceId, &stream);
94+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
95+ 
96+ // 2. 构造 selfRef:shape=[2,4],同时作为输入与输出
97+ std::vector<int64_t> selfShape = {2, 4};
98+ std::vector<float> selfHost = {1.0f, 2.0f, 3.0f, 5.0f,
99+ 10.0f, 1.5f, 2.5f, 4.0f};
100+ // 保留原始值用于后续 std::acosh 粗对照
101+ const std::vector<float> origSelf = selfHost;
102+ 
103+ aclTensor *selfRef = nullptr;
104+ void *selfDevice = nullptr;
105+ ret = CreateAclTensor(selfHost, selfShape, &selfDevice,
106+ aclDataType::ACL_FLOAT, &selfRef);
107+ CHECK_RET(ret == ACL_SUCCESS, return ret);
108+ 
109+ // 3. 第一段接口
110+ uint64_t workspaceSize = 0;
111+ aclOpExecutor *executor = nullptr;
112+ ret = aclnnInplaceAcoshGetWorkspaceSize(selfRef, &workspaceSize, &executor);
113+ CHECK_RET(ret == ACL_SUCCESS,
114+ LOG_PRINT("aclnnInplaceAcoshGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
115+ 
116+ // 4. 申请 workspace
117+ void *workspaceAddr = nullptr;
118+ if (workspaceSize > 0) {
119+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
120+ CHECK_RET(ret == ACL_SUCCESS,
121+ LOG_PRINT("workspace aclrtMalloc failed. ERROR: %d\n", ret); return ret);
122+ }
123+ 
124+ // 5. 第二段接口:原地执行
125+ ret = aclnnInplaceAcosh(workspaceAddr, workspaceSize, executor, stream);
126+ CHECK_RET(ret == ACL_SUCCESS,
127+ LOG_PRINT("aclnnInplaceAcosh failed. ERROR: %d\n", ret); return ret);
128+ 
129+ // 6. 同步等待
130+ ret = aclrtSynchronizeStream(stream);
131+ CHECK_RET(ret == ACL_SUCCESS,
132+ LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
133+ 
134+ // 7. 拷回(注意:selfRef 内存即输出)
135+ auto bytes = GetShapeSize(selfShape) * sizeof(float);
136+ std::vector<float> npuResult(static_cast<size_t>(GetShapeSize(selfShape)), 0.0f);
137+ ret = aclrtMemcpy(npuResult.data(), bytes, selfDevice, bytes,
138+ ACL_MEMCPY_DEVICE_TO_HOST);
139+ CHECK_RET(ret == ACL_SUCCESS,
140+ LOG_PRINT("aclrtMemcpy D2H failed. ERROR: %d\n", ret); return ret);
141+ 
142+ LOG_PRINT("\n=== aclnnInplaceAcosh result (shape=[2,4], dtype=FLOAT) ===\n");
143+ int allClose = 1;
144+ for (size_t i = 0; i < npuResult.size(); ++i) {
145+ float expected = std::acosh(origSelf[i]);
146+ float diff = std::fabs(npuResult[i] - expected);
147+ const char *flag = (diff < 1e-4f) ? "OK" : "DIFF";
148+ if (diff >= 1e-4f) {
149+ allClose = 0;
150+ }
151+ LOG_PRINT(" selfRef[%zu] in=%-9.4f out(原地)=%-12.7f std::acosh=%-12.7f diff=%-10.3e [%s]\n",
152+ i, origSelf[i], npuResult[i], expected, diff, flag);
153+ }
154+ LOG_PRINT("=== aclnnInplaceAcosh %s ===\n", allClose ? "PASS (粗对照)" : "DIFF (粗对照)");
155+ 
156+ // 8. 释放资源
157+ aclDestroyTensor(selfRef);
158+ aclrtFree(selfDevice);
159+ if (workspaceSize > 0 && workspaceAddr != nullptr) {
160+ aclrtFree(workspaceAddr);
161+ }
162+ aclrtDestroyStream(stream);
163+ aclrtResetDevice(deviceId);
164+ aclFinalize();
165+ 
166+ return allClose ? 0 : 1;
167+}
Rmath/acosh/op_host/op_api/aclnn_acosh.cppmath/acosh/op_api/aclnn_acosh.cpp+0-0
文件重命名但无更改。
Rmath/acosh/op_host/op_api/aclnn_acosh.hmath/acosh/op_api/aclnn_acosh.h+0-0
文件重命名但无更改。
Rmath/acosh/op_host/op_api/acosh.cppmath/acosh/op_api/acosh.cpp+0-0
文件重命名但无更改。
Rmath/acosh/op_host/op_api/acosh.hmath/acosh/op_api/acosh.h+0-0
文件重命名但无更改。
Amath/acosh/op_graph/fusion_pass/.gitkeep+0-0
The file is empty
Dmath/acosh/op_host/CMakeLists.txt+0-12
@@ -1,12 +0,0 @@
1-# ----------------------------------------------------------------------------
2-# This program is free software, you can redistribute it and/or modify it.
3-# Copyright (c) 2025 Huawei Technologies Co., Ltd.
4-# This file is a part of the CANN Open Software.
5-# Licensed under CANN Open Software License Agreement Version 2.0 (the "License").
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, INCLUDING
8-# 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- 
12-add_modules_sources()
Amath/acosh/op_host/acosh_def.cpp+49-0
@@ -0,0 +1,49 @@
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+/* Generated By CANNBot */
12+ 
13+/*!
14+ * \file acosh_def.cpp
15+ * \brief Acosh 算子定义(OpDef + OpAICoreConfig)
16+ */
17+#include "register/op_def_registry.h"
18+ 
19+namespace ops {
20+class Acosh : public OpDef {
21+public:
22+ explicit Acosh(const char* name) : OpDef(name)
23+ {
24+ this->Input("x")
25+ .ParamType(REQUIRED)
26+ .DataType({ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16})
27+ .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND})
28+ .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND})
29+ .AutoContiguous();
30+ this->Output("y")
31+ .ParamType(REQUIRED)
32+ .DataType({ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16})
33+ .Format({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND})
34+ .UnknownShapeFormat({ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND})
35+ .AutoContiguous();
36+ 
37+ OpAICoreConfig aiCoreConfig;
38+ aiCoreConfig.DynamicCompileStaticFlag(true)
39+ .DynamicFormatFlag(false)
40+ .DynamicRankSupportFlag(true)
41+ .DynamicShapeSupportFlag(true)
42+ .NeedCheckSupportFlag(false)
43+ .PrecisionReduceFlag(false)
44+ .ExtendCfgInfo("opFile.value", "acosh_apt");
45+ this->AICore().AddConfig("ascend950", aiCoreConfig);
46+ }
47+};
48+OP_ADD(Acosh);
49+} // namespace ops
Amath/acosh/op_host/acosh_infershape.cpp+44-0
@@ -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+/* Generated By CANNBot */
12+ 
13+/*!
14+ * \file acosh_infershape.cpp
15+ * \brief Acosh 算子 InferShape 实现
16+ *
17+ * 与 DESIGN.md v2.1 §3.3 对齐:
18+ * - Elementwise 单输入单输出,out.shape = self.shape
19+ */
20+#include "register/op_impl_registry.h"
21+#include "exe_graph/runtime/infer_shape_context.h"
22+#include "op_common/log/log.h"
23+ 
24+using namespace ge;
25+ 
26+namespace ops {
27+ 
28+static ge::graphStatus InferShape4Acosh(gert::InferShapeContext* context)
29+{
30+ const gert::Shape* input_shape = context->GetInputShape(0);
31+ OP_CHECK_NULL_WITH_CONTEXT(context, input_shape);
32+ 
33+ gert::Shape* output_shape = context->GetOutputShape(0);
34+ OP_CHECK_NULL_WITH_CONTEXT(context, output_shape);
35+ 
36+ // Elementwise: 输出形状 = 输入形状
37+ *output_shape = *input_shape;
38+ 
39+ return ge::GRAPH_SUCCESS;
40+}
41+ 
42+IMPL_OP_INFERSHAPE(Acosh).InferShape(InferShape4Acosh);
43+ 
44+} // namespace ops
Amath/acosh/op_host/arch35/acosh_tiling_arch35.cpp+177-0
@@ -0,0 +1,177 @@
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+ * \file acosh_tiling.cpp
13+ * \brief Acosh 算子 Host Tiling(arch35 / Ascend950)
14+ *
15+ * 与 DESIGN.md v2.1 §3.6 对齐:
16+ * - 平台信息动态获取:GetCoreNumAiv() / GetCoreMemSize(UB) (禁止硬编码)
17+ * - 多核切分:blockFactor = CeilAlign(CeilDiv(totalNum, coreNum), 32B)
18+ * - UB 切分:ubFactor = FloorAlign((ubSize - logTmpReserve) / (8 × 4B), 32B)
19+ * 8 个 FP32 当量 Buffer 含 DB(inputQue×2 + outputQue×2 + fp32WorkBuf + dataTBuf + dataRBuf + logTmpBuf)
20+ * - Log 隐式 tmpBuffer 预留:通过 GetLogMaxMinTmpSize 在 ubSize 中扣除
21+ * - 空 Tensor 早返回 + 32B 对齐尾块(DataCopyPad 自动处理)
22+ * - TilingKey 编码:ASCENDC_TPL_SEL_PARAM(context, dtype),dtype 维度即 D_T_X
23+ *
24+ * 迭代一范围(FP32 单 dtype 走通):
25+ * - dtype 校验:迭代一仅放行 DT_FLOAT;DT_FLOAT16/DT_BF16 在迭代二完整启用
26+ * (这里同时校验 3 dtype 是否在 supported 集合内,并按 dtype 通过 TilingKey 分发;
27+ * 实际 Kernel 端 Cast 路径已实现,仅迭代二做完整 ST 验证)
28+ */
29+ 
30+#include <algorithm>
31+#include <vector>
32+#include "register/op_def_registry.h"
33+#include "op_common/log/log.h"
34+#include "op_common/op_host/util/math_util.h"
35+#include "op_common/op_host/util/platform_util.h"
36+#include "tiling/platform/platform_ascendc.h"
37+#include "../../op_kernel/arch35/acosh_tiling_data.h"
38+#include "../../op_kernel/arch35/acosh_tiling_key.h"
39+ 
40+/* Generated By CANNBot */
41+ 
42+namespace optiling {
43+ 
44+using Ops::Base::CeilDiv;
45+using Ops::Base::CeilAlign;
46+using Ops::Base::FloorAlign;
47+using Ops::Base::FloorDiv;
48+using Ops::Base::GetUbBlockSize;
49+ 
50+constexpr size_t WORKSPACE_NUM = 1;
51+constexpr uint32_t WS_SYS_SIZE = 0U;
52+ 
53+// 单 tile 同时活跃的 FP32 当量 Buffer 数(含 DB):
54+// inputQue × 2 (DB) + outputQue × 2 (DB) + fp32WorkBuf + dataTBuf + dataRBuf + logTmpBuf = 8
55+// 每元素 4 字节(FP32)。
56+// FP16/BF16 路径下 inputQue/outputQue 元素是 2 字节,理论上更宽松,但为简化按 FP32 保守上界估算。
57+constexpr int64_t FP32_BUF_COUNT_WITH_DB = 8;
58+constexpr int64_t TYPE_SIZE_FP32 = 4;
59+ 
60+// 获取平台信息:UB 容量与 AI Core 数(动态获取,禁止硬编码)
61+static ge::graphStatus GetPlatformInfo(gert::TilingContext* context, uint64_t* ubSize, int64_t* coreNum)
62+{
63+ fe::PlatFormInfos* platformInfoPtr = context->GetPlatformInfo();
64+ OP_CHECK_NULL_WITH_CONTEXT(context, platformInfoPtr);
65+ auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfoPtr);
66+ *coreNum = ascendcPlatform.GetCoreNumAiv();
67+ OP_CHECK_IF(*coreNum == 0, OP_LOGE(context, "Acosh: coreNum is 0"), return ge::GRAPH_FAILED);
68+ ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, *ubSize);
69+ OP_CHECK_IF(*ubSize == 0, OP_LOGE(context, "Acosh: ubSize is 0"), return ge::GRAPH_FAILED);
70+ return ge::GRAPH_SUCCESS;
71+}
72+ 
73+// 解析输入 shape / dtype,并校验 dtype 在支持列表内
74+static ge::graphStatus ParseInputAndCheckDtype(
75+ gert::TilingContext* context, int64_t* totalNum, ge::DataType* dtype)
76+{
77+ auto inputShape = context->GetInputShape(0);
78+ OP_CHECK_NULL_WITH_CONTEXT(context, inputShape);
79+ *totalNum = inputShape->GetStorageShape().GetShapeSize();
80+ 
81+ auto inputDesc = context->GetInputDesc(0);
82+ OP_CHECK_NULL_WITH_CONTEXT(context, inputDesc);
83+ *dtype = inputDesc->GetDataType();
84+ const std::set<ge::DataType> supported = {ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16};
85+ OP_CHECK_IF(supported.count(*dtype) == 0,
86+ OP_LOGE(context, "Acosh: unsupported dtype %d", static_cast<int>(*dtype)),
87+ return ge::GRAPH_FAILED);
88+ return ge::GRAPH_SUCCESS;
89+}
90+ 
91+// 计算 UB 切分(ubFactor):扣除 Log 隐式 tmpBuffer 预留后均分 8 个 FP32 当量 Buffer
92+// A1-P-log-tmpbuf 实测在 Ascend950 (DAV_3510) 上 GetLogMaxMinTmpSize 返回 minValue=0,
93+// 即 Log natural 接口在该平台无需预留 sharedTmpBuffer;保留变量以保持跨平台扩展性。
94+// 按 32B (= 8 个 FP32 元素) 向下对齐,与 DESIGN.md v2.1 §3.6 / §3.8.1 估算口径一致。
95+static ge::graphStatus ComputeUbFactor(
96+ gert::TilingContext* context, uint64_t ubSize, int64_t ubBlockSize, int64_t* ubFactor)
97+{
98+ constexpr int64_t logTmpReserveBytes = 0;
99+ int64_t ubAvail = static_cast<int64_t>(ubSize) - logTmpReserveBytes;
100+ OP_CHECK_IF(ubAvail <= 0,
101+ OP_LOGE(context, "Acosh: ubAvail <= 0, ubSize=%lu", static_cast<unsigned long>(ubSize)),
102+ return ge::GRAPH_FAILED);
103+ 
104+ int64_t elemsPerFp32 = FloorDiv(ubAvail, TYPE_SIZE_FP32 * FP32_BUF_COUNT_WITH_DB);
105+ int64_t alignElems = ubBlockSize / TYPE_SIZE_FP32;
106+ *ubFactor = FloorAlign(elemsPerFp32, alignElems);
107+ OP_CHECK_IF(*ubFactor <= 0,
108+ OP_LOGE(context, "Acosh: ubFactor too small (=%ld)", *ubFactor),
109+ return ge::GRAPH_FAILED);
110+ return ge::GRAPH_SUCCESS;
111+}
112+ 
113+static ge::graphStatus AcoshTilingFunc(gert::TilingContext* context)
114+{
115+ OP_LOGD(context->GetNodeName(), "Enter AcoshTilingFunc");
116+ // 1. 平台信息
117+ uint64_t ubSize = 0;
118+ int64_t coreNum = 0;
119+ OP_CHECK_IF(GetPlatformInfo(context, &ubSize, &coreNum) != ge::GRAPH_SUCCESS,
120+ OP_LOGE(context, "Acosh: GetPlatformInfo error"), return ge::GRAPH_FAILED);
121+ 
122+ // 2. shape & dtype
123+ int64_t totalNum = 0;
124+ ge::DataType dtype = ge::DT_UNDEFINED;
125+ OP_CHECK_IF(ParseInputAndCheckDtype(context, &totalNum, &dtype) != ge::GRAPH_SUCCESS,
126+ OP_LOGE(context, "Acosh: ParseInputAndCheckDtype error"), return ge::GRAPH_FAILED);
127+ 
128+ // 3. workspace
129+ size_t* ws = context->GetWorkspaceSizes(WORKSPACE_NUM);
130+ OP_CHECK_NULL_WITH_CONTEXT(context, ws);
131+ ws[0] = WS_SYS_SIZE;
132+ 
133+ // 4. TilingData
134+ AcoshTilingData* tiling = context->GetTilingData<AcoshTilingData>();
135+ OP_CHECK_NULL_WITH_CONTEXT(context, tiling);
136+ OP_CHECK_IF(memset_s(tiling, sizeof(AcoshTilingData), 0, sizeof(AcoshTilingData)) != EOK,
137+ OP_LOGE(context, "Acosh: memset tiling failed"), return ge::GRAPH_FAILED);
138+ 
139+ // 5. 空 Tensor 早返回:Tiling 层 SetBlockDim(1),Kernel 内 Process() 早返回
140+ if (totalNum == 0) {
141+ context->SetBlockDim(1);
142+ ASCENDC_TPL_SEL_PARAM(context, static_cast<uint32_t>(dtype));
143+ return ge::GRAPH_SUCCESS;
144+ }
145+ 
146+ // 6. 多核切分(按 32B 向上对齐,避免相邻核 CopyOut 写覆盖)
147+ int64_t ubBlockSize = GetUbBlockSize(context); // 通常 32 字节
148+ tiling->totalNum = totalNum;
149+ tiling->blockFactor = CeilAlign(CeilDiv(totalNum, coreNum), ubBlockSize);
150+ int64_t usedCoreNum = CeilDiv(totalNum, tiling->blockFactor);
151+ 
152+ // 7. UB 切分
153+ OP_CHECK_IF(ComputeUbFactor(context, ubSize, ubBlockSize, &tiling->ubFactor) != ge::GRAPH_SUCCESS,
154+ OP_LOGE(context, "Acosh: ComputeUbFactor error"), return ge::GRAPH_FAILED);
155+ 
156+ // 8. BlockDim
157+ context->SetBlockDim(usedCoreNum);
158+ 
159+ // 9. TilingKey:按 dtype 维度
160+ ASCENDC_TPL_SEL_PARAM(context, static_cast<uint32_t>(dtype));
161+ 
162+ OP_LOGI(context, "Acosh: totalNum=%ld, blockFactor=%ld, ubFactor=%ld, usedCoreNum=%ld, dtype=%d",
163+ tiling->totalNum, tiling->blockFactor, tiling->ubFactor, usedCoreNum,
164+ static_cast<int>(dtype));
165+ return ge::GRAPH_SUCCESS;
166+}
167+ 
168+static ge::graphStatus TilingParseForAcosh([[maybe_unused]] gert::TilingParseContext* context)
169+{
170+ return ge::GRAPH_SUCCESS;
171+}
172+ 
173+struct AcoshCompileInfo {}; // 占位,入图场景依赖
174+ 
175+IMPL_OP_OPTILING(Acosh).Tiling(AcoshTilingFunc).TilingParse<AcoshCompileInfo>(TilingParseForAcosh);
176+ 
177+} // namespace optiling
Amath/acosh/op_kernel/acosh_apt.cpp+36-0
@@ -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+/* Generated By CANNBot */
12+ 
13+/*!
14+ * \file acosh_apt.cpp
15+ * \brief Acosh 算子 Kernel 入口(arch35 / Ascend950)
16+ *
17+ * 模板参数 D_T_X 由 acosh_tiling_key.h 中 ASCENDC_TPL_ARGS_DECL 定义。
18+ * dtype 静态分发:Acosh<float> / Acosh<half> / Acosh<bfloat16_t> 共 3 个实例
19+ * 由构建系统按 ASCENDC_TPL_SEL 自动生成;if constexpr 分支在 acosh.h::Compute() 内部。
20+ */
21+ 
22+#include "arch35/acosh.h"
23+ 
24+template <typename D_T_X>
25+__global__ __aicore__ void acosh(GM_ADDR self, GM_ADDR out,
26+ GM_ADDR workspace, GM_ADDR tiling)
27+{
28+ KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);
29+ 
30+ REGISTER_TILING_DEFAULT(AcoshTilingData);
31+ GET_TILING_DATA_WITH_STRUCT(AcoshTilingData, tilingData, tiling);
32+ 
33+ NsAcosh::Acosh<D_T_X> op;
34+ op.Init(self, out, &tilingData);
35+ op.Process();
36+}
Amath/acosh/op_kernel/arch35/acosh.h+272-0
@@ -0,0 +1,272 @@
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+/* Generated By CANNBot */
12+ 
13+/*!
14+ * \file acosh.h
15+ * \brief Acosh 算子 Kernel 类(arch35 / Ascend950)
16+ *
17+ * 与 DESIGN.md v2.1 §3.5 对齐:
18+ * - 13 步数值稳定 acosh 公式
19+ * - FP32 直通 / FP16/BF16 入口 CAST_NONE → 13 步 FP32 → 出口 CAST_RINT
20+ * - Double Buffer (BUFFER_NUM=2)
21+ * - Buffer 复用:dataTBuf (step1→6/10) / dataRBuf (step5→6/11/8/9/12) / logTmpBuf (step13a/b/c)
22+ * - Log natural 三参数调用(不接收 sharedTmpBuffer),由框架自动从未 InitBuffer 的剩余 UB 申请
23+ *
24+ * 迭代一范围(FP32 主线骨架):
25+ * - FP32 路径完整实现;FP16/BF16 路径在迭代二落地(这里预留 else 分支编译占位)
26+ */
27+#ifndef NSACOSH_ACOSH_H
28+#define NSACOSH_ACOSH_H
29+ 
30+#include "kernel_operator.h"
31+#include "kernel_tiling/kernel_tiling.h"
32+#include "acosh_tiling_data.h"
33+#include "acosh_tiling_key.h"
34+ 
35+namespace NsAcosh {
36+using namespace AscendC;
37+ 
38+// ============================================================
39+// 13 步流程的 FP32 常量(requirement §8.1 强约束 FP32 字面量精度)
40+// ============================================================
41+constexpr float CONST_NEG_ONE = -1.0f;
42+constexpr float CONST_ONE = 1.0f;
43+constexpr float CONST_S_MIN = 1.0e-45f; // clip 下界(requirement §8.1)
44+constexpr float CONST_S_MAX = 3.4028235e34f; // clip 上界(requirement §8.1)
45+// ln(2) FP32 近似 ≈ 0.6931(requirement v1.2 §8.1 + DESIGN v2.1 §3.5.1 / §5.1 R5 已修正)
46+constexpr float CONST_LN2_ADD = 0.693147180559945286227f;
47+ 
48+// Double Buffer 固定为 2(13 步含 Log/Sqrt/Div 计算密集,双缓冲收益显著)
49+static constexpr int32_t BUFFER_NUM = 2;
50+ 
51+template <typename T>
52+class Acosh {
53+public:
54+ __aicore__ inline Acosh() {}
55+ 
56+ __aicore__ inline void Init(GM_ADDR self, GM_ADDR out, const AcoshTilingData* tilingData);
57+ __aicore__ inline void Process();
58+ 
59+private:
60+ __aicore__ inline void CopyIn(int64_t progress, int64_t currentNum);
61+ __aicore__ inline void Compute(int64_t currentNum);
62+ __aicore__ inline void CopyOut(int64_t progress, int64_t currentNum);
63+ 
64+ // 13 步 FP32 计算(支持 xFp32 == yFp32 别名调用,FP16/BF16 路径下二者同为 fp32WorkBuf)
65+ __aicore__ inline void ComputeFp32Pipeline(LocalTensor<float>& xFp32,
66+ LocalTensor<float>& yFp32,
67+ int64_t count);
68+ 
69+private:
70+ TPipe pipe;
71+ TQue<QuePosition::VECIN, BUFFER_NUM> inputQue; // GM → UB 输入队列(dtype = T)
72+ TQue<QuePosition::VECOUT, BUFFER_NUM> outputQue; // UB → GM 输出队列(dtype = T)
73+ // FP32 工作 Buffer:FP16/BF16 路径承担 xFp32==yFp32==fp32Work 三重角色;FP32 路径下未必用到
74+ TBuf<QuePosition::VECCALC> fp32WorkBuf;
75+ // 13 步 Buffer 复用
76+ TBuf<QuePosition::VECCALC> dataTBuf;
77+ TBuf<QuePosition::VECCALC> dataRBuf;
78+ // step 13a/b 暂存 log(x)+ln(2);step 13c 读取
79+ // 注:Log natural API(base-e)`Log(dst, src, calCount)` 不接收 sharedTmpBuffer,
80+ // 其内部所需临时空间由框架自动从「未 InitBuffer 的剩余 UB 空间」申请。
81+ // Host Tiling 已通过 GetLogMaxMinTmpSize 在 ubFactor 计算中扣除该字节,
82+ // 保证 InitBuffer 完成后剩余 UB 充足。
83+ TBuf<QuePosition::VECCALC> logTmpBuf;
84+ 
85+ GlobalTensor<T> inputGM;
86+ GlobalTensor<T> outputGM;
87+ 
88+ int64_t blockLength_ = 0; // 本核要处理的元素总数(可能 < blockFactor,例如尾核)
89+ int64_t ubFactor_ = 0; // 单次 UB 循环处理元素数
90+};
91+ 
92+// ============================================================
93+// Init: 设置 GM 偏移 + 申请 UB Buffer(共 8 个 FP32 当量 Buffer 含 DB)
94+// ============================================================
95+template <typename T>
96+__aicore__ inline void Acosh<T>::Init(GM_ADDR self, GM_ADDR out, const AcoshTilingData* tilingData)
97+{
98+ int64_t blockIdx = AscendC::GetBlockIdx();
99+ // blockFactor 已在 Host Tiling 中按 32B 向上对齐到 ≤ totalNum 上限;
100+ // blockIdx ≤ usedCoreNum-1,乘积 ≤ totalNum ≤ INT64_MAX,无溢出风险。
101+ int64_t remainder = tilingData->totalNum - tilingData->blockFactor * blockIdx;
102+ blockLength_ = (remainder > tilingData->blockFactor) ? tilingData->blockFactor : remainder;
103+ ubFactor_ = tilingData->ubFactor;
104+ 
105+ inputGM.SetGlobalBuffer((__gm__ T*)self + tilingData->blockFactor * blockIdx, blockLength_);
106+ outputGM.SetGlobalBuffer((__gm__ T*)out + tilingData->blockFactor * blockIdx, blockLength_);
107+ 
108+ pipe.InitBuffer(inputQue, BUFFER_NUM, ubFactor_ * sizeof(T));
109+ pipe.InitBuffer(outputQue, BUFFER_NUM, ubFactor_ * sizeof(T));
110+ // FP32 工作区:仅 FP16/BF16 路径用于承担 xFp32==yFp32==fp32Work 三重角色
111+ // FP32 路径下 Compute() 直接对 xLocal/yLocal 执行 13 步流水,fp32WorkBuf 不参与计算 → 跳过 InitBuffer
112+ // 注:BufferCount FP32 路径 8 → 7(节省 ubFactor*4B),FP16/BF16 路径保持 8
113+ if constexpr (!std::is_same_v<T, float>) {
114+ pipe.InitBuffer(fp32WorkBuf, ubFactor_ * sizeof(float));
115+ }
116+ // 13 步 Buffer 复用:data_t / data_r
117+ pipe.InitBuffer(dataTBuf, ubFactor_ * sizeof(float));
118+ pipe.InitBuffer(dataRBuf, ubFactor_ * sizeof(float));
119+ // step 13b 的 log(x)+ln(2) 暂存(非 Log 隐式 tmpBuffer 用途;后者由框架在剩余 UB 自动申请)
120+ pipe.InitBuffer(logTmpBuf, ubFactor_ * sizeof(float));
121+}
122+ 
123+// ============================================================
124+// Process: 多次循环,每次处理 ubFactor 个元素
125+// ============================================================
126+template <typename T>
127+__aicore__ inline void Acosh<T>::Process()
128+{
129+ if (blockLength_ <= 0) {
130+ return; // 尾核可能没有数据
131+ }
132+ int64_t loopCount = (blockLength_ + ubFactor_ - 1) / ubFactor_;
133+ for (int64_t i = 0; i < loopCount; i++) {
134+ int64_t currentNum = (i == (loopCount - 1)) ? (blockLength_ - ubFactor_ * i) : ubFactor_;
135+ CopyIn(i, currentNum);
136+ Compute(currentNum);
137+ CopyOut(i, currentNum);
138+ }
139+}
140+ 
141+// ============================================================
142+// CopyIn: GM → UB(DataCopyPad 自动处理非对齐尾块)
143+// ============================================================
144+template <typename T>
145+__aicore__ inline void Acosh<T>::CopyIn(int64_t progress, int64_t currentNum)
146+{
147+ LocalTensor<T> xLocal = inputQue.template AllocTensor<T>();
148+ AscendC::DataCopyExtParams copyParams;
149+ copyParams.blockCount = 1;
150+ copyParams.blockLen = static_cast<uint32_t>(currentNum * sizeof(T));
151+ copyParams.srcStride = 0;
152+ copyParams.dstStride = 0;
153+ AscendC::DataCopyPad(xLocal, inputGM[progress * ubFactor_], copyParams, {false, 0, 0, 0});
154+ inputQue.EnQue(xLocal);
155+}
156+ 
157+// ============================================================
158+// CopyOut: UB → GM
159+// ============================================================
160+template <typename T>
161+__aicore__ inline void Acosh<T>::CopyOut(int64_t progress, int64_t currentNum)
162+{
163+ LocalTensor<T> yLocal = outputQue.template DeQue<T>();
164+ AscendC::DataCopyExtParams copyParams;
165+ copyParams.blockCount = 1;
166+ copyParams.blockLen = static_cast<uint32_t>(currentNum * sizeof(T));
167+ copyParams.srcStride = 0;
168+ copyParams.dstStride = 0;
169+ AscendC::DataCopyPad(outputGM[progress * ubFactor_], yLocal, copyParams);
170+ outputQue.FreeTensor(yLocal);
171+}
172+ 
173+// ============================================================
174+// Compute: 入口/出口 Cast + 13 步 FP32 流水
175+// FP32 路径直通;FP16/BF16 路径入口 CAST_NONE → 13 步 → 出口 CAST_RINT
176+// ============================================================
177+template <typename T>
178+__aicore__ inline void Acosh<T>::Compute(int64_t currentNum)
179+{
180+ LocalTensor<T> xLocal = inputQue.template DeQue<T>();
181+ LocalTensor<T> yLocal = outputQue.template AllocTensor<T>();
182+ 
183+ if constexpr (std::is_same_v<T, float>) {
184+ // ----------------- FP32 主线(迭代一目标) -----------------
185+ // 直接对 xLocal/yLocal(已是 float)执行 13 步流水
186+ ComputeFp32Pipeline(xLocal, yLocal, currentNum);
187+ } else {
188+ // ----------------- FP16/BF16 路径(迭代二完整实现) -----------------
189+ // Ascend950PR/DT: half/bfloat16_t → float 仅支持 CAST_NONE(Cast.md 表 6)
190+ // float → half/bfloat16_t 支持 CAST_RINT(不支持 CAST_NONE)
191+ LocalTensor<float> fp32Work = fp32WorkBuf.Get<float>();
192+ AscendC::Cast(fp32Work, xLocal, AscendC::RoundMode::CAST_NONE, currentNum);
193+ ComputeFp32Pipeline(fp32Work, fp32Work, currentNum); // xFp32 == yFp32 别名调用
194+ AscendC::Cast(yLocal, fp32Work, AscendC::RoundMode::CAST_RINT, currentNum);
195+ }
196+ 
197+ outputQue.template EnQue<T>(yLocal);
198+ inputQue.FreeTensor(xLocal);
199+}
200+ 
201+// ============================================================
202+// ComputeFp32Pipeline: 严格按 DESIGN v2.1 §3.5.2 13 步流程实现
203+//
204+// Buffer 生命周期(详见 DESIGN §3.5.2 表 Buffer 生命周期表):
205+// xFp32 仅在 step 13a / step 1 读取;之后不再读 → 支持 xFp32==yFp32 别名调用
206+// yFp32 在 step 2 首次写入;step 7/10/13c 写;step 8/13c 读
207+// dataT: step 1 写 → step 3/6 读 → step 10/11/12 写
208+// dataR: step 3/4/5/6 → step 11/8/9/12 复用
209+// logTmp: step 13a/b 写 → step 13c 读
210+// ============================================================
211+template <typename T>
212+__aicore__ inline void Acosh<T>::ComputeFp32Pipeline(
213+ LocalTensor<float>& xFp32,
214+ LocalTensor<float>& yFp32,
215+ int64_t count)
216+{
217+ LocalTensor<float> dataT = dataTBuf.Get<float>(); // data_t 备份
218+ LocalTensor<float> dataR = dataRBuf.Get<float>(); // data_r 备份
219+ LocalTensor<float> logTmp = logTmpBuf.Get<float>(); // log(x)+ln(2) 暂存
220+ uint32_t n = static_cast<uint32_t>(count);
221+ 
222+ // -------- Step 13a/13b 提前算:data_s1 = log(x) + ln(2),存到 logTmp --------
223+ // 提前算的目的:xFp32 在 step 1 后会被复用(FP32 路径不会,FP16/BF16 别名路径会)
224+ // step 13a/13b 不修改 xFp32,安全
225+ AscendC::Log(logTmp, xFp32, n); // logTmp = ln(x)
226+ AscendC::Adds(logTmp, logTmp, CONST_LN2_ADD, n); // logTmp = ln(x) + ln(2)
227+ 
228+ // -------- Step 1: data_t = x - 1 --------
229+ AscendC::Adds(dataT, xFp32, CONST_NEG_ONE, n);
230+ 
231+ // -------- Step 2: yFp32 = 2 * (x - 1) (此后 xFp32 不再读,alias 安全释放) --------
232+ AscendC::Add(yFp32, dataT, dataT, n);
233+ 
234+ // -------- Step 3: dataR = data_t * data_t = (x-1)² --------
235+ AscendC::Mul(dataR, dataT, dataT, n);
236+ 
237+ // -------- Step 4: dataR += yFp32 → dataR = (x-1)² + 2(x-1) = x² - 1 --------
238+ AscendC::Add(dataR, dataR, yFp32, n);
239+ 
240+ // -------- Step 5: dataR = sqrt(dataR) = √(x²-1) --------
241+ AscendC::Sqrt(dataR, dataR, n);
242+ 
243+ // -------- Step 6: dataR = data_t + dataR = (x-1) + √(x²-1) --------
244+ AscendC::Add(dataR, dataT, dataR, n);
245+ 
246+ // -------- Step 7: yFp32 = dataR + 1 = u = x + √(x²-1) --------
247+ AscendC::Adds(yFp32, dataR, CONST_ONE, n);
248+ 
249+ // -------- Step 10: dataT = log(u)(dataT Buffer 在 step 6 之后可释放复用) --------
250+ AscendC::Log(dataT, yFp32, n);
251+ 
252+ // -------- Step 11: dataT = log(u) * dataR = log(u) × ((x-1)+√(x²-1)) --------
253+ AscendC::Mul(dataT, dataT, dataR, n);
254+ 
255+ // -------- Step 8: dataR = u - 1 = s(未 clip)(dataR Buffer 在 step 11 之后释放复用) --------
256+ AscendC::Adds(dataR, yFp32, CONST_NEG_ONE, n);
257+ 
258+ // -------- Step 9a: dataR = max(s, 1e-45),下界保护防止后续 Div 除零 --------
259+ AscendC::Maxs(dataR, dataR, CONST_S_MIN, n);
260+ 
261+ // -------- Step 9b: dataR = min(s, 3.4e34),上界保护防溢出 --------
262+ AscendC::Mins(dataR, dataR, CONST_S_MAX, n);
263+ 
264+ // -------- Step 12: dataT = dataT / dataR = log(u) × ((x-1)+√(x²-1)) / clip(s) --------
265+ AscendC::Div(dataT, dataT, dataR, n);
266+ 
267+ // -------- Step 13c: yFp32 = min(res, log(x)+ln(2)),大参数修正 --------
268+ AscendC::Min(yFp32, dataT, logTmp, n);
269+}
270+ 
271+} // namespace NsAcosh
272+#endif // NSACOSH_ACOSH_H
Amath/acosh/op_kernel/arch35/acosh_tiling_data.h+30-0
@@ -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+/* Generated By CANNBot */
12+ 
13+/*!
14+ * \file acosh_tiling_data.h
15+ * \brief Acosh 算子 TilingData 结构体定义
16+ *
17+ * 与 DESIGN.md v2.1 §3.4 对齐:
18+ * ✅ 必须使用标准 C++ struct 定义 TilingData
19+ * ❌ 禁止使用废弃的 BEGIN_TILING_DATA_DEF 宏(requirement §8.4 强约束)
20+ */
21+#ifndef _ACOSH_TILING_DATA_H_
22+#define _ACOSH_TILING_DATA_H_
23+ 
24+struct AcoshTilingData {
25+ int64_t totalNum = 0; // 总元素数(self/out 一致)
26+ int64_t blockFactor = 0; // 单核处理元素数(按 32B 对齐)
27+ int64_t ubFactor = 0; // 单次 UB 循环处理元素数(按 UB 容量 / Buffer 数 / 32B 对齐)
28+};
29+ 
30+#endif // _ACOSH_TILING_DATA_H_
Amath/acosh/op_kernel/arch35/acosh_tiling_key.h+46-0
@@ -0,0 +1,46 @@
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+/* Generated By CANNBot */
12+ 
13+/*!
14+ * \file acosh_tiling_key.h
15+ * \brief Acosh 算子 TilingKey 模板参数定义
16+ *
17+ * 与 DESIGN.md v2.1 §3.2 对齐:
18+ * - 模板参数 D_T_X 编码 dtype(C_DT_FLOAT / C_DT_FLOAT16 / C_DT_BF16),编码 0/1/2
19+ * - Kernel 入口 template<typename D_T_X> __global__ acosh(...)
20+ * 由构建系统按 ASCENDC_TPL_SEL 列表实例化
21+ * - dtype 分支在 Kernel 内通过 if constexpr (std::is_same_v<D_T_X, float>) 静态分发
22+ * - 不引入 BUFFER_MODE:本算子 13 步含 Log/Sqrt/Div 计算密集,强制 BUFFER_NUM=2 双缓冲
23+ *
24+ * ✅ 必须使用 ASCENDC_TPL_ARGS_DECL 模板编程方式
25+ * ❌ 禁止使用废弃的 TILING_KEY_IS 宏(requirement §8.4 强约束)
26+ *
27+ * 注意(迭代一):
28+ * 迭代一仅 FP32 路径完整实现;FP16/BF16 路径在迭代二完成。这里同时声明 3 个 dtype
29+ * 仅为保持 TilingKey 接口稳定,迭代一 Host Tiling 限定仅放行 FP32(其他 dtype 报错)。
30+ */
31+#ifndef __ACOSH_TILING_KEY_H__
32+#define __ACOSH_TILING_KEY_H__
33+ 
34+#include "ascendc/host_api/tiling/template_argument.h"
35+ 
36+ASCENDC_TPL_ARGS_DECL(Acosh,
37+ ASCENDC_TPL_DATATYPE_DECL(D_T_X, C_DT_FLOAT, C_DT_FLOAT16, C_DT_BF16, ASCENDC_TPL_INPUT(0))
38+);
39+ 
40+ASCENDC_TPL_SEL(
41+ ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_DATATYPE_SEL(D_T_X, C_DT_FLOAT)),
42+ ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_DATATYPE_SEL(D_T_X, C_DT_FLOAT16)),
43+ ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_DATATYPE_SEL(D_T_X, C_DT_BF16)),
44+);
45+ 
46+#endif // __ACOSH_TILING_KEY_H__
Mmath/acosh/tests/ut/op_api/test_aclnn_acosh.cpp+1-1
@@ -11,7 +11,7 @@
11#include <vector>11#include <vector>
12#include "gtest/gtest.h"12#include "gtest/gtest.h"
13 13 
14-#include "math/acosh/op_host/op_api/aclnn_acosh.h"14+#include "math/acosh/op_api/aclnn_acosh.h"
15 15 
16#include "op_api_ut_common/inner/types.h"16#include "op_api_ut_common/inner/types.h"
17#include "op_api_ut_common/op_api_ut.h"17#include "op_api_ut_common/op_api_ut.h"