Line data Source code
1 : /**
2 : * Copyright (c) 2025-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 : #include "aclnn_foreach_addcdiv_scalar.h"
12 : #include "foreach_addcdiv_scalar_v2.h"
13 : #include "../../foreach_utils/op_host/foreach_contiguous_helper.h"
14 : #include "aclnn_kernels/contiguous.h"
15 : #include "op_api/op_api_def_nn.h"
16 : #include "op_api/aclnn_util.h"
17 : #include "aclnn_kernels/common/op_error_check.h"
18 : #include "opdev/make_op_executor.h"
19 : #include "opdev/op_dfx.h"
20 : #include "opdev/tensor_view_utils.h"
21 : #include "opdev/platform.h"
22 :
23 : using namespace op;
24 :
25 : #ifdef __cplusplus
26 : extern "C" {
27 : #endif
28 :
29 : static const std::initializer_list<DataType> EMPTY_LIST = {};
30 :
31 : static const std::initializer_list<DataType> SCALAR_FLOAT_SUPPORT_LIST = {DataType::DT_FLOAT, DataType::DT_DOUBLE};
32 : static const std::initializer_list<DataType> SCALAR_FLOAT16_SUPPORT_LIST = {DataType::DT_FLOAT16, DataType::DT_DOUBLE};
33 :
34 : static const std::initializer_list<DataType> ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST = {
35 : DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_BF16};
36 :
37 : static const std::initializer_list<DataType>& GetDtypeSupportList()
38 : {
39 : auto curArch = GetCurrentPlatformInfo().GetCurNpuArch();
40 : if (curArch != NpuArch::DAV_2201 && !Ops::NN::AclnnUtil::IsRegbase(curArch)) {
41 : return EMPTY_LIST;
42 : }
43 : return ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST;
44 : }
45 :
46 : static inline bool CheckNotNull(const aclTensorList* x1, const aclTensorList* x2, const aclTensorList* x3,
47 : const aclTensor* scalar, const aclTensorList* out)
48 : {
49 : OP_CHECK_NULL(out, return false);
50 : OP_CHECK_NULL(x1, return false);
51 : OP_CHECK_NULL(x2, return false);
52 : OP_CHECK_NULL(x3, return false);
53 : OP_CHECK_NULL(scalar, return false);
54 : return true;
55 : }
56 :
57 : static inline bool CheckFormat(const aclTensorList* x1, const aclTensorList* x2, const aclTensorList* x3,
58 : const aclTensorList* out)
59 : {
60 : for (uint64_t i = 0; i < x1->Size(); i++) {
61 : if (IsPrivateFormat((*out)[i]->GetStorageFormat()) || IsPrivateFormat((*x1)[i]->GetStorageFormat()) ||
62 : IsPrivateFormat((*x2)[i]->GetStorageFormat()) || IsPrivateFormat((*x3)[i]->GetStorageFormat())) {
63 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Format only support ND, NCHW, NHWC, HWCN, NDHWC, NCDHW.");
64 : return false;
65 : }
66 : }
67 : return true;
68 : }
69 :
70 : static inline bool CheckDtypeValid(const aclTensorList* x1, const aclTensorList* x2, const aclTensorList* x3,
71 : const aclTensor* scalar, const aclTensorList* out)
72 : {
73 : if (x1->Size() == 0) {
74 : return true;
75 : }
76 :
77 : const auto& dtypeSupportList = GetDtypeSupportList();
78 : if (dtypeSupportList.size() == 0) {
79 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "support for %s is not implemented",
80 : op::ToString(GetCurrentPlatformInfo().GetSocVersion()).GetString());
81 : return false;
82 : }
83 :
84 : auto selfDtype = (*x1)[0]->GetDataType();
85 : OP_CHECK_DTYPE_NOT_SUPPORT((*x1)[0], dtypeSupportList, return false);
86 :
87 : if (selfDtype == DataType::DT_BF16 || selfDtype == DataType::DT_FLOAT) {
88 : OP_CHECK_DTYPE_NOT_SUPPORT(scalar, SCALAR_FLOAT_SUPPORT_LIST, return false);
89 : } else if (selfDtype == DataType::DT_FLOAT16) {
90 : OP_CHECK_DTYPE_NOT_SUPPORT(scalar, SCALAR_FLOAT16_SUPPORT_LIST, return false);
91 : }
92 :
93 : for (uint64_t i = 0; i < out->Size(); i++) {
94 : OP_CHECK_DTYPE_NOT_MATCH((*out)[i], selfDtype, return false);
95 : }
96 : for (uint64_t i = 0; i < x3->Size(); i++) {
97 : OP_CHECK_DTYPE_NOT_MATCH((*x3)[i], selfDtype, return false);
98 : }
99 : for (uint64_t i = 0; i < x2->Size(); i++) {
100 : OP_CHECK_DTYPE_NOT_MATCH((*x2)[i], selfDtype, return false);
101 : }
102 : for (uint64_t i = 0; i < x1->Size(); i++) {
103 : OP_CHECK_DTYPE_NOT_MATCH((*x1)[i], selfDtype, return false);
104 : }
105 : return true;
106 : }
107 :
108 : static inline bool CheckShape(const aclTensorList* x1, const aclTensorList* x2, const aclTensorList* x3,
109 : const aclTensorList* out)
110 : {
111 : if (x1->Size() != x2->Size() || x1->Size() != x3->Size() || x1->Size() != out->Size()) {
112 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Tensor lists must have the same number of tensors");
113 : return false;
114 : }
115 :
116 : for (uint64_t i = 0; i < x1->Size(); i++) {
117 : OP_CHECK_SHAPE_NOT_EQUAL((*x1)[i], (*out)[i], return false);
118 : }
119 :
120 : for (uint64_t i = 0; i < x1->Size(); i++) {
121 : OP_CHECK_MAX_DIM((*x1)[i], MAX_SUPPORT_DIMS_NUMS, return false);
122 : }
123 :
124 : for (uint64_t i = 0; i < x1->Size(); i++) {
125 : OP_CHECK_SHAPE_NOT_EQUAL((*x1)[i], (*x2)[i], return false);
126 : OP_CHECK_SHAPE_NOT_EQUAL((*x1)[i], (*x3)[i], return false);
127 : }
128 : return true;
129 : }
130 :
131 : static inline aclnnStatus CheckParams(const aclTensorList* x1, const aclTensorList* x2, const aclTensorList* x3,
132 : const aclTensor* scalar, const aclTensorList* out)
133 : {
134 : CHECK_RET(CheckNotNull(x1, x2, x3, scalar, out), ACLNN_ERR_PARAM_NULLPTR);
135 :
136 : // Check every entry in tensor lists is not null, to avoid null pointer
137 : // dereference in CheckDtypeValid/CheckShape/CheckFormat.
138 0 : for (uint64_t i = 0; i < x1->Size(); i++) {
139 0 : if ((*x1)[i] == nullptr) {
140 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "x1[%lu] is null.", i);
141 0 : return ACLNN_ERR_PARAM_INVALID;
142 : }
143 : }
144 0 : for (uint64_t i = 0; i < x2->Size(); i++) {
145 0 : if ((*x2)[i] == nullptr) {
146 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "x2[%lu] is null.", i);
147 0 : return ACLNN_ERR_PARAM_INVALID;
148 : }
149 : }
150 0 : for (uint64_t i = 0; i < x3->Size(); i++) {
151 0 : if ((*x3)[i] == nullptr) {
152 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "x3[%lu] is null.", i);
153 0 : return ACLNN_ERR_PARAM_INVALID;
154 : }
155 : }
156 0 : for (uint64_t i = 0; i < out->Size(); i++) {
157 0 : if ((*out)[i] == nullptr) {
158 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "out[%lu] is null.", i);
159 0 : return ACLNN_ERR_PARAM_INVALID;
160 : }
161 : }
162 :
163 : CHECK_RET(CheckDtypeValid(x1, x2, x3, scalar, out), ACLNN_ERR_PARAM_INVALID);
164 : CHECK_RET(CheckShape(x1, x2, x3, out), ACLNN_ERR_PARAM_INVALID);
165 : CHECK_RET(CheckFormat(x1, x2, x3, out), ACLNN_ERR_PARAM_INVALID);
166 : return ACLNN_SUCCESS;
167 : }
168 :
169 : static aclnnStatus ExecForeachAddcdivScalarGetWorkspaceSize(const aclTensorList* x1, const aclTensorList* x2,
170 : const aclTensorList* x3, const aclTensor* scalar,
171 : const aclTensorList* out, uint64_t* workspaceSize,
172 : aclOpExecutor** executor)
173 : {
174 : auto uniqueExecutor = CREATE_EXECUTOR();
175 : CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
176 :
177 : auto ret = CheckParams(x1, x2, x3, scalar, out);
178 : CHECK_RET(ret == ACLNN_SUCCESS, ret);
179 :
180 : if (x1->Size() == 0 || x2->Size() == 0 || x3->Size() == 0) {
181 : *workspaceSize = 0;
182 : uniqueExecutor.ReleaseTo(executor);
183 : return ACLNN_SUCCESS;
184 : }
185 :
186 : // 输出如果非连续,需要转连续作为kernel输出buffer;连续/空则直接使用
187 : auto contiguousOut = ForeachMakeContiguousTensorList(out, uniqueExecutor.get());
188 : CHECK_RET(contiguousOut != nullptr, ACLNN_ERR_INNER_NULLPTR);
189 :
190 : // 输入如果非连续,需要转连续(空tensor直接用,保持索引一致)
191 : auto contiguousTensorsX3 = ForeachMakeContiguousTensorList(x3, uniqueExecutor.get());
192 : CHECK_RET(contiguousTensorsX3 != nullptr, ACLNN_ERR_INNER_NULLPTR);
193 : auto contiguousTensorsX2 = ForeachMakeContiguousTensorList(x2, uniqueExecutor.get());
194 : CHECK_RET(contiguousTensorsX2 != nullptr, ACLNN_ERR_INNER_NULLPTR);
195 : auto contiguousTensorsX1 = ForeachMakeContiguousTensorList(x1, uniqueExecutor.get());
196 : CHECK_RET(contiguousTensorsX1 != nullptr, ACLNN_ERR_INNER_NULLPTR);
197 :
198 : // 复用V2桥接,scalar(aclTensor*)直接透传,输出到连续buffer
199 : auto result = l0op::ForeachAddcdivScalarV2(contiguousTensorsX1, contiguousTensorsX2, contiguousTensorsX3, scalar,
200 : contiguousOut, uniqueExecutor.get());
201 : CHECK_RET(result != nullptr, ACLNN_ERR_INNER_NULLPTR);
202 :
203 : // 将连续计算结果拷贝到输出out上,out可能是非连续的tensor(空/连续跳过)
204 : CHECK_RET(ForeachViewCopyToOutputTensorList(contiguousOut, out, uniqueExecutor.get()), ACLNN_ERR_INNER_NULLPTR);
205 :
206 : *workspaceSize = uniqueExecutor->GetWorkspaceSize();
207 : uniqueExecutor.ReleaseTo(executor);
208 : return ACLNN_SUCCESS;
209 : }
210 :
211 : aclnnStatus aclnnForeachAddcdivScalarGetWorkspaceSize(const aclTensorList* x1, const aclTensorList* x2,
212 : const aclTensorList* x3, const aclTensor* scalar,
213 : aclTensorList* out, uint64_t* workspaceSize,
214 : aclOpExecutor** executor)
215 : {
216 : L2_DFX_PHASE_1(aclnnForeachAddcdivScalar, DFX_IN(x1, x2, x3, scalar), DFX_OUT(out));
217 : return ExecForeachAddcdivScalarGetWorkspaceSize(x1, x2, x3, scalar, out, workspaceSize, executor);
218 : }
219 :
220 : aclnnStatus aclnnForeachAddcdivScalar(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor,
221 : const aclrtStream stream)
222 : {
223 : L2_DFX_PHASE_2(aclnnForeachAddcdivScalar);
224 : return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
225 : }
226 :
227 : #ifdef __cplusplus
228 : }
229 : #endif
|