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_sub_scalar_v2.cpp
13 : * \brief
14 : */
15 :
16 : #include "aclnn_foreach_sub_scalar_v2.h"
17 : #include "foreach_sub_scalar_v2.h"
18 : #include "aclnn_kernels/contiguous.h"
19 : #include "op_api/op_api_def_nn.h"
20 : #include "op_api/aclnn_util.h"
21 : #include "aclnn_kernels/common/op_error_check.h"
22 : #include "opdev/op_dfx.h"
23 : #include "opdev/platform.h"
24 : #include "opdev/make_op_executor.h"
25 :
26 : using namespace op;
27 :
28 : #ifdef __cplusplus
29 : extern "C" {
30 : #endif
31 :
32 : static const std::initializer_list<ge::DataType> ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST = {
33 : ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16, ge::DT_INT32};
34 :
35 : static const std::initializer_list<ge::DataType> FOREACH_SCALAR_FLOAT_SUPPORT_LIST = {ge::DT_FLOAT, ge::DT_DOUBLE};
36 :
37 : static const std::initializer_list<ge::DataType> FOREACH_SCALAR_FLOAT16_SUPPORT_LIST = {ge::DT_FLOAT16, ge::DT_DOUBLE};
38 :
39 : static const std::initializer_list<ge::DataType> FOREACH_SCALAR_INT_SUPPORT_LIST = {ge::DT_INT32, ge::DT_INT64};
40 :
41 : static const std::initializer_list<ge::DataType> EMPTY_LIST = {};
42 :
43 : static inline bool CheckNotNull(const aclTensorList* self, const aclScalar* scalar, const aclTensorList* out)
44 : {
45 : OP_CHECK_NULL(self, return false);
46 : OP_CHECK_NULL(scalar, return false);
47 : OP_CHECK_NULL(out, return false);
48 : return true;
49 : }
50 :
51 : static inline bool CheckFormat(const aclTensorList* self, const aclTensorList* out)
52 : {
53 : for (uint64_t i = 0; i < self->Size(); i++) {
54 : // 输入输出的格式需要一致
55 : if ((*self)[i]->GetStorageFormat() != (*out)[i]->GetStorageFormat()) {
56 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Format of input and output should be equal. self [%s], out [%s].",
57 : ToString((*self)[i]->GetStorageShape()).GetString(),
58 : ToString((*out)[i]->GetStorageShape()).GetString());
59 : return false;
60 : }
61 :
62 : // self格式不能是私有格式
63 : if (IsPrivateFormat((*self)[i]->GetStorageFormat())) {
64 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Format only support ND, NCHW, NHWC, HWCN, NDHWC, NCDHW.");
65 : return false;
66 : }
67 : }
68 : return true;
69 : }
70 :
71 : static const std::initializer_list<ge::DataType>& GetDtypeSupportList()
72 : {
73 : auto curArch = GetCurrentPlatformInfo().GetCurNpuArch();
74 : if (curArch == NpuArch::DAV_2201 || Ops::NN::AclnnUtil::IsRegbase(curArch)) {
75 : return ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST;
76 : } else {
77 : OP_LOGE(ACLNN_ERR_RUNTIME_ERROR, "support for %s is not implemented",
78 : op::ToString(GetCurrentPlatformInfo().GetSocVersion()).GetString());
79 : return EMPTY_LIST;
80 : }
81 : }
82 :
83 : static inline bool CheckDtypeValid(const aclTensorList* self, const aclScalar* scalar, const aclTensorList* out)
84 : {
85 : const auto& dtypeSupportList = GetDtypeSupportList();
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 : if (self->Size() == 0) {
92 : return true;
93 : }
94 :
95 : // checkself input dtype, and check the releation of input and out
96 : auto selfDtyte = (*self)[0]->GetDataType();
97 : OP_CHECK_DTYPE_NOT_SUPPORT((*self)[0], dtypeSupportList, return false);
98 : for (uint64_t i = 0; i < self->Size(); i++) {
99 : OP_CHECK_DTYPE_NOT_MATCH((*self)[i], selfDtyte, return false);
100 : }
101 :
102 : for (uint64_t i = 0; i < out->Size(); i++) {
103 : OP_CHECK_DTYPE_NOT_MATCH((*out)[i], selfDtyte, return false);
104 : }
105 :
106 : // check the releation of self and scalar
107 : if (selfDtyte == ge::DT_BF16 || selfDtyte == ge::DT_FLOAT) {
108 : OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_FLOAT_SUPPORT_LIST, return false);
109 : } else if (selfDtyte == ge::DT_FLOAT16) {
110 : OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_FLOAT16_SUPPORT_LIST, return false);
111 : } else {
112 : OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_INT_SUPPORT_LIST, return false);
113 : }
114 : return true;
115 : }
116 :
117 : static inline bool CheckShape(const aclTensorList* self, const aclTensorList* out)
118 : {
119 : // tensor 维度检查
120 : for (uint64_t p = 0; p < self->Size(); p++) {
121 : OP_CHECK_MAX_DIM((*self)[p], MAX_SUPPORT_DIMS_NUMS, return false);
122 : }
123 :
124 : // self和out的shape必须一致
125 : for (uint64_t p = 0; p < self->Size(); p++) {
126 : OP_CHECK_SHAPE_NOT_EQUAL((*self)[p], (*out)[p], return false);
127 : }
128 : return true;
129 : }
130 :
131 : static inline aclnnStatus CheckParams(const aclTensorList* self, const aclScalar* scalar, const aclTensorList* out)
132 : {
133 : // 1. 检查参数是否为空指针
134 : CHECK_RET(CheckNotNull(self, 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 < self->Size(); i++) {
139 0 : if ((*self)[i] == nullptr) {
140 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "self[%lu] is null.", i);
141 0 : return ACLNN_ERR_PARAM_INVALID;
142 : }
143 : }
144 0 : for (uint64_t i = 0; i < out->Size(); i++) {
145 0 : if ((*out)[i] == nullptr) {
146 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "out[%lu] is null.", i);
147 0 : return ACLNN_ERR_PARAM_INVALID;
148 : }
149 : }
150 :
151 : // 2. 检查输入的数据类型是否在API支持的数据类型范围之内,需要根据api定义校验
152 : CHECK_RET(CheckDtypeValid(self, scalar, out), ACLNN_ERR_PARAM_INVALID);
153 : // 3. 检查shape是否满足约束
154 : CHECK_RET(CheckShape(self, out), ACLNN_ERR_PARAM_INVALID);
155 : // 4. 检查Format是否满足约束
156 : CHECK_RET(CheckFormat(self, out), ACLNN_ERR_PARAM_INVALID);
157 : return ACLNN_SUCCESS;
158 : }
159 :
160 : static aclnnStatus ExecForeachSubScalarV2GetWorkspaceSize(const aclTensorList* x, const aclScalar* scalar,
161 : const aclTensorList* out, uint64_t* workspaceSize,
162 : aclOpExecutor** executor)
163 : {
164 : // 固定写法,创建OpExecutor
165 : auto uniqueExecutor = CREATE_EXECUTOR();
166 : CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
167 :
168 : // 固定写法,参数检查
169 : auto ret = CheckParams(x, scalar, out);
170 : CHECK_RET(ret == ACLNN_SUCCESS, ret);
171 :
172 : // 空Tensorlist处理
173 : if (x->Size() == 0) {
174 : *workspaceSize = 0;
175 : uniqueExecutor.ReleaseTo(executor);
176 : return ACLNN_SUCCESS;
177 : }
178 :
179 : // self如果非连续,需要转连续
180 : std::vector<const aclTensor*> tensorsVec;
181 : for (size_t i = 0; i < x->Size(); ++i) {
182 : auto secondContiguous = l0op::Contiguous((*x)[i], uniqueExecutor.get());
183 : CHECK_RET(secondContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
184 : tensorsVec.push_back(secondContiguous);
185 : }
186 : auto contiguousTensors = uniqueExecutor.get()->AllocTensorList(tensorsVec.data(), tensorsVec.size());
187 : CHECK_RET(contiguousTensors != nullptr, ACLNN_ERR_INNER_NULLPTR);
188 :
189 : // sclar to tensor
190 : const aclTensor* otherTensor;
191 : if ((*x)[0]->GetDataType() == ge::DT_BF16) {
192 : otherTensor = uniqueExecutor.get()->ConvertToTensor(scalar, ge::DT_FLOAT);
193 : } else {
194 : otherTensor = uniqueExecutor.get()->ConvertToTensor(scalar, (*x)[0]->GetDataType());
195 : }
196 :
197 : // 调用l0算子ForeachSubScalarV2进行计算
198 : auto result = l0op::ForeachSubScalarV2(contiguousTensors, otherTensor, out, uniqueExecutor.get());
199 : CHECK_RET(result != nullptr, ACLNN_ERR_INNER_NULLPTR);
200 :
201 : // 固定写法,获取计算过程中需要使用的workspace大小
202 : *workspaceSize = uniqueExecutor->GetWorkspaceSize();
203 : uniqueExecutor.ReleaseTo(executor);
204 : return ACLNN_SUCCESS;
205 : }
206 :
207 : aclnnStatus aclnnForeachSubScalarV2GetWorkspaceSize(const aclTensorList* x, const aclScalar* scalar, aclTensorList* out,
208 : uint64_t* workspaceSize, aclOpExecutor** executor)
209 : {
210 : L2_DFX_PHASE_1(aclnnForeachSubScalarV2, DFX_IN(x, scalar), DFX_OUT(out));
211 : return ExecForeachSubScalarV2GetWorkspaceSize(x, scalar, out, workspaceSize, executor);
212 : }
213 :
214 : aclnnStatus aclnnForeachSubScalarV2(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor,
215 : const aclrtStream stream)
216 : {
217 : L2_DFX_PHASE_2(aclnnForeachSubScalarV2);
218 : return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
219 : }
220 :
221 : #ifdef __cplusplus
222 : }
223 : #endif
|