已合并
[PR1/3] migrate transdata aicpu kernel: kernel impl + format_transfer base + basic UT #4113
[PR1/3] migrate transdata aicpu kernel: kernel impl + format_transfer base + basic UT #4113
已合并
pantong创建于 7月16日
10 个文件变更+1495-16
Mcmake/symbol.cmake+16-15
@@ -86,7 +86,7 @@ function(merge_graph_headers)
86endfunction()86endfunction()
87 87 
88function(gen_es_math_lib_ready)88function(gen_es_math_lib_ready)
89- # 合并proto.h生成ops_proto_math.h和ops_proto_math.cpp 89+ # 合并proto.h生成ops_proto_math.h和ops_proto_math.cpp
90 merge_graph_headers(TARGET merge_ops_proto_${PKG_NAME} OUT_DIR ${ASCEND_GRAPH_CONF_DST})90 merge_graph_headers(TARGET merge_ops_proto_${PKG_NAME} OUT_DIR ${ASCEND_GRAPH_CONF_DST})
91 add_library(91 add_library(
92 proto_${PKG_NAME} SHARED92 proto_${PKG_NAME} SHARED
@@ -103,7 +103,7 @@ function(gen_es_math_lib_ready)
103 )103 )
104 target_link_directories(proto_${PKG_NAME} PRIVATE ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64)104 target_link_directories(proto_${PKG_NAME} PRIVATE ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64)
105 105 
106- # 生成 es_math 106+ # 生成 es_math
107 add_es_library_and_whl(107 add_es_library_and_whl(
108 ES_LINKABLE_AND_ALL_TARGET es_${PKG_NAME}108 ES_LINKABLE_AND_ALL_TARGET es_${PKG_NAME}
109 OPP_PROTO_TARGET proto_${PKG_NAME}109 OPP_PROTO_TARGET proto_${PKG_NAME}
@@ -146,7 +146,7 @@ function(gen_es_math_lib_ready_cust)
146 )146 )
147 target_link_directories(proto_${PKG_NAME}_cust PRIVATE ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64)147 target_link_directories(proto_${PKG_NAME}_cust PRIVATE ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64)
148 148 
149- # 生成 es_math 149+ # 生成 es_math
150 add_es_library(150 add_es_library(
151 ES_LINKABLE_AND_ALL_TARGET es_${PKG_NAME}151 ES_LINKABLE_AND_ALL_TARGET es_${PKG_NAME}
152 OPP_PROTO_TARGET proto_${PKG_NAME}_cust152 OPP_PROTO_TARGET proto_${PKG_NAME}_cust
@@ -180,17 +180,17 @@ function(gen_opgraph_symbol)
180 add_library(180 add_library(
181 ${OPGRAPH_NAME} SHARED181 ${OPGRAPH_NAME} SHARED
182 $<$<TARGET_EXISTS:${GRAPH_PLUGIN_NAME}_obj>:$<TARGET_OBJECTS:${GRAPH_PLUGIN_NAME}_obj>>182 $<$<TARGET_EXISTS:${GRAPH_PLUGIN_NAME}_obj>:$<TARGET_OBJECTS:${GRAPH_PLUGIN_NAME}_obj>>
183- $<$<TARGET_EXISTS:opbase_util_objs>:$<TARGET_OBJECTS:opbase_util_objs>> 183+ $<$<TARGET_EXISTS:opbase_util_objs>:$<TARGET_OBJECTS:opbase_util_objs>>
184 $<$<TARGET_EXISTS:opbase_infer_objs>:$<TARGET_OBJECTS:opbase_infer_objs>>184 $<$<TARGET_EXISTS:opbase_infer_objs>:$<TARGET_OBJECTS:opbase_infer_objs>>
185 )185 )
186 add_dependencies(${OPGRAPH_NAME} merge_ops_proto_${PKG_NAME})186 add_dependencies(${OPGRAPH_NAME} merge_ops_proto_${PKG_NAME})
187 187 
188- target_sources( 188+ target_sources(
189- ${OPGRAPH_NAME} 189+ ${OPGRAPH_NAME}
190- PRIVATE 190+ PRIVATE
191- ${ASCEND_GRAPH_CONF_DST}/ops_proto_math.cpp 191+ ${ASCEND_GRAPH_CONF_DST}/ops_proto_math.cpp
192 )192 )
193- 193+ 
194 target_link_libraries(194 target_link_libraries(
195 ${OPGRAPH_NAME}195 ${OPGRAPH_NAME}
196 PRIVATE $<BUILD_INTERFACE:intf_pub_cxx17>196 PRIVATE $<BUILD_INTERFACE:intf_pub_cxx17>
@@ -205,12 +205,12 @@ function(gen_opgraph_symbol)
205 -Wl,-Bsymbolic205 -Wl,-Bsymbolic
206 ge_compiler206 ge_compiler
207 )207 )
208- 208+ 
209- target_link_directories(${OPGRAPH_NAME} PRIVATE 209+ target_link_directories(${OPGRAPH_NAME} PRIVATE
210 ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64210 ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64
211 ${CMAKE_BINARY_DIR}/es_packages/lib64211 ${CMAKE_BINARY_DIR}/es_packages/lib64
212 )212 )
213- set_target_properties(${OPGRAPH_NAME} PROPERTIES 213+ set_target_properties(${OPGRAPH_NAME} PROPERTIES
214 LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/opp/built-in/op_proto214 LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/opp/built-in/op_proto
215 )215 )
216 216 
@@ -332,7 +332,7 @@ function(gen_cust_proto_symbol)
332 $<$<TARGET_EXISTS:opbase_util_objs>:$<TARGET_OBJECTS:opbase_util_objs>>332 $<$<TARGET_EXISTS:opbase_util_objs>:$<TARGET_OBJECTS:opbase_util_objs>>
333 $<$<TARGET_EXISTS:opbase_infer_objs>:$<TARGET_OBJECTS:opbase_infer_objs>>333 $<$<TARGET_EXISTS:opbase_infer_objs>:$<TARGET_OBJECTS:opbase_infer_objs>>
334 )334 )
335- 335+ 
336 target_link_libraries(336 target_link_libraries(
337 cust_proto337 cust_proto
338 PUBLIC $<BUILD_INTERFACE:intf_pub_cxx17>338 PUBLIC $<BUILD_INTERFACE:intf_pub_cxx17>
@@ -460,6 +460,7 @@ function(gen_aicpu_kernel_symbol enable_built_in)
460 -o ${ARM_SO_OUTPUT}460 -o ${ARM_SO_OUTPUT}
461 DEPENDS ${AICPU_CUST_OBJ_TARGETS}461 DEPENDS ${AICPU_CUST_OBJ_TARGETS}
462 COMMENT "Linking aicpu_kernels.so using ARM toolchain"462 COMMENT "Linking aicpu_kernels.so using ARM toolchain"
463+ COMMAND_EXPAND_LISTS
463 )464 )
464 465 
465 add_custom_target(aicpu_kernels ALL DEPENDS ${ARM_SO_OUTPUT})466 add_custom_target(aicpu_kernels ALL DEPENDS ${ARM_SO_OUTPUT})
@@ -619,7 +620,7 @@ function(gen_norm_symbol)
619 gen_opapi_symbol()620 gen_opapi_symbol()
620 621 
621 gen_onnx_plugin_symbol()622 gen_onnx_plugin_symbol()
622- 623+ 
623 gen_tf_plugin_symbol()624 gen_tf_plugin_symbol()
624 625 
625 gen_aicpu_const_symbol()626 gen_aicpu_const_symbol()
@@ -637,4 +638,4 @@ function(gen_cust_symbol)
637 gen_aicpu_json_symbol(FALSE)638 gen_aicpu_json_symbol(FALSE)
638 639 
639 gen_aicpu_kernel_symbol(FALSE)640 gen_aicpu_kernel_symbol(FALSE)
640-endfunction()641+endfunction()
Mconversion/trans_data/CMakeLists.txt+15-1
@@ -13,4 +13,18 @@
13set(SUPPORT_COMPUTE_UNIT "ascend950")13set(SUPPORT_COMPUTE_UNIT "ascend950")
14# 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译14# 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译
15set(SUPPORT_TILING_DIR "arch35")15set(SUPPORT_TILING_DIR "arch35")
16-add_all_modules_sources(OPTYPE trans_data ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE)16+add_all_modules_sources(OPTYPE trans_data ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE)
17+ 
18+# format_transfer 辅助源文件不匹配 *_aicpu.cpp glob,需显式追加到已创建的 OBJECT 目标
19+file(GLOB TRANS_DATA_FT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/op_kernel_aicpu/format_transfer/*.cpp)
20+if(TRANS_DATA_FT_SRCS)
21+ if(TARGET ${OPHOST_NAME}_aicpu_obj)
22+ target_sources(${OPHOST_NAME}_aicpu_obj PRIVATE ${TRANS_DATA_FT_SRCS})
23+ endif()
24+ if(TARGET trans_data_obj)
25+ target_sources(trans_data_obj PRIVATE ${TRANS_DATA_FT_SRCS})
26+ endif()
27+ if(TARGET trans_data_cases_obj)
28+ target_sources(trans_data_cases_obj PRIVATE ${TRANS_DATA_FT_SRCS})
29+ endif()
30+endif()
Aconversion/trans_data/op_kernel_aicpu/format_transfer/format_transfer_utils.cpp+318-0
@@ -0,0 +1,318 @@
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 "format_transfer_utils.h"
12+ 
13+#include "formats_definitions.h"
14+#include "kernel_util.h"
15+#include "securec.h"
16+#include "log.h"
17+#include "graph/types.h"
18+ 
19+using namespace std;
20+using namespace ge;
21+ 
22+namespace aicpu {
23+namespace formats {
24+bool IsShapeValid(const vector<int64_t>& shape)
25+{
26+ if (shape.empty()) {
27+ return false;
28+ }
29+ int64_t num = 1;
30+ for (auto dim : shape) {
31+ if (dim < 0) {
32+ string error = "Invalid negative dims in the shape " + FmtToStr(VectorToString(shape));
33+ KERNEL_LOG_ERROR("%s", error.c_str());
34+ return false;
35+ }
36+ if (dim != 0 && kShapeItemNumMAX / dim < num) {
37+ string error = "Shape overflow, the total count should be less than " + FmtToStr(kShapeItemNumMAX);
38+ KERNEL_LOG_ERROR("%s", error.c_str());
39+ return false;
40+ }
41+ num *= dim;
42+ }
43+ return true;
44+}
45+ 
46+bool CheckShapeValid(const vector<int64_t>& shape, const int64_t expect_dims)
47+{
48+ if (expect_dims <= 0 || shape.size() != static_cast<size_t>(expect_dims)) {
49+ string error = "Invalid shape, dims num " + FmtToStr(shape.size()) + ", expect " + FmtToStr(expect_dims);
50+ KERNEL_LOG_ERROR("%s", error.c_str());
51+ return false;
52+ }
53+ return IsShapeValid(shape);
54+}
55+ 
56+int64_t GetCubeSizeByDataType(DataType data_type)
57+{
58+ // Current cube does not support 4 bytes and longer data
59+ auto size = GetSizeByDataType(data_type);
60+ if (size <= 0) {
61+ std::string error = "Failed to get cube size, the data type " + FmtToStr(DTypeStr(data_type)) + " is invalid";
62+ KERNEL_LOG_ERROR("%s", error.c_str());
63+ return -1;
64+ } else if (size == 1) {
65+ return kCubeSize * 2; // 32 bytes cube size
66+ } else {
67+ return kCubeSize;
68+ }
69+}
70+ 
71+int64_t GetC0ValueForTransShape(DataType data_type, const int32_t format)
72+{
73+ if (ge::HasC0Format(format)) {
74+ return ge::GetC0Value(format);
75+ } else {
76+ return GetCubeSizeByDataType(data_type);
77+ }
78+}
79+ 
80+int64_t GetC0ValueForTransFormat(DataType data_type, const int32_t input_format, const int32_t output_format)
81+{
82+ if (ge::HasC0Format(input_format)) {
83+ return ge::GetC0Value(input_format);
84+ } else if (ge::HasC0Format(output_format)) {
85+ return ge::GetC0Value(output_format);
86+ } else {
87+ return GetCubeSizeByDataType(data_type);
88+ }
89+}
90+ 
91+bool IsTransShapeSrcCorrect(const TransArgs& args, std::vector<int64_t>& expect_shape)
92+{
93+ if (args.src_shape != expect_shape) {
94+ string error = "Failed to trans format from" + FmtToStr(FormatToSerialString(args.src_format)) + " to " +
95+ FmtToStr(FormatToSerialString(args.dst_format)) + ", invalid relationship between src shape " +
96+ FmtToStr(VectorToString(args.src_shape)) + " and dst " +
97+ FmtToStr(VectorToString(args.dst_shape));
98+ KERNEL_LOG_ERROR("%s", error.c_str());
99+ return false;
100+ }
101+ return true;
102+}
103+ 
104+bool IsTransShapeDstCorrect(const TransArgs& args, vector<int64_t>& expect_shape)
105+{
106+ if (!args.dst_shape.empty() && args.dst_shape != expect_shape) {
107+ string error = "Failed to trans format from " + FmtToStr(FormatToSerialString(args.src_format)) + " to " +
108+ FmtToStr(FormatToSerialString(args.dst_format)) + ", the dst shape" +
109+ FmtToStr(VectorToString(args.dst_shape)) + " is invalid, expect" +
110+ FmtToStr(VectorToString(expect_shape));
111+ KERNEL_LOG_ERROR("%s", error.c_str());
112+ return false;
113+ }
114+ return true;
115+}
116+ 
117+int64_t GetItemNumByShape(const vector<int64_t>& shape)
118+{
119+ // shape will not be greater than INT_MAX
120+ int64_t num = 1;
121+ for (auto dim : shape) {
122+ num *= dim;
123+ }
124+ return num;
125+}
126+ 
127+uint32_t TransFormat(const TransArgs& args)
128+{
129+ auto transfer = BuildFormatTransfer(args);
130+ if (transfer == nullptr) {
131+ string error = "Failed to trans data from format " + FmtToStr(FormatToSerialString(args.src_format)) + " to " +
132+ FmtToStr(FormatToSerialString(args.dst_format));
133+ KERNEL_LOG_WARN("%s", error.c_str());
134+ return KERNEL_STATUS_PARAM_INVALID;
135+ }
136+ 
137+ auto src_shape_size = GetItemNumByShape(args.src_shape);
138+ if (args.data == nullptr && src_shape_size != 0) {
139+ KERNEL_LOG_WARN("Invalid input null data");
140+ return KERNEL_STATUS_PARAM_INVALID;
141+ }
142+ 
143+ return transfer->TransFormat(args);
144+}
145+ 
146+int64_t Measure(int64_t x, int64_t y)
147+{
148+ if (y == 0) {
149+ return 1;
150+ }
151+ int64_t z = y;
152+ while (x % y != 0) {
153+ z = x % y;
154+ x = y;
155+ y = z;
156+ }
157+ return z;
158+}
159+// least common multiple
160+int64_t Lcm(int64_t a, int64_t b)
161+{
162+ if (b == 0) {
163+ return -1;
164+ }
165+ int64_t temp = (a * b) / (Measure(a, b));
166+ return temp;
167+}
168+ 
169+void copy_data(const uint8_t* input_data, uint8_t* dst, int64_t src_index, int64_t dst_index, int64_t data_size)
170+{
171+ auto ret = memcpy_s(dst + dst_index * data_size, static_cast<size_t>(data_size), input_data + src_index * data_size,
172+ static_cast<size_t>(data_size));
173+ if (ret != EOK) {
174+ KERNEL_LOG_ERROR("memcpy_s failed, ret [%d].", ret);
175+ }
176+}
177+ 
178+KernelStatus CheckDimOri(int64_t cin_ori, int64_t cout_ori)
179+{
180+ if (cin_ori == 0 || cout_ori == 0) {
181+ KERNEL_LOG_ERROR("Cin_ori, cout_ori must not be equal 0, and current cin_ori is [%ld], "
182+ "cout_ori is [%ld]",
183+ cin_ori, cout_ori);
184+ return KERNEL_STATUS_PARAM_INVALID;
185+ }
186+ return KERNEL_STATUS_OK;
187+}
188+ 
189+uint32_t Prepare4dFormatBasics(const Format& format_4d, const std::vector<int64_t>& shape_4d, const TransArgs& args,
190+ Format4dBasics& out)
191+{
192+ out.d_dim = 1;
193+ out.h_dim = 0;
194+ out.w_dim = 0;
195+ out.c_dim = 0;
196+ out.n_dim = 0;
197+ if (GetFormatDim(out.d_dim, out.h_dim, out.w_dim, out.c_dim, out.n_dim, format_4d, shape_4d) != KERNEL_STATUS_OK) {
198+ return KERNEL_STATUS_PARAM_INVALID;
199+ }
200+ out.data_type = args.src_data_type;
201+ out.c0 = GetC0ValueForTransFormat(out.data_type, args.input_format, args.output_format);
202+ out.data_size = GetSizeByDataType(out.data_type);
203+ out.dst_size = GetItemNumByShape(args.dst_shape) * out.data_size;
204+ return KERNEL_STATUS_OK;
205+}
206+ 
207+uint32_t ComputeCinCoutOri(int64_t n, int64_t c, int64_t groups, int64_t cube_k, int64_t& cin_ori, int64_t& cout_ori)
208+{
209+ if (groups == 0 || cube_k == 0) {
210+ KERNEL_LOG_ERROR("Groups and cube_k must not be equal to 0, now [%ld] [%ld]", groups, cube_k);
211+ return KERNEL_STATUS_PARAM_INVALID;
212+ }
213+ cin_ori = c;
214+ // groups is not equal to 0, which had been checked above.
215+ cout_ori = n / groups;
216+ if (cin_ori == 0 || cout_ori == 0) {
217+ KERNEL_LOG_ERROR("Cin_ori, cout_ori must not be equal 0, "
218+ "and current cin_ori, cout_ori, groups are [%ld] [%ld] [%ld]",
219+ cin_ori, cout_ori, groups);
220+ return KERNEL_STATUS_PARAM_INVALID;
221+ }
222+ return KERNEL_STATUS_OK;
223+}
224+ 
225+uint32_t BuildFzWithGroupsShape(int64_t n, int64_t c, int64_t spatial_dim, int64_t cube_k, int64_t groups,
226+ std::vector<int64_t>& dst_shape)
227+{
228+ int64_t cin_ori = 0;
229+ int64_t cout_ori = 0;
230+ if (ComputeCinCoutOri(n, c, groups, cube_k, cin_ori, cout_ori) != KERNEL_STATUS_OK) {
231+ return KERNEL_STATUS_PARAM_INVALID;
232+ }
233+ // ComputeCinCoutOri guarantees cube_k > 0 and cin_ori/cout_ori > 0 on success;
234+ // reassert locally to satisfy static analyzers on the divisions below.
235+ if (cube_k == 0 || cin_ori == 0 || cout_ori == 0) {
236+ KERNEL_LOG_ERROR("Invalid cube_k/cin_ori/cout_ori [%ld] [%ld] [%ld].", cube_k, cin_ori, cout_ori);
237+ return KERNEL_STATUS_PARAM_INVALID;
238+ }
239+ if (cube_k == 0) {
240+ KERNEL_LOG_ERROR("cube_k must not be 0.");
241+ return KERNEL_STATUS_PARAM_INVALID;
242+ }
243+ if (cin_ori == 0 || cout_ori == 0) {
244+ KERNEL_LOG_ERROR("cin_ori/cout_ori must not be 0.");
245+ return KERNEL_STATUS_PARAM_INVALID;
246+ }
247+ const int64_t e_mult = std::min(
248+ Lcm(Lcm(cin_ori, cube_k) / cin_ori, Lcm(cout_ori, static_cast<int64_t>(kCubeSize)) / cout_ori), groups);
249+ if (e_mult == 0) {
250+ KERNEL_LOG_ERROR("e_mult must not be 0.");
251+ return KERNEL_STATUS_PARAM_INVALID;
252+ }
253+ const int64_t cin_opt = Ceil(e_mult * cin_ori, cube_k) * cube_k;
254+ const int64_t c1_dim = cin_opt / cube_k;
255+ const int64_t g_dim = Ceil(groups, e_mult);
256+ const int64_t n1 = Ceil(cout_ori * e_mult, static_cast<int64_t>(kCubeSize));
257+ dst_shape.clear();
258+ dst_shape.push_back(g_dim * c1_dim * spatial_dim);
259+ dst_shape.push_back(n1);
260+ dst_shape.push_back(kNiSize);
261+ dst_shape.push_back(cube_k);
262+ if (!IsShapeValid(dst_shape)) {
263+ KERNEL_LOG_ERROR("Check shape failed, dst shape [%s]", VectorToString(dst_shape).c_str());
264+ return KERNEL_STATUS_PARAM_INVALID;
265+ }
266+ return KERNEL_STATUS_OK;
267+}
268+ 
269+KernelStatus GetFormatDim(int64_t& d_dim, int64_t& h_dim, int64_t& w_dim, int64_t& c_dim, int64_t& n_dim,
270+ const Format& input_format, const std::vector<int64_t>& dims)
271+{
272+ if (input_format == FORMAT_NCDHW) {
273+ n_dim = dims[kNcdhwN];
274+ c_dim = dims[kNcdhwC];
275+ d_dim = dims[kNcdhwD];
276+ h_dim = dims[kNcdhwH];
277+ w_dim = dims[kNcdhwW];
278+ } else if (input_format == FORMAT_DHWCN) {
279+ d_dim = dims[kDhwcnD];
280+ h_dim = dims[kDhwcnH];
281+ w_dim = dims[kDhwcnW];
282+ c_dim = dims[kDhwcnC];
283+ n_dim = dims[kDhwcnN];
284+ } else if (input_format == FORMAT_NDHWC) {
285+ n_dim = dims[kNdhwcN];
286+ d_dim = dims[kNdhwcD];
287+ h_dim = dims[kNdhwcH];
288+ w_dim = dims[kNdhwcW];
289+ c_dim = dims[kNdhwcC];
290+ } else if (input_format == FORMAT_NHWC) {
291+ n_dim = dims[kNhwcN];
292+ h_dim = dims[kNhwcH];
293+ d_dim = 1;
294+ w_dim = dims[kNhwcW];
295+ c_dim = dims[kNhwcC];
296+ } else if (input_format == FORMAT_NCHW) {
297+ n_dim = dims[kNchwN];
298+ c_dim = dims[kNchwC];
299+ h_dim = dims[kNchwH];
300+ w_dim = dims[kNchwW];
301+ d_dim = 1;
302+ } else if (input_format == FORMAT_HWCN) {
303+ h_dim = dims[kHwcnH];
304+ w_dim = dims[kHwcnW];
305+ c_dim = dims[kHwcnC];
306+ n_dim = dims[kHwcnN];
307+ d_dim = 1;
308+ } else {
309+ KERNEL_LOG_WARN("Format is not FORMAT_DHWCN or FORMAT_NDHWC or FORMAT_NCDHW or "
310+ "FORMAT_NHWC or FORMAT_NCHW or FORMAT_HWCN, current input "
311+ "format is [%d]",
312+ static_cast<int32_t>(input_format));
313+ return KERNEL_STATUS_PARAM_INVALID;
314+ }
315+ return KERNEL_STATUS_OK;
316+}
317+} // namespace formats
318+} // namespace aicpu
Aconversion/trans_data/op_kernel_aicpu/format_transfer/format_transfer_utils.h+113-0
@@ -0,0 +1,113 @@
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_HOST_FORMAT_TRANSFER_FORMAT_TRANSFER_UTILS_H_
12+#define AICPU_KERNELS_HOST_FORMAT_TRANSFER_FORMAT_TRANSFER_UTILS_H_
13+ 
14+#include <string>
15+#include <vector>
16+#include "kernel_util.h"
17+#include "status.h"
18+#include "register_format_transfer.h"
19+ 
20+namespace aicpu {
21+namespace formats {
22+static const int kCubeSize = 16;
23+static const int kNiSize = 16;
24+static const int kC0 = 4;
25+static const int64_t kShapeItemNumMAX = 1024UL * 1024UL * 1024UL * 1024UL;
26+int64_t Measure(int64_t x, int64_t y);
27+int64_t Lcm(int64_t a, int64_t b);
28+bool IsShapeValid(const std::vector<int64_t>& shape);
29+ 
30+bool CheckShapeValid(const std::vector<int64_t>& shape, const int64_t expect_dims);
31+ 
32+int64_t GetC0ValueForTransShape(DataType data_type, const int32_t format);
33+ 
34+int64_t GetC0ValueForTransFormat(DataType data_type, const int32_t input_format, const int32_t output_format);
35+ 
36+int64_t GetCubeSizeByDataType(DataType data_type);
37+ 
38+bool IsTransShapeSrcCorrect(const TransArgs& args, std::vector<int64_t>& expect_shape);
39+ 
40+bool IsTransShapeDstCorrect(const TransArgs& args, std::vector<int64_t>& expect_shape);
41+ 
42+int64_t GetItemNumByShape(const std::vector<int64_t>& shape);
43+ 
44+void copy_data(const uint8_t* input_data, uint8_t* dst, int64_t src_index, int64_t dst_index, int64_t data_size);
45+ 
46+KernelStatus GetFormatDim(int64_t& d_dim, int64_t& h_dim, int64_t& w_dim, int64_t& c_dim, int64_t& n_dim,
47+ const Format& input_format, const std::vector<int64_t>& dims);
48+KernelStatus CheckDimOri(int64_t cin_ori, int64_t cout_ori);
49+ 
50+// Shared 4D-format preamble used by TransFormatToC1hwc0 / TransFormatToWINO.
51+struct Format4dBasics {
52+ int64_t d_dim;
53+ int64_t h_dim;
54+ int64_t w_dim;
55+ int64_t c_dim;
56+ int64_t n_dim;
57+ DataType data_type;
58+ int64_t c0;
59+ int64_t data_size;
60+ int64_t dst_size;
61+};
62+uint32_t Prepare4dFormatBasics(const Format& format_4d, const std::vector<int64_t>& shape_4d, const TransArgs& args,
63+ Format4dBasics& out);
64+ 
65+// Shared groups/cube_k/cin/cout validation used by TransShapeToFz*WithGroups.
66+uint32_t ComputeCinCoutOri(int64_t n, int64_t c, int64_t groups, int64_t cube_k, int64_t& cin_ori, int64_t& cout_ori);
67+ 
68+// Shared shape builder for both TransShapeToFzWithGroups (fractal_z, spatial_dim = h*w)
69+// and TransShapeToFz3DWithGroups (fractalz_3d, spatial_dim = d*h*w).
70+uint32_t BuildFzWithGroupsShape(int64_t n, int64_t c, int64_t spatial_dim, int64_t cube_k, int64_t groups,
71+ std::vector<int64_t>& dst_shape);
72+ 
73+// Shared grouped-format loop skeleton used by TransFormatWithGroups in fractal_z / fractalz_3d.
74+template <typename Ctx, typename CopyHwSliceFn>
75+uint32_t RunGroupedFormatTransfer(const TransArgs& args, const Ctx& ctx, CopyHwSliceFn copy_hw_slice)
76+{
77+ if (ctx.dst_size == 0) {
78+ return KERNEL_STATUS_OK;
79+ }
80+ if (!BiggerMemSet(args.output, static_cast<size_t>(ctx.dst_size), 0, static_cast<size_t>(ctx.dst_size))) {
81+ KERNEL_LOG_ERROR("BiggerMemSet failed, size [%ld].", ctx.dst_size);
82+ return KERNEL_STATUS_PARAM_INVALID;
83+ }
84+ for (int64_t g = 0; g < args.groups; g++) {
85+ for (int64_t d = 0; d < ctx.d_dim; d++) {
86+ for (int64_t c = 0; c < ctx.c_dim; c++) {
87+ copy_hw_slice(g, d, c);
88+ }
89+ }
90+ }
91+ return KERNEL_STATUS_OK;
92+}
93+ 
94+template <typename T>
95+T Ceil(T n1, T n2)
96+{
97+ if (n1 == 0) {
98+ return 0;
99+ }
100+ return (n2 != 0) ? (n1 - 1) / n2 + 1 : 0;
101+}
102+ 
103+/**
104+ * Convert the data format, and put the converted format and length in the
105+ * result
106+ * @param args
107+ * @param result
108+ * @return
109+ */
110+uint32_t TransFormat(const TransArgs& args);
111+} // namespace formats
112+} // namespace aicpu
113+#endif // AICPU_KERNELS_HOST_FORMAT_TRANSFER_FORMAT_TRANSFER_UTILS_H_
Aconversion/trans_data/op_kernel_aicpu/format_transfer/formats_definitions.h+55-0
@@ -0,0 +1,55 @@
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_HOST_FORMAT_TRANSFER_FORMAT_TRANSFERS_FORMAT_TRANSFER_DEFINITIONS_H
12+#define AICPU_KERNELS_HOST_FORMAT_TRANSFER_FORMAT_TRANSFERS_FORMAT_TRANSFER_DEFINITIONS_H
13+ 
14+namespace aicpu {
15+namespace formats {
16+enum NchwDimIndex { kNchwN, kNchwC, kNchwH, kNchwW, kNchwDimsNum };
17+ 
18+enum NhwcDimIndex { kNhwcN, kNhwcH, kNhwcW, kNhwcC, kNhwcDimsNum };
19+ 
20+enum HwcnDimIndex { kHwcnH, kHwcnW, kHwcnC, kHwcnN, kHwcnDimsNum };
21+ 
22+enum ChwnDimIndex { kChwnC, kChwnH, kChwnW, kChwnN, kChwnDimsNum };
23+ 
24+enum Nc1hwc0DimIndex { kNc1hwc0N, kNc1hwc0C1, kNc1hwc0H, kNc1hwc0W, kNc1hwc0C0, kNc1hwc0DimsNum };
25+ 
26+enum C1hwncoc0DimIndex {
27+ kC1hwncoc0C1,
28+ kC1hwncoc0H,
29+ kC1hwncoc0W,
30+ kC1hwncoc0N,
31+ kC1hwncoc0Co,
32+ kC1hwncoc0C0,
33+ kC1hwncoc0DimsNum
34+};
35+ 
36+enum FracZDimIndex { kFracZHWC1, kFracZN0, kFracZNi, kFracZC0, kFracZDimsNum };
37+ 
38+enum DhwcnDimIndex { kDhwcnD, kDhwcnH, kDhwcnW, kDhwcnC, kDhwcnN, kDhwcnDimsNum };
39+ 
40+enum NcdhwDimIndex { kNcdhwN, kNcdhwC, kNcdhwD, kNcdhwH, kNcdhwW, kNcdhwDimsNum };
41+ 
42+enum NdhwcDimIndex { kNdhwcN, kNdhwcD, kNdhwcH, kNdhwcW, kNdhwcC, kNdhwcDimsNum };
43+ 
44+enum FracZWinoDimIndex {
45+ kFracZWinoC1,
46+ kFracZWinoN1,
47+ kFracZWinoN0_2,
48+ kFracZWinoHW,
49+ kFracZWinoN0_8,
50+ kFracZWinoC0,
51+ kFracZWinoDimsNum
52+};
53+} // namespace formats
54+} // namespace aicpu
55+#endif // AICPU_KERNELS_HOST_FORMAT_TRANSFER_FORMAT_TRANSFERS_FORMAT_TRANSFER_DEFINITIONS_H_
Aconversion/trans_data/op_kernel_aicpu/format_transfer/register_format_transfer.cpp+63-0
@@ -0,0 +1,63 @@
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+#include "register_format_transfer.h"
11+ 
12+#include <map>
13+ 
14+using namespace std;
15+ 
16+namespace aicpu {
17+namespace formats {
18+namespace {
19+struct FormatTransferRegistry {
20+ void RegisterBuilder(Format src, Format dst, FormatTransferBuilder builder)
21+ {
22+ src_dst_builder[src][dst] = std::move(builder);
23+ }
24+ map<Format, map<Format, FormatTransferBuilder>> src_dst_builder;
25+};
26+ 
27+FormatTransferRegistry& GetFormatTransferRegistry()
28+{
29+ static FormatTransferRegistry registry;
30+ return registry;
31+}
32+} // namespace
33+ 
34+FormatTransferRegister::FormatTransferRegister(FormatTransferBuilder builder, Format src, Format dst)
35+{
36+ GetFormatTransferRegistry().RegisterBuilder(src, dst, std::move(builder));
37+}
38+ 
39+shared_ptr<FormatTransfer> BuildFormatTransfer(const TransArgs& args)
40+{
41+ auto& registry = GetFormatTransferRegistry();
42+ auto dst_builder = registry.src_dst_builder.find(args.src_format);
43+ if (dst_builder == registry.src_dst_builder.end()) {
44+ return nullptr;
45+ }
46+ auto builder_iter = dst_builder->second.find(args.dst_format);
47+ if (builder_iter == dst_builder->second.end()) {
48+ return nullptr;
49+ }
50+ return builder_iter->second();
51+}
52+ 
53+bool FormatTransferExists(const TransArgs& args)
54+{
55+ auto& registry = GetFormatTransferRegistry();
56+ auto dst_builder = registry.src_dst_builder.find(args.src_format);
57+ if (dst_builder == registry.src_dst_builder.end()) {
58+ return false;
59+ }
60+ return dst_builder->second.count(args.dst_format) > 0;
61+}
62+} // namespace formats
63+} // namespace aicpu
Aconversion/trans_data/op_kernel_aicpu/format_transfer/register_format_transfer.h+74-0
@@ -0,0 +1,74 @@
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+#ifndef AICPU_KERNELS_HOST_FORMAT_TRANSFER_REGISTER_FORMAT_TRANSFER_H
11+#define AICPU_KERNELS_HOST_FORMAT_TRANSFER_REGISTER_FORMAT_TRANSFER_H
12+ 
13+#include <functional>
14+#include <memory>
15+#include <vector>
16+ 
17+#include "cpu_types.h"
18+#include "cpu_context.h"
19+ 
20+namespace aicpu {
21+namespace formats {
22+struct TransArgs {
23+ const uint8_t* data;
24+ uint8_t* output;
25+ // format from GetFormat
26+ const int32_t input_format;
27+ const int32_t output_format;
28+ // primary format
29+ Format src_format;
30+ Format dst_format;
31+ // For scenes that need to supplement the shape, for example, 5D to 4D
32+ // It is not possible to convert the format normally if you only get the
33+ // src_shape, and must get the shape before you mend the shape. So the
34+ // parameters here need to be passed in both src_shape and dst_shape
35+ std::vector<int64_t> src_shape;
36+ std::vector<int64_t> dst_shape;
37+ DataType src_data_type;
38+ int64_t groups;
39+ const CpuKernelContext* ctx;
40+};
41+ 
42+class FormatTransfer {
43+public:
44+ virtual ~FormatTransfer() = default;
45+ virtual uint32_t TransFormat(const TransArgs& args) = 0;
46+ virtual uint32_t TransShape(const TransArgs& args, std::vector<int64_t>& dst_shape, bool reverse) = 0;
47+};
48+ 
49+using FormatTransferBuilder = std::function<std::shared_ptr<FormatTransfer>()>;
50+ 
51+class FormatTransferRegister {
52+public:
53+ FormatTransferRegister(FormatTransferBuilder builder, Format src, Format dst);
54+ ~FormatTransferRegister() = default;
55+};
56+ 
57+#define REGISTER_FORMAT_TRANSFER(TransferClass, format1, format2) \
58+ namespace { \
59+ FormatTransferRegister format_transfer_register_##TransferClass##format1##format2( \
60+ []() { return std::make_shared<TransferClass>(); }, format1, format2); \
61+ }
62+ 
63+/**
64+ * Build a FormatTransfer according to 'args'
65+ * @param args
66+ * @param result
67+ * @return
68+ */
69+std::shared_ptr<FormatTransfer> BuildFormatTransfer(const TransArgs& args);
70+ 
71+bool FormatTransferExists(const TransArgs& args);
72+} // namespace formats
73+} // namespace aicpu
74+#endif
Aconversion/trans_data/op_kernel_aicpu/trans_data_aicpu.cpp+717-0
@@ -0,0 +1,717 @@
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+#include "trans_data_aicpu.h"
11+ 
12+#include <algorithm>
13+ 
14+#include "Eigen/Core"
15+#include "cpu_types.h"
16+#include "format_transfer/format_transfer_utils.h"
17+#include "format_transfer/formats_definitions.h"
18+#include "log.h"
19+#include "securec.h"
20+#include "status.h"
21+#include "unsupported/Eigen/CXX11/Tensor"
22+#include "utils/kernel_util.h"
23+ 
24+using namespace std;
25+ 
26+namespace {
27+const char* const kTransData = "TransData";
28+constexpr int64_t kDimN0 = 16;
29+constexpr int64_t kCubeN = 16;
30+constexpr int64_t kGroupNum = 1;
31+constexpr int64_t kMaxDimsNumC = 4;
32+constexpr size_t kMinInputDimsNum = 4;
33+constexpr int32_t kCubeSize = 16;
34+constexpr int32_t kShapeOffset = 2;
35+ 
36+using aicpu::DTypeStr;
37+using aicpu::FormatToSerialString;
38+using aicpu::GetPrimaryFormat;
39+using aicpu::GetSizeByDataType;
40+using aicpu::KERNEL_STATUS_INNER_ERROR;
41+using aicpu::KERNEL_STATUS_OK;
42+using aicpu::KERNEL_STATUS_PARAM_INVALID;
43+using aicpu::formats::Lcm;
44+ 
45+template <typename T>
46+std::string VectorToString(const std::vector<T>& vec)
47+{
48+ std::stringstream ss;
49+ bool first = true;
50+ for (auto& ele : vec) {
51+ if (first) {
52+ first = false;
53+ } else {
54+ ss << ",";
55+ }
56+ ss << ele;
57+ }
58+ return ss.str();
59+}
60+ 
61+int64_t VectorToNum(const std::vector<int64_t>& vec)
62+{
63+ int64_t result = 1;
64+ for (auto& ele : vec) {
65+ result *= ele;
66+ }
67+ return result;
68+}
69+ 
70+void TransShapeByPerm(const std::vector<int64_t>& src_shape, const std::vector<int64_t>& perm_arg,
71+ std::vector<int64_t>& dst_shape)
72+{
73+ dst_shape.resize(src_shape.size());
74+ for (size_t i = 0; i < perm_arg.size(); ++i) {
75+ dst_shape[i] = src_shape[perm_arg[i]];
76+ }
77+}
78+ 
79+void GetIndexMap(const std::vector<int64_t>& perm_arg, std::map<int32_t, int32_t>& index_map)
80+{
81+ for (size_t i = 0; i < perm_arg.size(); i++) {
82+ index_map[perm_arg[i]] = static_cast<int32_t>(i);
83+ }
84+}
85+ 
86+void GetShapeHead(const std::vector<int64_t>& shape, std::vector<int64_t>& shape_head)
87+{
88+ shape_head.resize(shape.size());
89+ shape_head[shape.size() - 1] = 1;
90+ for (int i = static_cast<int>(shape.size() - kShapeOffset); i >= 0; i--) {
91+ shape_head[i] = shape_head[i + 1] * shape[i + 1];
92+ }
93+}
94+ 
95+int32_t GetSrcIndex(int64_t dst_index, const std::vector<int64_t>& src_shape, const std::vector<int64_t>& dst_shape,
96+ const std::vector<int64_t>& src_shape_head, const std::vector<int64_t>& dst_shape_head,
97+ std::map<int32_t, int32_t> index_map)
98+{
99+ std::vector<int32_t> src_vec(dst_shape.size());
100+ for (size_t i = 0; i < dst_shape.size(); i++) {
101+ src_vec[i] = dst_index / dst_shape_head[i];
102+ dst_index = dst_index % dst_shape_head[i];
103+ }
104+ int32_t src_index = 0;
105+ for (size_t i = 0; i < src_shape.size(); i++) {
106+ src_index += static_cast<int32_t>(src_shape_head[i] * src_vec[index_map[i]]);
107+ }
108+ return src_index;
109+}
110+ 
111+// get the result of two number divisor and let result round up
112+static int64_t Ceil(int64_t a, int64_t b)
113+{
114+ if (b == 0) {
115+ return -1;
116+ } else {
117+ int64_t ret = a / b;
118+ if ((a % b) != 0) {
119+ ret++;
120+ }
121+ return ret;
122+ }
123+}
124+ 
125+struct TransDataTensorInfo {
126+ uint8_t* data;
127+ aicpu::DataType data_type;
128+ std::vector<int64_t> dims;
129+ aicpu::Format format;
130+};
131+ 
132+uint32_t ExtractTensorInfo(aicpu::Tensor* tensor, TransDataTensorInfo& info, const char* who)
133+{
134+ KERNEL_CHECK_NULLPTR(tensor, KERNEL_STATUS_PARAM_INVALID, "%s get tensor failed, tensor is nullptr.", who);
135+ info.data = reinterpret_cast<uint8_t*>(tensor->GetData());
136+ info.data_type = tensor->GetDataType();
137+ auto shape = tensor->GetTensorShape();
138+ KERNEL_CHECK_NULLPTR(shape, KERNEL_STATUS_PARAM_INVALID, "%s get shape failed, shape is nullptr.", who);
139+ info.dims = shape->GetDimSizes();
140+ info.format = shape->GetFormat();
141+ return KERNEL_STATUS_OK;
142+}
143+ 
144+struct DealDataCtx {
145+ aicpu::Format input_format;
146+ int64_t d_dim;
147+ int64_t h_dim;
148+ int64_t w_dim;
149+ int64_t c_dim;
150+ int64_t n_dim;
151+ int64_t cin_ori;
152+ int64_t cout_ori;
153+ int64_t cube_k;
154+ int64_t e_mult;
155+ int64_t cout_opt;
156+ int64_t c1_dim;
157+ int64_t size_output_data;
158+};
159+ 
160+uint32_t BuildDealDataCtx(const aicpu::Tensor* input_tensor, int64_t group, int64_t cube_k, DealDataCtx& c)
161+{
162+ if (group == 0) {
163+ KERNEL_LOG_ERROR("Group must not be equal to 0");
164+ return KERNEL_STATUS_PARAM_INVALID;
165+ }
166+ if (cube_k == 0) {
167+ KERNEL_LOG_ERROR("Cube_k must not be equal to 0, data type [%s]",
168+ DTypeStr(static_cast<aicpu::DataType>(input_tensor->GetDataType())).c_str());
169+ return KERNEL_STATUS_PARAM_INVALID;
170+ }
171+ auto input_shape = input_tensor->GetTensorShape();
172+ const aicpu::Format ge_input_format = input_shape->GetFormat();
173+ c.input_format = static_cast<aicpu::Format>(GetPrimaryFormat(static_cast<int32_t>(ge_input_format)));
174+ std::vector<int64_t> dims = input_shape->GetDimSizes();
175+ c.d_dim = 0;
176+ c.h_dim = 0;
177+ c.w_dim = 0;
178+ c.c_dim = 0;
179+ c.n_dim = 0;
180+ if (aicpu::formats::GetFormatDim(c.d_dim, c.h_dim, c.w_dim, c.c_dim, c.n_dim, c.input_format, dims) !=
181+ KERNEL_STATUS_OK) {
182+ return KERNEL_STATUS_PARAM_INVALID;
183+ }
184+ c.cin_ori = c.c_dim;
185+ c.cout_ori = c.n_dim / group;
186+ if (aicpu::formats::CheckDimOri(c.cin_ori, c.cout_ori) != KERNEL_STATUS_OK) {
187+ return KERNEL_STATUS_PARAM_INVALID;
188+ }
189+ c.cube_k = cube_k;
190+ c.e_mult = std::min(Lcm(Lcm(c.cin_ori, cube_k) / (c.cin_ori), Lcm(c.cout_ori, kCubeN) / (c.cout_ori)), group);
191+ if (c.e_mult == 0) {
192+ KERNEL_LOG_ERROR("E_mult must not be equal to 0");
193+ return KERNEL_STATUS_PARAM_INVALID;
194+ }
195+ const int64_t cin_opt = Ceil(c.e_mult * c.cin_ori, cube_k) * cube_k;
196+ c.cout_opt = Ceil(c.e_mult * c.cout_ori, kCubeN) * kCubeN;
197+ c.c1_dim = cin_opt / cube_k;
198+ const int64_t g_dim = Ceil(group, c.e_mult);
199+ c.size_output_data = g_dim * c.d_dim * c.c1_dim * c.h_dim * c.w_dim * c.cout_opt * cube_k;
200+ return KERNEL_STATUS_OK;
201+}
202+ 
203+inline int64_t ComputeSrcIndexForDealData(const DealDataCtx& c, int64_t d, int64_t h, int64_t w, int64_t co,
204+ int64_t src_co)
205+{
206+ if ((c.input_format == aicpu::FORMAT_DHWCN) || (c.input_format == aicpu::FORMAT_HWCN)) {
207+ return d * c.h_dim * c.w_dim * c.c_dim * c.n_dim + h * c.w_dim * c.c_dim * c.n_dim + w * c.c_dim * c.n_dim +
208+ co * c.n_dim + src_co;
209+ }
210+ if ((c.input_format == aicpu::FORMAT_NCDHW) || (c.input_format == aicpu::FORMAT_NCHW)) {
211+ return src_co * c.c_dim * c.d_dim * c.h_dim * c.w_dim + co * c.d_dim * c.h_dim * c.w_dim +
212+ d * c.h_dim * c.w_dim + h * c.w_dim + w;
213+ }
214+ if ((c.input_format == aicpu::FORMAT_NDHWC) || (c.input_format == aicpu::FORMAT_NHWC)) {
215+ return src_co * c.d_dim * c.h_dim * c.w_dim * c.c_dim + d * c.h_dim * c.w_dim * c.c_dim +
216+ h * c.w_dim * c.c_dim + w * c.c_dim + co;
217+ }
218+ return 0;
219+}
220+ 
221+template <typename T>
222+void DealDataInner(const T* input_data, T* output_data, const DealDataCtx& c, int64_t g, int64_t d, int64_t co,
223+ int64_t h, int64_t w)
224+{
225+ for (int64_t n = 0; n < c.cout_ori; n++) {
226+ const int64_t e_val = g % c.e_mult;
227+ const int64_t dst_ci = e_val * c.cin_ori + co;
228+ const int64_t dst_co = e_val * c.cout_ori + n;
229+ const int64_t src_co = g * c.cout_ori + n;
230+ const int64_t tempory = dst_ci % c.cube_k;
231+ const int64_t dst_inx = (g / c.e_mult) * c.d_dim * c.c1_dim * c.h_dim * c.w_dim * c.cout_opt * c.cube_k +
232+ d * c.c1_dim * c.h_dim * c.w_dim * c.cout_opt * c.cube_k +
233+ (dst_ci / c.cube_k) * c.h_dim * c.w_dim * c.cout_opt * c.cube_k +
234+ h * c.w_dim * c.cout_opt * c.cube_k + w * c.cout_opt * c.cube_k + dst_co * c.cube_k +
235+ tempory;
236+ const int64_t srx_inx = ComputeSrcIndexForDealData(c, d, h, w, co, src_co);
237+ output_data[dst_inx] = input_data[srx_inx];
238+ }
239+}
240+ 
241+template <typename T>
242+void DealDataForHW(const T* input_data, T* output_data, const DealDataCtx& c, int64_t g, int64_t d, int64_t co)
243+{
244+ for (int64_t h = 0; h < c.h_dim; h++) {
245+ for (int64_t w = 0; w < c.w_dim; w++) {
246+ DealDataInner<T>(input_data, output_data, c, g, d, co, h, w);
247+ }
248+ }
249+}
250+ 
251+constexpr int64_t kMaxPaddingBufferBytes = 1LL << 32; // 4 GiB upper bound for padding buffer
252+ 
253+uint32_t AllocatePaddingBuffer(int64_t dst_byte_size, std::shared_ptr<uint8_t>& dst)
254+{
255+ if (dst_byte_size <= 0 || dst_byte_size > kMaxPaddingBufferBytes) {
256+ KERNEL_LOG_ERROR("Invalid padding buffer size [%ld], expect (0, %ld]", dst_byte_size, kMaxPaddingBufferBytes);
257+ return KERNEL_STATUS_PARAM_INVALID;
258+ }
259+ dst.reset(new (std::nothrow) uint8_t[dst_byte_size], std::default_delete<uint8_t[]>());
260+ if (dst == nullptr) {
261+ KERNEL_LOG_ERROR("New Memory failed!");
262+ return KERNEL_STATUS_INNER_ERROR;
263+ }
264+ const errno_t ret_mem = memset_s(dst.get(), dst_byte_size, 0, dst_byte_size);
265+ if (ret_mem != 0) {
266+ KERNEL_LOG_ERROR("Memset failed, ret is [%d]", ret_mem);
267+ return KERNEL_STATUS_INNER_ERROR;
268+ }
269+ return KERNEL_STATUS_OK;
270+}
271+void LogTransBegin(const TransDataTensorInfo& in, const TransDataTensorInfo& out, int64_t group)
272+{
273+ KERNEL_LOG_DEBUG("Begin trans formats from [%s] to [%s], shape [%s] to [%s], data type "
274+ "[%s] to [%s], group is [%ld]",
275+ FormatToSerialString(in.format).c_str(), FormatToSerialString(out.format).c_str(),
276+ VectorToString(in.dims).c_str(), VectorToString(out.dims).c_str(), DTypeStr(in.data_type).c_str(),
277+ DTypeStr(out.data_type).c_str(), group);
278+}
279+ 
280+void LogTransEnd(const TransDataTensorInfo& in, const TransDataTensorInfo& out)
281+{
282+ KERNEL_LOG_DEBUG("End trans formats from [%s] to [%s], shape [%s] to [%s], data type "
283+ "[%s] to [%s]",
284+ FormatToSerialString(in.format).c_str(), FormatToSerialString(out.format).c_str(),
285+ VectorToString(in.dims).c_str(), VectorToString(out.dims).c_str(), DTypeStr(in.data_type).c_str(),
286+ DTypeStr(out.data_type).c_str());
287+}
288+ 
289+void LogTransUnsupported(const TransDataTensorInfo& in, const TransDataTensorInfo& out)
290+{
291+ KERNEL_LOG_WARN("Transfer from format[%s] to [%s], shape [%s] to [%s], data type [%s] "
292+ "to [%s] is not supported",
293+ FormatToSerialString(in.format).c_str(), FormatToSerialString(out.format).c_str(),
294+ VectorToString(in.dims).c_str(), VectorToString(out.dims).c_str(), DTypeStr(in.data_type).c_str(),
295+ DTypeStr(out.data_type).c_str());
296+}
297+ 
298+void LogTransFailed(const TransDataTensorInfo& in, const TransDataTensorInfo& out)
299+{
300+ KERNEL_LOG_WARN("Failed to trans formats from[%s] to [%s], shape [%s] to [%s], data "
301+ "type [%s]",
302+ FormatToSerialString(in.format).c_str(), FormatToSerialString(out.format).c_str(),
303+ VectorToString(in.dims).c_str(), VectorToString(out.dims).c_str(), DTypeStr(in.data_type).c_str());
304+}
305+ 
306+aicpu::formats::TransArgs BuildTransArgs(const TransDataTensorInfo& in, const TransDataTensorInfo& out, int64_t group,
307+ const aicpu::CpuKernelContext* ctx)
308+{
309+ return aicpu::formats::TransArgs{in.data,
310+ out.data,
311+ static_cast<int32_t>(in.format),
312+ static_cast<int32_t>(out.format),
313+ static_cast<aicpu::Format>(GetPrimaryFormat(static_cast<int32_t>(in.format))),
314+ static_cast<aicpu::Format>(GetPrimaryFormat(static_cast<int32_t>(out.format))),
315+ in.dims,
316+ out.dims,
317+ in.data_type,
318+ group,
319+ ctx};
320+}
321+ 
322+uint32_t RunFormatTransfer(const TransDataTensorInfo& in, const TransDataTensorInfo& out, int64_t group,
323+ const aicpu::CpuKernelContext* ctx)
324+{
325+ LogTransBegin(in, out, group);
326+ const aicpu::formats::TransArgs trans_args = BuildTransArgs(in, out, group, ctx);
327+ if (in.data_type != out.data_type || in.dims.empty() || !aicpu::formats::FormatTransferExists(trans_args)) {
328+ LogTransUnsupported(in, out);
329+ return KERNEL_STATUS_PARAM_INVALID;
330+ }
331+ const uint32_t ret = aicpu::formats::TransFormat(trans_args);
332+ if (ret != KERNEL_STATUS_OK) {
333+ LogTransFailed(in, out);
334+ return ret;
335+ }
336+ LogTransEnd(in, out);
337+ return KERNEL_STATUS_OK;
338+}
339+} // namespace
340+ 
341+namespace aicpu {
342+bool TransDataCpuKernel::IsOriginSupportFormatTransfer(Format src_format, Format dst_format)
343+{
344+ static const map<Format, map<Format, int32_t>> kOriginSupportFormatTransfer = {
345+ {FORMAT_HWCN, {{FORMAT_FRACTAL_Z_C04, 1}}}};
346+ auto dst = kOriginSupportFormatTransfer.find(src_format);
347+ if (dst == kOriginSupportFormatTransfer.end()) {
348+ return false;
349+ }
350+ return dst->second.count(dst_format) > 0;
351+}
352+ 
353+uint32_t TransDataCpuKernel::NewCompute(const CpuKernelContext& ctx)
354+{
355+ TransDataTensorInfo input_info;
356+ TransDataTensorInfo output_info;
357+ if (ExtractTensorInfo(ctx.Input(0), input_info, kTransData) != KERNEL_STATUS_OK) {
358+ return KERNEL_STATUS_PARAM_INVALID;
359+ }
360+ if (ExtractTensorInfo(ctx.Output(0), output_info, kTransData) != KERNEL_STATUS_OK) {
361+ return KERNEL_STATUS_PARAM_INVALID;
362+ }
363+ KERNEL_CHECK_NULLPTR(output_info.data, KERNEL_STATUS_PARAM_INVALID,
364+ "%s get output_data failed, output_data is nullptr.", kTransData);
365+ int64_t group = kGroupNum;
366+ AttrValue* groups = ctx.GetAttr("groups");
367+ if (groups != nullptr) {
368+ group = groups->GetInt();
369+ }
370+ return RunFormatTransfer(input_info, output_info, group, &ctx);
371+}
372+ 
373+template <typename T>
374+uint32_t TransDataCpuKernel::DealData(const T* input_data, T* output_data, const Tensor* input_tensor,
375+ Tensor* output_tensor, int64_t group)
376+{
377+ (void)output_tensor;
378+ DealDataCtx c{};
379+ if (BuildDealDataCtx(input_tensor, group, GetCubeSizeByDataType(static_cast<DataType>(input_tensor->GetDataType())),
380+ c) != KERNEL_STATUS_OK) {
381+ return KERNEL_STATUS_PARAM_INVALID;
382+ }
383+ const errno_t ret_mem = memset_s(output_data, static_cast<int64_t>(sizeof(T)) * c.size_output_data, 0,
384+ static_cast<int64_t>(sizeof(T)) * c.size_output_data);
385+ if (ret_mem != EOK) {
386+ KERNEL_LOG_ERROR("memset_s failed, ret [%d].", ret_mem);
387+ return KERNEL_STATUS_PARAM_INVALID;
388+ }
389+ for (int64_t g = 0; g < group; g++) {
390+ for (int64_t d = 0; d < c.d_dim; d++) {
391+ for (int64_t co = 0; co < c.c_dim; co++) {
392+ DealDataForHW<T>(input_data, output_data, c, g, d, co);
393+ }
394+ }
395+ }
396+ return KERNEL_STATUS_OK;
397+}
398+ 
399+// TransData supports input formats (NCDHW, DHWCN, NDHWC) convert to
400+// FORMAT_FRACTAL_Z_3D (GDC1HWN1N0C0), and also supports NHWC, NCHW, HWCN
401+// converte to FORMAT_FRACTAL_Z (GC1HWN1N0C0), HWCN to FZC04. The final effect
402+// achieved is for the data to be distributed diagonally. For example: When the
403+// input filter format is NCDHW, calculated the Correspondence of index between
404+// NCDHW and FORMAT_FRACTAL_Z_3D , then Convert the old filter to the new
405+// filter, and finally added 0 to the position where there is no data.
406+uint32_t TransDataCpuKernel::HandleHwcnToFzC04(const Tensor* input_tensor, Tensor* output_tensor)
407+{
408+ KERNEL_LOG_DEBUG("Begin trans formats from FORMAT_HWCN to FORMAT_FRACTAL_Z_C04");
409+ const DataType data_type = static_cast<DataType>(input_tensor->GetDataType());
410+ const int64_t cube = GetCubeSizeByDataType(data_type);
411+ if (cube < 0) {
412+ KERNEL_LOG_WARN("Don't support dtype[%s]", DTypeStr(data_type).c_str());
413+ return KERNEL_STATUS_PARAM_INVALID;
414+ }
415+ const uint64_t data_type_size = output_tensor->GetDataSize();
416+ const uint64_t data_byte_size = GetSizeByDataType(data_type) * data_type_size;
417+ TransArgs args = {reinterpret_cast<uint8_t*>(input_tensor->GetData()),
418+ input_tensor->GetTensorShape()->GetDimSizes(), output_tensor->GetTensorShape()->GetDimSizes(),
419+ data_type};
420+ auto output_addr = reinterpret_cast<uint8_t*>(output_tensor->GetData());
421+ const int64_t c0_cube = formats::GetC0ValueForTransShape(
422+ args.src_data_type, static_cast<int32_t>(output_tensor->GetTensorShape()->GetFormat()));
423+ KERNEL_CHECK_FALSE((c0_cube > 0), KERNEL_STATUS_PARAM_INVALID, "c0_cube must greater than 0, now is [%ld].",
424+ c0_cube);
425+ const uint32_t ret = FormatTransferHwcnToFZC04(args, output_addr, data_byte_size, c0_cube);
426+ if (ret != KERNEL_STATUS_OK) {
427+ KERNEL_LOG_ERROR("FormatTransferHwcnToFZC04 function failed");
428+ return ret;
429+ }
430+ KERNEL_LOG_DEBUG("Finish trans formats from FORMAT_HWCN to FORMAT_FRACTAL_Z_C04");
431+ return KERNEL_STATUS_OK;
432+}
433+ 
434+uint32_t TransDataCpuKernel::DispatchDealData(DataType dt, void* input_data_temp, void* output_data_temp,
435+ const Tensor* input_tensor, Tensor* output_tensor, int64_t group)
436+{
437+ switch (dt) {
438+ case DT_INT8:
439+ return DealData(reinterpret_cast<int8_t*>(input_data_temp), reinterpret_cast<int8_t*>(output_data_temp),
440+ input_tensor, output_tensor, group);
441+ case DT_FLOAT:
442+ return DealData(reinterpret_cast<float*>(input_data_temp), reinterpret_cast<float*>(output_data_temp),
443+ input_tensor, output_tensor, group);
444+ case DT_FLOAT16:
445+ return DealData(reinterpret_cast<Eigen::half*>(input_data_temp),
446+ reinterpret_cast<Eigen::half*>(output_data_temp), input_tensor, output_tensor, group);
447+ default:
448+ KERNEL_LOG_WARN("DateType is not DT_INT8 or DT_FLOAT or DT_FLOAT16, and current "
449+ "DataType is [%d]",
450+ static_cast<int32_t>(dt));
451+ return KERNEL_STATUS_PARAM_INVALID;
452+ }
453+}
454+ 
455+uint32_t TransDataCpuKernel::Compute(CpuKernelContext& ctx)
456+{
457+ Tensor* input_tensor = ctx.Input(0);
458+ KERNEL_CHECK_NULLPTR(input_tensor, KERNEL_STATUS_PARAM_INVALID, "%s get input_tensor failed", kTransData);
459+ const auto input_format = GetPrimaryFormat(static_cast<int32_t>(input_tensor->GetTensorShape()->GetFormat()));
460+ Tensor* output_tensor = ctx.Output(0);
461+ KERNEL_CHECK_NULLPTR(output_tensor, KERNEL_STATUS_PARAM_INVALID, "%s get output_tensor failed", kTransData);
462+ const auto output_format = GetPrimaryFormat(static_cast<int32_t>(output_tensor->GetTensorShape()->GetFormat()));
463+ if (!IsOriginSupportFormatTransfer(static_cast<Format>(input_format), static_cast<Format>(output_format))) {
464+ return NewCompute(ctx);
465+ }
466+ if ((input_format == FORMAT_HWCN) && (output_format == FORMAT_FRACTAL_Z_C04)) {
467+ return HandleHwcnToFzC04(input_tensor, output_tensor);
468+ }
469+ const int32_t primary_out_put_format = GetPrimaryFormat(static_cast<int32_t>(output_format));
470+ if ((primary_out_put_format != static_cast<int32_t>(FORMAT_FRACTAL_Z)) &&
471+ (primary_out_put_format != static_cast<int32_t>(FORMAT_FRACTAL_Z_3D))) {
472+ KERNEL_LOG_EVENT("%s unsupport output_format [%d]", kTransData, primary_out_put_format);
473+ return KERNEL_STATUS_PARAM_INVALID;
474+ }
475+ auto input_shape = input_tensor->GetTensorShape();
476+ KERNEL_CHECK_NULLPTR(input_shape, KERNEL_STATUS_PARAM_INVALID, "%s get input_shape failed", kTransData);
477+ const std::vector<int64_t> dims = input_shape->GetDimSizes();
478+ if ((dims.size()) < kMinInputDimsNum) {
479+ KERNEL_LOG_WARN("%s dims size [%zu] must >= 4", kTransData, dims.size());
480+ return KERNEL_STATUS_PARAM_INVALID;
481+ }
482+ AttrValue* groups = ctx.GetAttr("groups");
483+ int64_t group = kGroupNum;
484+ if (groups != nullptr) {
485+ group = groups->GetInt();
486+ KERNEL_CHECK_FALSE((group != 0L), KERNEL_STATUS_PARAM_INVALID, "groups can't be 0.");
487+ }
488+ const DataType dt = static_cast<DataType>(input_tensor->GetDataType());
489+ auto input_data_temp = input_tensor->GetData();
490+ KERNEL_CHECK_NULLPTR(input_data_temp, KERNEL_STATUS_PARAM_INVALID, "%s get input_data failed", kTransData);
491+ auto output_data_temp = output_tensor->GetData();
492+ KERNEL_CHECK_NULLPTR(output_data_temp, KERNEL_STATUS_PARAM_INVALID, "%s get output_data failed", kTransData);
493+ return DispatchDealData(dt, input_data_temp, output_data_temp, input_tensor, output_tensor, group);
494+}
495+ 
496+uint32_t TransDataCpuKernel::FormatTransferHwcnToFZC04(TransArgs& args, uint8_t* output_addr, uint64_t length,
497+ int64_t c0_cube)
498+{
499+ KERNEL_LOG_DEBUG("Begin to trans format from HWCN to FZC04, src shape [%s], data type "
500+ "[%s], dst shape [%s], c0_cube [%ld]",
501+ VectorToString(args.src_shape).c_str(), DTypeStr(args.src_data_type).c_str(),
502+ VectorToString(args.dst_shape).c_str(), c0_cube);
503+ std::shared_ptr<uint8_t> dst_padding_one(nullptr);
504+ uint32_t ret = PaddingOne(args, dst_padding_one);
505+ if (ret != KERNEL_STATUS_OK) {
506+ return ret;
507+ }
508+ std::vector<int64_t> perm_arg_tmp_one = {3, 0, 1, 2};
509+ std::shared_ptr<uint8_t> dst_transpose_one(nullptr);
510+ ret = Transpose(args, perm_arg_tmp_one, dst_transpose_one);
511+ if (ret != KERNEL_STATUS_OK) {
512+ return ret;
513+ }
514+ std::vector<int64_t>& src_shape = args.src_shape;
515+ std::vector<int64_t> src_shape_tmp = src_shape;
516+ constexpr size_t new_dims = 2;
517+ src_shape.resize(new_dims);
518+ src_shape[0] = src_shape_tmp[formats::kHwcnH];
519+ src_shape[1] = src_shape_tmp[formats::kHwcnW] * src_shape_tmp[formats::kHwcnC] * src_shape_tmp[formats::kHwcnN];
520+ std::shared_ptr<uint8_t> dst_padding_two(nullptr);
521+ ret = PaddingTwo(args, dst_padding_two, c0_cube);
522+ if (ret != KERNEL_STATUS_OK) {
523+ return ret;
524+ }
525+ 
526+ KERNEL_CHECK_FALSE((c0_cube > 0), KERNEL_STATUS_PARAM_INVALID, "c0_cube must greater than 0, now is [%ld].",
527+ c0_cube); // for avoid warning for div 0
528+ src_shape_tmp = src_shape;
529+ src_shape.resize(formats::kHwcnDimsNum);
530+ src_shape[formats::kHwcnH] = src_shape_tmp[0] / kDimN0;
531+ src_shape[formats::kHwcnW] = kDimN0;
532+ src_shape[formats::kHwcnC] = src_shape_tmp[1] / c0_cube;
533+ src_shape[formats::kHwcnN] = c0_cube;
534+ std::vector<int64_t> perm_arg_tmp_two = {2, 0, 1, 3};
535+ std::shared_ptr<uint8_t> dst_transpose_two(nullptr);
536+ ret = Transpose(args, perm_arg_tmp_two, dst_transpose_two);
537+ if (ret != KERNEL_STATUS_OK) {
538+ return ret;
539+ }
540+ auto ret_mem = BiggerMemCpy(output_addr, length, args.data,
541+ VectorToNum(args.src_shape) * GetSizeByDataType(args.src_data_type));
542+ if (!ret_mem) {
543+ KERNEL_LOG_ERROR("BiggerMemCpy failed");
544+ return KERNEL_STATUS_INNER_ERROR;
545+ }
546+ return KERNEL_STATUS_OK;
547+}
548+ 
549+uint32_t TransDataCpuKernel::PaddingOne(TransArgs& args, std::shared_ptr<uint8_t>& dst)
550+{
551+ DataType data_type = args.src_data_type;
552+ std::vector<int64_t> dst_shape;
553+ uint32_t ret = GetPaddingOneShape(args, dst_shape);
554+ if (ret != KERNEL_STATUS_OK) {
555+ return ret;
556+ }
557+ int32_t type_size = GetSizeByDataType(data_type);
558+ int64_t dst_byte_size = VectorToNum(dst_shape) * type_size;
559+ if (AllocatePaddingBuffer(dst_byte_size, dst) != KERNEL_STATUS_OK) {
560+ return KERNEL_STATUS_INNER_ERROR;
561+ }
562+ std::vector<int64_t>& src_shape = args.src_shape;
563+ auto h = src_shape.at(0);
564+ auto w = src_shape.at(1);
565+ auto c = src_shape.at(2);
566+ auto n = src_shape.at(3);
567+ auto h_padding = dst_shape[0];
568+ auto w_padding = dst_shape[1];
569+ auto c_padding = dst_shape[2];
570+ auto n_padding = dst_shape[3];
571+ auto src_add = args.data;
572+ auto dst_add = dst.get();
573+ auto protect_size = h_padding * w_padding * c_padding * n_padding * type_size;
574+ for (int i = 0; i < h; i++) {
575+ for (int j = 0; j < w; j++) {
576+ for (int k = 0; k < c; k++) {
577+ auto dst_stride = ((i * w_padding + j) * c_padding + k) * n_padding * type_size;
578+ auto ret_cpy = memcpy_s(dst_add + dst_stride, protect_size - dst_stride,
579+ src_add + ((i * w + j) * c + k) * n * type_size, n * type_size);
580+ if (ret_cpy != 0) {
581+ KERNEL_LOG_ERROR("Memcpy failed, ret is [%d]", ret_cpy);
582+ return KERNEL_STATUS_INNER_ERROR;
583+ }
584+ }
585+ }
586+ }
587+ args.data = dst.get();
588+ src_shape = dst_shape;
589+ return KERNEL_STATUS_OK;
590+}
591+ 
592+uint32_t TransDataCpuKernel::PaddingTwo(TransArgs& args, std::shared_ptr<uint8_t>& dst, int64_t c0_cube)
593+{
594+ DataType data_type = args.src_data_type;
595+ std::vector<int64_t> dst_shape;
596+ uint32_t ret = GetPaddingTwoShape(args, dst_shape, c0_cube);
597+ if (ret != KERNEL_STATUS_OK) {
598+ return ret;
599+ }
600+ int32_t type_size = GetSizeByDataType(data_type);
601+ int64_t dst_byte_size = VectorToNum(dst_shape) * type_size;
602+ if (AllocatePaddingBuffer(dst_byte_size, dst) != KERNEL_STATUS_OK) {
603+ return KERNEL_STATUS_INNER_ERROR;
604+ }
605+ std::vector<int64_t>& src_shape = args.src_shape;
606+ auto n = src_shape.at(0);
607+ auto z = src_shape.at(1);
608+ auto n_padding = dst_shape[0];
609+ auto z_padding = dst_shape[1];
610+ auto src_add = args.data;
611+ auto dst_add = dst.get();
612+ auto protect_size = n_padding * z_padding * type_size;
613+ for (int i = 0; i < n; i++) {
614+ auto dst_stride = i * z_padding * type_size;
615+ auto ret_cpy = memcpy_s(dst_add + dst_stride, protect_size - dst_stride, src_add + i * z * type_size,
616+ z * type_size);
617+ if (ret_cpy != 0) {
618+ KERNEL_LOG_ERROR("Memcpy failed, ret is [%d]", ret_cpy);
619+ return KERNEL_STATUS_INNER_ERROR;
620+ }
621+ }
622+ args.data = dst.get();
623+ src_shape = dst_shape;
624+ return KERNEL_STATUS_OK;
625+}
626+ 
627+uint32_t TransDataCpuKernel::GetPaddingOneShape(const TransArgs& args, std::vector<int64_t>& dst_shape)
628+{
629+ int64_t cube = kDimN0;
630+ auto h = args.src_shape.at(formats::kHwcnH);
631+ auto w = args.src_shape.at(formats::kHwcnW);
632+ auto c = args.src_shape.at(formats::kHwcnC);
633+ auto n = args.src_shape.at(formats::kHwcnN);
634+ if (c > kMaxDimsNumC) {
635+ KERNEL_LOG_ERROR("Invalid dim c num[%lu].It should be in (0, %ld]", c, kMaxDimsNumC);
636+ return KERNEL_STATUS_PARAM_INVALID;
637+ }
638+ dst_shape.resize(formats::kHwcnDimsNum);
639+ dst_shape[formats::kHwcnH] = h;
640+ dst_shape[formats::kHwcnW] = w;
641+ dst_shape[formats::kHwcnC] = kMaxDimsNumC;
642+ int64_t tmp = Ceil(n, cube);
643+ dst_shape[formats::kHwcnN] = tmp * cube;
644+ return KERNEL_STATUS_OK;
645+}
646+ 
647+uint32_t TransDataCpuKernel::GetPaddingTwoShape(const TransArgs& args, std::vector<int64_t>& dst_shape, int64_t cube)
648+{
649+ auto n = args.src_shape.at(0);
650+ auto z = args.src_shape.at(1);
651+ constexpr size_t new_size = 2;
652+ dst_shape.resize(new_size);
653+ dst_shape[0] = n;
654+ int64_t tmp = Ceil(z, cube);
655+ dst_shape[1] = tmp * cube;
656+ return KERNEL_STATUS_OK;
657+}
658+ 
659+uint32_t TransDataCpuKernel::Transpose(TransArgs& args, const std::vector<int64_t>& perm_arg,
660+ std::shared_ptr<uint8_t>& dst)
661+{
662+ std::vector<int64_t>& src_shape = args.src_shape;
663+ std::vector<int64_t> dst_shape;
664+ TransShapeByPerm(src_shape, perm_arg, dst_shape);
665+ DataType src_data_type = args.src_data_type;
666+ KERNEL_LOG_DEBUG("Begin to transpose, src shape [%s], perm arg [%s], dst shape [%s], data "
667+ "type [%s]",
668+ VectorToString(src_shape).c_str(), VectorToString(perm_arg).c_str(),
669+ VectorToString(dst_shape).c_str(), DTypeStr(src_data_type).c_str());
670+ int64_t dst_ele_num = VectorToNum(dst_shape);
671+ int64_t data_size = GetSizeByDataType(src_data_type);
672+ int64_t dst_size = data_size * dst_ele_num;
673+ dst.reset(new (std::nothrow) uint8_t[dst_size], std::default_delete<uint8_t[]>());
674+ if (dst == nullptr) {
675+ KERNEL_LOG_ERROR("New Memory failed!");
676+ return KERNEL_STATUS_INNER_ERROR;
677+ }
678+ int64_t dst_index = 0;
679+ std::vector<int64_t> src_shape_head;
680+ GetShapeHead(src_shape, src_shape_head);
681+ std::vector<int64_t> dst_shape_head;
682+ GetShapeHead(dst_shape, dst_shape_head);
683+ std::map<int32_t, int32_t> index_map;
684+ GetIndexMap(perm_arg, index_map);
685+ while (dst_index < dst_ele_num) {
686+ auto src_index = GetSrcIndex(dst_index, src_shape, dst_shape, src_shape_head, dst_shape_head, index_map);
687+ const int64_t remain = dst_size - dst_index * data_size;
688+ const size_t protect_size = (remain < static_cast<int64_t>(SECUREC_MEM_MAX_LEN)) ? static_cast<size_t>(remain) :
689+ SECUREC_MEM_MAX_LEN;
690+ auto ret = memcpy_s(dst.get() + dst_index * data_size, protect_size, args.data + src_index * data_size,
691+ static_cast<size_t>(data_size));
692+ if (ret != 0) {
693+ KERNEL_LOG_ERROR("Memcpy failed, ret is [%d]", ret);
694+ return KERNEL_STATUS_INNER_ERROR;
695+ }
696+ dst_index += 1;
697+ }
698+ src_shape = dst_shape;
699+ args.data = dst.get();
700+ return KERNEL_STATUS_OK;
701+}
702+ 
703+int64_t TransDataCpuKernel::GetCubeSizeByDataType(DataType data_type)
704+{
705+ // Current cube does not support 4 bytes and longer data
706+ auto size = GetSizeByDataType(data_type);
707+ if (size <= 0) {
708+ KERNEL_LOG_ERROR("Failed to get cube size, the data type [%s] is invalid", DTypeStr(data_type).c_str());
709+ return -1;
710+ } else if (size == 1) {
711+ return kCubeSize * 2; // 32 bytes cube size
712+ } else {
713+ return kCubeSize;
714+ }
715+}
716+REGISTER_CPU_KERNEL(kTransData, TransDataCpuKernel);
717+} // namespace aicpu
Aconversion/trans_data/op_kernel_aicpu/trans_data_aicpu.h+48-0
@@ -0,0 +1,48 @@
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+#ifndef OPS_MATH_CONVERSION_TRANS_DATA_AICPU_H
11+#define OPS_MATH_CONVERSION_TRANS_DATA_AICPU_H
12+ 
13+#include "cpu_kernel.h"
14+ 
15+namespace aicpu {
16+struct TransArgs {
17+ const uint8_t* data;
18+ std::vector<int64_t> src_shape;
19+ std::vector<int64_t> dst_shape;
20+ DataType src_data_type;
21+};
22+ 
23+class TransDataCpuKernel : public CpuKernel {
24+public:
25+ ~TransDataCpuKernel() = default;
26+ uint32_t Compute(CpuKernelContext& ctx) override;
27+ 
28+private:
29+ template <typename T>
30+ uint32_t DealData(const T* input_Data, T* output_data, const Tensor* input_tensor, Tensor* out_put_tensor,
31+ int64_t group);
32+ uint32_t FormatTransferHwcnToFZC04(TransArgs& args, uint8_t* output_addr, uint64_t length, int64_t c0_cube);
33+ uint32_t PaddingOne(TransArgs& args, std::shared_ptr<uint8_t>& dst);
34+ uint32_t PaddingTwo(TransArgs& args, std::shared_ptr<uint8_t>& dst, int64_t c0_cube);
35+ uint32_t GetPaddingOneShape(const TransArgs& args, std::vector<int64_t>& dst_shape);
36+ uint32_t GetPaddingTwoShape(const TransArgs& args, std::vector<int64_t>& dst_shape, int64_t cube);
37+ uint32_t Transpose(TransArgs& args, const std::vector<int64_t>& perm_arg, std::shared_ptr<uint8_t>& dst);
38+ int64_t GetCubeSizeByDataType(DataType data_type);
39+ 
40+ bool IsOriginSupportFormatTransfer(Format src_fromat, Format dst_format);
41+ 
42+ uint32_t NewCompute(const CpuKernelContext& ctx);
43+ uint32_t HandleHwcnToFzC04(const Tensor* input_tensor, Tensor* output_tensor);
44+ uint32_t DispatchDealData(DataType dt, void* input_data_temp, void* output_data_temp, const Tensor* input_tensor,
45+ Tensor* output_tensor, int64_t group);
46+};
47+} // namespace aicpu
48+#endif
Aconversion/trans_data/tests/ut/op_kernel_aicpu/test_trans_data.cpp+76-0
@@ -0,0 +1,76 @@
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+#include "Eigen/Core"
22+ 
23+using namespace aicpu;
24+ 
25+class TEST_TRANS_DATA_UT : public testing::Test {};
26+ 
27+namespace {
28+std::shared_ptr<NodeDef> BuildTransDataNode(DataType dtype, Format src_fmt, Format dst_fmt,
29+ const std::vector<int64_t>& src_shape,
30+ const std::vector<int64_t>& dst_shape, void* src_data, void* dst_data,
31+ const std::string& src_format_str, const std::string& dst_format_str,
32+ int64_t groups = 1)
33+{
34+ auto node_def = CpuKernelUtils::CreateNodeDef();
35+ NodeDefBuilder(node_def.get(), "TransData", "TransData")
36+ .Input({"src", dtype, src_shape, src_data, src_fmt})
37+ .Output({"dst", dtype, dst_shape, dst_data, dst_fmt})
38+ .Attr("src_format", src_format_str)
39+ .Attr("dst_format", dst_format_str)
40+ .Attr("groups", groups);
41+ return node_def;
42+}
43+} // namespace
44+ 
45+TEST_F(TEST_TRANS_DATA_UT, unsupported_output_format_returns_param_invalid)
46+{
47+ std::vector<int64_t> src_shape = {1, 2, 2, 4};
48+ std::vector<int64_t> dst_shape = {1, 2, 2, 4};
49+ std::vector<float> src(16, 1.0f);
50+ std::vector<float> dst(16, 0.0f);
51+ auto node_def = BuildTransDataNode(DT_FLOAT, FORMAT_NHWC, FORMAT_NHWC, src_shape, dst_shape, src.data(), dst.data(),
52+ "NHWC", "NHWC");
53+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
54+}
55+ 
56+TEST_F(TEST_TRANS_DATA_UT, insufficient_dims_returns_param_invalid)
57+{
58+ std::vector<int64_t> src_shape = {2, 4};
59+ std::vector<int64_t> dst_shape = {1, 1, 16, 16};
60+ std::vector<float> src(8, 1.0f);
61+ std::vector<float> dst(256, 0.0f);
62+ auto node_def = BuildTransDataNode(DT_FLOAT, FORMAT_HWCN, FORMAT_FRACTAL_Z, src_shape, dst_shape, src.data(),
63+ dst.data(), "HWCN", "FRACTAL_Z");
64+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
65+}
66+ 
67+TEST_F(TEST_TRANS_DATA_UT, groups_zero_returns_param_invalid)
68+{
69+ std::vector<int64_t> src_shape = {1, 1, 1, 16};
70+ std::vector<int64_t> dst_shape = {1, 1, 16, 16};
71+ std::vector<float> src(16, 1.0f);
72+ std::vector<float> dst(256, 0.0f);
73+ auto node_def = BuildTransDataNode(DT_FLOAT, FORMAT_HWCN, FORMAT_FRACTAL_Z, src_shape, dst_shape, src.data(),
74+ dst.data(), "HWCN", "FRACTAL_Z", 0);
75+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
76+}
atomgit-bot
atomgit-botatomgit-bot7月16日

🟡 Medium Priority

test_trans_data.cpp 中的两个测试用例当前都能通过并返回 KERNEL_STATUS_PARAM_INVALID,但并非因为触发了 kernel 内部的校验逻辑,而是因为所测格式组合(HWCN→FRACTAL_Z)在 PR1 中尚未注册格式转换实现。

证据链:

后果: 这两个测试名称暗示它们验证 kernel 侧的 groups/dims 校验,但实际路径绕开了这些校验。当 PR2/PR3 注册 HWCN→FRACTAL_Z 格式转换后,测试将进入真正的转换逻辑,届时 NewCompute 缺失的 groups/dims 校验会导致测试失败或触发 UB(参见前述两个 kernel 侧 findings)。当前测试状态掩盖了 NewCompute 的校验缺失问题。

建议:建议:1) 修复 kernel 侧 NewCompute 缺失的 groups 和 dims 校验(参见前述 findings);2) 修复后这两个测试将正确覆盖新代码路径的校验逻辑。在 PR1 中也可以考虑增加一个不会注册格式转换但能触发 Compute 旧路径校验的测试(如使用 FORMAT_FRACTAL_Z 作为输出格式且 dims < 4),以独立验证 dims 校验。

likedislike