已合并
[feat]Add two aicpu op ReduceAll and Div #2750
FengHaozhan创建于 5月14日
[feat]Add two aicpu op ReduceAll and Div #2750
已合并
FengHaozhan创建于 5月14日
13 个文件变更+1682-3
@@ -592,7 +592,7 @@
592 <td>√</td>592 <td>√</td>
593 <td>√</td>593 <td>√</td>
594 <td>√</td>594 <td>√</td>
595- <td>AI Core</td>595+ <td>AI Core/AI CPU</td>
596 <td>张量运算函数,用于执行乘除加组合操作,将张量除法(带缩放)+ 张量加法合并为单个操作。</td>596 <td>张量运算函数,用于执行乘除加组合操作,将张量除法(带缩放)+ 张量加法合并为单个操作。</td>
597 </tr>597 </tr>
598 <tr>598 <tr>
@@ -1392,7 +1392,7 @@
1392 <td>×</td>1392 <td>×</td>
1393 <td>×</td>1393 <td>×</td>
1394 <td>×</td>1394 <td>×</td>
1395- <td>AI Core</td>1395+ <td>AI Core/AI CPU</td>
1396 <td>该算子暂无Ascend C代码实现,欢迎开发者补充贡献,贡献方式参考<a href="../../CONTRIBUTING.md">贡献指南</a>。</td>1396 <td>该算子暂无Ascend C代码实现,欢迎开发者补充贡献,贡献方式参考<a href="../../CONTRIBUTING.md">贡献指南</a>。</td>
1397 </tr>1397 </tr>
1398 <tr>1398 <tr>
@@ -73,3 +73,4 @@
73| 调用方式 | 样例代码 | 说明 |73| 调用方式 | 样例代码 | 说明 |
74| ---------------- | --------------------------- | --------------------------------------------------- |74| ---------------- | --------------------------- | --------------------------------------------------- |
75| aclnn接口 | [test_aclnn_div](examples/test_aclnn_div.cpp) | 通过[AclnnDiv](docs/aclnnDiv&aclnnInplaceDiv.md)接口方式调用Div算子。 |75| aclnn接口 | [test_aclnn_div](examples/test_aclnn_div.cpp) | 通过[AclnnDiv](docs/aclnnDiv&aclnnInplaceDiv.md)接口方式调用Div算子。 |
76+| 图模式调用 | [test_geir_div](examples/test_geir_div.cpp) | 通过[算子IR](op_graph/div_proto.h)构图方式调用Div算子。 |
@@ -0,0 +1,216 @@
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 test_geir_div.cpp
13+ * \brief Test Div via GE IR graph mode
14+ */
15+ 
16+#include <cmath>
17+#include <cstdint>
18+#include <cstdio>
19+#include <ctime>
20+#include <map>
21+#include <new>
22+#include <string>
23+#include <vector>
24+ 
25+#include "array_ops.h"
26+#include "ge_api.h"
27+#include "ge_api_types.h"
28+#include "ge_error_codes.h"
29+#include "ge_ir_build.h"
30+#include "graph.h"
31+#include "tensor.h"
32+#include "types.h"
33+ 
34+#include "../op_graph/div_proto.h"
35+ 
36+#define FAILED -1
37+#define SUCCESS 0
38+ 
39+using namespace ge;
40+using std::map;
41+using std::string;
42+using std::vector;
43+ 
44+string GetTime()
45+{
46+ time_t timep;
47+ time(&timep);
48+ char tmp[64];
49+ struct tm tm_info;
50+ strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime_r(&timep, &tm_info));
51+ return tmp;
52+}
53+ 
54+template <typename T>
55+int32_t GenTensorData(const vector<int64_t>& shapes, const vector<T>& values, TensorDesc& tensor_desc, Tensor& tensor)
56+{
57+ tensor_desc.SetRealDimCnt(shapes.size());
58+ size_t element_count = 1;
59+ for (size_t i = 0; i < shapes.size(); ++i) {
60+ element_count *= static_cast<size_t>(shapes[i]);
61+ }
62+ if (values.size() != element_count) {
63+ return FAILED;
64+ }
65+ 
66+ tensor = Tensor(
67+ tensor_desc, reinterpret_cast<const uint8_t*>(values.data()),
68+ values.size() * sizeof(typename vector<T>::value_type));
69+ return SUCCESS;
70+}
71+ 
72+int CreateOpInGraph(vector<Tensor>& input_tensors, vector<Operator>& inputs, vector<Operator>& outputs, Graph& graph)
73+{
74+ Status ret = SUCCESS;
75+ auto div_op = op::Div("div_graph");
76+ vector<int64_t> input_shape = {4, 2};
77+ 
78+ auto x1 = op::Data("x1").set_attr_index(0);
79+ TensorDesc x1_desc(Shape(input_shape), FORMAT_ND, DT_DOUBLE);
80+ x1_desc.SetPlacement(ge::kPlacementHost);
81+ x1_desc.SetFormat(FORMAT_ND);
82+ Tensor x1_tensor;
83+ ret = GenTensorData<double>(input_shape, {8.0, 9.0, 10.0, 12.0, 15.0, 21.0, 28.0, 32.0}, x1_desc, x1_tensor);
84+ if (ret != SUCCESS) {
85+ printf("%s - ERROR - [XIR]: Generate x1 data failed\n", GetTime().c_str());
86+ return FAILED;
87+ }
88+ x1.update_input_desc_x(x1_desc);
89+ x1.update_output_desc_y(x1_desc);
90+ input_tensors.push_back(x1_tensor);
91+ graph.AddOp(x1);
92+ div_op.set_input_x1(x1);
93+ div_op.update_input_desc_x1(x1_desc);
94+ inputs.push_back(x1);
95+ 
96+ auto x2 = op::Data("x2").set_attr_index(1);
97+ TensorDesc x2_desc(Shape(input_shape), FORMAT_ND, DT_DOUBLE);
98+ x2_desc.SetPlacement(ge::kPlacementHost);
99+ x2_desc.SetFormat(FORMAT_ND);
100+ Tensor x2_tensor;
101+ ret = GenTensorData<double>(input_shape, {2.0, 3.0, 5.0, 3.0, 5.0, 7.0, 4.0, 8.0}, x2_desc, x2_tensor);
102+ if (ret != SUCCESS) {
103+ printf("%s - ERROR - [XIR]: Generate x2 data failed\n", GetTime().c_str());
104+ return FAILED;
105+ }
106+ x2.update_input_desc_x(x2_desc);
107+ x2.update_output_desc_y(x2_desc);
108+ input_tensors.push_back(x2_tensor);
109+ graph.AddOp(x2);
110+ div_op.set_input_x2(x2);
111+ div_op.update_input_desc_x2(x2_desc);
112+ inputs.push_back(x2);
113+ 
114+ TensorDesc y_desc(Shape(input_shape), FORMAT_ND, DT_DOUBLE);
115+ div_op.update_output_desc_y(y_desc);
116+ outputs.push_back(div_op);
117+ return SUCCESS;
118+}
119+ 
120+int VerifyOutput(const vector<Tensor>& output_tensors)
121+{
122+ static const double expected[] = {4.0, 3.0, 2.0, 4.0, 3.0, 3.0, 7.0, 4.0};
123+ if (output_tensors.size() != 1) {
124+ printf("Unexpected output tensor count: %zu\n", output_tensors.size());
125+ return FAILED;
126+ }
127+ 
128+ const Tensor& output_tensor = output_tensors[0];
129+ int64_t element_count = output_tensor.GetTensorDesc().GetShape().GetShapeSize();
130+ if (element_count != static_cast<int64_t>(sizeof(expected) / sizeof(expected[0]))) {
131+ printf("Unexpected output element count: %ld\n", element_count);
132+ return FAILED;
133+ }
134+ 
135+ const auto* result_data = reinterpret_cast<const double*>(output_tensor.GetData());
136+ for (int64_t i = 0; i < element_count; ++i) {
137+ printf("result[%ld] is: %.6f\n", i, result_data[i]);
138+ if (std::fabs(result_data[i] - expected[i]) > 1e-9) {
139+ printf("Div output mismatch at index %ld, expect %.6f but got %.6f\n", i, expected[i], result_data[i]);
140+ return FAILED;
141+ }
142+ }
143+ return SUCCESS;
144+}
145+ 
146+int main(int argc, char* argv[])
147+{
148+ (void)argc;
149+ (void)argv;
150+ 
151+ const char* graph_name = "tc_ge_irrun_div";
152+ Graph graph(graph_name);
153+ vector<Tensor> input_tensors;
154+ 
155+ printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str());
156+ map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
157+ Status ret = ge::GEInitialize(global_options);
158+ if (ret != SUCCESS) {
159+ printf("%s - ERROR - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str());
160+ return FAILED;
161+ }
162+ 
163+ vector<Operator> inputs;
164+ vector<Operator> outputs;
165+ ret = CreateOpInGraph(input_tensors, inputs, outputs, graph);
166+ if (ret != SUCCESS) {
167+ ge::GEFinalize();
168+ return FAILED;
169+ }
170+ 
171+ if (!inputs.empty() && !outputs.empty()) {
172+ graph.SetInputs(inputs).SetOutputs(outputs);
173+ }
174+ 
175+ map<AscendString, AscendString> build_options;
176+ ge::Session* session = new (std::nothrow) Session(build_options);
177+ if (session == nullptr) {
178+ printf("%s - ERROR - [XIR]: Create ir session failed\n", GetTime().c_str());
179+ ge::GEFinalize();
180+ return FAILED;
181+ }
182+ 
183+ map<AscendString, AscendString> graph_options = {{"ge.exec.precision_mode", "allow_mix_precision"}};
184+ uint32_t graph_id = 0;
185+ ret = session->AddGraph(graph_id, graph, graph_options);
186+ if (ret != SUCCESS) {
187+ printf("%s - ERROR - [XIR]: Add graph failed\n", GetTime().c_str());
188+ delete session;
189+ ge::GEFinalize();
190+ return FAILED;
191+ }
192+ 
193+ vector<Tensor> output_tensors;
194+ ret = session->RunGraph(graph_id, input_tensors, output_tensors);
195+ if (ret != SUCCESS) {
196+ printf("%s - ERROR - [XIR]: Run graph failed\n", GetTime().c_str());
197+ delete session;
198+ ge::GEFinalize();
199+ return FAILED;
200+ }
201+ 
202+ ret = VerifyOutput(output_tensors);
203+ delete session;
204+ if (ret != SUCCESS) {
205+ ge::GEFinalize();
206+ return FAILED;
207+ }
208+ 
209+ printf("%s - INFO - [XIR]: Div double graph example verified successfully\n", GetTime().c_str());
210+ ret = ge::GEFinalize();
211+ if (ret != SUCCESS) {
212+ printf("%s - ERROR - [XIR]: GE Finalize failed\n", GetTime().c_str());
213+ return FAILED;
214+ }
215+ return SUCCESS;
216+}
@@ -0,0 +1,458 @@
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+#include "div_aicpu.h"
12+ 
13+#include <complex>
14+#include <limits>
15+#include <type_traits>
16+ 
17+#include "cmath"
18+#include "cpu_kernel_utils.h"
19+#include "utils/eigen_tensor.h"
20+#include "utils/kernel_util.h"
21+ 
22+namespace {
23+const uint32_t kOutputNum = 1;
24+const uint32_t kInputNum = 2;
25+const char* kDiv = "Div";
26+constexpr int64_t kParallelDataNum = 2 * 1024;
27+constexpr int64_t kParallelDataNumMid = 16 * 1024;
28+constexpr int64_t kParallelDataNumSameShape = 7 * 1024;
29+constexpr int64_t kParallelDataNumSameShapeMid = 35 * 1024;
30+ 
31+template <typename T>
32+typename std::enable_if<std::is_signed<T>::value, bool>::type IsDivOverflow(T lhs, T rhs)
33+{
34+ return lhs == std::numeric_limits<T>::min() && rhs == static_cast<T>(-1);
35+}
36+ 
37+template <typename T>
38+typename std::enable_if<!std::is_signed<T>::value, bool>::type IsDivOverflow(T, T)
39+{
40+ return false;
41+}
42+ 
43+template <typename T>
44+typename std::enable_if<std::is_signed<T>::value, bool>::type NeedFloorAdjust(T lhs, T rhs, T mod)
45+{
46+ return mod != static_cast<T>(0) && ((lhs < static_cast<T>(0)) != (rhs < static_cast<T>(0)));
47+}
48+ 
49+template <typename T>
50+typename std::enable_if<!std::is_signed<T>::value, bool>::type NeedFloorAdjust(T, T, T)
51+{
52+ return false;
53+}
54+ 
55+template <typename T>
56+uint32_t CheckDivOverflow(T lhs, T rhs)
57+{
58+ if (IsDivOverflow(lhs, rhs)) {
59+ KERNEL_LOG_ERROR("Invalid argument: Integer division overflow.");
60+ return aicpu::KERNEL_STATUS_INNER_ERROR;
61+ }
62+ return aicpu::KERNEL_STATUS_OK;
63+}
64+ 
65+template <typename T>
66+uint32_t CheckNoBcastDivOverflow(aicpu::CpuKernelContext& ctx)
67+{
68+ if (!std::is_signed<T>::value) {
69+ return aicpu::KERNEL_STATUS_OK;
70+ }
71+ 
72+ auto input0 = reinterpret_cast<const T*>(ctx.Input(0)->GetData());
73+ auto input1 = reinterpret_cast<const T*>(ctx.Input(1)->GetData());
74+ int64_t input0_elements_nums = ctx.Input(0)->NumElements();
75+ int64_t input1_elements_nums = ctx.Input(1)->NumElements();
76+ int64_t data_num = ctx.Output(0)->NumElements();
77+ aicpu::BcastShapeType type = input0_elements_nums == input1_elements_nums ?
78+ aicpu::BcastShapeType::SAME_SHAPE :
79+ (input0_elements_nums == 1 ? aicpu::BcastShapeType::X_ONE_ELEMENT :
80+ aicpu::BcastShapeType::Y_ONE_ELEMENT);
81+ 
82+ switch (type) {
83+ case aicpu::BcastShapeType::SAME_SHAPE:
84+ for (int64_t i = 0; i < data_num; ++i) {
85+ uint32_t result = CheckDivOverflow(*(input0 + i), *(input1 + i));
86+ if (result != aicpu::KERNEL_STATUS_OK) {
87+ return result;
88+ }
89+ }
90+ break;
91+ case aicpu::BcastShapeType::X_ONE_ELEMENT:
92+ for (int64_t i = 0; i < data_num; ++i) {
93+ uint32_t result = CheckDivOverflow(*input0, *(input1 + i));
94+ if (result != aicpu::KERNEL_STATUS_OK) {
95+ return result;
96+ }
97+ }
98+ break;
99+ case aicpu::BcastShapeType::Y_ONE_ELEMENT:
100+ for (int64_t i = 0; i < data_num; ++i) {
101+ uint32_t result = CheckDivOverflow(*(input0 + i), *input1);
102+ if (result != aicpu::KERNEL_STATUS_OK) {
103+ return result;
104+ }
105+ }
106+ break;
107+ default:
108+ KERNEL_LOG_WARN("Invalid type [%d]", static_cast<int32_t>(type));
109+ break;
110+ }
111+ return aicpu::KERNEL_STATUS_OK;
112+}
113+ 
114+template <typename T>
115+uint32_t CheckBcastDivOverflow(aicpu::CpuKernelContext& ctx, aicpu::Bcast& bcast)
116+{
117+ if (!std::is_signed<T>::value) {
118+ return aicpu::KERNEL_STATUS_OK;
119+ }
120+ 
121+ auto input0 = reinterpret_cast<const T*>(ctx.Input(0)->GetData());
122+ auto input1 = reinterpret_cast<const T*>(ctx.Input(1)->GetData());
123+ int64_t data_num = ctx.Output(0)->NumElements();
124+ for (int64_t i = 0; i < data_num; ++i) {
125+ T lhs = *(input0 + bcast.GetBroadcastXIndex(i));
126+ T rhs = *(input1 + bcast.GetBroadcastYIndex(i));
127+ uint32_t result = CheckDivOverflow(lhs, rhs);
128+ if (result != aicpu::KERNEL_STATUS_OK) {
129+ return result;
130+ }
131+ }
132+ return aicpu::KERNEL_STATUS_OK;
133+}
134+ 
135+inline aicpu::BcastShapeType GetNoBcastShapeType(int64_t input0_elements_nums, int64_t input1_elements_nums)
136+{
137+ return input0_elements_nums == input1_elements_nums ?
138+ aicpu::BcastShapeType::SAME_SHAPE :
139+ (input0_elements_nums == 1 ? aicpu::BcastShapeType::X_ONE_ELEMENT :
140+ aicpu::BcastShapeType::Y_ONE_ELEMENT);
141+}
142+ 
143+inline uint32_t GetDivParallelCoreNum(
144+ const aicpu::CpuKernelContext& ctx, int64_t data_num, int64_t parallel_data_num_mid)
145+{
146+ uint32_t min_core_num = 1;
147+ uint32_t max_core_num = std::max(min_core_num, aicpu::CpuKernelUtils::GetCPUNum(ctx) - 2);
148+ if (data_num <= parallel_data_num_mid) {
149+ max_core_num = std::min(max_core_num, 4U);
150+ }
151+ if (max_core_num > data_num) {
152+ max_core_num = data_num;
153+ }
154+ return max_core_num;
155+}
156+ 
157+template <typename ComputeFn>
158+uint32_t RunDivRangeCompute(const aicpu::CpuKernelContext& ctx, int64_t data_num, int64_t parallel_data_num,
159+ int64_t parallel_data_num_mid, const ComputeFn& compute)
160+{
161+ if (data_num < parallel_data_num) {
162+ return compute(0, data_num);
163+ }
164+ 
165+ uint32_t max_core_num = GetDivParallelCoreNum(ctx, data_num, parallel_data_num_mid);
166+ auto sharder_div = [&](int64_t start, int64_t end) { (void)compute(start, end); };
167+ return aicpu::CpuKernelUtils::ParallelFor(ctx, data_num, data_num / max_core_num, sharder_div);
168+}
169+ 
170+template <typename T>
171+uint32_t ComputeIntDivValue(T lhs, T rhs, T* output)
172+{
173+ if (rhs == static_cast<T>(0)) {
174+ KERNEL_LOG_ERROR("Invalid argument: Division by zero.");
175+ return aicpu::KERNEL_STATUS_INNER_ERROR;
176+ }
177+ 
178+ T mod = lhs % rhs;
179+ if (NeedFloorAdjust(lhs, rhs, mod)) {
180+ *output = lhs / rhs - static_cast<T>(1);
181+ } else {
182+ *output = lhs / rhs;
183+ }
184+ return aicpu::KERNEL_STATUS_OK;
185+}
186+ 
187+template <typename T, typename LhsGetter, typename RhsGetter>
188+uint32_t ComputeIntDivRange(
189+ int64_t start, int64_t end, T* output, const LhsGetter& lhs_getter, const RhsGetter& rhs_getter)
190+{
191+ for (int64_t i = start; i < end; ++i) {
192+ uint32_t result = ComputeIntDivValue(lhs_getter(i), rhs_getter(i), output + i);
193+ if (result != aicpu::KERNEL_STATUS_OK) {
194+ return result;
195+ }
196+ }
197+ return aicpu::KERNEL_STATUS_OK;
198+}
199+ 
200+template <typename T, typename LhsGetter, typename RhsGetter>
201+uint32_t ComputeDivRange(
202+ int64_t start, int64_t end, T* output, const LhsGetter& lhs_getter, const RhsGetter& rhs_getter)
203+{
204+ for (int64_t i = start; i < end; ++i) {
205+ *(output + i) = lhs_getter(i) / rhs_getter(i);
206+ }
207+ return aicpu::KERNEL_STATUS_OK;
208+}
209+ 
210+#define DIV_COMPUTE_CASE_INT(DTYPE, TYPE, CTX) \
211+ case (DTYPE): { \
212+ uint32_t result = DivComputeInt<TYPE>(CTX); \
213+ if (result != KERNEL_STATUS_OK) { \
214+ KERNEL_LOG_ERROR("Div kernel compute failed."); \
215+ return result; \
216+ } \
217+ break; \
218+ }
219+ 
220+#define DIV_COMPUTE_CASE(DTYPE, TYPE, CTX) \
221+ case (DTYPE): { \
222+ uint32_t result = DivCompute<TYPE>(CTX); \
223+ if (result != KERNEL_STATUS_OK) { \
224+ KERNEL_LOG_ERROR("Div kernel compute failed."); \
225+ return result; \
226+ } \
227+ break; \
228+ }
229+} // namespace
230+ 
231+namespace aicpu {
232+uint32_t DivCpuKernel::Compute(CpuKernelContext& ctx)
233+{
234+ KERNEL_HANDLE_ERROR(NormalCheck(ctx, kInputNum, kOutputNum), "[%s] check input and output failed.", kDiv);
235+ KERNEL_HANDLE_ERROR(DivParamCheck(ctx), "Div check params failed.");
236+ 
237+ auto data_type = ctx.Input(0)->GetDataType();
238+ switch (data_type) {
239+ DIV_COMPUTE_CASE_INT(DT_INT8, int8_t, ctx)
240+ DIV_COMPUTE_CASE_INT(DT_INT16, int16_t, ctx)
241+ DIV_COMPUTE_CASE_INT(DT_INT32, int32_t, ctx)
242+ DIV_COMPUTE_CASE_INT(DT_INT64, int64_t, ctx)
243+ DIV_COMPUTE_CASE_INT(DT_UINT8, uint8_t, ctx)
244+ DIV_COMPUTE_CASE_INT(DT_UINT16, uint16_t, ctx)
245+ DIV_COMPUTE_CASE(DT_FLOAT16, Eigen::half, ctx)
246+ DIV_COMPUTE_CASE(DT_FLOAT, float, ctx)
247+ DIV_COMPUTE_CASE(DT_DOUBLE, double, ctx)
248+ DIV_COMPUTE_CASE(DT_COMPLEX64, std::complex<float>, ctx)
249+ DIV_COMPUTE_CASE(DT_COMPLEX128, std::complex<double>, ctx)
250+ default:
251+ KERNEL_LOG_ERROR("Div kernel data type [%s] not support.", DTypeStr(data_type).c_str());
252+ return KERNEL_STATUS_PARAM_INVALID;
253+ }
254+ return KERNEL_STATUS_OK;
255+}
256+ 
257+uint32_t DivCpuKernel::DivParamCheck(CpuKernelContext& ctx)
258+{
259+ Tensor* input_0 = ctx.Input(0);
260+ Tensor* input_1 = ctx.Input(1);
261+ Tensor* output = ctx.Output(0);
262+ KERNEL_CHECK_NULLPTR(input_0->GetData(), KERNEL_STATUS_PARAM_INVALID, "Get input 0 data failed.")
263+ KERNEL_CHECK_NULLPTR(input_1->GetData(), KERNEL_STATUS_PARAM_INVALID, "Get input 1 data failed.")
264+ KERNEL_CHECK_NULLPTR(output->GetData(), KERNEL_STATUS_PARAM_INVALID, "Get output data failed")
265+ DataType input0_type = input_0->GetDataType();
266+ DataType input1_type = input_1->GetDataType();
267+ KERNEL_CHECK_FALSE(
268+ (input0_type == input1_type), KERNEL_STATUS_PARAM_INVALID,
269+ "The data type of input0 [%s] need be same with "
270+ "input1 [%s].",
271+ DTypeStr(input0_type).c_str(), DTypeStr(input1_type).c_str())
272+ KERNEL_LOG_DEBUG(
273+ "DivCpuKernel[%s], input0: size[%llu];"
274+ "input1: size[%llu], output: size[%llu].",
275+ ctx.GetOpType().c_str(), input_0->GetDataSize(), input_1->GetDataSize(), output->GetDataSize());
276+ 
277+ return KERNEL_STATUS_OK;
278+}
279+ 
280+template <typename T>
281+uint32_t DivCpuKernel::DivParamCheckZero(CpuKernelContext& ctx)
282+{
283+ auto input1 = reinterpret_cast<T*>(ctx.Input(1)->GetData());
284+ int64_t input1_elements_nums = ctx.Input(1)->NumElements();
285+ for (int64_t i = 0; i < input1_elements_nums; i++) {
286+ if (static_cast<double>(*(input1 + i)) == 0) {
287+ KERNEL_LOG_ERROR("Invalid argument: Division by zero.");
288+ return KERNEL_STATUS_INNER_ERROR;
289+ }
290+ }
291+ return KERNEL_STATUS_OK;
292+}
293+ 
294+/**
295+special compute is used in the following situations.
296+1. the shapes of input1 and input2 are the same
297+2. input1 is a 1D tensor with only one element or input1 is scalar
298+3. input2 is a 1D tensor with only one element or input2 is scalar
299+4. the shapes of input1 and input2 are different
300+*/
301+template <typename T>
302+uint32_t DivCpuKernel::SpecialComputeInt(
303+ BcastShapeType type, int64_t start, int64_t end, const T* input1, const T* input2, T* output)
304+{
305+ switch (type) {
306+ case BcastShapeType::SAME_SHAPE:
307+ return ComputeIntDivRange<T>(
308+ start, end, output, [&](int64_t i) { return *(input1 + i); }, [&](int64_t i) { return *(input2 + i); });
309+ case BcastShapeType::X_ONE_ELEMENT:
310+ return ComputeIntDivRange<T>(
311+ start, end, output, [&](int64_t) { return *input1; }, [&](int64_t i) { return *(input2 + i); });
312+ case BcastShapeType::Y_ONE_ELEMENT:
313+ return ComputeIntDivRange<T>(
314+ start, end, output, [&](int64_t i) { return *(input1 + i); }, [&](int64_t) { return *input2; });
315+ default:
316+ KERNEL_LOG_WARN("Invalid type [%d]", static_cast<int32_t>(type));
317+ break;
318+ }
319+ return KERNEL_STATUS_OK;
320+}
321+ 
322+template <typename T>
323+uint32_t DivCpuKernel::SpecialCompute(
324+ BcastShapeType type, int64_t start, int64_t end, const T* input1, const T* input2, T* output)
325+{
326+ switch (type) {
327+ case BcastShapeType::SAME_SHAPE:
328+ return ComputeDivRange<T>(
329+ start, end, output, [&](int64_t i) { return *(input1 + i); }, [&](int64_t i) { return *(input2 + i); });
330+ case BcastShapeType::X_ONE_ELEMENT:
331+ return ComputeDivRange<T>(
332+ start, end, output, [&](int64_t) { return *input1; }, [&](int64_t i) { return *(input2 + i); });
333+ case BcastShapeType::Y_ONE_ELEMENT:
334+ return ComputeDivRange<T>(
335+ start, end, output, [&](int64_t i) { return *(input1 + i); }, [&](int64_t) { return *input2; });
336+ default:
337+ KERNEL_LOG_WARN("Invalid type [%d]", static_cast<int32_t>(type));
338+ break;
339+ }
340+ return KERNEL_STATUS_OK;
341+}
342+ 
343+template <typename T>
344+uint32_t DivCpuKernel::NoBcastComputeInt(CpuKernelContext& ctx)
345+{
346+ auto in0 = reinterpret_cast<T*>(ctx.Input(0)->GetData());
347+ auto in1 = reinterpret_cast<T*>(ctx.Input(1)->GetData());
348+ auto out = reinterpret_cast<T*>(ctx.Output(0)->GetData());
349+ int64_t in0_elements_nums = ctx.Input(0)->NumElements();
350+ int64_t in1_elements_nums = ctx.Input(1)->NumElements();
351+ int64_t data_num = ctx.Output(0)->NumElements();
352+ BcastShapeType type = GetNoBcastShapeType(in0_elements_nums, in1_elements_nums);
353+ return RunDivRangeCompute(ctx, data_num, kParallelDataNumSameShape, kParallelDataNumSameShapeMid,
354+ [&](int64_t start, int64_t end) { return SpecialComputeInt<T>(type, start, end, in0, in1, out); });
355+}
356+ 
357+template <typename T>
358+uint32_t DivCpuKernel::NoBcastCompute(CpuKernelContext& ctx)
359+{
360+ auto in0 = reinterpret_cast<T*>(ctx.Input(0)->GetData());
361+ auto in1 = reinterpret_cast<T*>(ctx.Input(1)->GetData());
362+ auto out = reinterpret_cast<T*>(ctx.Output(0)->GetData());
363+ int64_t in0_elements_nums = ctx.Input(0)->NumElements();
364+ int64_t in1_elements_nums = ctx.Input(1)->NumElements();
365+ int64_t data_num = ctx.Output(0)->NumElements();
366+ BcastShapeType type = GetNoBcastShapeType(in0_elements_nums, in1_elements_nums);
367+ return RunDivRangeCompute(ctx, data_num, kParallelDataNumSameShape, kParallelDataNumSameShapeMid,
368+ [&](int64_t start, int64_t end) { return SpecialCompute<T>(type, start, end, in0, in1, out); });
369+}
370+ 
371+template <typename T>
372+uint32_t DivCpuKernel::BcastComputeInt(CpuKernelContext& ctx, Bcast& bcast)
373+{
374+ auto in0 = reinterpret_cast<T*>(ctx.Input(0)->GetData());
375+ auto in1 = reinterpret_cast<T*>(ctx.Input(1)->GetData());
376+ auto out = reinterpret_cast<T*>(ctx.Output(0)->GetData());
377+ int64_t data_num = ctx.Output(0)->NumElements();
378+ return RunDivRangeCompute(ctx, data_num, kParallelDataNum, kParallelDataNumMid,
379+ [&](int64_t start, int64_t end) {
380+ return ComputeIntDivRange<T>(start, end, out, [&](int64_t i) { return *(in0 + bcast.GetBroadcastXIndex(i)); },
381+ [&](int64_t i) { return *(in1 + bcast.GetBroadcastYIndex(i)); });
382+ });
383+}
384+ 
385+template <typename T>
386+uint32_t DivCpuKernel::BcastCompute(CpuKernelContext& ctx, Bcast& bcast)
387+{
388+ auto in0 = reinterpret_cast<T*>(ctx.Input(0)->GetData());
389+ auto in1 = reinterpret_cast<T*>(ctx.Input(1)->GetData());
390+ auto out = reinterpret_cast<T*>(ctx.Output(0)->GetData());
391+ int64_t data_num = ctx.Output(0)->NumElements();
392+ return RunDivRangeCompute(ctx, data_num, kParallelDataNum, kParallelDataNumMid,
393+ [&](int64_t start, int64_t end) {
394+ return ComputeDivRange<T>(start, end, out, [&](int64_t i) { return *(in0 + bcast.GetBroadcastXIndex(i)); },
395+ [&](int64_t i) { return *(in1 + bcast.GetBroadcastYIndex(i)); });
396+ });
397+}
398+ 
399+template <typename T>
400+uint32_t DivCpuKernel::DivComputeInt(CpuKernelContext& ctx)
401+{
402+ Tensor* input0_tensor = ctx.Input(0);
403+ auto input0_shape = input0_tensor->GetTensorShape()->GetDimSizes();
404+ int64_t input0_elements_nums = input0_tensor->NumElements();
405+ Tensor* input1_tensor = ctx.Input(1);
406+ auto input1_shape = input1_tensor->GetTensorShape()->GetDimSizes();
407+ int64_t input1_elements_nums = input1_tensor->NumElements();
408+ bool is_need_bcast = (input0_shape == input1_shape) || (input0_elements_nums == 1) || (input1_elements_nums == 1);
409+ uint32_t result = DivParamCheckZero<T>(ctx);
410+ if (result != KERNEL_STATUS_OK) {
411+ KERNEL_LOG_ERROR("Invalid argument: Division by zero.");
412+ return result;
413+ }
414+ 
415+ if (is_need_bcast) {
416+ result = CheckNoBcastDivOverflow<T>(ctx);
417+ if (result != KERNEL_STATUS_OK) {
418+ return result;
419+ }
420+ return NoBcastComputeInt<T>(ctx);
421+ }
422+ 
423+ Bcast bcast(input0_shape, input1_shape);
424+ if (!bcast.IsValid()) {
425+ KERNEL_LOG_ERROR("[%s] broadcast failed.", ctx.GetOpType().c_str());
426+ return KERNEL_STATUS_PARAM_INVALID;
427+ }
428+ result = CheckBcastDivOverflow<T>(ctx, bcast);
429+ if (result != KERNEL_STATUS_OK) {
430+ return result;
431+ }
432+ return BcastComputeInt<T>(ctx, bcast);
433+}
434+ 
435+template <typename T>
436+uint32_t DivCpuKernel::DivCompute(CpuKernelContext& ctx)
437+{
438+ Tensor* input0_tensor = ctx.Input(0);
439+ auto input0_shape = input0_tensor->GetTensorShape()->GetDimSizes();
440+ int64_t input0_elements_nums = input0_tensor->NumElements();
441+ Tensor* input1_tensor = ctx.Input(1);
442+ auto input1_shape = input1_tensor->GetTensorShape()->GetDimSizes();
443+ int64_t input1_elements_nums = input1_tensor->NumElements();
444+ bool is_need_bcast = (input0_shape == input1_shape) || (input0_elements_nums == 1) || (input1_elements_nums == 1);
445+ if (is_need_bcast) {
446+ return NoBcastCompute<T>(ctx);
447+ }
448+ 
449+ Bcast bcast(input0_shape, input1_shape);
450+ if (!bcast.IsValid()) {
451+ KERNEL_LOG_ERROR("[%s] broadcast failed.", ctx.GetOpType().c_str());
452+ return KERNEL_STATUS_PARAM_INVALID;
453+ }
454+ return BcastCompute<T>(ctx, bcast);
455+}
456+ 
457+REGISTER_CPU_KERNEL(kDiv, DivCpuKernel);
458+} // namespace aicpu
@@ -0,0 +1,64 @@
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+#ifndef OPS_MATH_DIV_AICPU_H_
12+#define OPS_MATH_DIV_AICPU_H_
13+ 
14+#define EIGEN_USE_THREADS
15+#define EIGEN_USE_SIMPLE_THREAD_POOL
16+ 
17+#include "cpu_kernel.h"
18+#include "cpu_types.h"
19+#include "utils/bcast.h"
20+ 
21+namespace aicpu {
22+class DivCpuKernel : public CpuKernel {
23+public:
24+ DivCpuKernel() = default;
25+ ~DivCpuKernel() override = default;
26+ 
27+protected:
28+ uint32_t Compute(CpuKernelContext& ctx) override;
29+ 
30+private:
31+ uint32_t DivParamCheck(CpuKernelContext& ctx);
32+ 
33+ template <typename T>
34+ uint32_t DivParamCheckZero(CpuKernelContext& ctx);
35+ 
36+ template <typename T>
37+ uint32_t SpecialComputeInt(
38+ BcastShapeType type, int64_t start, int64_t end, const T* input1, const T* input2, T* output);
39+ 
40+ template <typename T>
41+ uint32_t SpecialCompute(
42+ BcastShapeType type, int64_t start, int64_t end, const T* input1, const T* input2, T* output);
43+ 
44+ template <typename T>
45+ uint32_t NoBcastComputeInt(CpuKernelContext& ctx);
46+ 
47+ template <typename T>
48+ uint32_t NoBcastCompute(CpuKernelContext& ctx);
49+ 
50+ template <typename T>
51+ uint32_t BcastComputeInt(CpuKernelContext& ctx, Bcast& bcast);
52+ 
53+ template <typename T>
54+ uint32_t BcastCompute(CpuKernelContext& ctx, Bcast& bcast);
55+ 
56+ template <typename T>
57+ uint32_t DivComputeInt(CpuKernelContext& ctx);
58+ 
59+ template <typename T>
60+ uint32_t DivCompute(CpuKernelContext& ctx);
61+};
62+} // namespace aicpu
63+ 
64+#endif
@@ -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+#include "register/op_def_registry.h"
12+#include "../../../common/inc/aicpu/aicpu_op_def.h"
13+ 
14+namespace ops {
15+class Div : public OpDef {
16+public:
17+ explicit Div(const char* name) : OpDef(name)
18+ {
19+ this->Input("x1").DataType(
20+ {ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_DOUBLE, ge::DT_UINT8, ge::DT_INT8, ge::DT_UINT16, ge::DT_INT16,
21+ ge::DT_INT32, ge::DT_INT64, ge::DT_COMPLEX64, ge::DT_COMPLEX128});
22+ this->Input("x2").DataType(
23+ {ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_DOUBLE, ge::DT_UINT8, ge::DT_INT8, ge::DT_UINT16, ge::DT_INT16,
24+ ge::DT_INT32, ge::DT_INT64, ge::DT_COMPLEX64, ge::DT_COMPLEX128});
25+ this->Output("y").DataType(
26+ {ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_DOUBLE, ge::DT_UINT8, ge::DT_INT8, ge::DT_UINT16, ge::DT_INT16,
27+ ge::DT_INT32, ge::DT_INT64, ge::DT_COMPLEX64, ge::DT_COMPLEX128});
28+ 
29+ ApplyMathAicpuDefaultCfg(*this);
30+ this->AICPU().ExtendCfgInfo(OP_INFO_FORMAT_AGNOSTIC.c_str(), TRUE_FORMAT_AGNOSTIC.c_str());
31+ this->AICPU().ExtendCfgInfo(OP_INFO_OPS_FLAG.c_str(), OPEN_OPS_FLAG.c_str());
32+ }
33+};
34+ 
35+OP_ADD(Div);
36+} // namespace ops
@@ -0,0 +1,173 @@
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+#include "gtest/gtest.h"
12+#ifndef private
13+#define private public
14+#define protected public
15+#endif
16+#include "utils/aicpu_test_utils.h"
17+#include "cpu_kernel_utils.h"
18+#include "node_def_builder.h"
19+#undef private
20+#undef protected
21+ 
22+#include <algorithm>
23+#include <cmath>
24+#include <complex>
25+#include <limits>
26+ 
27+#include "Eigen/Core"
28+ 
29+using namespace std;
30+using namespace aicpu;
31+ 
32+class TEST_DIV_UT : public testing::Test {};
33+ 
34+#define CREATE_DIV_NODEDEF(shapes, data_types, datas) \
35+ auto node_def = CpuKernelUtils::CreateNodeDef(); \
36+ NodeDefBuilder(node_def.get(), "Div", "Div") \
37+ .Input({"x1", data_types[0], shapes[0], datas[0]}) \
38+ .Input({"x2", data_types[1], shapes[1], datas[1]}) \
39+ .Output({"y", data_types[2], shapes[2], datas[2]})
40+ 
41+TEST_F(TEST_DIV_UT, IntFloorDivisionSameShape)
42+{
43+ vector<DataType> data_types = {DT_INT32, DT_INT32, DT_INT32};
44+ vector<vector<int64_t>> shapes = {{4}, {4}, {4}};
45+ int32_t input1[4] = {-7, -5, 7, 5};
46+ int32_t input2[4] = {2, -2, -2, 2};
47+ int32_t output[4] = {0};
48+ vector<void*> datas = {input1, input2, output};
49+ 
50+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
51+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
52+ 
53+ int32_t expected[4] = {-4, 2, -4, 2};
54+ EXPECT_EQ(CompareResult(output, expected, 4), true);
55+}
56+ 
57+TEST_F(TEST_DIV_UT, IntBroadcastDivScalar)
58+{
59+ vector<DataType> data_types = {DT_INT16, DT_INT16, DT_INT16};
60+ vector<vector<int64_t>> shapes = {{4}, {1}, {4}};
61+ int16_t input1[4] = {12, 5, -12, -5};
62+ int16_t input2[1] = {3};
63+ int16_t output[4] = {0};
64+ vector<void*> datas = {input1, input2, output};
65+ 
66+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
67+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
68+ 
69+ int16_t expected[4] = {4, 1, -4, -2};
70+ EXPECT_EQ(CompareResult(output, expected, 4), true);
71+}
72+ 
73+TEST_F(TEST_DIV_UT, FloatBroadcastScalarDivVector)
74+{
75+ vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT};
76+ vector<vector<int64_t>> shapes = {{1}, {4}, {4}};
77+ float input1[1] = {8.0f};
78+ float input2[4] = {16.0f, 8.0f, 4.0f, 2.0f};
79+ float output[4] = {0.0f};
80+ vector<void*> datas = {input1, input2, output};
81+ 
82+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
83+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
84+ 
85+ float expected[4] = {0.5f, 1.0f, 2.0f, 4.0f};
86+ EXPECT_EQ(CompareResult(output, expected, 4), true);
87+}
88+ 
89+TEST_F(TEST_DIV_UT, ComplexSameShape)
90+{
91+ vector<DataType> data_types = {DT_COMPLEX64, DT_COMPLEX64, DT_COMPLEX64};
92+ vector<vector<int64_t>> shapes = {{2}, {2}, {2}};
93+ std::complex<float> input1[2] = {{4.0f, 2.0f}, {3.0f, -3.0f}};
94+ std::complex<float> input2[2] = {{2.0f, 0.0f}, {1.0f, -1.0f}};
95+ std::complex<float> output[2] = {{0.0f, 0.0f}, {0.0f, 0.0f}};
96+ vector<void*> datas = {input1, input2, output};
97+ 
98+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
99+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
100+ 
101+ std::complex<float> expected[2] = {{2.0f, 1.0f}, {3.0f, 0.0f}};
102+ EXPECT_EQ(CompareResult(output, expected, 2), true);
103+}
104+ 
105+TEST_F(TEST_DIV_UT, InvalidBroadcastShape)
106+{
107+ vector<DataType> data_types = {DT_INT32, DT_INT32, DT_INT32};
108+ vector<vector<int64_t>> shapes = {{2, 2, 4}, {2, 2, 3}, {2, 2, 4}};
109+ int32_t input1[16] = {0};
110+ int32_t input2[16] = {0};
111+ int32_t output[16] = {0};
112+ std::fill_n(input1, 16, 1);
113+ std::fill_n(input2, 16, 1);
114+ vector<void*> datas = {input1, input2, output};
115+ 
116+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
117+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
118+}
119+ 
120+TEST_F(TEST_DIV_UT, IntegerZeroDivisorReturnsError)
121+{
122+ vector<DataType> data_types = {DT_UINT16, DT_UINT16, DT_UINT16};
123+ vector<vector<int64_t>> shapes = {{4}, {4}, {4}};
124+ uint16_t input1[4] = {1, 2, 3, 4};
125+ uint16_t input2[4] = {1, 0, 2, 3};
126+ uint16_t output[4] = {0};
127+ vector<void*> datas = {input1, input2, output};
128+ 
129+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
130+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_INNER_ERROR);
131+}
132+ 
133+TEST_F(TEST_DIV_UT, IntegerMinDivMinusOneReturnsErrorSameShape)
134+{
135+ vector<DataType> data_types = {DT_INT32, DT_INT32, DT_INT32};
136+ vector<vector<int64_t>> shapes = {{2}, {2}, {2}};
137+ int32_t input1[2] = {std::numeric_limits<int32_t>::min(), 8};
138+ int32_t input2[2] = {-1, 2};
139+ int32_t output[2] = {0};
140+ vector<void*> datas = {input1, input2, output};
141+ 
142+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
143+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_INNER_ERROR);
144+}
145+ 
146+TEST_F(TEST_DIV_UT, IntegerMinDivMinusOneReturnsErrorBroadcastScalar)
147+{
148+ vector<DataType> data_types = {DT_INT32, DT_INT32, DT_INT32};
149+ vector<vector<int64_t>> shapes = {{4}, {1}, {4}};
150+ int32_t input1[4] = {1, std::numeric_limits<int32_t>::min(), 3, 4};
151+ int32_t input2[1] = {-1};
152+ int32_t output[4] = {0};
153+ vector<void*> datas = {input1, input2, output};
154+ 
155+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
156+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_INNER_ERROR);
157+}
158+ 
159+TEST_F(TEST_DIV_UT, FloatZeroDivisorKeepsOkStatus)
160+{
161+ vector<DataType> data_types = {DT_FLOAT, DT_FLOAT, DT_FLOAT};
162+ vector<vector<int64_t>> shapes = {{1}, {1}, {1}};
163+ float input1[1] = {1.0f};
164+ float input2[1] = {0.0f};
165+ float output[1] = {0.0f};
166+ vector<void*> datas = {input1, input2, output};
167+ 
168+ CREATE_DIV_NODEDEF(shapes, data_types, datas);
169+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
170+ 
171+ EXPECT_TRUE(std::isinf(output[0]));
172+ EXPECT_GT(output[0], 0.0f);
173+}
@@ -89,4 +89,5 @@
89 89 
90| 调用方式 | 样例代码 | 说明 |90| 调用方式 | 样例代码 | 说明 |
91| ---------------- |------------------------------------------------------------------------------|--------------------------------------------------|91| ---------------- |------------------------------------------------------------------------------|--------------------------------------------------|
92-| aclnn接口 | [test_aclnn_all.cpp](examples/test_aclnn_all.cpp) | 通过[aclnnAll](docs/aclnnAll.md)接口方式调用ReduceAll算子。 |92+| 图模式调用 | [test_geir_reduce_all.cpp](examples/test_geir_reduce_all.cpp) | 通过GE IR图模式调用ReduceAll算子。 |
93+| aclnn调用 | [test_aclnn_all.cpp](examples/test_aclnn_all.cpp) | 通过[aclnnAll](docs/aclnnAll.md)接口方式调用ReduceAll算子。 |
@@ -0,0 +1,282 @@
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 test_geir_reduce_all.cpp
13+ * \brief Test ReduceAll via GE IR graph mode
14+ */
15+ 
16+#include <fstream>
17+#include <iostream>
18+#include <map>
19+#include <string>
20+#include <string.h>
21+#include <stdint.h>
22+#include <vector>
23+ 
24+#include "assert.h"
25+#include "array_ops.h"
26+#include "ge_api.h"
27+#include "ge_api_types.h"
28+#include "ge_error_codes.h"
29+#include "ge_ir_build.h"
30+#include "graph.h"
31+#include "tensor.h"
32+#include "types.h"
33+ 
34+#include "../op_graph/reduce_all_proto.h"
35+ 
36+#define FAILED -1
37+#define SUCCESS 0
38+ 
39+using namespace ge;
40+using std::map;
41+using std::string;
42+using std::vector;
43+ 
44+#define LOG_PRINT(message, ...) \
45+ do { \
46+ printf(message, ##__VA_ARGS__); \
47+ } while (0)
48+ 
49+string GetTime()
50+{
51+ time_t timep;
52+ time(&timep);
53+ char tmp[64];
54+ struct tm tm_info;
55+ strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime_r(&timep, &tm_info));
56+ return tmp;
57+}
58+ 
59+uint32_t GetDataTypeSize(DataType dt)
60+{
61+ if (dt == ge::DT_BOOL || dt == ge::DT_INT8 || dt == ge::DT_UINT8) {
62+ return 1;
63+ }
64+ if (dt == ge::DT_INT16 || dt == ge::DT_UINT16 || dt == ge::DT_FLOAT16 || dt == ge::DT_BF16) {
65+ return 2;
66+ }
67+ if (dt == ge::DT_INT32 || dt == ge::DT_UINT32 || dt == ge::DT_FLOAT) {
68+ return 4;
69+ }
70+ if (dt == ge::DT_INT64 || dt == ge::DT_UINT64 || dt == ge::DT_DOUBLE) {
71+ return 8;
72+ }
73+ return 0;
74+}
75+ 
76+int32_t WriteDataToFile(const string &bin_file, uint64_t data_size, const uint8_t *input_data)
77+{
78+ FILE *fp = fopen(bin_file.c_str(), "wb");
79+ if (fp == nullptr) {
80+ printf("Failed to open file: %s\n", bin_file.c_str());
81+ return FAILED;
82+ }
83+ size_t written = fwrite(input_data, sizeof(uint8_t), data_size, fp);
84+ fclose(fp);
85+ if (written != data_size) {
86+ printf("Failed to write file: %s\n", bin_file.c_str());
87+ return FAILED;
88+ }
89+ return SUCCESS;
90+}
91+ 
92+int32_t GenBoolData(const vector<int64_t> &shapes, Tensor &input_tensor, TensorDesc &input_tensor_desc,
93+ const vector<bool> &values)
94+{
95+ input_tensor_desc.SetRealDimCnt(shapes.size());
96+ size_t size = 1;
97+ for (size_t i = 0; i < shapes.size(); ++i) {
98+ size *= static_cast<size_t>(shapes[i]);
99+ }
100+ if (values.size() != size) {
101+ return FAILED;
102+ }
103+ 
104+ vector<uint8_t> raw_data(size);
105+ for (size_t i = 0; i < size; ++i) {
106+ raw_data[i] = static_cast<uint8_t>(values[i]);
107+ }
108+ input_tensor = Tensor(input_tensor_desc, raw_data.data(), raw_data.size());
109+ return SUCCESS;
110+}
111+ 
112+int32_t GenInt32Data(const vector<int64_t> &shapes, Tensor &input_tensor, TensorDesc &input_tensor_desc,
113+ const vector<int32_t> &values)
114+{
115+ input_tensor_desc.SetRealDimCnt(shapes.size());
116+ size_t size = 1;
117+ for (size_t i = 0; i < shapes.size(); ++i) {
118+ size *= static_cast<size_t>(shapes[i]);
119+ }
120+ if (values.size() != size) {
121+ return FAILED;
122+ }
123+ 
124+ input_tensor = Tensor(input_tensor_desc, reinterpret_cast<const uint8_t *>(values.data()),
125+ values.size() * sizeof(int32_t));
126+ return SUCCESS;
127+}
128+ 
129+int CreateOppInGraph(vector<ge::Tensor> &input, vector<Operator> &inputs, vector<Operator> &outputs, Graph &graph)
130+{
131+ Status ret = SUCCESS;
132+ auto reduce_all = op::ReduceAll("reduce_all_graph");
133+ vector<int64_t> x_shape = {2, 3};
134+ vector<int64_t> axes_shape = {1};
135+ vector<int64_t> y_shape = {2};
136+ 
137+ auto x = op::Data("placeholder0").set_attr_index(0);
138+ TensorDesc x_desc(ge::Shape(x_shape), FORMAT_ND, DT_BOOL);
139+ x_desc.SetPlacement(ge::kPlacementHost);
140+ x_desc.SetFormat(FORMAT_ND);
141+ Tensor x_tensor;
142+ ret = GenBoolData(x_shape, x_tensor, x_desc, {true, true, false, true, true, true});
143+ if (ret != SUCCESS) {
144+ printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str());
145+ return FAILED;
146+ }
147+ x.update_input_desc_x(x_desc);
148+ x.update_output_desc_y(x_desc);
149+ input.push_back(x_tensor);
150+ graph.AddOp(x);
151+ reduce_all.set_input_x(x);
152+ inputs.push_back(x);
153+ 
154+ auto axes = op::Data("placeholder1").set_attr_index(1);
155+ TensorDesc axes_desc(ge::Shape(axes_shape), FORMAT_ND, DT_INT32);
156+ axes_desc.SetPlacement(ge::kPlacementHost);
157+ axes_desc.SetFormat(FORMAT_ND);
158+ Tensor axes_tensor;
159+ ret = GenInt32Data(axes_shape, axes_tensor, axes_desc, {1});
160+ if (ret != SUCCESS) {
161+ printf("%s - ERROR - [XIR]: Generate axes data failed\n", GetTime().c_str());
162+ return FAILED;
163+ }
164+ axes.update_input_desc_x(axes_desc);
165+ axes.update_output_desc_y(axes_desc);
166+ input.push_back(axes_tensor);
167+ graph.AddOp(axes);
168+ reduce_all.set_input_axes(axes);
169+ reduce_all.update_input_desc_axes(axes_desc);
170+ inputs.push_back(axes);
171+ 
172+ TensorDesc y_desc(ge::Shape(y_shape), FORMAT_ND, DT_BOOL);
173+ reduce_all.update_output_desc_y(y_desc);
174+ reduce_all.set_attr_keep_dims(false);
175+ outputs.push_back(reduce_all);
176+ return SUCCESS;
177+}
178+ 
179+int SaveInputOutput(const vector<ge::Tensor> &input, const vector<ge::Tensor> &output)
180+{
181+ for (size_t i = 0; i < input.size(); ++i) {
182+ string input_file = "./tc_ge_irrun_reduce_all_npu_input_" + std::to_string(i) + ".bin";
183+ const uint8_t *input_data = input[i].GetData();
184+ int64_t input_shape = input[i].GetTensorDesc().GetShape().GetShapeSize();
185+ uint32_t data_size = input_shape * GetDataTypeSize(input[i].GetTensorDesc().GetDataType());
186+ if (WriteDataToFile(input_file, data_size, input_data) != SUCCESS) {
187+ return FAILED;
188+ }
189+ }
190+ 
191+ const bool expected[] = {false, true};
192+ for (size_t i = 0; i < output.size(); ++i) {
193+ string output_file = "./tc_ge_irrun_reduce_all_npu_output_" + std::to_string(i) + ".bin";
194+ const uint8_t *output_data = output[i].GetData();
195+ int64_t output_shape = output[i].GetTensorDesc().GetShape().GetShapeSize();
196+ uint32_t data_size = output_shape * GetDataTypeSize(output[i].GetTensorDesc().GetDataType());
197+ if (WriteDataToFile(output_file, data_size, output_data) != SUCCESS) {
198+ return FAILED;
199+ }
200+ const bool *result_data = reinterpret_cast<const bool *>(output_data);
201+ for (int64_t j = 0; j < output_shape; ++j) {
202+ LOG_PRINT("result[%ld] is: %u\n", j, static_cast<unsigned int>(result_data[j]));
203+ if (result_data[j] != expected[j]) {
204+ printf("ReduceAll output mismatch at index %ld\n", j);
205+ return FAILED;
206+ }
207+ }
208+ }
209+ return SUCCESS;
210+}
211+ 
212+int main(int argc, char *argv[])
213+{
214+ (void)argc;
215+ (void)argv;
216+ 
217+ const char *graph_name = "tc_ge_irrun_reduce_all";
218+ Graph graph(graph_name);
219+ vector<ge::Tensor> input;
220+ 
221+ printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str());
222+ map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
223+ Status ret = ge::GEInitialize(global_options);
224+ if (ret != SUCCESS) {
225+ printf("%s - ERROR - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str());
226+ return FAILED;
227+ }
228+ 
229+ vector<Operator> inputs;
230+ vector<Operator> outputs;
231+ ret = CreateOppInGraph(input, inputs, outputs, graph);
232+ if (ret != SUCCESS) {
233+ ge::GEFinalize();
234+ return FAILED;
235+ }
236+ 
237+ if (!inputs.empty() && !outputs.empty()) {
238+ graph.SetInputs(inputs).SetOutputs(outputs);
239+ }
240+ 
241+ map<AscendString, AscendString> build_options;
242+ ge::Session *session = new (std::nothrow) Session(build_options);
243+ if (session == nullptr) {
244+ printf("%s - ERROR - [XIR]: Create ir session failed\n", GetTime().c_str());
245+ ge::GEFinalize();
246+ return FAILED;
247+ }
248+ 
249+ map<AscendString, AscendString> graph_options = {{"ge.exec.precision_mode", "allow_mix_precision"}};
250+ uint32_t graph_id = 0;
251+ ret = session->AddGraph(graph_id, graph, graph_options);
252+ if (ret != SUCCESS) {
253+ printf("%s - ERROR - [XIR]: Add graph failed\n", GetTime().c_str());
254+ delete session;
255+ ge::GEFinalize();
256+ return FAILED;
257+ }
258+ 
259+ vector<ge::Tensor> output;
260+ ret = session->RunGraph(graph_id, input, output);
261+ if (ret != SUCCESS) {
262+ printf("%s - ERROR - [XIR]: Run graph failed\n", GetTime().c_str());
263+ delete session;
264+ ge::GEFinalize();
265+ return FAILED;
266+ }
267+ 
268+ ret = SaveInputOutput(input, output);
269+ delete session;
270+ if (ret != SUCCESS) {
271+ ge::GEFinalize();
272+ return FAILED;
273+ }
274+ 
275+ ret = ge::GEFinalize();
276+ if (ret != SUCCESS) {
277+ printf("%s - ERROR - [XIR]: GE Finalize failed\n", GetTime().c_str());
278+ return FAILED;
279+ }
280+ 
281+ return SUCCESS;
282+}
@@ -0,0 +1,254 @@
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+#include "reduce_all_aicpu.h"
12+ 
13+#include <map>
14+#include <vector>
15+ 
16+#include "cpu_kernel_utils.h"
17+#include "log.h"
18+#include "utils/kernel_util.h"
19+ 
20+namespace {
21+constexpr uint32_t kReduceAllInputNum = 1;
22+constexpr uint32_t kReduceAllOutputNum = 1;
23+const char *const kReduceAll = "ReduceAll";
24+}
25+ 
26+namespace aicpu {
27+uint32_t ReduceAllCpuKernel::GenDataNoAxis(const CpuKernelContext &ctx) const
28+{
29+ auto x_data = reinterpret_cast<bool *>(ctx.Input(kFirstInputIndex)->GetData());
30+ auto y_data = reinterpret_cast<bool *>(ctx.Output(kFirstOutputIndex)->GetData());
31+ int64_t input_data_size = ctx.Input(kFirstInputIndex)->NumElements();
32+ bool output_y = true;
33+ for (int64_t i = 0; i < input_data_size; ++i) {
34+ output_y = output_y && x_data[i];
35+ }
36+ y_data[0] = output_y;
37+ return KERNEL_STATUS_OK;
38+}
39+ 
40+template <typename T>
41+uint32_t ReduceAllCpuKernel::AxisCal(
42+ T axis, const std::vector<int64_t> &data_dims, int64_t &head_dim, int64_t &end_dim) const
43+{
44+ bool axis_appear = false;
45+ size_t data_dims_size = data_dims.size();
46+ for (size_t i = 0; i < data_dims_size; i++) {
47+ if (static_cast<T>(i) == axis) {
48+ axis_appear = true;
49+ continue;
50+ }
51+ if (axis_appear) {
52+ if (data_dims[i] != 0 && end_dim > (INT64_MAX / data_dims[i])) {
53+ KERNEL_LOG_ERROR("Product is overflow. multiplier 1: %ld. multiplier 2: %ld.", end_dim, data_dims[i]);
54+ return KERNEL_STATUS_PARAM_INVALID;
55+ }
56+ end_dim *= data_dims[i];
57+ } else {
58+ if (data_dims[i] != 0 && head_dim > (INT64_MAX / data_dims[i])) {
59+ KERNEL_LOG_ERROR(
60+ "Product is overflow. multiplier 1: %ld. multiplier 2: %ld.", head_dim, data_dims[i]);
61+ return KERNEL_STATUS_PARAM_INVALID;
62+ }
63+ head_dim *= data_dims[i];
64+ }
65+ }
66+ return KERNEL_STATUS_OK;
67+}
68+ 
69+template <typename T>
70+std::vector<int64_t> ReduceAllCpuKernel::GetOutputShape(const std::vector<int64_t> &input_shape, const T &axis)
71+{
72+ std::vector<int64_t> output_shape;
73+ for (size_t i = 0; i < input_shape.size(); ++i) {
74+ if (static_cast<T>(i) == axis) {
75+ if (keep_dims_) {
76+ output_shape.push_back(1);
77+ }
78+ continue;
79+ }
80+ output_shape.push_back(input_shape[i]);
81+ }
82+ return output_shape;
83+}
84+ 
85+template <typename T>
86+uint32_t ReduceAllCpuKernel::AxesRankCheckAndReverse(
87+ const CpuKernelContext &ctx, const T *axis_data, const int64_t &axes_num, std::map<T, int64_t> &axis_map,
88+ int32_t &rank)
89+{
90+ T axis_temp = 0;
91+ rank = static_cast<T>(rank);
92+ for (int64_t i = 0; i < axes_num; i++) {
93+ if (axis_data[i] < -rank || axis_data[i] > (rank - 1)) {
94+ KERNEL_LOG_ERROR(
95+ "[%s] the value of axes should be in [-%d, %d], axes is %ld", ctx.GetOpType().c_str(), rank, rank,
96+ static_cast<int64_t>(axis_data[i]));
97+ return KERNEL_STATUS_PARAM_INVALID;
98+ }
99+ if (axis_data[i] < 0) {
100+ axis_temp = axis_data[i] + rank;
101+ } else {
102+ axis_temp = axis_data[i];
103+ }
104+ if (axis_map.find(axis_temp) != axis_map.end()) {
105+ KERNEL_LOG_ERROR(
106+ "[%s] invalid reduction arguments: axes contains duplicate dimension: %ld", ctx.GetOpType().c_str(),
107+ static_cast<int64_t>(axis_temp));
108+ return KERNEL_STATUS_PARAM_INVALID;
109+ }
110+ axis_map.emplace(std::pair<T, int64_t>(axis_temp, i));
111+ }
112+ return KERNEL_STATUS_OK;
113+}
114+ 
115+template <typename T, typename T2>
116+uint32_t ReduceAllCpuKernel::ReduceAllOneAxes(
117+ const T *input_data, std::vector<int64_t> &input_dims, T *output_data, const int64_t &output_num,
118+ std::vector<T2> &axes)
119+{
120+ if (axes_idx_ >= axes.size()) {
121+ for (int64_t i = 0; i < output_num; i++) {
122+ output_data[i] = input_data[i];
123+ }
124+ return KERNEL_STATUS_OK;
125+ }
126+ int64_t head_dim = 1;
127+ int64_t end_dim = 1;
128+ uint32_t ret = AxisCal<T2>(axes[axes_idx_], input_dims, head_dim, end_dim);
129+ if (ret != KERNEL_STATUS_OK) {
130+ return KERNEL_STATUS_PARAM_INVALID;
131+ }
132+ auto *output_data_temp = new (std::nothrow) T[head_dim * end_dim];
133+ KERNEL_CHECK_NULLPTR(output_data_temp, KERNEL_STATUS_INNER_ERROR, "apply memory failed.");
134+ bool tmp_x = true;
135+ bool tmp_y = true;
136+ auto axis_dim = input_dims[axes[axes_idx_]];
137+ for (int64_t i = 0; i < head_dim; ++i) {
138+ for (int64_t j = 0; j < end_dim; ++j) {
139+ tmp_x = input_data[i * end_dim * axis_dim + j];
140+ for (int64_t k = 1; k < axis_dim; ++k) {
141+ tmp_y = input_data[i * end_dim * axis_dim + j + k * end_dim];
142+ tmp_x = tmp_x && tmp_y;
143+ }
144+ output_data_temp[i * end_dim + j] = tmp_x;
145+ }
146+ }
147+ input_dims = GetOutputShape<T2>(input_dims, axes[axes_idx_]);
148+ ++axes_idx_;
149+ uint32_t result = ReduceAllOneAxes<T, T2>(output_data_temp, input_dims, output_data, output_num, axes);
150+ delete[] output_data_temp;
151+ return result;
152+}
153+ 
154+template <typename T, typename T2>
155+uint32_t ReduceAllCpuKernel::ReduceAllCompute(const CpuKernelContext &ctx)
156+{
157+ axes_idx_ = 0;
158+ Tensor *x = ctx.Input(kFirstInputIndex);
159+ Tensor *axes = ctx.Input(kSecondInputIndex);
160+ Tensor *y = ctx.Output(kFirstInputIndex);
161+ 
162+ auto *output_data = reinterpret_cast<T *>(y->GetData());
163+ auto *keep_dims = ctx.GetAttr("keep_dims");
164+ KERNEL_CHECK_NULLPTR(keep_dims, KERNEL_STATUS_PARAM_INVALID, "Get attr [keep_dims] failed.");
165+ keep_dims_ = keep_dims->GetBool();
166+ int64_t output_num = y->NumElements();
167+ 
168+ if (x->GetDataSize() == 0) {
169+ KERNEL_LOG_INFO("[%s] Input is empty tensor.", ctx.GetOpType().c_str());
170+ if (output_num > 0) {
171+ for (int64_t i = 0; i < output_num; ++i) {
172+ output_data[i] = true;
173+ }
174+ }
175+ return KERNEL_STATUS_OK;
176+ }
177+ 
178+ if (axes == nullptr || axes->GetDataSize() == 0) {
179+ return GenDataNoAxis(ctx);
180+ }
181+ 
182+ auto *input_data = reinterpret_cast<T *>(x->GetData());
183+ auto *axis_data = reinterpret_cast<T2 *>(axes->GetData());
184+ int64_t axes_num = axes->GetTensorShape()->NumElements();
185+ std::vector<int64_t> input_dims = x->GetTensorShape()->GetDimSizes();
186+ int32_t rank = x->GetTensorShape()->GetDims();
187+ std::map<T2, int64_t> axis_map;
188+ 
189+ if (AxesRankCheckAndReverse<T2>(ctx, axis_data, axes_num, axis_map, rank) != KERNEL_STATUS_OK) {
190+ return KERNEL_STATUS_PARAM_INVALID;
191+ }
192+ std::vector<T2> axes_data;
193+ for (auto iter = axis_map.rbegin(); iter != axis_map.rend(); iter++) {
194+ axes_data.push_back((*iter).first);
195+ }
196+ 
197+ uint32_t res = ReduceAllOneAxes<T, T2>(input_data, input_dims, output_data, output_num, axes_data);
198+ if (res != KERNEL_STATUS_OK) {
199+ return KERNEL_STATUS_PARAM_INVALID;
200+ }
201+ return KERNEL_STATUS_OK;
202+}
203+ 
204+uint32_t ReduceAllCpuKernel::ReduceAllCheck(const CpuKernelContext &ctx) const
205+{
206+ auto *x = ctx.Input(kFirstInputIndex);
207+ auto *axes = ctx.Input(kSecondInputIndex);
208+ if (x != nullptr && x->GetData() != nullptr) {
209+ KERNEL_CHECK_FALSE(
210+ (x->GetDataType() == DT_BOOL), KERNEL_STATUS_PARAM_INVALID,
211+ "Data type of x is not support, x data type is [%u].", static_cast<uint32_t>(x->GetDataType()));
212+ }
213+ if (axes != nullptr && axes->GetData() != nullptr) {
214+ KERNEL_CHECK_FALSE(
215+ (axes->GetDataType() == DT_INT32 || axes->GetDataType() == DT_INT64), KERNEL_STATUS_PARAM_INVALID,
216+ "Data type of axis is not support, axis data type is [%u].",
217+ static_cast<uint32_t>(axes->GetDataType()));
218+ }
219+ return KERNEL_STATUS_OK;
220+}
221+ 
222+uint32_t ReduceAllCpuKernel::Compute(CpuKernelContext &ctx)
223+{
224+ KERNEL_HANDLE_ERROR(NormalCheck(ctx, kReduceAllInputNum, kReduceAllOutputNum),
225+ "[%s] check input and output failed.", kReduceAll);
226+ KERNEL_HANDLE_ERROR(ReduceAllCheck(ctx), "[%s] check params failed.", kReduceAll);
227+ 
228+ Tensor *axes = ctx.Input(kSecondInputIndex);
229+ if (axes == nullptr || axes->GetDataSize() == 0) {
230+ return ReduceAllCompute<bool, int32_t>(ctx);
231+ }
232+ 
233+ auto axes_data_type = axes->GetDataType();
234+ uint32_t ret = KERNEL_STATUS_PARAM_INVALID;
235+ switch (axes_data_type) {
236+ case DT_INT32:
237+ ret = ReduceAllCompute<bool, int32_t>(ctx);
238+ break;
239+ case DT_INT64:
240+ ret = ReduceAllCompute<bool, int64_t>(ctx);
241+ break;
242+ default:
243+ KERNEL_LOG_ERROR("Data type not support[%s].", DTypeStr(axes_data_type).c_str());
244+ return KERNEL_STATUS_PARAM_INVALID;
245+ }
246+ 
247+ if (ret != KERNEL_STATUS_OK) {
248+ return KERNEL_STATUS_PARAM_INVALID;
249+ }
250+ return ret;
251+}
252+ 
253+REGISTER_CPU_KERNEL(kReduceAll, ReduceAllCpuKernel);
254+} // namespace aicpu
@@ -0,0 +1,56 @@
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+#ifndef AICPU_KERNELS_NORMALIZED_REDUCE_ALL_AICPU_H
12+#define AICPU_KERNELS_NORMALIZED_REDUCE_ALL_AICPU_H
13+ 
14+#include <map>
15+#include <vector>
16+ 
17+#include "cpu_kernel.h"
18+ 
19+namespace aicpu {
20+class ReduceAllCpuKernel : public CpuKernel {
21+public:
22+ ReduceAllCpuKernel() = default;
23+ ~ReduceAllCpuKernel() override = default;
24+ 
25+ uint32_t Compute(CpuKernelContext &ctx) override;
26+ 
27+private:
28+ template <typename T, typename T2>
29+ uint32_t ReduceAllCompute(const CpuKernelContext &ctx);
30+ 
31+ uint32_t GenDataNoAxis(const CpuKernelContext &ctx) const;
32+ 
33+ template <typename T>
34+ uint32_t AxisCal(T axis, const std::vector<int64_t> &data_dims, int64_t &head_dim, int64_t &end_dim) const;
35+ 
36+ template <typename T, typename T2>
37+ uint32_t ReduceAllOneAxes(
38+ const T *input_data, std::vector<int64_t> &input_dims, T *output_data, const int64_t &output_num,
39+ std::vector<T2> &axes);
40+ 
41+ template <typename T>
42+ std::vector<int64_t> GetOutputShape(const std::vector<int64_t> &input_shape, const T &axis);
43+ 
44+ template <typename T>
45+ uint32_t AxesRankCheckAndReverse(
46+ const CpuKernelContext &ctx, const T *axis_data, const int64_t &axes_num, std::map<T, int64_t> &axis_map,
47+ int32_t &rank);
48+ 
49+ uint32_t ReduceAllCheck(const CpuKernelContext &ctx) const;
50+ 
51+ bool keep_dims_ = false;
52+ size_t axes_idx_ = 0;
53+};
54+} // namespace aicpu
55+ 
56+#endif
@@ -0,0 +1,29 @@
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+#include "register/op_def_registry.h"
12+#include "../../../common/inc/aicpu/aicpu_op_def.h"
13+ 
14+namespace ops {
15+class ReduceAll : public OpDef {
16+public:
17+ explicit ReduceAll(const char *name) : OpDef(name)
18+ {
19+ this->Input("x").DataType({ge::DT_BOOL});
20+ this->Input("axes").DataType({ge::DT_INT32, ge::DT_INT64});
21+ this->Output("y").DataType({ge::DT_BOOL});
22+ 
23+ ApplyMathAicpuDefaultCfg(*this);
24+ this->AICPU().ExtendCfgInfo(OP_INFO_OPS_FLAG.c_str(), OPEN_OPS_FLAG.c_str());
25+ }
26+};
27+ 
28+OP_ADD(ReduceAll);
29+} // namespace ops
@@ -0,0 +1,109 @@
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+#include "gtest/gtest.h"
12+#ifndef private
13+#define private public
14+#define protected public
15+#endif
16+#include "utils/aicpu_test_utils.h"
17+#include "cpu_kernel_utils.h"
18+#include "node_def_builder.h"
19+#undef private
20+#undef protected
21+ 
22+using namespace std;
23+using namespace aicpu;
24+ 
25+class TEST_REDUCE_ALL_UT : public testing::Test {};
26+ 
27+#define CREATE_NODEDEF(shapes, data_types, datas, keep_dims) \
28+ auto node_def = CpuKernelUtils::CreateNodeDef(); \
29+ NodeDefBuilder(node_def.get(), "ReduceAll", "ReduceAll") \
30+ .Input({"x", data_types[0], shapes[0], datas[0]}) \
31+ .Input({"axes", data_types[1], shapes[1], datas[1]}) \
32+ .Output({"y", data_types[2], shapes[2], datas[2]}) \
33+ .Attr("keep_dims", keep_dims)
34+ 
35+TEST_F(TEST_REDUCE_ALL_UT, ReduceSingleAxisInt32)
36+{
37+ vector<DataType> data_types = {DT_BOOL, DT_INT32, DT_BOOL};
38+ vector<vector<int64_t>> shapes = {{2, 3}, {1}, {2}};
39+ bool input[6] = {true, true, false, true, true, true};
40+ int32_t axes[1] = {1};
41+ bool output[2] = {false, false};
42+ vector<void *> datas = {(void *)input, (void *)axes, (void *)output};
43+ 
44+ CREATE_NODEDEF(shapes, data_types, datas, false);
45+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
46+ 
47+ bool expected[2] = {false, true};
48+ EXPECT_EQ(CompareResult<bool>(output, expected, 2), true);
49+}
50+ 
51+TEST_F(TEST_REDUCE_ALL_UT, ReduceMultiAxisInt64KeepDims)
52+{
53+ vector<DataType> data_types = {DT_BOOL, DT_INT64, DT_BOOL};
54+ vector<vector<int64_t>> shapes = {{2, 2, 2}, {2}, {1, 2, 1}};
55+ bool input[8] = {true, true, true, false, true, true, true, true};
56+ int64_t axes[2] = {0, -1};
57+ bool output[2] = {false, false};
58+ vector<void *> datas = {(void *)input, (void *)axes, (void *)output};
59+ 
60+ CREATE_NODEDEF(shapes, data_types, datas, true);
61+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
62+ 
63+ bool expected[2] = {true, false};
64+ EXPECT_EQ(CompareResult<bool>(output, expected, 2), true);
65+}
66+ 
67+TEST_F(TEST_REDUCE_ALL_UT, EmptyAxesReduceAll)
68+{
69+ vector<DataType> data_types = {DT_BOOL, DT_INT32, DT_BOOL};
70+ vector<vector<int64_t>> shapes = {{2, 2}, {}, {}};
71+ bool input[4] = {true, true, true, false};
72+ bool output[1] = {true};
73+ vector<void *> datas = {(void *)input, nullptr, (void *)output};
74+ 
75+ CREATE_NODEDEF(shapes, data_types, datas, false);
76+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
77+ 
78+ bool expected[1] = {false};
79+ EXPECT_EQ(CompareResult<bool>(output, expected, 1), true);
80+}
81+ 
82+TEST_F(TEST_REDUCE_ALL_UT, EmptyInputKeepDims)
83+{
84+ vector<DataType> data_types = {DT_BOOL, DT_INT32, DT_BOOL};
85+ vector<vector<int64_t>> shapes = {{2, 0, 3}, {1}, {2, 1, 3}};
86+ bool input[1] = {false};
87+ int32_t axes[1] = {1};
88+ bool output[6] = {false, false, false, false, false, false};
89+ vector<void *> datas = {(void *)input, (void *)axes, (void *)output};
90+ 
91+ CREATE_NODEDEF(shapes, data_types, datas, true);
92+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
93+ 
94+ bool expected[6] = {true, true, true, true, true, true};
95+ EXPECT_EQ(CompareResult<bool>(output, expected, 6), true);
96+}
97+ 
98+TEST_F(TEST_REDUCE_ALL_UT, AxisOutOfRange)
99+{
100+ vector<DataType> data_types = {DT_BOOL, DT_INT32, DT_BOOL};
101+ vector<vector<int64_t>> shapes = {{2, 2}, {1}, {2}};
102+ bool input[4] = {true, true, false, true};
103+ int32_t axes[1] = {2};
104+ bool output[2] = {false, false};
105+ vector<void *> datas = {(void *)input, (void *)axes, (void *)output};
106+ 
107+ CREATE_NODEDEF(shapes, data_types, datas, false);
108+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
109+}