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 : /*!
12 : * \file aclnn_foreach_addcdiv_scalar_v2.cpp
13 : * \brief
14 : */
15 :
16 : #include "aclnn_foreach_addcdiv_scalar_v2.h"
17 : #include "foreach_addcdiv_scalar_v2.h"
18 : #include "aclnn_kernels/contiguous.h"
19 : #include "op_api/op_api_def_nn.h"
20 : #include "aclnn_kernels/common/op_error_check.h"
21 : #include "opdev/op_dfx.h"
22 : #include "opdev/make_op_executor.h"
23 : #include "op_api/aclnn_util.h"
24 : #include "opdev/platform.h"
25 :
26 : using namespace op;
27 :
28 : #ifdef __cplusplus
29 : extern "C" {
30 : #endif
31 :
32 : static const std::initializer_list<DataType> FOREACH_ADDCDIV_SCALAR_V2_ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST = {
33 : DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_BF16};
34 :
35 : static const std::initializer_list<DataType> FOREACH_ADDCDIV_SCALAR_V2_FLOAT_SUPPORT_LIST = {DataType::DT_FLOAT,
36 : DataType::DT_DOUBLE};
37 :
38 : static const std::initializer_list<DataType> FOREACH_ADDCDIV_SCALAR_V2_FLOAT16_SUPPORT_LIST = {DataType::DT_FLOAT16,
39 : DataType::DT_DOUBLE};
40 :
41 : static const std::initializer_list<DataType> EMPTY_LIST = {};
42 :
43 : static inline bool ForeachAddcdivScalarV2CheckNotNull(const aclTensorList* self, const aclTensorList* x2,
44 : const aclTensorList* x3, const aclScalar* scalar,
45 : const aclTensorList* out)
46 : {
47 : OP_CHECK_NULL(self, return false);
48 : OP_CHECK_NULL(x2, return false);
49 : OP_CHECK_NULL(x3, return false);
50 : OP_CHECK_NULL(scalar, return false);
51 : OP_CHECK_NULL(out, return false);
52 : return true;
53 : }
54 :
55 : static inline bool ForeachAddcdivScalarV2CheckFormat(const aclTensorList* self, const aclTensorList* x2,
56 : const aclTensorList* x3, const aclTensorList* out)
57 : {
58 : for (uint64_t i = 0; i < self->Size(); i++) {
59 : // self格式不能是私有格式
60 : if (IsPrivateFormat((*self)[i]->GetStorageFormat()) || IsPrivateFormat((*x2)[i]->GetStorageFormat()) ||
61 : IsPrivateFormat((*x3)[i]->GetStorageFormat()) || IsPrivateFormat((*out)[i]->GetStorageFormat())) {
62 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Format only support ND, NCHW, NHWC, HWCN, NDHWC, NCDHW.");
63 : return false;
64 : }
65 : }
66 : return true;
67 : }
68 :
69 : static const std::initializer_list<DataType>& ForeachAddcdivScalarV2GetDtypeSupportList()
70 : {
71 : auto curArch = GetCurrentPlatformInfo().GetCurNpuArch();
72 : if (curArch == NpuArch::DAV_2201 || Ops::NN::AclnnUtil::IsRegbase(curArch)) {
73 : return FOREACH_ADDCDIV_SCALAR_V2_ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST;
74 : } else {
75 : OP_LOGE(ACLNN_ERR_RUNTIME_ERROR, "support for %s is not implemented",
76 : op::ToString(GetCurrentPlatformInfo().GetSocVersion()).GetString());
77 : return EMPTY_LIST;
78 : }
79 : }
80 :
81 : static inline bool ForeachAddcdivScalarV2CheckDtypeValid(const aclTensorList* self, const aclTensorList* x2,
82 : const aclTensorList* x3, const aclScalar* scalar,
83 : const aclTensorList* out)
84 : {
85 : const auto& dtypeSupportList = ForeachAddcdivScalarV2GetDtypeSupportList();
86 : if (dtypeSupportList.size() == 0) {
87 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "support for %s is not implemented",
88 : op::ToString(GetCurrentPlatformInfo().GetSocVersion()).GetString());
89 : return false;
90 : }
91 :
92 : if (self->Size() == 0) {
93 : return true;
94 : }
95 :
96 : // checkself input dtype, and check the releation of input and out
97 : auto selfDtyte = (*self)[0]->GetDataType();
98 : OP_CHECK_DTYPE_NOT_SUPPORT((*self)[0], dtypeSupportList, return false);
99 :
100 : // check the releation of self and scalar
101 : if (selfDtyte == DataType::DT_BF16 || selfDtyte == DataType::DT_FLOAT) {
102 : OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_ADDCDIV_SCALAR_V2_FLOAT_SUPPORT_LIST, return false);
103 : } else if (selfDtyte == DataType::DT_FLOAT16) {
104 : OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_ADDCDIV_SCALAR_V2_FLOAT16_SUPPORT_LIST, return false);
105 : }
106 :
107 : for (uint64_t i = 0; i < self->Size(); i++) {
108 : OP_CHECK_DTYPE_NOT_MATCH((*self)[i], selfDtyte, return false);
109 : }
110 :
111 : for (uint64_t i = 0; i < x2->Size(); i++) {
112 : OP_CHECK_DTYPE_NOT_MATCH((*x2)[i], selfDtyte, return false);
113 : ;
114 : }
115 :
116 : for (uint64_t i = 0; i < x3->Size(); i++) {
117 : OP_CHECK_DTYPE_NOT_MATCH((*x3)[i], selfDtyte, return false);
118 : }
119 : for (uint64_t i = 0; i < out->Size(); i++) {
120 : OP_CHECK_DTYPE_NOT_MATCH((*out)[i], selfDtyte, return false);
121 : }
122 : return true;
123 : }
124 :
125 : static inline bool ForeachAddcdivScalarV2CheckShape(const aclTensorList* self, const aclTensorList* x2,
126 : const aclTensorList* x3, const aclTensorList* out)
127 : {
128 : // tensorlist size检查
129 : if (self->Size() != x2->Size()) {
130 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Tensor lists must have the same number of tensors, got %lu and %lu",
131 : self->Size(), x2->Size());
132 : return false;
133 : }
134 :
135 : // tensorlist size检查
136 : if (self->Size() != x3->Size()) {
137 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Tensor lists must have the same number of tensors, got %lu and %lu",
138 : self->Size(), x3->Size());
139 : return false;
140 : }
141 :
142 : // tensorlist中tensor shape一致性检查
143 : for (uint64_t i = 0; i < self->Size(); i++) {
144 : OP_CHECK_SHAPE_NOT_EQUAL((*self)[i], (*x2)[i], return false);
145 : OP_CHECK_SHAPE_NOT_EQUAL((*self)[i], (*x3)[i], return false);
146 : }
147 :
148 : // tensor 维度检查
149 : for (uint64_t i = 0; i < self->Size(); i++) {
150 : OP_CHECK_MAX_DIM((*self)[i], MAX_SUPPORT_DIMS_NUMS, return false);
151 : }
152 :
153 : // self和out的shape必须一致
154 : for (uint64_t i = 0; i < self->Size(); i++) {
155 : OP_CHECK_SHAPE_NOT_EQUAL((*self)[i], (*out)[i], return false);
156 : }
157 : return true;
158 : }
159 :
160 : static inline aclnnStatus ForeachAddcdivScalarV2CheckParams(const aclTensorList* self, const aclTensorList* x2,
161 : const aclTensorList* x3, const aclScalar* scalar,
162 : const aclTensorList* out)
163 : {
164 : // 1. 检查参数是否为空指针
165 : CHECK_RET(ForeachAddcdivScalarV2CheckNotNull(self, x2, x3, scalar, out), ACLNN_ERR_PARAM_NULLPTR);
166 :
167 : // 检查 tensor list 内部每个条目非空,避免后续空指针解引用
168 12 : for (uint64_t i = 0; i < self->Size(); i++) {
169 6 : if ((*self)[i] == nullptr) {
170 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "self[%lu] is null.", i);
171 0 : return ACLNN_ERR_PARAM_INVALID;
172 : }
173 : }
174 12 : for (uint64_t i = 0; i < x2->Size(); i++) {
175 6 : if ((*x2)[i] == nullptr) {
176 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "x2[%lu] is null.", i);
177 0 : return ACLNN_ERR_PARAM_INVALID;
178 : }
179 : }
180 12 : for (uint64_t i = 0; i < x3->Size(); i++) {
181 6 : if ((*x3)[i] == nullptr) {
182 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "x3[%lu] is null.", i);
183 0 : return ACLNN_ERR_PARAM_INVALID;
184 : }
185 : }
186 12 : for (uint64_t i = 0; i < out->Size(); i++) {
187 6 : if ((*out)[i] == nullptr) {
188 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "out[%lu] is null.", i);
189 0 : return ACLNN_ERR_PARAM_INVALID;
190 : }
191 : }
192 :
193 : // 2. 检查输入的数据类型是否在API支持的数据类型范围之内,需要根据api定义校验
194 : CHECK_RET(ForeachAddcdivScalarV2CheckDtypeValid(self, x2, x3, scalar, out), ACLNN_ERR_PARAM_INVALID);
195 : // 3. 检查shape是否满足约束
196 : CHECK_RET(ForeachAddcdivScalarV2CheckShape(self, x2, x3, out), ACLNN_ERR_PARAM_INVALID);
197 : // 4. 检查Format是否满足约束
198 : CHECK_RET(ForeachAddcdivScalarV2CheckFormat(self, x2, x3, out), ACLNN_ERR_PARAM_INVALID);
199 : return ACLNN_SUCCESS;
200 : }
201 :
202 : static aclnnStatus ExecForeachAddcdivScalarV2GetWorkspaceSize(const aclTensorList* x1, const aclTensorList* x2,
203 : const aclTensorList* x3, const aclScalar* scalar,
204 : const aclTensorList* out, uint64_t* workspaceSize,
205 : aclOpExecutor** executor)
206 : {
207 : // 固定写法,创建OpExecutor
208 : auto uniqueExecutor = CREATE_EXECUTOR();
209 : CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
210 :
211 : // 固定写法,参数检查
212 : auto ret = ForeachAddcdivScalarV2CheckParams(x1, x2, x3, scalar, out);
213 : CHECK_RET(ret == ACLNN_SUCCESS, ret);
214 :
215 : // 空Tensorlist处理
216 : if (x1->Size() == 0 || x2->Size() == 0 || x3->Size() == 0) {
217 : *workspaceSize = 0;
218 : uniqueExecutor.ReleaseTo(executor);
219 : return ACLNN_SUCCESS;
220 : }
221 :
222 : // self如果非连续,需要转连续
223 : std::vector<const aclTensor*> tensorsVec1;
224 : std::vector<const aclTensor*> tensorsVec2;
225 : std::vector<const aclTensor*> tensorsVec3;
226 : for (size_t i = 0; i < x1->Size(); ++i) {
227 : auto secondContiguous_1 = l0op::Contiguous((*x1)[i], uniqueExecutor.get());
228 : CHECK_RET(secondContiguous_1 != nullptr, ACLNN_ERR_INNER_NULLPTR);
229 : tensorsVec1.push_back(secondContiguous_1);
230 : }
231 : auto contiguousTensorsX1 = uniqueExecutor.get()->AllocTensorList(tensorsVec1.data(), tensorsVec1.size());
232 : CHECK_RET(contiguousTensorsX1 != nullptr, ACLNN_ERR_INNER_NULLPTR);
233 :
234 : for (size_t i = 0; i < x2->Size(); ++i) {
235 : auto secondContiguous_1 = l0op::Contiguous((*x2)[i], uniqueExecutor.get());
236 : CHECK_RET(secondContiguous_1 != nullptr, ACLNN_ERR_INNER_NULLPTR);
237 : tensorsVec2.push_back(secondContiguous_1);
238 : }
239 : auto contiguousTensorsX2 = uniqueExecutor.get()->AllocTensorList(tensorsVec2.data(), tensorsVec2.size());
240 : CHECK_RET(contiguousTensorsX2 != nullptr, ACLNN_ERR_INNER_NULLPTR);
241 :
242 : for (size_t i = 0; i < x3->Size(); ++i) {
243 : auto secondContiguous_1 = l0op::Contiguous((*x3)[i], uniqueExecutor.get());
244 : CHECK_RET(secondContiguous_1 != nullptr, ACLNN_ERR_INNER_NULLPTR);
245 : tensorsVec3.push_back(secondContiguous_1);
246 : }
247 : auto contiguousTensorsX3 = uniqueExecutor.get()->AllocTensorList(tensorsVec3.data(), tensorsVec3.size());
248 : CHECK_RET(contiguousTensorsX3 != nullptr, ACLNN_ERR_INNER_NULLPTR);
249 :
250 : // sclar to tensor
251 : const aclTensor* otherTensor;
252 : if ((*x1)[0]->GetDataType() == DataType::DT_BF16) {
253 : otherTensor = uniqueExecutor.get()->ConvertToTensor(scalar, DataType::DT_FLOAT);
254 : } else {
255 : otherTensor = uniqueExecutor.get()->ConvertToTensor(scalar, (*x1)[0]->GetDataType());
256 : }
257 :
258 : // 调用l0算子ForeachAddcdivScalarV2进行计算
259 : auto result = l0op::ForeachAddcdivScalarV2(contiguousTensorsX1, contiguousTensorsX2, contiguousTensorsX3,
260 : otherTensor, out, uniqueExecutor.get());
261 : CHECK_RET(result != nullptr, ACLNN_ERR_INNER_NULLPTR);
262 :
263 : // 固定写法,获取计算过程中需要使用的workspace大小
264 : *workspaceSize = uniqueExecutor->GetWorkspaceSize();
265 : uniqueExecutor.ReleaseTo(executor);
266 : return ACLNN_SUCCESS;
267 : }
268 :
269 : aclnnStatus aclnnForeachAddcdivScalarV2GetWorkspaceSize(const aclTensorList* x1, const aclTensorList* x2,
270 : const aclTensorList* x3, const aclScalar* scalar,
271 : aclTensorList* out, uint64_t* workspaceSize,
272 : aclOpExecutor** executor)
273 : {
274 : L2_DFX_PHASE_1(aclnnForeachAddcdivScalarV2, DFX_IN(x1, x2, x3, scalar), DFX_OUT(out));
275 : return ExecForeachAddcdivScalarV2GetWorkspaceSize(x1, x2, x3, scalar, out, workspaceSize, executor);
276 : }
277 :
278 : aclnnStatus aclnnForeachAddcdivScalarV2(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor,
279 : const aclrtStream stream)
280 : {
281 : L2_DFX_PHASE_2(aclnnForeachAddcdivScalarV2);
282 : return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
283 : }
284 :
285 : #ifdef __cplusplus
286 : }
287 : #endif
|