LCOV - code coverage report
Current view: top level - ut/foreach/foreach_minimum_scalar/op_host/op_api - aclnn_foreach_minimum_scalar_v2.cpp Coverage Total Hit
Test: CHG Lines: 0.0 % 8 0
Test Date: 2026-08-29 15:24:08
Legend: Lines: hit not hit

            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_minimum_scalar_v2.h"
      12              : #include "foreach_minimum_scalar_v2.h"
      13              : #include "aclnn_kernels/contiguous.h"
      14              : #include "op_api/op_api_def_nn.h"
      15              : #include "aclnn_kernels/common/op_error_check.h"
      16              : #include "opdev/op_dfx.h"
      17              : #include "op_api/aclnn_util.h"
      18              : #include "opdev/platform.h"
      19              : #include "opdev/make_op_executor.h"
      20              : 
      21              : using namespace op;
      22              : 
      23              : #ifdef __cplusplus
      24              : extern "C" {
      25              : #endif
      26              : 
      27              : namespace {
      28              : const float FLOAT32_MIN_VALUE = -3.4028235e+38f;
      29              : const float FLOAT32_MAX_VALUE = 3.4028235e+38f;
      30              : const float FLOAT16_MAX_VALUE = 65504.0f;
      31              : const float FLOAT16_MIN_VALUE = -65504.0f;
      32              : const int32_t INT32_MIN_VAL = -2147483648;
      33              : const float BFLOAT16_MAX_VALUE = 3.3895314e+38f;
      34              : const float BFLOAT16_MIN_VALUE = -3.3895314e+38f;
      35              : const int32_t INT32_MAX_VAL = 2147483647;
      36              : } // namespace
      37              : 
      38              : static const std::initializer_list<DataType> ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST = {
      39              :     DataType::DT_FLOAT, DataType::DT_FLOAT16, DataType::DT_BF16, DataType::DT_INT32};
      40              : 
      41              : static const std::initializer_list<DataType> FOREACH_SCALAR_FLOAT16_SUPPORT_LIST = {DataType::DT_FLOAT16,
      42              :                                                                                     DataType::DT_DOUBLE};
      43              : 
      44              : static const std::initializer_list<DataType> FOREACH_SCALAR_INT_SUPPORT_LIST = {DataType::DT_INT32, DataType::DT_INT64};
      45              : 
      46              : static const std::initializer_list<DataType> FOREACH_SCALAR_FLOAT_SUPPORT_LIST = {DataType::DT_FLOAT,
      47              :                                                                                   DataType::DT_DOUBLE};
      48              : 
      49              : static const std::initializer_list<DataType> EMPTY_LIST = {};
      50              : 
      51              : static inline bool CheckNull(const aclTensorList* self, const aclScalar* scalar, const aclTensorList* out)
      52              : {
      53              :     OP_CHECK_NULL(self, return false);
      54              :     OP_CHECK_NULL(scalar, return false);
      55              :     OP_CHECK_NULL(out, return false);
      56              :     return true;
      57              : }
      58              : 
      59              : static inline bool CheckFormat(const aclTensorList* self, const aclTensorList* out)
      60              : {
      61              :     for (uint64_t m = 0; m < self->Size(); m++) {
      62              :         // self格式不能是私有格式
      63              :         if (IsPrivateFormat((*self)[m]->GetStorageFormat()) || IsPrivateFormat((*out)[m]->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<DataType>& GetDtypeSupportList()
      72              : {
      73              :     auto curArch_2 = GetCurrentPlatformInfo().GetCurNpuArch();
      74              :     if (Ops::NN::AclnnUtil::IsRegbase(curArch_2) || curArch_2 == NpuArch::DAV_2201) {
      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_2 = GetDtypeSupportList();
      86              :     if (dtypeSupportList_2.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              :     auto selfDtyte = (*self)[0]->GetDataType();
      92              :     if (self->Size() == 0) {
      93              :         return true;
      94              :     }
      95              :     // checkself input dtype, and check the releation of input and out
      96              :     OP_CHECK_DTYPE_NOT_SUPPORT((*self)[0], dtypeSupportList_2, return false);
      97              :     for (uint64_t k = 0; k < self->Size(); k++) {
      98              :         OP_CHECK_DTYPE_NOT_MATCH((*self)[k], selfDtyte, return false);
      99              :     }
     100              : 
     101              :     for (uint64_t k = 0; k < out->Size(); k++) {
     102              :         OP_CHECK_DTYPE_NOT_MATCH((*out)[k], selfDtyte, return false);
     103              :     }
     104              : 
     105              :     // check the releation of self and scalar
     106              :     if (selfDtyte == DataType::DT_FLOAT || selfDtyte == DataType::DT_BF16) {
     107              :         OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_FLOAT_SUPPORT_LIST, return false);
     108              :     } else if (selfDtyte == DataType::DT_FLOAT16) {
     109              :         OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_FLOAT16_SUPPORT_LIST, return false);
     110              :     } else {
     111              :         OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_INT_SUPPORT_LIST, return false);
     112              :     }
     113              :     return true;
     114              : }
     115              : 
     116              : static inline bool CheckShape(const aclTensorList* self, const aclTensorList* out)
     117              : {
     118              :     // tensor 维度检查
     119              :     for (uint64_t k = 0; k < self->Size(); k++) {
     120              :         OP_CHECK_MAX_DIM((*self)[k], MAX_SUPPORT_DIMS_NUMS, return false);
     121              :     }
     122              : 
     123              :     // self和out的shape必须一致
     124              :     for (uint64_t k = 0; k < self->Size(); k++) {
     125              :         OP_CHECK_SHAPE_NOT_EQUAL((*self)[k], (*out)[k], return false);
     126              :     }
     127              :     return true;
     128              : }
     129              : 
     130              : static inline aclnnStatus CheckParams(const aclTensorList* self, const aclScalar* scalar, const aclTensorList* out)
     131              : {
     132              :     // 1. 检查参数是否为空指针
     133              :     CHECK_RET(CheckNull(self, scalar, out), ACLNN_ERR_PARAM_NULLPTR);
     134              : 
     135              :     // Check every entry in tensor lists is not null, to avoid null pointer
     136              :     // dereference in CheckDtypeValid/CheckShape/CheckFormat.
     137            0 :     for (uint64_t i = 0; i < self->Size(); i++) {
     138            0 :         if ((*self)[i] == nullptr) {
     139            0 :             OP_LOGE(ACLNN_ERR_PARAM_INVALID, "self[%lu] is null.", i);
     140            0 :             return ACLNN_ERR_PARAM_INVALID;
     141              :         }
     142              :     }
     143            0 :     for (uint64_t i = 0; i < out->Size(); i++) {
     144            0 :         if ((*out)[i] == nullptr) {
     145            0 :             OP_LOGE(ACLNN_ERR_PARAM_INVALID, "out[%lu] is null.", i);
     146            0 :             return ACLNN_ERR_PARAM_INVALID;
     147              :         }
     148              :     }
     149              : 
     150              :     // 2. 检查输入的数据类型是否在API支持的数据类型范围之内,需要根据api定义校验
     151              :     CHECK_RET(CheckDtypeValid(self, scalar, out), ACLNN_ERR_PARAM_INVALID);
     152              :     // 3. 检查shape是否满足约束
     153              :     CHECK_RET(CheckShape(self, out), ACLNN_ERR_PARAM_INVALID);
     154              :     // 4. 检查Format是否满足约束
     155              :     CHECK_RET(CheckFormat(self, out), ACLNN_ERR_PARAM_INVALID);
     156              :     return ACLNN_SUCCESS;
     157              : }
     158              : 
     159              : static inline aclnnStatus CheckScalarValueValid(const aclScalar* scalar, const DataType tensorDtype)
     160              : {
     161              :     if (scalar->GetDataType() == tensorDtype) {
     162              :         return ACLNN_SUCCESS;
     163              :     }
     164              : 
     165              :     double val = static_cast<double>(scalar->ToDouble());
     166              : 
     167              :     switch (tensorDtype) {
     168              :         case DataType::DT_INT32:
     169              :             if (val > static_cast<double>(INT32_MAX_VAL) || val < static_cast<double>(INT32_MIN_VAL)) {
     170              :                 OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Scalar value exceeds int32 range.");
     171              :                 return ACLNN_ERR_PARAM_INVALID;
     172              :             }
     173              :             return ACLNN_SUCCESS;
     174              :         case DataType::DT_FLOAT:
     175              :             if (val < static_cast<double>(FLOAT32_MIN_VALUE) || val > static_cast<double>(FLOAT32_MAX_VALUE)) {
     176              :                 OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Scalar value exceeds float32 range.");
     177              :                 return ACLNN_ERR_PARAM_INVALID;
     178              :             }
     179              :             return ACLNN_SUCCESS;
     180              :         case DataType::DT_FLOAT16:
     181              :             if (val > static_cast<double>(FLOAT16_MAX_VALUE) || val < static_cast<double>(FLOAT16_MIN_VALUE)) {
     182              :                 OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Scalar value exceeds float16 range.");
     183              :                 return ACLNN_ERR_PARAM_INVALID;
     184              :             }
     185              :             return ACLNN_SUCCESS;
     186              :         case DataType::DT_BF16:
     187              :             if (val > static_cast<double>(BFLOAT16_MAX_VALUE) || val < static_cast<double>(BFLOAT16_MIN_VALUE)) {
     188              :                 OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Scalar value exceeds bfloat16 range.");
     189              :                 return ACLNN_ERR_PARAM_INVALID;
     190              :             }
     191              :             return ACLNN_SUCCESS;
     192              :         default:
     193              :             OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Unsupported tensor data type for scalar value check");
     194              :             return ACLNN_ERR_PARAM_INVALID;
     195              :     }
     196              : }
     197              : 
     198              : static aclnnStatus ExecForeachMinimumScalarV2GetWorkspaceSize(const aclTensorList* x, const aclScalar* scalar,
     199              :                                                               const aclTensorList* out, uint64_t* workspaceSize,
     200              :                                                               aclOpExecutor** executor)
     201              : {
     202              :     // 固定写法,创建OpExecutor
     203              :     auto uniqueExecutor = CREATE_EXECUTOR();
     204              :     CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
     205              : 
     206              :     // 固定写法,参数检查
     207              :     auto ret_3 = CheckParams(x, scalar, out);
     208              :     CHECK_RET(ret_3 == ACLNN_SUCCESS, ret_3);
     209              : 
     210              :     // 空Tensorlist处理
     211              :     if (x->Size() == 0) {
     212              :         *workspaceSize = 0;
     213              :         uniqueExecutor.ReleaseTo(executor);
     214              :         return ACLNN_SUCCESS;
     215              :     }
     216              : 
     217              :     // self如果非连续,需要转连续
     218              :     std::vector<const aclTensor*> tensorsVec;
     219              :     for (size_t j = 0; j < x->Size(); ++j) {
     220              :         auto secondContiguous = l0op::Contiguous((*x)[j], uniqueExecutor.get());
     221              :         CHECK_RET(secondContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
     222              :         tensorsVec.push_back(secondContiguous);
     223              :     }
     224              :     auto contiguousTensors = uniqueExecutor.get()->AllocTensorList(tensorsVec.data(), tensorsVec.size());
     225              :     CHECK_RET(contiguousTensors != nullptr, ACLNN_ERR_INNER_NULLPTR);
     226              : 
     227              :     // 校验scalar的数值是否满足约束
     228              :     ret_3 = CheckScalarValueValid(scalar, (*x)[0]->GetDataType());
     229              :     CHECK_RET(ret_3 == ACLNN_SUCCESS, ret_3);
     230              : 
     231              :     // sclar to tensor
     232              :     const aclTensor* otherTensor;
     233              :     if ((*x)[0]->GetDataType() == DataType::DT_BF16) {
     234              :         otherTensor = uniqueExecutor.get()->ConvertToTensor(scalar, DataType::DT_FLOAT);
     235              :     } else {
     236              :         otherTensor = uniqueExecutor.get()->ConvertToTensor(scalar, (*x)[0]->GetDataType());
     237              :     }
     238              : 
     239              :     // 调用l0算子ForeachMinimumScalarV2进行计算
     240              :     auto result = l0op::ForeachMinimumScalarV2(contiguousTensors, otherTensor, out, uniqueExecutor.get());
     241              :     CHECK_RET(result != nullptr, ACLNN_ERR_INNER_NULLPTR);
     242              : 
     243              :     // 固定写法,获取计算过程中需要使用的workspace大小
     244              :     *workspaceSize = uniqueExecutor->GetWorkspaceSize();
     245              :     uniqueExecutor.ReleaseTo(executor);
     246              :     return ACLNN_SUCCESS;
     247              : }
     248              : 
     249              : aclnnStatus aclnnForeachMinimumScalarV2GetWorkspaceSize(const aclTensorList* x, const aclScalar* scalar,
     250              :                                                         aclTensorList* out, uint64_t* workspaceSize,
     251              :                                                         aclOpExecutor** executor)
     252              : {
     253              :     L2_DFX_PHASE_1(aclnnForeachMinimumScalarV2, DFX_IN(x, scalar), DFX_OUT(out));
     254              :     return ExecForeachMinimumScalarV2GetWorkspaceSize(x, scalar, out, workspaceSize, executor);
     255              : }
     256              : 
     257              : aclnnStatus aclnnForeachMinimumScalarV2(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor,
     258              :                                         const aclrtStream stream)
     259              : {
     260              :     L2_DFX_PHASE_2(aclnnForeachMinimumScalarV2);
     261              :     return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
     262              : }
     263              : 
     264              : #ifdef __cplusplus
     265              : }
     266              : #endif
        

Generated by: LCOV version 2.0-1