已合并
fix: restore reshape axis padding before autofuse can-fuse #4309
fix: restore reshape axis padding before autofuse can-fuse #4309
已合并
ling-DT创建于 8月8日
22 个文件变更+2307-66
@@ -86,6 +86,17 @@ Status CacheGraphAfterMerge(const NodePtr &new_node, const NodePtr &node1, const
86 return SUCCESS;86 return SUCCESS;
87}87}
88 88 
89+bool CompleteReshapeAxesForBackendCanFuse(const NodePtr &node1, const NodePtr &node2, const NodeFuseInfo &fuse_info) {
90+ // Backend can-fuse checks rely on complete axis semantics. Complete axes recorded by no-op reshape lowering here
91+ // so graph/node/tensor attrs are in the same axis space before evaluating fusion legality.
92+ if (BackendUtils::CompleteReshapeAxesForBackendCanFuse(node1, node2, fuse_info) == SUCCESS) {
93+ return true;
94+ }
95+ GELOGI("node1 %s(%s) and node2 %s(%s) cannot fuse, complete reshape axes before backend can-fuse failed.",
96+ node1->GetNamePtr(), node1->GetType().c_str(), node2->GetNamePtr(), node2->GetType().c_str());
97+ return false;
98+}
99+ 
89bool AscBackendSubGraphFusionDecider::CanFuse(const NodePtr &node1, const NodePtr &node2) const {100bool AscBackendSubGraphFusionDecider::CanFuse(const NodePtr &node1, const NodePtr &node2) const {
90 uint32_t max_fusion_node_input_size = AutoFuseConfig::Config().GetFusionStrategySolver().max_input_nums_after_fuse;101 uint32_t max_fusion_node_input_size = AutoFuseConfig::Config().GetFusionStrategySolver().max_input_nums_after_fuse;
91 if (!BackendUtils::CanFuseByStrategy(node1, node2, max_fusion_node_input_size)) {102 if (!BackendUtils::CanFuseByStrategy(node1, node2, max_fusion_node_input_size)) {
@@ -156,6 +167,7 @@ NodePtr AscBackendSubGraphFusionDecider::Fuse(const NodePtr &node1, const NodePt
156 node2->GetType().c_str());167 node2->GetType().c_str());
157 // 子图融合流程异常时dump图的缓存融合前dump图流程168 // 子图融合流程异常时dump图的缓存融合前dump图流程
158 GE_ASSERT_SUCCESS(CacheGraphBeforeSubGraphMerge(node1, node2, origin_graph));169 GE_ASSERT_SUCCESS(CacheGraphBeforeSubGraphMerge(node1, node2, origin_graph));
170+ GE_ASSERT_TRUE(CompleteReshapeAxesForBackendCanFuse(node1, node2, node_fuse_info));
159 171 
160 GE_ASSERT_SUCCESS(BackendUtils::UpdateSubgraphOutputAttr(graph1, node1));172 GE_ASSERT_SUCCESS(BackendUtils::UpdateSubgraphOutputAttr(graph1, node1));
161 GE_ASSERT_SUCCESS(BackendUtils::UpdateSubgraphOutputAttr(graph2, node2));173 GE_ASSERT_SUCCESS(BackendUtils::UpdateSubgraphOutputAttr(graph2, node2));
@@ -413,6 +425,8 @@ Status AscBackendFusionDecider::UpdateNewNodeAttr(const OpDescPtr op, const Node
413 GetInterAttrs(attr).fuse_type = fuse_type;425 GetInterAttrs(attr).fuse_type = fuse_type;
414 BackendUtils::SetReduceOriginalAxisInfo(GetInterAttrs(attr), GetInterAttrs(autofuse_attr1),426 BackendUtils::SetReduceOriginalAxisInfo(GetInterAttrs(attr), GetInterAttrs(autofuse_attr1),
415 GetInterAttrs(autofuse_attr2));427 GetInterAttrs(autofuse_attr2));
428+ BackendUtils::SetReshapeAxisChangeInfo(GetInterAttrs(attr), GetInterAttrs(autofuse_attr1),
429+ GetInterAttrs(autofuse_attr2));
416 430 
417 // 处理is_reduce_all_load属性:按照优先级设置融合后的值431 // 处理is_reduce_all_load属性:按照优先级设置融合后的值
418 // 优先级1:存在REDUCE_ALL_LOAD_NOT_ALL,则设置为REDUCE_ALL_LOAD_NOT_ALL432 // 优先级1:存在REDUCE_ALL_LOAD_NOT_ALL,则设置为REDUCE_ALL_LOAD_NOT_ALL
@@ -936,6 +950,7 @@ NodePtr AscBackendFusionDecider::Fuse(const NodePtr &node1, const NodePtr &node2
936 node2->GetType().c_str());950 node2->GetType().c_str());
937 // 异常时dump图的缓存融合前dump图流程951 // 异常时dump图的缓存融合前dump图流程
938 GE_ASSERT_SUCCESS(CacheGraphBeforeMerge(node1, node2));952 GE_ASSERT_SUCCESS(CacheGraphBeforeMerge(node1, node2));
953+ GE_ASSERT_TRUE(CompleteReshapeAxesForBackendCanFuse(node1, node2, node_fuse_info));
939 954 
940 GE_ASSERT_SUCCESS(BackendUtils::UpdateSubgraphOutputAttr(graph1, node1));955 GE_ASSERT_SUCCESS(BackendUtils::UpdateSubgraphOutputAttr(graph1, node1));
941 GE_ASSERT_SUCCESS(BackendUtils::UpdateSubgraphOutputAttr(graph2, node2));956 GE_ASSERT_SUCCESS(BackendUtils::UpdateSubgraphOutputAttr(graph2, node2));
@@ -842,6 +842,8 @@ Status AscGraphAxisMapping::FlushAscSubGraphAxisInfo(const NodePtr &node, const
842 }842 }
843 GE_ASSERT_SUCCESS(BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(node, asc_node, axis_before_Flush,843 GE_ASSERT_SUCCESS(BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(node, asc_node, axis_before_Flush,
844 output_desc_tensor_attr->axis));844 output_desc_tensor_attr->axis));
845+ GE_ASSERT_SUCCESS(
846+ BackendUtils::FlushReshapeAxisChanges(node, asc_node, axis_before_Flush, output_desc_tensor_attr->axis));
845 }847 }
846 }848 }
847 auto graph_attr = graph->GetAttrsGroup<AscGraphAttr>();849 auto graph_attr = graph->GetAttrsGroup<AscGraphAttr>();
@@ -310,7 +310,6 @@ class AscGraphAxisMapping {
310 return open_log_;310 return open_log_;
311 }311 }
312 312 
313- private:
314 /**313 /**
315 * 该函数用于获取指定节点的前置节点的属性信息,包括维度、轴和大小。。314 * 该函数用于获取指定节点的前置节点的属性信息,包括维度、轴和大小。。
316 *315 *
@@ -336,6 +335,7 @@ class AscGraphAxisMapping {
336 Status GetCurNodeAttrs(const NodePtr &node, const int32_t index, std::vector<int64_t> &axis,335 Status GetCurNodeAttrs(const NodePtr &node, const int32_t index, std::vector<int64_t> &axis,
337 std::vector<ge::Expression> &repeats) const;336 std::vector<ge::Expression> &repeats) const;
338 337 
338+ private:
339 /**339 /**
340 * 该函数用于找到节点(node_repeats)在基准信息(base_repeats)中的索引。340 * 该函数用于找到节点(node_repeats)在基准信息(base_repeats)中的索引。
341 * 它会遍历node_repeats中的每个元素,并在base_repeats中查找匹配的元素,记录其索引。341 * 它会遍历node_repeats中的每个元素,并在base_repeats中查找匹配的元素,记录其索引。
@@ -28,6 +28,7 @@
28#include "ascir_ops.h"28#include "ascir_ops.h"
29#include "post_process/scheduler_adapter/torch_adaption_fallback_load.h"29#include "post_process/scheduler_adapter/torch_adaption_fallback_load.h"
30#include "post_process/scheduler_adapter/adaption_complete_node_attrs.h"30#include "post_process/scheduler_adapter/adaption_complete_node_attrs.h"
31+#include "post_process/scheduler_adapter/adaption_reshape_axis_padding.h"
31#include "asc_graph_axis_mapping.h"32#include "asc_graph_axis_mapping.h"
32#include "can_fuse/autofuse_graph_manager.h"33#include "can_fuse/autofuse_graph_manager.h"
33#include "utils/not_fuse_reason_code.h"34#include "utils/not_fuse_reason_code.h"
@@ -2745,6 +2746,11 @@ Status BackendUtils::UpdateTransposeBeforeMerge(const NodePtr &node2, const Comp
2745 return SUCCESS;2746 return SUCCESS;
2746}2747}
2747 2748 
2749+Status BackendUtils::CompleteReshapeAxesForBackendCanFuse(const NodePtr &node1, const NodePtr &node2,
2750+ const NodeFuseInfo &fuse_info) {
2751+ return asc_adapt::CompletePairReshapeAxes(node1, node2, fuse_info);
2752+}
2753+ 
2748Status CompleteNodeAttrsBeforeMerge(const NodePtr &node1, const NodePtr &node2) {2754Status CompleteNodeAttrsBeforeMerge(const NodePtr &node1, const NodePtr &node2) {
2749 auto asc_graph1 = BackendUtils::GetNodeFusedAscGraph(node1);2755 auto asc_graph1 = BackendUtils::GetNodeFusedAscGraph(node1);
2750 GE_ASSERT_NOTNULL(asc_graph1);2756 GE_ASSERT_NOTNULL(asc_graph1);
@@ -3291,7 +3297,10 @@ bool BackendUtils::IsOnlyPointwise(const NodePtr &node) {
3291 3297 
3292void BackendUtils::SetReduceOriginalAxisInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,3298void BackendUtils::SetReduceOriginalAxisInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,
3293 const AutofuseInnerAttrs &attr2) {3299 const AutofuseInnerAttrs &attr2) {
3294- // 目前业界暂不支持融合reduce和reduce,即融合的两个节点只有一个是reduce,后期如果要融合两个reduce则需要根据reduce节点名字保存对应的原始轴信息3300+ attr_new.reduce_original_axis_infos = attr1.reduce_original_axis_infos;
3301+ attr_new.reduce_original_axis_infos.insert(attr2.reduce_original_axis_infos.begin(),
3302+ attr2.reduce_original_axis_infos.end());
3303+ 
3295 if (!attr1.reduce_original_axis.empty()) {3304 if (!attr1.reduce_original_axis.empty()) {
3296 attr_new.reduce_original_axis = attr1.reduce_original_axis;3305 attr_new.reduce_original_axis = attr1.reduce_original_axis;
3297 } else {3306 } else {
@@ -3304,6 +3313,11 @@ void BackendUtils::SetReduceOriginalAxisInfo(AutofuseInnerAttrs &attr_new, const
3304 }3313 }
3305}3314}
3306 3315 
3316+void BackendUtils::SetReshapeAxisChangeInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,
3317+ const AutofuseInnerAttrs &attr2) {
3318+ asc_adapt::InheritReshapeAxisChanges(attr_new, attr1, attr2);
3319+}
3320+ 
3307// 融合存在轴映射之后index对应的axis变化的场景,则记录的reduce的原始axis也要相应变化3321// 融合存在轴映射之后index对应的axis变化的场景,则记录的reduce的原始axis也要相应变化
3308Status BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node, const NodePtr &asc_node,3322Status BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node, const NodePtr &asc_node,
3309 const std::vector<int64_t> axis_before_Flush,3323 const std::vector<int64_t> axis_before_Flush,
@@ -3329,7 +3343,7 @@ Status BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node,
3329 auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(node);3343 auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(node);
3330 GE_ASSERT_NOTNULL(autofuse_attr);3344 GE_ASSERT_NOTNULL(autofuse_attr);
3331 3345 
3332- auto reduce_original_axis = autofuse_attr->GetReduceOriginalAxis();3346+ auto reduce_original_axis = autofuse_attr->GetReduceOriginalAxis(asc_node->GetName());
3333 if (reduce_original_axis.empty()) {3347 if (reduce_original_axis.empty()) {
3334 return SUCCESS;3348 return SUCCESS;
3335 }3349 }
@@ -3353,13 +3367,20 @@ Status BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node,
3353 }3367 }
3354 }3368 }
3355 3369 
3356- autofuse_attr->SetReduceOriginalAxis(updated_axis);3370+ autofuse_attr->SetReduceOriginalAxis(asc_node->GetName(), updated_axis);
3357 GELOGD("Flush reduce original axis for asc_node %s, before: %s, after: %s", asc_node->GetName().c_str(),3371 GELOGD("Flush reduce original axis for asc_node %s, before: %s, after: %s", asc_node->GetName().c_str(),
3358 AutofuseUtils::VectorToStr(reduce_original_axis).c_str(), AutofuseUtils::VectorToStr(updated_axis).c_str());3372 AutofuseUtils::VectorToStr(reduce_original_axis).c_str(), AutofuseUtils::VectorToStr(updated_axis).c_str());
3359 3373 
3360 return SUCCESS;3374 return SUCCESS;
3361}3375}
3362 3376 
3377+// Keep AutoFuseAttrs reshape axis metadata in the current AscGraph axis space after axis mapping flush.
3378+Status BackendUtils::FlushReshapeAxisChanges(const NodePtr &node, const NodePtr &asc_node,
3379+ const std::vector<int64_t> axis_before_Flush,
3380+ const std::vector<int64_t> axis_after_Flush) {
3381+ return asc_adapt::FlushReshapeAxisChanges(node, asc_node, axis_before_Flush, axis_after_Flush);
3382+}
3383+ 
3363Status GetNodeTransposeInfo(const NodePtr &node, const TensorAttrInfo &temp_graph_attr,3384Status GetNodeTransposeInfo(const NodePtr &node, const TensorAttrInfo &temp_graph_attr,
3364 std::vector<std::pair<int64_t, int64_t>> &transpose_info) {3385 std::vector<std::pair<int64_t, int64_t>> &transpose_info) {
3365 const auto cur_op_desc = node->GetOpDesc();3386 const auto cur_op_desc = node->GetOpDesc();
@@ -670,6 +670,8 @@ class BackendUtils {
670 static Status ApplySwaps(TensorAttrInfo &temp_data_attr, const std::vector<std::pair<int64_t, int64_t>> &swaps);670 static Status ApplySwaps(TensorAttrInfo &temp_data_attr, const std::vector<std::pair<int64_t, int64_t>> &swaps);
671 static Status PostProBackSteppingViewOp(AscGraph &asc_graph, const NodePtr &cur_node, ViewOpAttrInfo &attr_info,671 static Status PostProBackSteppingViewOp(AscGraph &asc_graph, const NodePtr &cur_node, ViewOpAttrInfo &attr_info,
672 bool is_back_broadcast);672 bool is_back_broadcast);
673+ static Status CompleteReshapeAxesForBackendCanFuse(const NodePtr &node1, const NodePtr &node2,
674+ const NodeFuseInfo &fuse_info);
673 static Status TuningSubgraphBeforeMerge(const NodePtr &node1, const NodePtr &node2, const ComputeGraphPtr &graph1,675 static Status TuningSubgraphBeforeMerge(const NodePtr &node1, const NodePtr &node2, const ComputeGraphPtr &graph1,
674 const ComputeGraphPtr &graph2, const NodeFuseInfo &fuse_info);676 const ComputeGraphPtr &graph2, const NodeFuseInfo &fuse_info);
675 static Status GetPreNodeAndAnchor(const NodePtr &node, const int32_t index, NodePtr &peer_node,677 static Status GetPreNodeAndAnchor(const NodePtr &node, const int32_t index, NodePtr &peer_node,
@@ -850,9 +852,16 @@ class BackendUtils {
850 static bool OnlyHasTypesInAscgraph(const NodePtr &node, const std::vector<std::string> &target_types);852 static bool OnlyHasTypesInAscgraph(const NodePtr &node, const std::vector<std::string> &target_types);
851 static void SetReduceOriginalAxisInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,853 static void SetReduceOriginalAxisInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,
852 const AutofuseInnerAttrs &attr2);854 const AutofuseInnerAttrs &attr2);
855+ // Inherit reshape axis changes when creating a fused backend node.
856+ static void SetReshapeAxisChangeInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,
857+ const AutofuseInnerAttrs &attr2);
853 static Status FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node, const NodePtr &asc_node,858 static Status FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node, const NodePtr &asc_node,
854 const std::vector<int64_t> axis_before_Flush,859 const std::vector<int64_t> axis_before_Flush,
855 const std::vector<int64_t> axis_after_Flush);860 const std::vector<int64_t> axis_after_Flush);
861+ // Refresh reshape axis changes after backend axis ids are remapped.
862+ static Status FlushReshapeAxisChanges(const NodePtr &node, const NodePtr &asc_node,
863+ const std::vector<int64_t> axis_before_Flush,
864+ const std::vector<int64_t> axis_after_Flush);
856 static Status GetTransposeInfos(865 static Status GetTransposeInfos(
857 AscGraph &asc_graph, bool &has_only_one_transpose,866 AscGraph &asc_graph, bool &has_only_one_transpose,
858 std::unordered_map<NodePtr, std::vector<std::pair<int64_t, int64_t>>> &fallback_node_to_transpose_info);867 std::unordered_map<NodePtr, std::vector<std::pair<int64_t, int64_t>>> &fallback_node_to_transpose_info);
@@ -14,7 +14,6 @@
14#include "can_fuse/strategy/fusion_strategy_registry.h"14#include "can_fuse/strategy/fusion_strategy_registry.h"
15#include "utils/not_fuse_reason_code.h"15#include "utils/not_fuse_reason_code.h"
16#include "utils/auto_fuse_config.h"16#include "utils/auto_fuse_config.h"
17-#include "utils/autofuse_utils.h"
18#include "can_fuse/backend/asc_graph_axis_mapping.h"17#include "can_fuse/backend/asc_graph_axis_mapping.h"
19 18 
20namespace ge {19namespace ge {
@@ -36,33 +35,6 @@ void CheckAndInitReduceAllLoadState(const NodePtr &node, AutoFuseAttrs *attr, co
36 }35 }
37}36}
38 37 
39-bool HasReduceOriginalInfo(const AutoFuseAttrs *attr) {
40- return (!attr->GetReduceOriginalAxis().empty()) || (!attr->GetReduceOriginalRepeats().empty());
41-}
42- 
43-bool IsReduceOriginalInfoCompatible(const NodePtr &node1, const AutoFuseAttrs *attr1, const NodePtr &node2,
44- const AutoFuseAttrs *attr2) {
45- if (!HasReduceOriginalInfo(attr1) || !HasReduceOriginalInfo(attr2)) {
46- return true;
47- }
48- 
49- const auto &axis1 = attr1->GetReduceOriginalAxis();
50- const auto &axis2 = attr2->GetReduceOriginalAxis();
51- const auto &repeats1 = attr1->GetReduceOriginalRepeats();
52- const auto &repeats2 = attr2->GetReduceOriginalRepeats();
53- if ((axis1.size() != repeats1.size()) || (axis2.size() != repeats2.size()) || (axis1 != axis2) ||
54- (repeats1 != repeats2)) {
55- GELOGI(
56- "node1 %s(%s) and node2 %s(%s) cannot fuse, reduce original axis or repeats conflict. node1 axis:%s, "
57- "repeats:%s; node2 axis:%s, repeats:%s.",
58- node1->GetNamePtr(), node1->GetType().c_str(), node2->GetNamePtr(), node2->GetType().c_str(),
59- AutofuseUtils::VectorToStr(axis1).c_str(), AutofuseUtils::VectorToStr(repeats1).c_str(),
60- AutofuseUtils::VectorToStr(axis2).c_str(), AutofuseUtils::VectorToStr(repeats2).c_str());
61- return false;
62- }
63- return true;
64-}
65- 
66bool ReduceFusionStrategy::CanFuse(const NodePtr &node1, const NodePtr &node2) {38bool ReduceFusionStrategy::CanFuse(const NodePtr &node1, const NodePtr &node2) {
67 const auto attr1 = BackendUtils::GetNodeAutoFuseAttr(node1);39 const auto attr1 = BackendUtils::GetNodeAutoFuseAttr(node1);
68 GE_ASSERT_NOTNULL(attr1);40 GE_ASSERT_NOTNULL(attr1);
@@ -73,10 +45,6 @@ bool ReduceFusionStrategy::CanFuse(const NodePtr &node1, const NodePtr &node2) {
73 std::string node1_desc = std::string("node1 ") + node1->GetNamePtr() + "(" + node1->GetType().c_str() + ")";45 std::string node1_desc = std::string("node1 ") + node1->GetNamePtr() + "(" + node1->GetType().c_str() + ")";
74 std::string node2_desc = std::string("node2 ") + node2->GetNamePtr() + "(" + node2->GetType().c_str() + ")";46 std::string node2_desc = std::string("node2 ") + node2->GetNamePtr() + "(" + node2->GetType().c_str() + ")";
75 47 
76- if (!IsReduceOriginalInfoCompatible(node1, attr1, node2, attr2)) {
77- return false;
78- }
79- 
80 // 检查并初始化node1的is_reduce_all_load状态48 // 检查并初始化node1的is_reduce_all_load状态
81 CheckAndInitReduceAllLoadState(node1, attr1, node1_desc);49 CheckAndInitReduceAllLoadState(node1, attr1, node1_desc);
82 50 
@@ -28,6 +28,14 @@
28namespace ge {28namespace ge {
29namespace loop {29namespace loop {
30using Edge = std::pair<const ge::OutDataAnchor *, const ge::InDataAnchor *>;30using Edge = std::pair<const ge::OutDataAnchor *, const ge::InDataAnchor *>;
31+struct ReshapeAxisMeta {
32+ std::vector<ReshapeAxisChangeInfo> axis_changes;
33+};
34+ 
35+struct NodeAxisMeta {
36+ ReshapeAxisMeta reshape;
37+};
38+ 
31// lazy init extra data, never hold any sharedptr of the node39// lazy init extra data, never hold any sharedptr of the node
32struct ExtraKernelBoxMeta {40struct ExtraKernelBoxMeta {
33 size_t num_ops = 0U;41 size_t num_ops = 0U;
@@ -37,6 +45,7 @@ struct ExtraKernelBoxMeta {
37 std::set<const ge::OutDataAnchor *> used_ascend_buffers;45 std::set<const ge::OutDataAnchor *> used_ascend_buffers;
38 std::set<const ge::OutDataAnchor *> optimized_ascend_buffers;46 std::set<const ge::OutDataAnchor *> optimized_ascend_buffers;
39 std::set<loop::Edge> concrete_edges; // edges consumed by this fused kernel47 std::set<loop::Edge> concrete_edges; // edges consumed by this fused kernel
48+ NodeAxisMeta node_axis_meta;
40 std::string stream_label;49 std::string stream_label;
41 std::string stream_priority;50 std::string stream_priority;
42 static ExtraKernelBoxMeta &Default() {51 static ExtraKernelBoxMeta &Default() {
@@ -86,6 +95,10 @@ struct KernelBoxMeta {
86 if (op->Type() == "ops.StoreStridedSlice") {95 if (op->Type() == "ops.StoreStridedSlice") {
87 extra->num_slices++;96 extra->num_slices++;
88 }97 }
98+ const auto &reshape_axis_changes = op->GetReshapeAxisChanges();
99+ auto &reshape_meta = extra->node_axis_meta.reshape;
100+ reshape_meta.axis_changes.insert(reshape_meta.axis_changes.end(), reshape_axis_changes.begin(),
101+ reshape_axis_changes.end());
89 const auto node = op->GetAscendIrNode();102 const auto node = op->GetAscendIrNode();
90 if (node != nullptr && seen_nodes.insert(node).second) {103 if (node != nullptr && seen_nodes.insert(node).second) {
91 if (extra->stream_label.empty()) {104 if (extra->stream_label.empty()) {
@@ -350,6 +363,10 @@ class KernelBox {
350 return GetExtraMeta().optimized_ascend_buffers;363 return GetExtraMeta().optimized_ascend_buffers;
351 }364 }
352 365 
366+ const std::vector<ReshapeAxisChangeInfo> &GetReshapeAxisChanges() {
367+ return GetExtraMeta().node_axis_meta.reshape.axis_changes;
368+ }
369+ 
353 size_t NumOps() {370 size_t NumOps() {
354 return GetExtraMeta().num_ops;371 return GetExtraMeta().num_ops;
355 }372 }
@@ -668,6 +668,28 @@ bool CheckAndGetDims(const std::vector<Expression> &long_dims, const std::vector
668 return !dims.empty();668 return !dims.empty();
669}669}
670 670 
671+std::vector<int64_t> MakeAxisByRank(const size_t rank) {
672+ std::vector<int64_t> axis;
673+ axis.reserve(rank);
674+ for (size_t i = 0U; i < rank; ++i) {
675+ axis.push_back(static_cast<int64_t>(i));
676+ }
677+ return axis;
678+}
679+ 
680+void AddReshapeAxisChange(const LoopVar &reshape, const std::vector<Expression> &src_dims,
681+ const std::vector<Expression> &dst_dims) {
682+ if (!reshape.IsValid()) {
683+ return;
684+ }
685+ ReshapeAxisChangeInfo change;
686+ change.before_axis = MakeAxisByRank(src_dims.size());
687+ change.before_repeats = src_dims;
688+ change.after_axis = MakeAxisByRank(dst_dims.size());
689+ change.after_repeats = dst_dims;
690+ reshape.Op()->AddReshapeAxisChange(change);
691+}
692+ 
671// Reshape只做attr为默认参数,且不进行轴转换,能进行unsqueeze/squeeze的情况。[3,4]->[1,3,4]/[2,1,3]->[2,3]693// Reshape只做attr为默认参数,且不进行轴转换,能进行unsqueeze/squeeze的情况。[3,4]->[1,3,4]/[2,1,3]->[2,3]
672// 新增支持 [A*B, C]->[A,B,C]/[A,B,C]->[A*B,C]694// 新增支持 [A*B, C]->[A,B,C]/[A,B,C]->[A*B,C]
673LoopVar Reshape(const LoopVar &op, const std::vector<Expression> &src_dims, const std::vector<Expression> &dst_dims) {695LoopVar Reshape(const LoopVar &op, const std::vector<Expression> &src_dims, const std::vector<Expression> &dst_dims) {
@@ -163,6 +163,8 @@ LoopVar Transpose(const LoopVar &op, const std::vector<ge::Expression> &dims, co
163LoopVar Squeeze(const LoopVar &op, int64_t dim);163LoopVar Squeeze(const LoopVar &op, int64_t dim);
164LoopVar Unsqueeze(const LoopVar &op, int64_t dim);164LoopVar Unsqueeze(const LoopVar &op, int64_t dim);
165LoopVar Reshape(const LoopVar &op, const std::vector<Expression> &src_dims, const std::vector<Expression> &dst_dims);165LoopVar Reshape(const LoopVar &op, const std::vector<Expression> &src_dims, const std::vector<Expression> &dst_dims);
166+void AddReshapeAxisChange(const LoopVar &reshape, const std::vector<Expression> &src_dims,
167+ const std::vector<Expression> &dst_dims);
166LoopVar LoadSeed(const std::string &name, const LoopVar &offset);168LoopVar LoadSeed(const std::string &name, const LoopVar &offset);
167LoopVar ReduceThenBroadcast(ReduceType type, const LoopVar &op, int64_t dim);169LoopVar ReduceThenBroadcast(ReduceType type, const LoopVar &op, int64_t dim);
168LoopVar ToDtypeBitcast(const LoopVar &x, ge::DataType dst_type, ge::DataType src_type);170LoopVar ToDtypeBitcast(const LoopVar &x, ge::DataType dst_type, ge::DataType src_type);
@@ -68,6 +68,13 @@ struct LoopAxis {
68 */68 */
69using Index = std::vector<ge::Expression>;69using Index = std::vector<ge::Expression>;
70 70 
71+struct ReshapeAxisChangeInfo {
72+ std::vector<int64_t> before_axis;
73+ std::vector<Expression> before_repeats;
74+ std::vector<int64_t> after_axis;
75+ std::vector<Expression> after_repeats;
76+};
77+ 
71/**78/**
72 * TensorLoopDesc用于表达一个Loop lowering后的Ascend IR输出值的循环描述,其包含了一个Loop的所有信息。79 * TensorLoopDesc用于表达一个Loop lowering后的Ascend IR输出值的循环描述,其包含了一个Loop的所有信息。
73 * 包括循环的遍历范围、循环的步长。80 * 包括循环的遍历范围、循环的步长。
@@ -114,8 +114,17 @@ class LoopOp {
114 return inputs_;114 return inputs_;
115 }115 }
116 116 
117+ void AddReshapeAxisChange(const ReshapeAxisChangeInfo &change) {
118+ reshape_axis_changes_.push_back(change);
119+ }
120+ 
121+ [[nodiscard]] const std::vector<ReshapeAxisChangeInfo> &GetReshapeAxisChanges() const {
122+ return reshape_axis_changes_;
123+ }
124+ 
117 [[nodiscard]] LoopOpPtr Clone() const {125 [[nodiscard]] LoopOpPtr Clone() const {
118 auto op = CloneImpl();126 auto op = CloneImpl();
127+ op->reshape_axis_changes_ = reshape_axis_changes_;
119 for (size_t i = 0U; i < inputs_.size(); ++i) {128 for (size_t i = 0U; i < inputs_.size(); ++i) {
120 op->inputs_[i] = op->inputs_[i]->Clone();129 op->inputs_[i] = op->inputs_[i]->Clone();
121 }130 }
@@ -132,6 +141,7 @@ class LoopOp {
132 141 
133 private:142 private:
134 static std::atomic<int64_t> global_id_;143 static std::atomic<int64_t> global_id_;
144+ std::vector<ReshapeAxisChangeInfo> reshape_axis_changes_;
135};145};
136 146 
137class LoopVar {147class LoopVar {
@@ -243,6 +243,21 @@ string CreateAscbackendName(loop::KernelBox &kernel_box, CounterPtr counter) {
243 return ascbackend_name;243 return ascbackend_name;
244}244}
245 245 
246+Status SaveReshapeAxisChangeInfo(loop::KernelBox &kernel_box, const std::shared_ptr<AscGraph> &asc_graph,
247+ AutoFuseAttrs *fuse_attrs) {
248+ (void)asc_graph;
249+ const auto &reshape_axis_changes = kernel_box.GetReshapeAxisChanges();
250+ for (const auto &loop_change : reshape_axis_changes) {
251+ af::ReshapeAxisChangeInfo change;
252+ change.before_axis = loop_change.before_axis;
253+ change.before_repeats = loop_change.before_repeats;
254+ change.after_axis = loop_change.after_axis;
255+ change.after_repeats = loop_change.after_repeats;
256+ fuse_attrs->AddReshapeAxisChange(change);
257+ }
258+ return SUCCESS;
259+}
260+ 
246graphStatus BuildOpForKernelBox(loop::KernelBox &kernel_box, CounterPtr counter,261graphStatus BuildOpForKernelBox(loop::KernelBox &kernel_box, CounterPtr counter,
247 shared_ptr<loop::AscOverrides> asc_graph, af::Operator &asc_op) {262 shared_ptr<loop::AscOverrides> asc_graph, af::Operator &asc_op) {
248 std::string asc_op_name = CreateAscbackendName(kernel_box, counter);263 std::string asc_op_name = CreateAscbackendName(kernel_box, counter);
@@ -424,6 +439,7 @@ OpDescPtr LoweringManager::BuildOpDescForKernelBox(loop::KernelBox &kernel_box,
424 GE_ASSERT_NOTNULL(fuse_attrs);439 GE_ASSERT_NOTNULL(fuse_attrs);
425 GE_ASSERT_NOTNULL(asc_graph->SharedGraph());440 GE_ASSERT_NOTNULL(asc_graph->SharedGraph());
426 fuse_attrs->SetAscGraph(asc_graph->SharedGraph(), kernel_box.Type());441 fuse_attrs->SetAscGraph(asc_graph->SharedGraph(), kernel_box.Type());
442+ GE_ASSERT_SUCCESS(SaveReshapeAxisChangeInfo(kernel_box, asc_graph->SharedGraph(), fuse_attrs));
427 fuse_attrs->SetOriginOutputBuffers({anchor});443 fuse_attrs->SetOriginOutputBuffers({anchor});
428 fuse_attrs->SetOriginNodes(kernel_box.GetAscendIrNodes());444 fuse_attrs->SetOriginNodes(kernel_box.GetAscendIrNodes());
429 fuse_attrs->SetOptimizedInputBuffers(kernel_box.GetOptimizedInputAscendBuffers());445 fuse_attrs->SetOptimizedInputBuffers(kernel_box.GetOptimizedInputAscendBuffers());
@@ -1914,11 +1914,21 @@ REGISTER_LOWERING(SquareSumV1) {
1914 1914 
1915REGISTER_LOWERING(Unsqueeze) {1915REGISTER_LOWERING(Unsqueeze) {
1916 auto x = loop::Load(node->GetInDataAnchor(0));1916 auto x = loop::Load(node->GetInDataAnchor(0));
1917+ GE_ASSERT_NOTNULL(node->GetInDataAnchor(0));
1918+ auto src = node->GetInDataAnchor(0)->GetPeerOutAnchor();
1919+ GE_ASSERT_NOTNULL(src);
1920+ std::vector<ge::Expression> dims;
1921+ LOWERING_WARN_RECORD_REASON(loop::GetBufferShape(src, dims) == GRAPH_SUCCESS, node,
1922+ "Failed to get 0th-input symbol shape.");
1923+ std::vector<ge::Expression> output_dims;
1924+ LOWERING_WARN_RECORD_REASON(loop::GetBufferShape(node->GetOutDataAnchor(0), output_dims) == GRAPH_SUCCESS, node,
1925+ "Failed to get 0th-output symbol shape.");
1917 std::vector<int64_t> vec_axes;1926 std::vector<int64_t> vec_axes;
1918 GE_ASSERT_TRUE(AttrUtils::GetListInt(node->GetOpDesc(), "axes", vec_axes));1927 GE_ASSERT_TRUE(AttrUtils::GetListInt(node->GetOpDesc(), "axes", vec_axes));
1919 for (const auto vec_axe : vec_axes) {1928 for (const auto vec_axe : vec_axes) {
1920 x = loop::Unsqueeze(x, vec_axe);1929 x = loop::Unsqueeze(x, vec_axe);
1921 }1930 }
1931+ loop::AddReshapeAxisChange(x, dims, output_dims);
1922 loop::StoreReshape(node->GetOutDataAnchor(0), x);1932 loop::StoreReshape(node->GetOutDataAnchor(0), x);
1923 return GRAPH_SUCCESS;1933 return GRAPH_SUCCESS;
1924}1934}
@@ -1950,6 +1960,10 @@ REGISTER_LOWERING(Squeeze) {
1950 for (size_t i = 0; i < vec_axes.size(); i++) {1960 for (size_t i = 0; i < vec_axes.size(); i++) {
1951 x = loop::Squeeze(x, vec_axes[i] - static_cast<int64_t>(i));1961 x = loop::Squeeze(x, vec_axes[i] - static_cast<int64_t>(i));
1952 }1962 }
1963+ std::vector<ge::Expression> output_dims;
1964+ LOWERING_WARN_RECORD_REASON(loop::GetBufferShape(node->GetOutDataAnchor(0), output_dims) == GRAPH_SUCCESS, node,
1965+ "Failed to get 0th-output symbol shape.");
1966+ loop::AddReshapeAxisChange(x, dims, output_dims);
1953 loop::Store(node->GetOutDataAnchor(0), x);1967 loop::Store(node->GetOutDataAnchor(0), x);
1954 return GRAPH_SUCCESS;1968 return GRAPH_SUCCESS;
1955}1969}
@@ -2121,8 +2135,6 @@ REGISTER_LOWERING(Reshape) {
2121 GE_ASSERT_NOTNULL(node->GetInDataAnchor(0));2135 GE_ASSERT_NOTNULL(node->GetInDataAnchor(0));
2122 auto src = node->GetInDataAnchor(0)->GetPeerOutAnchor();2136 auto src = node->GetInDataAnchor(0)->GetPeerOutAnchor();
2123 GE_ASSERT_NOTNULL(src);2137 GE_ASSERT_NOTNULL(src);
2124- auto desc = src->GetOwnerNode()->GetOpDesc()->GetOutputDescPtr(src->GetIdx());
2125- GE_ASSERT_NOTNULL(desc);
2126 std::vector<Expression> dims;2138 std::vector<Expression> dims;
2127 LOWERING_WARN_RECORD_REASON(loop::GetBufferShape(src, dims) == GRAPH_SUCCESS, node,2139 LOWERING_WARN_RECORD_REASON(loop::GetBufferShape(src, dims) == GRAPH_SUCCESS, node,
2128 "Failed to get 0th-input symbol shape");2140 "Failed to get 0th-input symbol shape");
@@ -2143,12 +2155,22 @@ REGISTER_LOWERING(Reshape) {
2143 auto x = loop::Load(node->GetInDataAnchor(0));2155 auto x = loop::Load(node->GetInDataAnchor(0));
2144 auto reshape = loop::Reshape(x, dims, output_dims);2156 auto reshape = loop::Reshape(x, dims, output_dims);
2145 LOWERING_WARN_RECORD_REASON(reshape.IsValid(), node, "no specific reshape pattern matched");2157 LOWERING_WARN_RECORD_REASON(reshape.IsValid(), node, "no specific reshape pattern matched");
2158+ loop::AddReshapeAxisChange(reshape, dims, output_dims);
2146 loop::StoreReshape(node->GetOutDataAnchor(0), reshape);2159 loop::StoreReshape(node->GetOutDataAnchor(0), reshape);
2147 return GRAPH_SUCCESS;2160 return GRAPH_SUCCESS;
2148}2161}
2149 2162 
2150REGISTER_LOWERING(ExpandDims) {2163REGISTER_LOWERING(ExpandDims) {
2151 auto x = loop::Load(node->GetInDataAnchor(0));2164 auto x = loop::Load(node->GetInDataAnchor(0));
2165+ GE_ASSERT_NOTNULL(node->GetInDataAnchor(0));
2166+ auto src = node->GetInDataAnchor(0)->GetPeerOutAnchor();
2167+ GE_ASSERT_NOTNULL(src);
2168+ std::vector<ge::Expression> input_dims;
2169+ LOWERING_WARN_RECORD_REASON(loop::GetBufferShape(src, input_dims) == GRAPH_SUCCESS, node,
2170+ "Failed to get 0th-input symbol shape.");
2171+ std::vector<ge::Expression> output_dims;
2172+ LOWERING_WARN_RECORD_REASON(loop::GetBufferShape(node->GetOutDataAnchor(0), output_dims) == GRAPH_SUCCESS, node,
2173+ "Failed to get 0th-output symbol shape.");
2152 const auto op = ge::OpDescUtils::CreateOperatorFromNode(node);2174 const auto op = ge::OpDescUtils::CreateOperatorFromNode(node);
2153 ge::Tensor axis_tensor;2175 ge::Tensor axis_tensor;
2154 LOWERING_WARN_RECORD_REASON(op.GetInputConstData("axis", axis_tensor) == ge::SUCCESS, node, "Input is dynamic axis");2176 LOWERING_WARN_RECORD_REASON(op.GetInputConstData("axis", axis_tensor) == ge::SUCCESS, node, "Input is dynamic axis");
@@ -2172,6 +2194,7 @@ REGISTER_LOWERING(ExpandDims) {
2172 }2194 }
2173 2195 
2174 x = loop::Unsqueeze(x, dim);2196 x = loop::Unsqueeze(x, dim);
2197+ loop::AddReshapeAxisChange(x, input_dims, output_dims);
2175 loop::StoreReshape(node->GetOutDataAnchor(0), x);2198 loop::StoreReshape(node->GetOutDataAnchor(0), x);
2176 return GRAPH_SUCCESS;2199 return GRAPH_SUCCESS;
2177}2200}
@@ -543,11 +543,12 @@ inline Status SaveReduceOriginalAxisToFuseAttrPro(AscGraph &asc_graph, [[maybe_u
543 GE_ASSERT_SUCCESS(asc_adapt::GetPeerOutNode(node, reduce_input_node, 0));543 GE_ASSERT_SUCCESS(asc_adapt::GetPeerOutNode(node, reduce_input_node, 0));
544 TensorAttrInfo reduce_input_node_attr;544 TensorAttrInfo reduce_input_node_attr;
545 GE_ASSERT_SUCCESS(BackendUtils::GetNodeTensorAttrInfo(reduce_input_node, reduce_input_node_attr));545 GE_ASSERT_SUCCESS(BackendUtils::GetNodeTensorAttrInfo(reduce_input_node, reduce_input_node_attr));
546- autofuse_attr->SetReduceOriginalAxis(reduce_input_node_attr.axis);546+ autofuse_attr->SetReduceOriginalAxisInfo(node->GetName(), reduce_input_node_attr.axis,
547- autofuse_attr->SetReduceOriginalRepeats(reduce_input_node_attr.repeats);547+ reduce_input_node_attr.repeats);
548- GELOGI("graph %s has broadcast linkto reduce, save axis(axis:%s repeat:%s) between broadcast reduce .",548+ GELOGI("graph %s has broadcast linkto reduce %s, save axis(axis:%s repeat:%s) between broadcast reduce .",
549- asc_graph.GetName().c_str(), AutofuseUtils::VectorToStr(autofuse_attr->GetReduceOriginalAxis()).c_str(),549+ asc_graph.GetName().c_str(), node->GetNamePtr(),
550- AutofuseUtils::VectorToStr(autofuse_attr->GetReduceOriginalRepeats()).c_str());550+ AutofuseUtils::VectorToStr(reduce_input_node_attr.axis).c_str(),
551+ AutofuseUtils::VectorToStr(reduce_input_node_attr.repeats).c_str());
551 }552 }
552 }553 }
553 return SUCCESS;554 return SUCCESS;
@@ -290,12 +290,9 @@ inline Status FlashContinueGraphAxis(std::vector<AxisPtr> &axis, const std::vect
290 return SUCCESS;290 return SUCCESS;
291}291}
292 292 
293-inline Status RemoveReduceOriginalInvalidAxis(const NodePtr &asc_node,293+inline Status RemoveReduceOriginalInvalidAxis(std::vector<int64_t> &reduce_original_axis,
294+ std::vector<Expression> &reduce_original_repeats, const NodePtr &asc_node,
294 const std::vector<int64_t> &graph_invalid_axis_id) {295 const std::vector<int64_t> &graph_invalid_axis_id) {
295- auto attr = BackendUtils::GetNodeAutoFuseAttr(asc_node);
296- GE_ASSERT_NOTNULL(attr);
297- auto reduce_original_axis = attr->GetReduceOriginalAxis();
298- auto reduce_original_repeats = attr->GetReduceOriginalRepeats();
299 if (reduce_original_axis.empty() || reduce_original_repeats.empty()) {296 if (reduce_original_axis.empty() || reduce_original_repeats.empty()) {
300 return SUCCESS;297 return SUCCESS;
301 }298 }
@@ -313,8 +310,25 @@ inline Status RemoveReduceOriginalInvalidAxis(const NodePtr &asc_node,
313 reduce_original_repeats.erase(reduce_original_repeats.begin() + axis_idx);310 reduce_original_repeats.erase(reduce_original_repeats.begin() + axis_idx);
314 }311 }
315 GE_ASSERT_SUCCESS(FlashContinueNodeAxis(reduce_original_axis, graph_invalid_axis_id));312 GE_ASSERT_SUCCESS(FlashContinueNodeAxis(reduce_original_axis, graph_invalid_axis_id));
313+ return SUCCESS;
314+}
315+ 
316+inline Status RemoveReduceOriginalInvalidAxis(const NodePtr &asc_node,
317+ const std::vector<int64_t> &graph_invalid_axis_id) {
318+ auto attr = BackendUtils::GetNodeAutoFuseAttr(asc_node);
319+ GE_ASSERT_NOTNULL(attr);
320+ 
321+ auto reduce_original_axis = attr->GetReduceOriginalAxis();
322+ auto reduce_original_repeats = attr->GetReduceOriginalRepeats();
323+ GE_ASSERT_SUCCESS(
324+ RemoveReduceOriginalInvalidAxis(reduce_original_axis, reduce_original_repeats, asc_node, graph_invalid_axis_id));
316 attr->SetReduceOriginalAxis(reduce_original_axis);325 attr->SetReduceOriginalAxis(reduce_original_axis);
317 attr->SetReduceOriginalRepeats(reduce_original_repeats);326 attr->SetReduceOriginalRepeats(reduce_original_repeats);
327+ 
328+ for (auto &reduce_info : attr->GetMutableInterAttrs().reduce_original_axis_infos) {
329+ GE_ASSERT_SUCCESS(RemoveReduceOriginalInvalidAxis(reduce_info.second.axis, reduce_info.second.repeats, asc_node,
330+ graph_invalid_axis_id));
331+ }
318 return SUCCESS;332 return SUCCESS;
319}333}
320 334 
@@ -72,14 +72,15 @@ inline Status InsertBroadcastBeforeNode(AscGraph &asc_graph, const NodePtr &node
72 return SUCCESS;72 return SUCCESS;
73}73}
74 74 
75-inline Status UpdateReduceNodeRepeats(const NodePtr &asc_node, TensorAttrInfo &temp_cur_attr) {75+inline Status UpdateReduceNodeRepeats(const NodePtr &asc_node, const NodePtr &reduce_node,
76+ TensorAttrInfo &temp_cur_attr) {
76 auto reduce_attrs = BackendUtils::GetNodeAutoFuseAttr(asc_node);77 auto reduce_attrs = BackendUtils::GetNodeAutoFuseAttr(asc_node);
77 if (reduce_attrs == nullptr) {78 if (reduce_attrs == nullptr) {
78 return SUCCESS;79 return SUCCESS;
79 }80 }
80 81 
81- const auto &original_axis = reduce_attrs->GetReduceOriginalAxis();82+ const auto &original_axis = reduce_attrs->GetReduceOriginalAxis(reduce_node->GetName());
82- const auto &original_repeats = reduce_attrs->GetReduceOriginalRepeats();83+ const auto &original_repeats = reduce_attrs->GetReduceOriginalRepeats(reduce_node->GetName());
83 84 
84 if (original_axis.empty() ||85 if (original_axis.empty() ||
85 original_repeats.empty()) { // 如果为空,说明前面是lowering出来不需要反推broadcast(load后或者融合点)的计算节点86 original_repeats.empty()) { // 如果为空,说明前面是lowering出来不需要反推broadcast(load后或者融合点)的计算节点
@@ -108,7 +109,7 @@ inline Status GetBroadcastInfoForNode(const NodePtr &cur_node, TensorAttrInfo &t
108 attr_info.broadcast_info.clear();109 attr_info.broadcast_info.clear();
109 110 
110 if (IsReduceNode(cur_node)) {111 if (IsReduceNode(cur_node)) {
111- GE_ASSERT_SUCCESS(UpdateReduceNodeRepeats(asc_node, temp_cur_attr));112+ GE_ASSERT_SUCCESS(UpdateReduceNodeRepeats(asc_node, cur_node, temp_cur_attr));
112 }113 }
113 114 
114 TensorAttrInfo temp_peer_out_attr;115 TensorAttrInfo temp_peer_out_attr;
@@ -0,0 +1,1741 @@
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 AUTOFUSE_POST_PROCESS_SCHEDULER_ADAPTER_ADAPTION_RESHAPE_AXIS_PADDING_H
12+#define AUTOFUSE_POST_PROCESS_SCHEDULER_ADAPTER_ADAPTION_RESHAPE_AXIS_PADDING_H
13+#include <algorithm>
14+#include <unordered_map>
15+#include <unordered_set>
16+#include "fusion/autofuse_attrs.h"
17+#include "fusion/fuse_type.h"
18+#include "graph/symbolizer/symbolic_utils.h"
19+#include "post_process/scheduler_adapter/adaption_complete_node_attrs.h"
20+#include "can_fuse/backend/asc_graph_axis_mapping.h"
21+#include "ascir_ops.h"
22+ 
23+namespace ge {
24+namespace asc_adapt {
25+inline bool IsSameRepeat(const Expression &lhs, const Expression &rhs) {
26+ return SymbolicUtils::StaticCheckEq(lhs, rhs) == TriBool::kTrue;
27+}
28+ 
29+inline bool IsUnitRepeat(const Expression &repeat) {
30+ return IsSameRepeat(repeat, kSymbolOne);
31+}
32+ 
33+inline bool IsSameRepeats(const std::vector<Expression> &lhs, const std::vector<Expression> &rhs) {
34+ return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin(), IsSameRepeat);
35+}
36+ 
37+inline std::vector<Expression> RemoveUnitRepeats(const std::vector<Expression> &repeats) {
38+ std::vector<Expression> non_unit_repeats;
39+ for (const auto &repeat : repeats) {
40+ if (!IsUnitRepeat(repeat)) {
41+ non_unit_repeats.push_back(repeat);
42+ }
43+ }
44+ return non_unit_repeats;
45+}
46+ 
47+inline std::vector<size_t> BuildUnitRepeatGapCounts(const std::vector<Expression> &repeats) {
48+ const auto non_unit_repeats = RemoveUnitRepeats(repeats);
49+ std::vector<size_t> unit_gap_counts(non_unit_repeats.size() + 1U, 0U);
50+ size_t non_unit_idx = 0U;
51+ for (const auto &repeat : repeats) {
52+ if (IsUnitRepeat(repeat)) {
53+ ++unit_gap_counts[non_unit_idx];
54+ } else if (non_unit_idx < non_unit_repeats.size()) {
55+ ++non_unit_idx;
56+ }
57+ }
58+ return unit_gap_counts;
59+}
60+ 
61+inline void MergeUnitRepeatGapCounts(const std::vector<size_t> &candidate_gaps, std::vector<size_t> &target_gaps) {
62+ if (target_gaps.empty()) {
63+ target_gaps = candidate_gaps;
64+ return;
65+ }
66+ if (target_gaps.size() != candidate_gaps.size()) {
67+ return;
68+ }
69+ for (size_t i = 0U; i < target_gaps.size(); ++i) {
70+ target_gaps[i] = std::max(target_gaps[i], candidate_gaps[i]);
71+ }
72+}
73+ 
74+inline std::vector<Expression> ApplyUnitRepeatGaps(const std::vector<Expression> &non_unit_repeats,
75+ const std::vector<size_t> &unit_gap_counts) {
76+ if (unit_gap_counts.size() != (non_unit_repeats.size() + 1U)) {
77+ return non_unit_repeats;
78+ }
79+ std::vector<Expression> target_repeats;
80+ for (size_t non_unit_idx = 0U; non_unit_idx < non_unit_repeats.size(); ++non_unit_idx) {
81+ target_repeats.insert(target_repeats.end(), unit_gap_counts[non_unit_idx], kSymbolOne);
82+ target_repeats.push_back(non_unit_repeats[non_unit_idx]);
83+ }
84+ target_repeats.insert(target_repeats.end(), unit_gap_counts.back(), kSymbolOne);
85+ return target_repeats;
86+}
87+ 
88+inline void AppendUniqueTargetRepeats(const std::vector<Expression> &target_repeats,
89+ std::vector<std::vector<Expression>> &target_candidates) {
90+ if (target_repeats.empty()) {
91+ return;
92+ }
93+ const auto it = std::find_if(target_candidates.begin(), target_candidates.end(),
94+ [&target_repeats](const auto &saved) { return IsSameRepeats(saved, target_repeats); });
95+ if (it == target_candidates.end()) {
96+ target_candidates.push_back(target_repeats);
97+ }
98+}
99+ 
100+inline std::vector<Expression> BuildNoOpReshapeTargetRepeats(const af::ReshapeAxisChangeInfo &axis_change) {
101+ const auto before_non_unit_repeats = RemoveUnitRepeats(axis_change.before_repeats);
102+ const auto after_non_unit_repeats = RemoveUnitRepeats(axis_change.after_repeats);
103+ if (!IsSameRepeats(before_non_unit_repeats, after_non_unit_repeats)) {
104+ return axis_change.before_repeats.size() >= axis_change.after_repeats.size() ? axis_change.before_repeats
105+ : axis_change.after_repeats;
106+ }
107+ 
108+ std::vector<size_t> unit_gap_counts;
109+ MergeUnitRepeatGapCounts(BuildUnitRepeatGapCounts(axis_change.before_repeats), unit_gap_counts);
110+ MergeUnitRepeatGapCounts(BuildUnitRepeatGapCounts(axis_change.after_repeats), unit_gap_counts);
111+ return ApplyUnitRepeatGaps(before_non_unit_repeats, unit_gap_counts);
112+}
113+ 
114+inline bool IsCompletedReshapeAxis(const AxisPtr &axis_info) {
115+ return (axis_info != nullptr) && (axis_info->name.rfind("reshape_axis_optimized_", 0U) == 0U);
116+}
117+ 
118+inline std::string GetCompletedReshapeAxisName(const int64_t axis_id) {
119+ return "reshape_axis_optimized_" + std::to_string(axis_id);
120+}
121+ 
122+inline void RefreshCompletedReshapeAxisName(const AxisPtr &axis_info) {
123+ if (IsCompletedReshapeAxis(axis_info)) {
124+ axis_info->name = GetCompletedReshapeAxisName(axis_info->id);
125+ }
126+}
127+ 
128+inline AxisPtr MakeNoOpReshapeAxis(const int64_t axis_id, const Expression &repeat) {
129+ auto axis_info = ComGraphMakeShared<Axis>();
130+ GE_ASSERT_NOTNULL(axis_info);
131+ axis_info->id = axis_id;
132+ axis_info->name = GetCompletedReshapeAxisName(axis_id);
133+ axis_info->type = Axis::kAxisTypeOriginal;
134+ axis_info->size = repeat;
135+ return axis_info;
136+}
137+ 
138+inline void ShiftAxisIdFrom(const int64_t insert_axis_id, int64_t &axis_id) {
139+ if (axis_id >= insert_axis_id) {
140+ ++axis_id;
141+ }
142+}
143+ 
144+inline void ShiftAxisInfoIdFrom(const int64_t insert_axis_id, const AxisPtr &axis_info) {
145+ if (axis_info == nullptr) {
146+ return;
147+ }
148+ const auto old_axis_id = axis_info->id;
149+ ShiftAxisIdFrom(insert_axis_id, axis_info->id);
150+ if (axis_info->id != old_axis_id) {
151+ RefreshCompletedReshapeAxisName(axis_info);
152+ }
153+}
154+ 
155+inline void ShiftAxisIdsFrom(const int64_t insert_axis_id, std::vector<int64_t> &axis) {
156+ for (auto &axis_id : axis) {
157+ ShiftAxisIdFrom(insert_axis_id, axis_id);
158+ }
159+}
160+ 
161+inline void ShiftReshapeAxisChangesFrom(const int64_t insert_axis_id,
162+ std::vector<af::ReshapeAxisChangeInfo> &reshape_axis_changes) {
163+ for (auto &change : reshape_axis_changes) {
164+ ShiftAxisIdsFrom(insert_axis_id, change.before_axis);
165+ ShiftAxisIdsFrom(insert_axis_id, change.after_axis);
166+ }
167+}
168+ 
169+inline Status ShiftAscGraphAxisIdsFrom(const AscGraph &asc_graph, const int64_t insert_axis_id) {
170+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
171+ const auto &op_desc = node->GetOpDesc();
172+ GE_ASSERT_NOTNULL(op_desc);
173+ auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();
174+ if (node_attr != nullptr) {
175+ ShiftAxisIdsFrom(insert_axis_id, node_attr->sched.axis);
176+ ShiftAxisIdFrom(insert_axis_id, node_attr->sched.loop_axis);
177+ }
178+ for (size_t i = 0U; i < node->GetAllInDataAnchorsSize(); ++i) {
179+ const auto input_tensor_desc = op_desc->MutableInputDesc(i);
180+ GE_ASSERT_NOTNULL(input_tensor_desc);
181+ auto tensor_attr = input_tensor_desc->GetAttrsGroup<AscTensorAttr>();
182+ if (tensor_attr == nullptr) {
183+ continue;
184+ }
185+ ShiftAxisIdsFrom(insert_axis_id, tensor_attr->axis);
186+ }
187+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
188+ const auto output_tensor_desc = op_desc->MutableOutputDesc(i);
189+ GE_ASSERT_NOTNULL(output_tensor_desc);
190+ auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
191+ if (tensor_attr == nullptr) {
192+ continue;
193+ }
194+ ShiftAxisIdsFrom(insert_axis_id, tensor_attr->axis);
195+ }
196+ }
197+ return SUCCESS;
198+}
199+ 
200+template <typename ScoreFunc>
201+inline std::vector<size_t> BuildBestOverlapTargetIndexes(const size_t source_size, const size_t target_size,
202+ const ScoreFunc &score_func) {
203+ if ((source_size == 0U) || (source_size > target_size)) {
204+ return {};
205+ }
206+ constexpr int32_t kInvalidScore = -1000000;
207+ std::vector<std::vector<int32_t>> dp(source_size + 1U, std::vector<int32_t>(target_size + 1U, kInvalidScore));
208+ for (size_t target_idx = 0U; target_idx <= target_size; ++target_idx) {
209+ dp[source_size][target_idx] = 0;
210+ }
211+ for (size_t source_idx = source_size; source_idx > 0U; --source_idx) {
212+ for (size_t target_idx = target_size; target_idx > 0U; --target_idx) {
213+ const auto source_pos = source_idx - 1U;
214+ const auto target_pos = target_idx - 1U;
215+ if ((source_size - source_pos) > (target_size - target_pos)) {
216+ continue;
217+ }
218+ const auto match_score = score_func(source_pos, target_pos) + dp[source_pos + 1U][target_pos + 1U];
219+ const auto skip_score = dp[source_pos][target_pos + 1U];
220+ dp[source_pos][target_pos] = std::max(match_score, skip_score);
221+ }
222+ }
223+ 
224+ std::vector<size_t> target_indexes(source_size, target_size);
225+ size_t source_idx = 0U;
226+ size_t target_idx = 0U;
227+ while ((source_idx < source_size) && (target_idx < target_size)) {
228+ const auto match_score = score_func(source_idx, target_idx) + dp[source_idx + 1U][target_idx + 1U];
229+ const auto skip_score = dp[source_idx][target_idx + 1U];
230+ if (((target_size - target_idx - 1U) >= (source_size - source_idx)) && (skip_score >= match_score)) {
231+ ++target_idx;
232+ continue;
233+ }
234+ target_indexes[source_idx++] = target_idx++;
235+ }
236+ return target_indexes;
237+}
238+ 
239+inline int64_t GetNextNoOpReshapeAxisId(const std::vector<AxisPtr> &graph_axis) {
240+ int64_t max_axis_id = -1;
241+ for (const auto &axis_info : graph_axis) {
242+ if (axis_info != nullptr) {
243+ max_axis_id = std::max(max_axis_id, axis_info->id);
244+ }
245+ }
246+ return max_axis_id + 1;
247+}
248+ 
249+inline int64_t GetNextNoOpReshapeAxisId(const std::vector<int64_t> &graph_axis_ids) {
250+ int64_t max_axis_id = -1;
251+ for (const auto axis_id : graph_axis_ids) {
252+ max_axis_id = std::max(max_axis_id, axis_id);
253+ }
254+ return max_axis_id + 1;
255+}
256+ 
257+inline std::vector<int64_t> CollectAxisIds(const std::vector<AxisPtr> &graph_axis) {
258+ std::vector<int64_t> axis_ids;
259+ axis_ids.reserve(graph_axis.size());
260+ for (const auto &axis_info : graph_axis) {
261+ if (axis_info != nullptr) {
262+ axis_ids.push_back(axis_info->id);
263+ }
264+ }
265+ return axis_ids;
266+}
267+ 
268+template <typename T>
269+inline void SortUniqueVector(std::vector<T> &values) {
270+ std::sort(values.begin(), values.end());
271+ values.erase(std::unique(values.begin(), values.end()), values.end());
272+}
273+ 
274+inline void ShiftAxisGroupFrom(const int64_t insert_axis_id, optimize::autoschedule::AxisGroup &axis_group) {
275+ auto shift_axis_ids = [insert_axis_id](std::vector<int64_t> &axis_ids) {
276+ for (auto &axis_id : axis_ids) {
277+ ShiftAxisIdFrom(insert_axis_id, axis_id);
278+ }
279+ SortUniqueVector(axis_ids);
280+ };
281+ 
282+ shift_axis_ids(axis_group.x_group);
283+ shift_axis_ids(axis_group.y_group);
284+ shift_axis_ids(axis_group.r_group);
285+ shift_axis_ids(axis_group.n_group);
286+ 
287+ for (auto &axis_order : axis_group.axes_order) {
288+ if (axis_order >= static_cast<size_t>(insert_axis_id)) {
289+ ++axis_order;
290+ }
291+ }
292+ SortUniqueVector(axis_group.axes_order);
293+}
294+ 
295+inline Status RefreshReshapeAxisGroupByInsertIndexes(const std::vector<int64_t> &axis_before_insert,
296+ const std::vector<size_t> &insert_indexes,
297+ optimize::autoschedule::AxisGroup &axis_group) {
298+ if (insert_indexes.empty() || axis_before_insert.empty() || axis_group.IsEmpty()) {
299+ return SUCCESS;
300+ }
301+ 
302+ auto current_axis_ids = axis_before_insert;
303+ auto sorted_insert_indexes = insert_indexes;
304+ std::sort(sorted_insert_indexes.begin(), sorted_insert_indexes.end());
305+ for (const auto insert_index : sorted_insert_indexes) {
306+ const auto insert_axis_id = (insert_index < current_axis_ids.size()) ? current_axis_ids[insert_index]
307+ : GetNextNoOpReshapeAxisId(current_axis_ids);
308+ ShiftAxisGroupFrom(insert_axis_id, axis_group);
309+ for (auto &axis_id : current_axis_ids) {
310+ ShiftAxisIdFrom(insert_axis_id, axis_id);
311+ }
312+ current_axis_ids.insert(
313+ current_axis_ids.begin() + static_cast<ptrdiff_t>(std::min(insert_index, current_axis_ids.size())),
314+ insert_axis_id);
315+ if (std::find(axis_group.y_group.begin(), axis_group.y_group.end(), insert_axis_id) == axis_group.y_group.end()) {
316+ axis_group.y_group.push_back(insert_axis_id);
317+ }
318+ if (std::find(axis_group.axes_order.begin(), axis_group.axes_order.end(), static_cast<size_t>(insert_axis_id)) ==
319+ axis_group.axes_order.end()) {
320+ axis_group.axes_order.push_back(static_cast<size_t>(insert_axis_id));
321+ }
322+ }
323+ 
324+ SortUniqueVector(axis_group.x_group);
325+ SortUniqueVector(axis_group.y_group);
326+ SortUniqueVector(axis_group.r_group);
327+ SortUniqueVector(axis_group.n_group);
328+ SortUniqueVector(axis_group.axes_order);
329+ return SUCCESS;
330+}
331+ 
332+inline Status RefreshReshapeAxisGroupByInsertedAxisIds(const std::vector<int64_t> &inserted_axis_ids,
333+ const std::vector<int64_t> &graph_axis_after_insert,
334+ optimize::autoschedule::AxisGroup &axis_group) {
335+ if (inserted_axis_ids.empty() || axis_group.IsEmpty()) {
336+ return SUCCESS;
337+ }
338+ 
339+ for (const auto axis_id : inserted_axis_ids) {
340+ if (std::find(axis_group.y_group.begin(), axis_group.y_group.end(), axis_id) == axis_group.y_group.end()) {
341+ axis_group.y_group.push_back(axis_id);
342+ }
343+ }
344+ axis_group.axes_order.clear();
345+ axis_group.axes_order.reserve(graph_axis_after_insert.size());
346+ for (const auto axis_id : graph_axis_after_insert) {
347+ axis_group.axes_order.push_back(static_cast<size_t>(axis_id));
348+ }
349+ SortUniqueVector(axis_group.y_group);
350+ return SUCCESS;
351+}
352+ 
353+inline std::vector<int64_t> CollectInsertedAxisIds(const std::vector<int64_t> &axis_before_insert,
354+ const std::vector<int64_t> &axis_after_insert) {
355+ std::vector<int64_t> inserted_axis_ids;
356+ for (const auto axis_id : axis_after_insert) {
357+ if (std::find(axis_before_insert.begin(), axis_before_insert.end(), axis_id) == axis_before_insert.end()) {
358+ inserted_axis_ids.push_back(axis_id);
359+ }
360+ }
361+ return inserted_axis_ids;
362+}
363+ 
364+inline void CopyTensorAttrs(const AscTensorAttr &src_attr, AscTensorAttr &dst_attr) {
365+ dst_attr.axis = src_attr.axis;
366+ dst_attr.repeats = src_attr.repeats;
367+ dst_attr.strides = src_attr.strides;
368+}
369+ 
370+inline void DumpTensorAttrs(const char *stage, const NodePtr &node, const AscTensorAttr &tensor_attr) {
371+ GELOGD("%s node %s(%s) tensor attr axis:%s, repeats:%s, strides:%s.", stage, node->GetNamePtr(),
372+ node->GetType().c_str(), AutofuseUtils::VectorToStr(tensor_attr.axis).c_str(),
373+ AutofuseUtils::VectorToStr(tensor_attr.repeats).c_str(),
374+ AutofuseUtils::VectorToStr(tensor_attr.strides).c_str());
375+}
376+ 
377+inline void ReorderGraphAxesToOriginalOrder(std::vector<AxisPtr> &axis) {
378+ std::stable_sort(axis.begin(), axis.end(), [](const AxisPtr &lhs, const AxisPtr &rhs) {
379+ if ((lhs == nullptr) || (rhs == nullptr)) {
380+ return lhs != nullptr;
381+ }
382+ return lhs->id < rhs->id;
383+ });
384+}
385+ 
386+inline void ReorderAxisIdsByGraphOrder(const std::vector<int64_t> &graph_axis_order, std::vector<int64_t> &axis) {
387+ std::vector<int64_t> reordered_axis;
388+ for (const auto graph_axis_id : graph_axis_order) {
389+ auto it = std::find(axis.begin(), axis.end(), graph_axis_id);
390+ if (it != axis.end()) {
391+ reordered_axis.push_back(graph_axis_id);
392+ }
393+ }
394+ for (const auto axis_id : axis) {
395+ if (std::find(graph_axis_order.begin(), graph_axis_order.end(), axis_id) == graph_axis_order.end()) {
396+ reordered_axis.push_back(axis_id);
397+ }
398+ }
399+ axis = reordered_axis;
400+}
401+ 
402+inline void ReorderTensorAttrsByGraphOrder(const std::vector<int64_t> &graph_axis_order, AscTensorAttr &tensor_attr) {
403+ if (tensor_attr.axis.empty()) {
404+ return;
405+ }
406+ if ((tensor_attr.repeats.size() != tensor_attr.axis.size()) ||
407+ (tensor_attr.strides.size() != tensor_attr.axis.size())) {
408+ return;
409+ }
410+ AscTensorAttr reordered_attr = tensor_attr;
411+ reordered_attr.axis.clear();
412+ reordered_attr.repeats.clear();
413+ reordered_attr.strides.clear();
414+ for (const auto graph_axis_id : graph_axis_order) {
415+ auto it = std::find(tensor_attr.axis.begin(), tensor_attr.axis.end(), graph_axis_id);
416+ if (it == tensor_attr.axis.end()) {
417+ continue;
418+ }
419+ const auto idx = static_cast<size_t>(std::distance(tensor_attr.axis.begin(), it));
420+ reordered_attr.axis.push_back(tensor_attr.axis[idx]);
421+ reordered_attr.repeats.push_back(tensor_attr.repeats[idx]);
422+ reordered_attr.strides.push_back(tensor_attr.strides[idx]);
423+ }
424+ for (size_t i = 0U; i < tensor_attr.axis.size(); ++i) {
425+ if (std::find(graph_axis_order.begin(), graph_axis_order.end(), tensor_attr.axis[i]) != graph_axis_order.end()) {
426+ continue;
427+ }
428+ reordered_attr.axis.push_back(tensor_attr.axis[i]);
429+ reordered_attr.repeats.push_back(tensor_attr.repeats[i]);
430+ reordered_attr.strides.push_back(tensor_attr.strides[i]);
431+ }
432+ CopyTensorAttrs(reordered_attr, tensor_attr);
433+}
434+ 
435+inline Status ReorderAscGraphAttrsByGraphOrder(const AscGraph &asc_graph,
436+ const std::vector<int64_t> &graph_axis_order) {
437+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
438+ const auto &op_desc = node->GetOpDesc();
439+ GE_ASSERT_NOTNULL(op_desc);
440+ auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();
441+ if (node_attr != nullptr) {
442+ ReorderAxisIdsByGraphOrder(graph_axis_order, node_attr->sched.axis);
443+ }
444+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
445+ const auto output_tensor_desc = op_desc->MutableOutputDesc(i);
446+ GE_ASSERT_NOTNULL(output_tensor_desc);
447+ auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
448+ if (tensor_attr == nullptr) {
449+ continue;
450+ }
451+ ReorderTensorAttrsByGraphOrder(graph_axis_order, *tensor_attr);
452+ }
453+ }
454+ return SUCCESS;
455+}
456+ 
457+inline Status ReorderAscGraphAttrsByCurrentGraphOrder(const AscGraph &asc_graph, const AscGraphAttr &graph_attr) {
458+ std::vector<int64_t> graph_axis_order;
459+ graph_axis_order.reserve(graph_attr.axis.size());
460+ for (const auto &axis_info : graph_attr.axis) {
461+ GE_ASSERT_NOTNULL(axis_info);
462+ graph_axis_order.push_back(axis_info->id);
463+ }
464+ GE_ASSERT_SUCCESS(ReorderAscGraphAttrsByGraphOrder(asc_graph, graph_axis_order));
465+ return SUCCESS;
466+}
467+ 
468+inline bool BuildTargetToTensorIndexByGraphOrder(const std::vector<int64_t> &graph_axis_order,
469+ const AscTensorAttr &tensor_attr,
470+ std::vector<size_t> &target_to_tensor_index) {
471+ const auto matched_target_indexes =
472+ BuildBestOverlapTargetIndexes(tensor_attr.axis.size(), graph_axis_order.size(),
473+ [&tensor_attr, &graph_axis_order](size_t source_idx, size_t target_idx) -> int32_t {
474+ return tensor_attr.axis[source_idx] == graph_axis_order[target_idx] ? 1 : 0;
475+ });
476+ if (matched_target_indexes.size() != tensor_attr.axis.size()) {
477+ return false;
478+ }
479+ 
480+ const size_t kInvalidIndex = graph_axis_order.size();
481+ target_to_tensor_index.assign(graph_axis_order.size(), kInvalidIndex);
482+ for (size_t tensor_axis_idx = 0U; tensor_axis_idx < matched_target_indexes.size(); ++tensor_axis_idx) {
483+ target_to_tensor_index[matched_target_indexes[tensor_axis_idx]] = tensor_axis_idx;
484+ }
485+ return true;
486+}
487+ 
488+inline bool AppendCompletedTensorAxisByGraphOrder(const size_t target_idx, const size_t kInvalidIndex,
489+ const std::vector<int64_t> &graph_axis_order,
490+ const AscTensorAttr &tensor_attr, AscTensorAttr &completed_attr,
491+ std::vector<int64_t> &inserted_axis_ids) {
492+ if (target_idx != kInvalidIndex) {
493+ completed_attr.axis.push_back(tensor_attr.axis[target_idx]);
494+ if (!tensor_attr.repeats.empty()) {
495+ completed_attr.repeats.push_back(tensor_attr.repeats[target_idx]);
496+ }
497+ if (!tensor_attr.strides.empty()) {
498+ completed_attr.strides.push_back(tensor_attr.strides[target_idx]);
499+ }
500+ return false;
501+ }
502+ const auto graph_axis_id = graph_axis_order[completed_attr.axis.size()];
503+ completed_attr.axis.push_back(graph_axis_id);
504+ if (!tensor_attr.repeats.empty()) {
505+ completed_attr.repeats.push_back(kSymbolOne);
506+ }
507+ if (!tensor_attr.strides.empty()) {
508+ completed_attr.strides.push_back(kSymbolZero);
509+ }
510+ inserted_axis_ids.push_back(graph_axis_id);
511+ return true;
512+}
513+ 
514+inline void CompleteTensorAttrsByGraphOrderPreserveStrides(const NodePtr &node, const size_t output_idx,
515+ const std::vector<int64_t> &graph_axis_order,
516+ AscTensorAttr &tensor_attr) {
517+ const auto old_axis = tensor_attr.axis;
518+ std::vector<int64_t> inserted_axis_ids;
519+ if (tensor_attr.axis.size() >= graph_axis_order.size()) {
520+ return;
521+ }
522+ 
523+ std::vector<size_t> target_to_tensor_index;
524+ if (!BuildTargetToTensorIndexByGraphOrder(graph_axis_order, tensor_attr, target_to_tensor_index)) {
525+ return;
526+ }
527+ 
528+ AscTensorAttr completed_attr = tensor_attr;
529+ completed_attr.axis.clear();
530+ if (!tensor_attr.repeats.empty()) {
531+ completed_attr.repeats.clear();
532+ }
533+ if (!tensor_attr.strides.empty()) {
534+ completed_attr.strides.clear();
535+ }
536+ const size_t kInvalidIndex = graph_axis_order.size();
537+ for (size_t i = 0U; i < graph_axis_order.size(); ++i) {
538+ if (AppendCompletedTensorAxisByGraphOrder(target_to_tensor_index[i], kInvalidIndex, graph_axis_order, tensor_attr,
539+ completed_attr, inserted_axis_ids)) {
540+ GELOGD("node %s(%s) output %zu complete preserve tensor attrs with reshape axis id %ld at graph axis idx %zu.",
541+ node->GetNamePtr(), node->GetType().c_str(), output_idx, graph_axis_order[i], i);
542+ }
543+ }
544+ CopyTensorAttrs(completed_attr, tensor_attr);
545+ if (!inserted_axis_ids.empty()) {
546+ GELOGD("node %s(%s) output %zu complete preserve tensor attrs with reshape axes %s, axis from %s to %s.",
547+ node->GetNamePtr(), node->GetType().c_str(), output_idx,
548+ AutofuseUtils::VectorToStr(inserted_axis_ids).c_str(), AutofuseUtils::VectorToStr(old_axis).c_str(),
549+ AutofuseUtils::VectorToStr(tensor_attr.axis).c_str());
550+ }
551+}
552+ 
553+inline Status InsertNoOpAxisByGraphOrder(const std::vector<int64_t> &graph_axis_order, const int64_t axis_id,
554+ std::vector<int64_t> &axis, std::vector<Expression> *repeats = nullptr,
555+ std::vector<Expression> *strides = nullptr) {
556+ if (std::find(axis.begin(), axis.end(), axis_id) != axis.end()) {
557+ return SUCCESS;
558+ }
559+ const auto graph_axis_it = std::find(graph_axis_order.begin(), graph_axis_order.end(), axis_id);
560+ GE_ASSERT_TRUE(graph_axis_it != graph_axis_order.end());
561+ const auto insert_it = std::find_if(axis.begin(), axis.end(), [&graph_axis_order, graph_axis_it](const auto axis_id) {
562+ const auto current_graph_axis_it = std::find(graph_axis_order.begin(), graph_axis_order.end(), axis_id);
563+ return (current_graph_axis_it != graph_axis_order.end()) && (current_graph_axis_it > graph_axis_it);
564+ });
565+ const auto insert_index = static_cast<size_t>(std::distance(axis.begin(), insert_it));
566+ axis.insert(insert_it, axis_id);
567+ if ((repeats != nullptr) && !repeats->empty()) {
568+ GE_ASSERT_TRUE(insert_index <= repeats->size());
569+ repeats->insert(repeats->begin() + static_cast<ptrdiff_t>(insert_index), kSymbolOne);
570+ }
571+ if ((strides != nullptr) && !strides->empty()) {
572+ GE_ASSERT_TRUE(insert_index <= strides->size());
573+ strides->insert(strides->begin() + static_cast<ptrdiff_t>(insert_index), kSymbolZero);
574+ }
575+ return SUCCESS;
576+}
577+ 
578+inline Status CompleteTensorAttrsByInsertedAxisIdsPreserveOrder(const NodePtr &node, const size_t output_idx,
579+ const std::vector<int64_t> &graph_axis_order,
580+ const std::vector<int64_t> &inserted_axis_ids,
581+ AscTensorAttr &tensor_attr) {
582+ const auto old_axis = tensor_attr.axis;
583+ if (tensor_attr.axis.empty()) {
584+ return SUCCESS;
585+ }
586+ for (const auto axis_id : inserted_axis_ids) {
587+ GE_ASSERT_SUCCESS(InsertNoOpAxisByGraphOrder(graph_axis_order, axis_id, tensor_attr.axis, &tensor_attr.repeats,
588+ &tensor_attr.strides));
589+ }
590+ if (old_axis != tensor_attr.axis) {
591+ GELOGD("node %s(%s) output %zu complete preserve tensor attrs with reshape axes %s, axis from %s to %s.",
592+ node->GetNamePtr(), node->GetType().c_str(), output_idx,
593+ AutofuseUtils::VectorToStr(inserted_axis_ids).c_str(), AutofuseUtils::VectorToStr(old_axis).c_str(),
594+ AutofuseUtils::VectorToStr(tensor_attr.axis).c_str());
595+ }
596+ return SUCCESS;
597+}
598+ 
599+inline Status UpdateTensorAttrsPreserveStrides(const NodePtr &node, const std::vector<int64_t> &axis,
600+ const std::vector<Expression> &repeats) {
601+ const auto &op_desc = node->GetOpDesc();
602+ GE_ASSERT_NOTNULL(op_desc);
603+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
604+ const auto output_tensor_desc = op_desc->MutableOutputDesc(i);
605+ GE_ASSERT_NOTNULL(output_tensor_desc);
606+ auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
607+ GE_ASSERT_NOTNULL(tensor_attr);
608+ if (node->GetType() == kScalarType) {
609+ tensor_attr->axis = axis;
610+ tensor_attr->repeats.assign(axis.size(), kSymbolOne);
611+ tensor_attr->strides.assign(axis.size(), kSymbolZero);
612+ continue;
613+ }
614+ if ((tensor_attr->axis.empty()) && (node->GetType() != kDataType)) {
615+ GE_ASSERT_SUCCESS(UpdateTensorAttrsIfEmpty(node, tensor_attr, axis, repeats));
616+ continue;
617+ }
618+ CompleteTensorAttrsByGraphOrderPreserveStrides(node, i, axis, *tensor_attr);
619+ GELOGD("after preserve attrs: node %s(%s), axis:%s, repeats:%s stride:%s.", node->GetNamePtr(),
620+ node->GetType().c_str(), AutofuseUtils::VectorToStr(tensor_attr->axis).c_str(),
621+ AutofuseUtils::VectorToStr(tensor_attr->repeats).c_str(),
622+ AutofuseUtils::VectorToStr(tensor_attr->strides).c_str());
623+ }
624+ return SUCCESS;
625+}
626+ 
627+inline Status UpdateTensorAttrsByInsertedAxisIdsPreserveOrder(const NodePtr &node, const std::vector<int64_t> &axis,
628+ const std::vector<Expression> &repeats,
629+ const std::vector<int64_t> &inserted_axis_ids) {
630+ const auto &op_desc = node->GetOpDesc();
631+ GE_ASSERT_NOTNULL(op_desc);
632+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
633+ const auto output_tensor_desc = op_desc->MutableOutputDesc(i);
634+ GE_ASSERT_NOTNULL(output_tensor_desc);
635+ auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
636+ GE_ASSERT_NOTNULL(tensor_attr);
637+ if (node->GetType() == kScalarType) {
638+ tensor_attr->axis = axis;
639+ tensor_attr->repeats.assign(axis.size(), kSymbolOne);
640+ tensor_attr->strides.assign(axis.size(), kSymbolZero);
641+ continue;
642+ }
643+ if ((tensor_attr->axis.empty()) && (node->GetType() != kDataType)) {
644+ GE_ASSERT_SUCCESS(UpdateTensorAttrsIfEmpty(node, tensor_attr, axis, repeats));
645+ continue;
646+ }
647+ GE_ASSERT_SUCCESS(
648+ CompleteTensorAttrsByInsertedAxisIdsPreserveOrder(node, i, axis, inserted_axis_ids, *tensor_attr));
649+ GELOGD("after preserve attrs: node %s(%s), axis:%s, repeats:%s stride:%s.", node->GetNamePtr(),
650+ node->GetType().c_str(), AutofuseUtils::VectorToStr(tensor_attr->axis).c_str(),
651+ AutofuseUtils::VectorToStr(tensor_attr->repeats).c_str(),
652+ AutofuseUtils::VectorToStr(tensor_attr->strides).c_str());
653+ }
654+ return SUCCESS;
655+}
656+ 
657+inline bool IsAxisSubsequence(const std::vector<int64_t> &axis, const std::vector<int64_t> &target_axis) {
658+ size_t target_idx = 0U;
659+ for (const auto axis_id : axis) {
660+ while ((target_idx < target_axis.size()) && (target_axis[target_idx] != axis_id)) {
661+ ++target_idx;
662+ }
663+ if (target_idx >= target_axis.size()) {
664+ return false;
665+ }
666+ ++target_idx;
667+ }
668+ return true;
669+}
670+ 
671+inline void CompleteGatherInputTensorAttrsByTargetAxis(const std::vector<int64_t> &target_axis,
672+ AscTensorAttr &tensor_attr) {
673+ std::unordered_map<int64_t, size_t> axis_to_index;
674+ for (size_t i = 0U; i < tensor_attr.axis.size(); ++i) {
675+ axis_to_index[tensor_attr.axis[i]] = i;
676+ }
677+ 
678+ AscTensorAttr completed_attr = tensor_attr;
679+ completed_attr.axis.clear();
680+ completed_attr.repeats.clear();
681+ completed_attr.strides.clear();
682+ for (const auto axis_id : target_axis) {
683+ completed_attr.axis.push_back(axis_id);
684+ const auto iter = axis_to_index.find(axis_id);
685+ if (iter != axis_to_index.end()) {
686+ const auto idx = iter->second;
687+ completed_attr.repeats.push_back(idx < tensor_attr.repeats.size() ? tensor_attr.repeats[idx] : kSymbolOne);
688+ completed_attr.strides.push_back(idx < tensor_attr.strides.size() ? tensor_attr.strides[idx] : kSymbolZero);
689+ } else {
690+ completed_attr.repeats.push_back(kSymbolOne);
691+ completed_attr.strides.push_back(kSymbolZero);
692+ }
693+ }
694+ CopyTensorAttrs(completed_attr, tensor_attr);
695+}
696+ 
697+inline void CompleteGatherInputTensorAttrsByDimOrder(const std::vector<int64_t> &target_axis,
698+ AscTensorAttr &tensor_attr) {
699+ AscTensorAttr completed_attr = tensor_attr;
700+ completed_attr.axis = target_axis;
701+ for (size_t i = 0U; i < completed_attr.axis.size(); ++i) {
702+ if (i >= completed_attr.repeats.size()) {
703+ completed_attr.repeats.push_back(kSymbolOne);
704+ }
705+ if (i >= completed_attr.strides.size()) {
706+ completed_attr.strides.push_back(kSymbolZero);
707+ }
708+ }
709+ completed_attr.repeats.resize(completed_attr.axis.size());
710+ completed_attr.strides.resize(completed_attr.axis.size());
711+ CopyTensorAttrs(completed_attr, tensor_attr);
712+}
713+ 
714+inline void CompleteGatherInputTensorAttrsByAxes(const std::vector<int64_t> &target_axis, AscTensorAttr &tensor_attr) {
715+ if (IsAxisSubsequence(tensor_attr.axis, target_axis)) {
716+ CompleteGatherInputTensorAttrsByTargetAxis(target_axis, tensor_attr);
717+ return;
718+ }
719+ CompleteGatherInputTensorAttrsByDimOrder(target_axis, tensor_attr);
720+}
721+ 
722+inline Status GetGatherInputDataNodes(const NodePtr &gather_node, NodePtr &params_data_node,
723+ NodePtr &indices_data_node) {
724+ std::vector<NodePtr> peer_out_nodes;
725+ GE_ASSERT_SUCCESS(asc_adapt::GetPeerOutNodes(gather_node, peer_out_nodes));
726+ GE_ASSERT_TRUE(peer_out_nodes.size() == 2U);
727+ params_data_node = peer_out_nodes[0];
728+ indices_data_node = peer_out_nodes[1];
729+ return SUCCESS;
730+}
731+ 
732+inline bool IsGatherFuseType(const NodePtr &asc_node) {
733+ const auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(asc_node);
734+ return (autofuse_attr != nullptr) && autofuse_attr->HasFuseType(loop::FuseType::kGather);
735+}
736+ 
737+inline Status GetGatherReplacementAxisIndex(const NodePtr &gather_node, const AscTensorAttr &params_attr,
738+ const AscTensorAttr &indices_attr, const AscTensorAttr &gather_output_attr,
739+ size_t &replacement_axis_index) {
740+ (void)indices_attr;
741+ int64_t gather_axis_index = 0;
742+ GE_ASSERT_SUCCESS(asc_adapt::GetGatherAxis(gather_node, gather_axis_index));
743+ GE_ASSERT_TRUE(gather_axis_index >= 0);
744+ GE_ASSERT_TRUE(static_cast<size_t>(gather_axis_index) < params_attr.axis.size());
745+ const auto replacement_axis_id = params_attr.axis[static_cast<size_t>(gather_axis_index)];
746+ const auto iter = std::find(gather_output_attr.axis.begin(), gather_output_attr.axis.end(), replacement_axis_id);
747+ GE_ASSERT_TRUE(iter != gather_output_attr.axis.end());
748+ replacement_axis_index = static_cast<size_t>(std::distance(gather_output_attr.axis.begin(), iter));
749+ if (replacement_axis_index != static_cast<size_t>(gather_axis_index)) {
750+ GE_ASSERT_SUCCESS(asc_adapt::SetGatherAxis(gather_node, static_cast<int64_t>(replacement_axis_index)));
751+ }
752+ return SUCCESS;
753+}
754+ 
755+inline Status CompleteGatherInputAttrsPreserveStrides(const AscGraph &asc_graph, const NodePtr &gather_node) {
756+ NodePtr params_data_node = nullptr;
757+ NodePtr indices_data_node = nullptr;
758+ GE_ASSERT_SUCCESS(GetGatherInputDataNodes(gather_node, params_data_node, indices_data_node));
759+ AscTensorAttr *gather_output_attr = nullptr;
760+ GE_ASSERT_SUCCESS(asc_adapt::GetOutputTensorAttr(gather_node, gather_output_attr));
761+ AscTensorAttr *params_attr = nullptr;
762+ GE_ASSERT_SUCCESS(asc_adapt::GetOutputTensorAttr(params_data_node, params_attr));
763+ AscTensorAttr *indices_attr = nullptr;
764+ GE_ASSERT_SUCCESS(asc_adapt::GetOutputTensorAttr(indices_data_node, indices_attr));
765+ if ((gather_output_attr->axis.empty()) || (params_attr->axis.empty()) || (indices_attr->axis.empty())) {
766+ return SUCCESS;
767+ }
768+ 
769+ size_t replacement_axis_index = 0U;
770+ GE_ASSERT_SUCCESS(GetGatherReplacementAxisIndex(gather_node, *params_attr, *indices_attr, *gather_output_attr,
771+ replacement_axis_index));
772+ GE_ASSERT_TRUE(replacement_axis_index + indices_attr->axis.size() <= gather_output_attr->axis.size());
773+ GELOGD("node %s(%s) complete gather input attrs in graph %s, replacement_axis_index:%zu.", gather_node->GetNamePtr(),
774+ gather_node->GetType().c_str(), asc_graph.GetName().c_str(), replacement_axis_index);
775+ DumpTensorAttrs("before complete gather output", gather_node, *gather_output_attr);
776+ DumpTensorAttrs("before complete gather params", params_data_node, *params_attr);
777+ DumpTensorAttrs("before complete gather indices", indices_data_node, *indices_attr);
778+ 
779+ std::vector<int64_t> params_axis;
780+ std::vector<int64_t> indices_axis;
781+ for (size_t i = 0U; i < gather_output_attr->axis.size(); ++i) {
782+ if (i == replacement_axis_index) {
783+ params_axis.push_back(gather_output_attr->axis[i]);
784+ indices_axis.push_back(gather_output_attr->axis[i]);
785+ } else if ((i > replacement_axis_index) && (i < replacement_axis_index + indices_attr->axis.size())) {
786+ indices_axis.push_back(gather_output_attr->axis[i]);
787+ } else {
788+ params_axis.push_back(gather_output_attr->axis[i]);
789+ }
790+ }
791+ GELOGI("node %s(%s) complete gather params axis from %s to %s in graph %s.", params_data_node->GetNamePtr(),
792+ params_data_node->GetType().c_str(), AutofuseUtils::VectorToStr(params_attr->axis).c_str(),
793+ AutofuseUtils::VectorToStr(params_axis).c_str(), asc_graph.GetName().c_str());
794+ GELOGI("node %s(%s) complete gather indices axis from %s to %s in graph %s.", indices_data_node->GetNamePtr(),
795+ indices_data_node->GetType().c_str(), AutofuseUtils::VectorToStr(indices_attr->axis).c_str(),
796+ AutofuseUtils::VectorToStr(indices_axis).c_str(), asc_graph.GetName().c_str());
797+ CompleteGatherInputTensorAttrsByAxes(params_axis, *params_attr);
798+ CompleteGatherInputTensorAttrsByAxes(indices_axis, *indices_attr);
799+ DumpTensorAttrs("after complete gather params", params_data_node, *params_attr);
800+ DumpTensorAttrs("after complete gather indices", indices_data_node, *indices_attr);
801+ return SUCCESS;
802+}
803+ 
804+inline Status CompleteGatherInputAttrsOnAscGraphPreserveStrides(const AscGraph &asc_graph) {
805+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
806+ if (node->GetType() != kGatherType) {
807+ continue;
808+ }
809+ GE_ASSERT_SUCCESS(CompleteGatherInputAttrsPreserveStrides(asc_graph, node));
810+ }
811+ return SUCCESS;
812+}
813+ 
814+inline Status CompleteNodeAttrsOnAscGraphPreserveStrides(AscGraph &asc_graph, const NodePtr &asc_node) {
815+ const auto is_gather_fuse_type = IsGatherFuseType(asc_node);
816+ TensorAttrInfo graph_attr;
817+ GE_ASSERT_SUCCESS(BackendUtils::GetGraphAttrInfo(asc_graph, graph_attr));
818+ GELOGI("max sched axis %s in graph %s, preserve tensor strides.", AutofuseUtils::VectorToStr(graph_attr.axis).c_str(),
819+ asc_graph.GetName().c_str());
820+ 
821+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
822+ if (IsTorchDataType(node)) {
823+ GELOGI("torch node %s(%s) not complete node attr.", node->GetNamePtr(), node->GetType().c_str());
824+ continue;
825+ }
826+ if (IsCubeRelatedAscNode(node)) {
827+ GELOGI("cube related node %s(%s) not complete node attr.", node->GetNamePtr(), node->GetType().c_str());
828+ continue;
829+ }
830+ if (((!is_gather_fuse_type) || (!IsGatherData(node))) && (!BackendUtils::IsOutputNode(node))) {
831+ GE_ASSERT_SUCCESS(UpdateTensorAttrsPreserveStrides(node, graph_attr.axis, graph_attr.repeats));
832+ }
833+ const auto &op_desc = node->GetOpDesc();
834+ GE_ASSERT_NOTNULL(op_desc);
835+ auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();
836+ GE_ASSERT_NOTNULL(node_attr);
837+ GELOGI("node %s(%s) before complete sched axis %s to %s in graph %s, preserve tensor strides.", node->GetNamePtr(),
838+ node->GetType().c_str(), AutofuseUtils::VectorToStr(node_attr->sched.axis).c_str(),
839+ AutofuseUtils::VectorToStr(graph_attr.axis).c_str(), asc_graph.GetName().c_str());
840+ node_attr->sched.axis = graph_attr.axis;
841+ GELOGI("node %s(%s) after complete sched axis %s to %s in graph %s, preserve tensor strides.", node->GetNamePtr(),
842+ node->GetType().c_str(), AutofuseUtils::VectorToStr(node_attr->sched.axis).c_str(),
843+ AutofuseUtils::VectorToStr(graph_attr.axis).c_str(), asc_graph.GetName().c_str());
844+ }
845+ if (is_gather_fuse_type) {
846+ GE_ASSERT_SUCCESS(CompleteGatherInputAttrsOnAscGraphPreserveStrides(asc_graph));
847+ }
848+ return SUCCESS;
849+}
850+ 
851+inline Status CompleteNodeAttrsByInsertedAxisIdsPreserveOrder(AscGraph &asc_graph, const NodePtr &asc_node,
852+ const std::vector<int64_t> &inserted_axis_ids) {
853+ const auto is_gather_fuse_type = IsGatherFuseType(asc_node);
854+ TensorAttrInfo graph_attr;
855+ GE_ASSERT_SUCCESS(BackendUtils::GetGraphAttrInfo(asc_graph, graph_attr));
856+ GELOGI("complete inserted reshape axes %s in graph %s, preserve node axis order.",
857+ AutofuseUtils::VectorToStr(inserted_axis_ids).c_str(), asc_graph.GetName().c_str());
858+ 
859+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
860+ if (IsTorchDataType(node)) {
861+ GELOGI("torch node %s(%s) not complete node attr.", node->GetNamePtr(), node->GetType().c_str());
862+ continue;
863+ }
864+ if (IsCubeRelatedAscNode(node)) {
865+ GELOGI("cube related node %s(%s) not complete node attr.", node->GetNamePtr(), node->GetType().c_str());
866+ continue;
867+ }
868+ if (((!is_gather_fuse_type) || (!IsGatherData(node))) && (!BackendUtils::IsOutputNode(node))) {
869+ GE_ASSERT_SUCCESS(UpdateTensorAttrsByInsertedAxisIdsPreserveOrder(node, graph_attr.axis, graph_attr.repeats,
870+ inserted_axis_ids));
871+ }
872+ const auto &op_desc = node->GetOpDesc();
873+ GE_ASSERT_NOTNULL(op_desc);
874+ auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();
875+ GE_ASSERT_NOTNULL(node_attr);
876+ const auto old_sched_axis = node_attr->sched.axis;
877+ if (node_attr->sched.axis.empty()) {
878+ node_attr->sched.axis = graph_attr.axis;
879+ } else {
880+ for (const auto axis_id : inserted_axis_ids) {
881+ GE_ASSERT_SUCCESS(InsertNoOpAxisByGraphOrder(graph_attr.axis, axis_id, node_attr->sched.axis));
882+ }
883+ }
884+ GELOGI("node %s(%s) complete sched axis from %s to %s in graph %s, preserve node axis order.", node->GetNamePtr(),
885+ node->GetType().c_str(), AutofuseUtils::VectorToStr(old_sched_axis).c_str(),
886+ AutofuseUtils::VectorToStr(node_attr->sched.axis).c_str(), asc_graph.GetName().c_str());
887+ }
888+ if (is_gather_fuse_type) {
889+ GE_ASSERT_SUCCESS(CompleteGatherInputAttrsOnAscGraphPreserveStrides(asc_graph));
890+ }
891+ return SUCCESS;
892+}
893+ 
894+inline Status DumpPadLeadingUnitAxisResult(const AscGraph &asc_graph, const NodePtr &asc_node, const char *process_name,
895+ const ComputeGraphPtr &fused_graph) {
896+ GELOGI("AscBackendPostProcessor: End to run the process(%s) on the graph, graph: %s, parent node: %s(%s).",
897+ process_name, fused_graph->GetName().c_str(), asc_node->GetNamePtr(), asc_node->GetType().c_str());
898+ GELOGD("dump node:%s(%s) asc graph info(with tensor attr info):", asc_node->GetNamePtr(),
899+ asc_node->GetType().c_str());
900+ (void)asc_graph;
901+ BackendUtils::DumpAscGraph(asc_node);
902+ return SUCCESS;
903+}
904+ 
905+struct InsertIndexMergeState {
906+ bool initialized = false;
907+ size_t original_rank = 0U;
908+ std::vector<size_t> gap_counts;
909+};
910+ 
911+inline std::vector<size_t> BuildInsertGapCounts(const size_t original_rank, const std::vector<size_t> &insert_indexes) {
912+ std::vector<size_t> gap_counts(original_rank + 1U, 0U);
913+ auto sorted_insert_indexes = insert_indexes;
914+ std::sort(sorted_insert_indexes.begin(), sorted_insert_indexes.end());
915+ 
916+ size_t inserted_count = 0U;
917+ for (const auto insert_index : sorted_insert_indexes) {
918+ const size_t gap_index = std::min(insert_index - std::min(insert_index, inserted_count), original_rank);
919+ ++gap_counts[gap_index];
920+ ++inserted_count;
921+ }
922+ return gap_counts;
923+}
924+ 
925+inline void BuildInsertIndexesFromGapCounts(const std::vector<size_t> &gap_counts,
926+ std::vector<size_t> &insert_indexes) {
927+ insert_indexes.clear();
928+ size_t inserted_count = 0U;
929+ for (size_t gap_index = 0U; gap_index < gap_counts.size(); ++gap_index) {
930+ for (size_t i = 0U; i < gap_counts[gap_index]; ++i) {
931+ insert_indexes.push_back(gap_index + inserted_count);
932+ ++inserted_count;
933+ }
934+ }
935+}
936+ 
937+inline Status MergeRelationInsertIndexes(const size_t original_rank, const std::vector<size_t> &relation_insert_indexes,
938+ InsertIndexMergeState &merge_state,
939+ std::vector<size_t> &merged_insert_indexes) {
940+ if (relation_insert_indexes.empty()) {
941+ return SUCCESS;
942+ }
943+ if (!merge_state.initialized) {
944+ merge_state.initialized = true;
945+ merge_state.original_rank = original_rank;
946+ merge_state.gap_counts.assign(original_rank + 1U, 0U);
947+ }
948+ if (merge_state.original_rank != original_rank) {
949+ GELOGD("skip merging relation insert indexes %s because original rank %zu does not match merged rank %zu.",
950+ AutofuseUtils::VectorToStr(relation_insert_indexes).c_str(), original_rank, merge_state.original_rank);
951+ return SUCCESS;
952+ }
953+ 
954+ const auto relation_gap_counts = BuildInsertGapCounts(original_rank, relation_insert_indexes);
955+ for (size_t i = 0U; i < merge_state.gap_counts.size(); ++i) {
956+ merge_state.gap_counts[i] = std::max(merge_state.gap_counts[i], relation_gap_counts[i]);
957+ }
958+ BuildInsertIndexesFromGapCounts(merge_state.gap_counts, merged_insert_indexes);
959+ GELOGD("merge relation insert indexes %s to merged insert indexes %s by original rank %zu.",
960+ AutofuseUtils::VectorToStr(relation_insert_indexes).c_str(),
961+ AutofuseUtils::VectorToStr(merged_insert_indexes).c_str(), original_rank);
962+ return SUCCESS;
963+}
964+ 
965+inline Status CompleteNoOpReshapeAxesByInsertIndexes(AscGraph &asc_graph, const std::vector<size_t> &insert_indexes,
966+ AscGraphAttr *graph_attr,
967+ std::vector<af::ReshapeAxisChangeInfo> *reshape_axis_changes,
968+ std::vector<int64_t> &inserted_axis_ids) {
969+ GE_ASSERT_NOTNULL(graph_attr);
970+ if (insert_indexes.empty()) {
971+ return SUCCESS;
972+ }
973+ 
974+ auto sorted_insert_indexes = insert_indexes;
975+ std::sort(sorted_insert_indexes.begin(), sorted_insert_indexes.end());
976+ for (const auto insert_index : sorted_insert_indexes) {
977+ int64_t insert_axis_id = GetNextNoOpReshapeAxisId(graph_attr->axis);
978+ if (insert_index < graph_attr->axis.size()) {
979+ GE_ASSERT_NOTNULL(graph_attr->axis[insert_index]);
980+ insert_axis_id = graph_attr->axis[insert_index]->id;
981+ }
982+ for (const auto &axis_info : graph_attr->axis) {
983+ ShiftAxisInfoIdFrom(insert_axis_id, axis_info);
984+ }
985+ if (reshape_axis_changes != nullptr) {
986+ ShiftReshapeAxisChangesFrom(insert_axis_id, *reshape_axis_changes);
987+ }
988+ GE_ASSERT_SUCCESS(ShiftAscGraphAxisIdsFrom(asc_graph, insert_axis_id));
989+ const auto graph_insert_it =
990+ graph_attr->axis.begin() + static_cast<ptrdiff_t>(std::min(insert_index, graph_attr->axis.size()));
991+ graph_attr->axis.insert(graph_insert_it, MakeNoOpReshapeAxis(insert_axis_id, kSymbolOne));
992+ inserted_axis_ids.push_back(insert_axis_id);
993+ GELOGD(
994+ "graph %s complete no-op reshape axis id %ld repeat %s at insert index %zu by relation before complete attrs.",
995+ asc_graph.GetName().c_str(), insert_axis_id, kSymbolOne.Str().get(), insert_index);
996+ }
997+ return SUCCESS;
998+}
999+ 
1000+inline Status CompleteNoOpReshapeAxesByInsertIndexesKeepOriginalAxisIds(AscGraph &asc_graph,
1001+ const std::vector<size_t> &insert_indexes,
1002+ AscGraphAttr *graph_attr,
1003+ std::vector<int64_t> &inserted_axis_ids) {
1004+ GE_ASSERT_NOTNULL(graph_attr);
1005+ if (insert_indexes.empty()) {
1006+ return SUCCESS;
1007+ }
1008+ 
1009+ auto sorted_insert_indexes = insert_indexes;
1010+ std::sort(sorted_insert_indexes.begin(), sorted_insert_indexes.end());
1011+ for (const auto insert_index : sorted_insert_indexes) {
1012+ const auto insert_axis_id = GetNextNoOpReshapeAxisId(graph_attr->axis);
1013+ const auto graph_insert_it =
1014+ graph_attr->axis.begin() + static_cast<ptrdiff_t>(std::min(insert_index, graph_attr->axis.size()));
1015+ graph_attr->axis.insert(graph_insert_it, MakeNoOpReshapeAxis(insert_axis_id, kSymbolOne));
1016+ inserted_axis_ids.push_back(insert_axis_id);
1017+ GELOGD(
1018+ "graph %s complete no-op reshape axis id %ld repeat %s at insert index %zu by relation without shifting "
1019+ "existing axis ids.",
1020+ asc_graph.GetName().c_str(), insert_axis_id, kSymbolOne.Str().get(), insert_index);
1021+ }
1022+ return SUCCESS;
1023+}
1024+ 
1025+inline Status PadLeadingUnitAxisByInsertIndexesAndCompleteAttrs(AscGraph &asc_graph, const NodePtr &asc_node,
1026+ const std::vector<size_t> &insert_indexes) {
1027+ if (insert_indexes.empty()) {
1028+ return SUCCESS;
1029+ }
1030+ constexpr const char *kPadLeadingUnitAxisProcName = "pad_leading_unit_axis";
1031+ const auto fused_graph = AscGraphUtils::GetComputeGraph(asc_graph);
1032+ GE_ASSERT_NOTNULL(fused_graph);
1033+ GE_ASSERT_SUCCESS(BackendUtils::AddInputOutputNodesForAscGraph(fused_graph));
1034+ GE_ASSERT_SUCCESS(CacheGraphBeforePostProcess(asc_node, kPadLeadingUnitAxisProcName, fused_graph));
1035+ auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(asc_node);
1036+ GE_ASSERT_NOTNULL(autofuse_attr);
1037+ const auto graph_attr = fused_graph->GetAttrsGroup<AscGraphAttr>();
1038+ GE_ASSERT_NOTNULL(graph_attr);
1039+ const auto axis_before_insert = CollectAxisIds(graph_attr->axis);
1040+ std::vector<int64_t> inserted_axis_ids;
1041+ GELOGD("node %s(%s) graph %s start to pad leading unit axes by relation insert indexes %s.", asc_node->GetNamePtr(),
1042+ asc_node->GetType().c_str(), asc_graph.GetName().c_str(), AutofuseUtils::VectorToStr(insert_indexes).c_str());
1043+ GE_ASSERT_SUCCESS(CompleteNoOpReshapeAxesByInsertIndexes(asc_graph, insert_indexes, graph_attr,
1044+ &autofuse_attr->GetMutableInterAttrs().reshape_axis_changes,
1045+ inserted_axis_ids));
1046+ GE_ASSERT_SUCCESS(CompleteNodeAttrsByInsertedAxisIdsPreserveOrder(asc_graph, asc_node, inserted_axis_ids));
1047+ GE_ASSERT_SUCCESS(RefreshReshapeAxisGroupByInsertIndexes(axis_before_insert, insert_indexes,
1048+ GetInterAttrs(autofuse_attr).axis_group));
1049+ GE_ASSERT_SUCCESS(DumpPadLeadingUnitAxisResult(asc_graph, asc_node, kPadLeadingUnitAxisProcName, fused_graph));
1050+ return SUCCESS;
1051+}
1052+ 
1053+inline Status PadLeadingUnitAxisByInsertIndexesAndCompleteAttrsKeepOriginalAxisIds(
1054+ AscGraph &asc_graph, const NodePtr &asc_node, const std::vector<size_t> &insert_indexes) {
1055+ if (insert_indexes.empty()) {
1056+ return SUCCESS;
1057+ }
1058+ constexpr const char *kPadLeadingUnitAxisProcName = "pad_leading_unit_axis_keep_original_axis_ids";
1059+ const auto fused_graph = AscGraphUtils::GetComputeGraph(asc_graph);
1060+ GE_ASSERT_NOTNULL(fused_graph);
1061+ GE_ASSERT_SUCCESS(BackendUtils::AddInputOutputNodesForAscGraph(fused_graph));
1062+ GE_ASSERT_SUCCESS(CacheGraphBeforePostProcess(asc_node, kPadLeadingUnitAxisProcName, fused_graph));
1063+ auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(asc_node);
1064+ GE_ASSERT_NOTNULL(autofuse_attr);
1065+ const auto graph_attr = fused_graph->GetAttrsGroup<AscGraphAttr>();
1066+ GE_ASSERT_NOTNULL(graph_attr);
1067+ std::vector<int64_t> inserted_axis_ids;
1068+ GELOGD(
1069+ "node %s(%s) graph %s start to pad leading unit axes without shifting existing axis ids by relation insert "
1070+ "indexes %s.",
1071+ asc_node->GetNamePtr(), asc_node->GetType().c_str(), asc_graph.GetName().c_str(),
1072+ AutofuseUtils::VectorToStr(insert_indexes).c_str());
1073+ GE_ASSERT_SUCCESS(CompleteNoOpReshapeAxesByInsertIndexesKeepOriginalAxisIds(asc_graph, insert_indexes, graph_attr,
1074+ inserted_axis_ids));
1075+ GE_ASSERT_SUCCESS(CompleteNodeAttrsByInsertedAxisIdsPreserveOrder(asc_graph, asc_node, inserted_axis_ids));
1076+ GE_ASSERT_SUCCESS(RefreshReshapeAxisGroupByInsertedAxisIds(inserted_axis_ids, CollectAxisIds(graph_attr->axis),
1077+ GetInterAttrs(autofuse_attr).axis_group));
1078+ GE_ASSERT_SUCCESS(DumpPadLeadingUnitAxisResult(asc_graph, asc_node, kPadLeadingUnitAxisProcName, fused_graph));
1079+ return SUCCESS;
1080+}
1081+ 
1082+inline bool IsSameReshapeAxisChange(const af::ReshapeAxisChangeInfo &lhs, const af::ReshapeAxisChangeInfo &rhs) {
1083+ return (lhs.before_axis == rhs.before_axis) && (lhs.after_axis == rhs.after_axis) &&
1084+ (lhs.before_repeats.size() == rhs.before_repeats.size()) &&
1085+ (lhs.after_repeats.size() == rhs.after_repeats.size()) &&
1086+ std::equal(lhs.before_repeats.begin(), lhs.before_repeats.end(), rhs.before_repeats.begin(), IsSameRepeat) &&
1087+ std::equal(lhs.after_repeats.begin(), lhs.after_repeats.end(), rhs.after_repeats.begin(), IsSameRepeat);
1088+}
1089+ 
1090+inline void AppendUniqueReshapeAxisChange(const af::ReshapeAxisChangeInfo &axis_change,
1091+ std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
1092+ const auto it = std::find_if(axis_changes.begin(), axis_changes.end(), [&axis_change](const auto &saved_change) {
1093+ return IsSameReshapeAxisChange(axis_change, saved_change);
1094+ });
1095+ if (it == axis_changes.end()) {
1096+ axis_changes.push_back(axis_change);
1097+ }
1098+}
1099+ 
1100+inline Status CollectNodeReshapeAxisChanges(const NodePtr &node, std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
1101+ if (!BackendUtils::IsBackendFuseNode(node)) {
1102+ return SUCCESS;
1103+ }
1104+ const auto attr = node->GetOpDescBarePtr()->GetAttrsGroup<AutoFuseAttrs>();
1105+ GE_ASSERT_NOTNULL(attr);
1106+ for (const auto &axis_change : attr->GetReshapeAxisChanges()) {
1107+ AppendUniqueReshapeAxisChange(axis_change, axis_changes);
1108+ }
1109+ if (node->GetType() == kAscBackendType) {
1110+ return SUCCESS;
1111+ }
1112+ if (node->GetType() != kFusedAscBackendType) {
1113+ return SUCCESS;
1114+ }
1115+ GE_ASSERT_NOTNULL(attr->GetFuseComputeGraph());
1116+ for (const auto &inner_node : attr->GetFuseComputeGraph()->GetAllNodes()) {
1117+ if ((inner_node == nullptr) || !BackendUtils::IsBackendFuseNode(inner_node) ||
1118+ (inner_node->GetType() != kAscBackendType)) {
1119+ continue;
1120+ }
1121+ GE_ASSERT_SUCCESS(CollectNodeReshapeAxisChanges(inner_node, axis_changes));
1122+ }
1123+ return SUCCESS;
1124+}
1125+ 
1126+inline Status SaveMergedReshapeAxisChanges(const NodePtr &node,
1127+ const std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
1128+ if (!BackendUtils::IsBackendFuseNode(node) || axis_changes.empty()) {
1129+ return SUCCESS;
1130+ }
1131+ const auto attr = BackendUtils::GetNodeAutoFuseAttr(node);
1132+ GE_ASSERT_NOTNULL(attr);
1133+ auto merged_axis_changes = attr->GetReshapeAxisChanges();
1134+ for (const auto &axis_change : axis_changes) {
1135+ AppendUniqueReshapeAxisChange(axis_change, merged_axis_changes);
1136+ }
1137+ attr->SetReshapeAxisChanges(merged_axis_changes);
1138+ return SUCCESS;
1139+}
1140+ 
1141+inline void AppendEndpointTargetCandidate(const std::vector<Expression> &current_repeats,
1142+ const std::vector<af::ReshapeAxisChangeInfo> &axis_changes,
1143+ std::vector<std::vector<Expression>> &target_candidates) {
1144+ if (current_repeats.empty()) {
1145+ return;
1146+ }
1147+ const auto current_non_unit_repeats = RemoveUnitRepeats(current_repeats);
1148+ for (const auto &axis_change : axis_changes) {
1149+ if (IsSameRepeats(current_non_unit_repeats, RemoveUnitRepeats(axis_change.before_repeats)) ||
1150+ IsSameRepeats(current_non_unit_repeats, RemoveUnitRepeats(axis_change.after_repeats))) {
1151+ AppendUniqueTargetRepeats(BuildNoOpReshapeTargetRepeats(axis_change), target_candidates);
1152+ }
1153+ }
1154+}
1155+ 
1156+inline Status BuildRelationTargetRepeats(const std::vector<Expression> &node1_repeats,
1157+ const std::vector<Expression> &node2_repeats,
1158+ const std::vector<af::ReshapeAxisChangeInfo> &node1_axis_changes,
1159+ const std::vector<af::ReshapeAxisChangeInfo> &node2_axis_changes,
1160+ std::vector<Expression> &target_repeats) {
1161+ target_repeats.clear();
1162+ if (node1_repeats.empty() && node2_repeats.empty()) {
1163+ return SUCCESS;
1164+ }
1165+ if (!node1_repeats.empty() && !node2_repeats.empty() &&
1166+ !IsSameRepeats(RemoveUnitRepeats(node1_repeats), RemoveUnitRepeats(node2_repeats))) {
1167+ GELOGD(
1168+ "skip relation reshape target because endpoint non-unit repeats are different, node1 repeats %s, node2 "
1169+ "repeats %s.",
1170+ AutofuseUtils::VectorToStr(node1_repeats).c_str(), AutofuseUtils::VectorToStr(node2_repeats).c_str());
1171+ return SUCCESS;
1172+ }
1173+ 
1174+ std::vector<std::vector<Expression>> candidates;
1175+ AppendUniqueTargetRepeats(node1_repeats, candidates);
1176+ AppendUniqueTargetRepeats(node2_repeats, candidates);
1177+ AppendEndpointTargetCandidate(node1_repeats, node1_axis_changes, candidates);
1178+ AppendEndpointTargetCandidate(node2_repeats, node2_axis_changes, candidates);
1179+ 
1180+ const auto base_repeats = !node1_repeats.empty() ? node1_repeats : node2_repeats;
1181+ const auto base_non_unit_repeats = RemoveUnitRepeats(base_repeats);
1182+ std::vector<size_t> unit_gap_counts = BuildUnitRepeatGapCounts(base_repeats);
1183+ bool matched = false;
1184+ for (const auto &candidate : candidates) {
1185+ if (!IsSameRepeats(base_non_unit_repeats, RemoveUnitRepeats(candidate))) {
1186+ continue;
1187+ }
1188+ MergeUnitRepeatGapCounts(BuildUnitRepeatGapCounts(candidate), unit_gap_counts);
1189+ matched = true;
1190+ }
1191+ if (!matched) {
1192+ return SUCCESS;
1193+ }
1194+ target_repeats = ApplyUnitRepeatGaps(base_non_unit_repeats, unit_gap_counts);
1195+ return SUCCESS;
1196+}
1197+ 
1198+inline Status CollectInsertIndexesByTargetRepeats(const std::vector<Expression> &current_repeats,
1199+ const std::vector<Expression> &target_repeats,
1200+ std::vector<size_t> &insert_indexes) {
1201+ if (current_repeats.empty() || target_repeats.empty() || (target_repeats.size() <= current_repeats.size())) {
1202+ return SUCCESS;
1203+ }
1204+ const auto current_non_unit_repeats = RemoveUnitRepeats(current_repeats);
1205+ const auto target_non_unit_repeats = RemoveUnitRepeats(target_repeats);
1206+ if (!IsSameRepeats(current_non_unit_repeats, target_non_unit_repeats)) {
1207+ return SUCCESS;
1208+ }
1209+ 
1210+ const auto current_gap_counts = BuildUnitRepeatGapCounts(current_repeats);
1211+ const auto target_gap_counts = BuildUnitRepeatGapCounts(target_repeats);
1212+ if (current_gap_counts.size() != target_gap_counts.size()) {
1213+ return SUCCESS;
1214+ }
1215+ 
1216+ insert_indexes.clear();
1217+ size_t current_gap_start = 0U;
1218+ for (size_t gap_idx = 0U; gap_idx < current_gap_counts.size(); ++gap_idx) {
1219+ if (target_gap_counts[gap_idx] < current_gap_counts[gap_idx]) {
1220+ return SUCCESS;
1221+ }
1222+ const auto extra_unit_count = target_gap_counts[gap_idx] - current_gap_counts[gap_idx];
1223+ for (size_t i = 0U; i < extra_unit_count; ++i) {
1224+ insert_indexes.push_back(current_gap_start + current_gap_counts[gap_idx] + i);
1225+ }
1226+ current_gap_start += current_gap_counts[gap_idx] + extra_unit_count;
1227+ if (gap_idx + 1U < current_gap_counts.size()) {
1228+ ++current_gap_start;
1229+ }
1230+ }
1231+ GELOGD("collect reshape insert indexes %s by current repeats %s and edge target repeats %s.",
1232+ AutofuseUtils::VectorToStr(insert_indexes).c_str(), AutofuseUtils::VectorToStr(current_repeats).c_str(),
1233+ AutofuseUtils::VectorToStr(target_repeats).c_str());
1234+ return SUCCESS;
1235+}
1236+ 
1237+inline Status PadNodeLeadingUnitAxisByInsertIndexes(const NodePtr &node, const std::vector<size_t> &insert_indexes) {
1238+ if (insert_indexes.empty() || !BackendUtils::IsBackendFuseNode(node)) {
1239+ return SUCCESS;
1240+ }
1241+ const auto attr = node->GetOpDescBarePtr()->GetAttrsGroup<AutoFuseAttrs>();
1242+ GE_ASSERT_NOTNULL(attr);
1243+ if (node->GetType() == kAscBackendType) {
1244+ GE_ASSERT_NOTNULL(attr->GetAscGraph());
1245+ GE_ASSERT_SUCCESS(PadLeadingUnitAxisByInsertIndexesAndCompleteAttrs(*(attr->GetAscGraph()), node, insert_indexes));
1246+ return SUCCESS;
1247+ }
1248+ if (node->GetType() != kFusedAscBackendType) {
1249+ return SUCCESS;
1250+ }
1251+ ComputeGraphPtr fused_graph;
1252+ GE_ASSERT_SUCCESS(BackendUtils::GetNodeFusedGraph(node, fused_graph));
1253+ GE_ASSERT_NOTNULL(fused_graph);
1254+ const auto fused_graph_attr = fused_graph->GetAttrsGroup<AscGraphAttr>();
1255+ GE_ASSERT_NOTNULL(fused_graph_attr);
1256+ const auto axis_before_insert = CollectAxisIds(fused_graph_attr->axis);
1257+ GE_ASSERT_NOTNULL(attr->GetFuseComputeGraph());
1258+ for (const auto &inner_node : attr->GetFuseComputeGraph()->GetAllNodes()) {
1259+ if ((inner_node == nullptr) || !BackendUtils::IsBackendFuseNode(inner_node) ||
1260+ (inner_node->GetType() != kAscBackendType)) {
1261+ continue;
1262+ }
1263+ GE_ASSERT_SUCCESS(PadNodeLeadingUnitAxisByInsertIndexes(inner_node, insert_indexes));
1264+ }
1265+ GE_ASSERT_SUCCESS(
1266+ RefreshReshapeAxisGroupByInsertIndexes(axis_before_insert, insert_indexes, GetInterAttrs(attr).axis_group));
1267+ return SUCCESS;
1268+}
1269+ 
1270+inline Status PadNodeLeadingUnitAxisByInsertIndexesKeepOriginalAxisIds(const NodePtr &node,
1271+ const std::vector<size_t> &insert_indexes) {
1272+ if (insert_indexes.empty() || !BackendUtils::IsBackendFuseNode(node)) {
1273+ return SUCCESS;
1274+ }
1275+ const auto attr = node->GetOpDescBarePtr()->GetAttrsGroup<AutoFuseAttrs>();
1276+ GE_ASSERT_NOTNULL(attr);
1277+ if (node->GetType() == kAscBackendType) {
1278+ GE_ASSERT_NOTNULL(attr->GetAscGraph());
1279+ GE_ASSERT_SUCCESS(PadLeadingUnitAxisByInsertIndexesAndCompleteAttrsKeepOriginalAxisIds(*(attr->GetAscGraph()), node,
1280+ insert_indexes));
1281+ return SUCCESS;
1282+ }
1283+ if (node->GetType() != kFusedAscBackendType) {
1284+ return SUCCESS;
1285+ }
1286+ ComputeGraphPtr fused_graph;
1287+ GE_ASSERT_SUCCESS(BackendUtils::GetNodeFusedGraph(node, fused_graph));
1288+ GE_ASSERT_NOTNULL(fused_graph);
1289+ const auto fused_graph_attr = fused_graph->GetAttrsGroup<AscGraphAttr>();
1290+ GE_ASSERT_NOTNULL(fused_graph_attr);
1291+ const auto axis_before_insert = CollectAxisIds(fused_graph_attr->axis);
1292+ GE_ASSERT_NOTNULL(attr->GetFuseComputeGraph());
1293+ for (const auto &inner_node : attr->GetFuseComputeGraph()->GetAllNodes()) {
1294+ if ((inner_node == nullptr) || !BackendUtils::IsBackendFuseNode(inner_node) ||
1295+ (inner_node->GetType() != kAscBackendType)) {
1296+ continue;
1297+ }
1298+ GE_ASSERT_SUCCESS(PadNodeLeadingUnitAxisByInsertIndexesKeepOriginalAxisIds(inner_node, insert_indexes));
1299+ }
1300+ GE_ASSERT_SUCCESS(RefreshReshapeAxisGroupByInsertedAxisIds(
1301+ CollectInsertedAxisIds(axis_before_insert, CollectAxisIds(fused_graph_attr->axis)),
1302+ CollectAxisIds(fused_graph_attr->axis), GetInterAttrs(attr).axis_group));
1303+ return SUCCESS;
1304+}
1305+ 
1306+inline bool IsReshapeSearchTerminal(const NodePtr &node, const bool search_forward) {
1307+ if (search_forward) {
1308+ return BackendUtils::IsOutputNode(node);
1309+ }
1310+ return (node->GetType() == kDataType) || (node->GetType() == kScalarType);
1311+}
1312+ 
1313+inline void GetConnectedPeerInNodesForReshapeSearch(const NodePtr &node, const int32_t out_data_idx,
1314+ std::vector<NodePtr> &peer_in_nodes) {
1315+ peer_in_nodes.clear();
1316+ const auto out_anchor = node->GetOutDataAnchor(out_data_idx);
1317+ if (out_anchor == nullptr) {
1318+ return;
1319+ }
1320+ for (const auto &peer_in_anchor : out_anchor->GetPeerInDataAnchors()) {
1321+ if (peer_in_anchor == nullptr) {
1322+ continue;
1323+ }
1324+ const auto peer_in_node = peer_in_anchor->GetOwnerNode();
1325+ if (peer_in_node != nullptr) {
1326+ peer_in_nodes.push_back(peer_in_node);
1327+ }
1328+ }
1329+}
1330+ 
1331+inline void GetConnectedPeerOutNodesForReshapeSearch(const NodePtr &node, std::vector<NodePtr> &peer_out_nodes) {
1332+ peer_out_nodes.clear();
1333+ const auto size = static_cast<int32_t>(node->GetAllInDataAnchorsSize());
1334+ for (int32_t i = 0; i < size; ++i) {
1335+ const auto in_anchor = node->GetInDataAnchor(i);
1336+ if (in_anchor == nullptr) {
1337+ continue;
1338+ }
1339+ const auto peer_out_anchor = in_anchor->GetPeerOutAnchor();
1340+ if (peer_out_anchor == nullptr) {
1341+ continue;
1342+ }
1343+ const auto peer_out_node = peer_out_anchor->GetOwnerNode();
1344+ if (peer_out_node != nullptr) {
1345+ peer_out_nodes.push_back(peer_out_node);
1346+ }
1347+ }
1348+}
1349+ 
1350+inline bool FindDirectionalNonUnitRepeatByAxisId(const NodePtr &node, const int64_t axis_id, const bool search_forward,
1351+ std::unordered_set<const void *> &visited, Expression &repeat) {
1352+ if ((node == nullptr) || (visited.find(node.get()) != visited.end())) {
1353+ return false;
1354+ }
1355+ visited.insert(node.get());
1356+ if (IsReshapeSearchTerminal(node, search_forward)) {
1357+ return false;
1358+ }
1359+ 
1360+ const auto op_desc = node->GetOpDesc();
1361+ if (op_desc == nullptr) {
1362+ return false;
1363+ }
1364+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
1365+ const auto output_desc = op_desc->MutableOutputDesc(i);
1366+ if (output_desc == nullptr) {
1367+ continue;
1368+ }
1369+ const auto tensor_attr = output_desc->GetAttrsGroup<AscTensorAttr>();
1370+ if (tensor_attr == nullptr) {
1371+ continue;
1372+ }
1373+ const auto axis_it = std::find(tensor_attr->axis.begin(), tensor_attr->axis.end(), axis_id);
1374+ if (axis_it == tensor_attr->axis.end()) {
1375+ continue;
1376+ }
1377+ const auto axis_index = static_cast<size_t>(std::distance(tensor_attr->axis.begin(), axis_it));
1378+ if ((axis_index < tensor_attr->repeats.size()) && !BackendUtils::IsEqOne(tensor_attr->repeats[axis_index])) {
1379+ repeat = tensor_attr->repeats[axis_index];
1380+ return true;
1381+ }
1382+ }
1383+ 
1384+ std::vector<NodePtr> peer_nodes;
1385+ if (search_forward) {
1386+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
1387+ GetConnectedPeerInNodesForReshapeSearch(node, static_cast<int32_t>(i), peer_nodes);
1388+ for (const auto &peer_node : peer_nodes) {
1389+ if (FindDirectionalNonUnitRepeatByAxisId(peer_node, axis_id, search_forward, visited, repeat)) {
1390+ return true;
1391+ }
1392+ }
1393+ }
1394+ return false;
1395+ }
1396+ 
1397+ GetConnectedPeerOutNodesForReshapeSearch(node, peer_nodes);
1398+ for (const auto &peer_node : peer_nodes) {
1399+ if (FindDirectionalNonUnitRepeatByAxisId(peer_node, axis_id, search_forward, visited, repeat)) {
1400+ return true;
1401+ }
1402+ }
1403+ return false;
1404+}
1405+ 
1406+inline bool FindAnchorRepeatByRepeatIndex(const NodePtr &node, const std::vector<int64_t> &axis,
1407+ const size_t repeat_index, const bool search_forward, Expression &repeat) {
1408+ if (repeat_index >= axis.size()) {
1409+ return false;
1410+ }
1411+ std::unordered_set<const void *> visited;
1412+ return FindDirectionalNonUnitRepeatByAxisId(node, axis[repeat_index], search_forward, visited, repeat);
1413+}
1414+ 
1415+inline void BuildUnitRepeatGapIndexes(const std::vector<Expression> &repeats,
1416+ std::vector<std::vector<size_t>> &gap_indexes, std::vector<size_t> &gap_starts) {
1417+ gap_indexes.assign(RemoveUnitRepeats(repeats).size() + 1U, {});
1418+ gap_starts.assign(gap_indexes.size(), 0U);
1419+ size_t gap_idx = 0U;
1420+ for (size_t i = 0U; i < repeats.size(); ++i) {
1421+ if (BackendUtils::IsEqOne(repeats[i])) {
1422+ gap_indexes[gap_idx].push_back(i);
1423+ continue;
1424+ }
1425+ ++gap_idx;
1426+ if (gap_idx < gap_starts.size()) {
1427+ gap_starts[gap_idx] = i + 1U;
1428+ }
1429+ }
1430+}
1431+ 
1432+inline void BuildUnitRepeatGapIndexes(const std::vector<Expression> &repeats,
1433+ std::vector<std::vector<size_t>> &gap_indexes) {
1434+ std::vector<size_t> unused_gap_starts;
1435+ BuildUnitRepeatGapIndexes(repeats, gap_indexes, unused_gap_starts);
1436+}
1437+ 
1438+inline void RemoveInsertIndexesInRange(const size_t range_start, const size_t range_end,
1439+ std::vector<size_t> &insert_indexes) {
1440+ insert_indexes.erase(std::remove_if(insert_indexes.begin(), insert_indexes.end(),
1441+ [range_start, range_end](const size_t insert_index) {
1442+ return (insert_index >= range_start) && (insert_index < range_end);
1443+ }),
1444+ insert_indexes.end());
1445+}
1446+ 
1447+inline bool CollectAnchorAlignedInsertIndexes(const NodePtr &node, const std::vector<int64_t> &axis,
1448+ const std::vector<size_t> &current_gap_indexes, const bool search_forward,
1449+ const NodePtr &peer_node, const std::vector<int64_t> &peer_axis,
1450+ const std::vector<size_t> &peer_gap_indexes,
1451+ const bool peer_search_forward, const size_t gap_start,
1452+ std::vector<size_t> &aligned_insert_indexes) {
1453+ constexpr size_t kInvalidIndex = static_cast<size_t>(-1);
1454+ std::vector<size_t> peer_offset_to_current_index(peer_gap_indexes.size(), kInvalidIndex);
1455+ for (const auto current_index : current_gap_indexes) {
1456+ Expression current_anchor;
1457+ if (!FindAnchorRepeatByRepeatIndex(node, axis, current_index, search_forward, current_anchor)) {
1458+ continue;
1459+ }
1460+ for (size_t peer_offset = 0U; peer_offset < peer_gap_indexes.size(); ++peer_offset) {
1461+ Expression peer_anchor;
1462+ if (FindAnchorRepeatByRepeatIndex(peer_node, peer_axis, peer_gap_indexes[peer_offset], peer_search_forward,
1463+ peer_anchor) &&
1464+ IsSameRepeat(current_anchor, peer_anchor)) {
1465+ peer_offset_to_current_index[peer_offset] = current_index;
1466+ break;
1467+ }
1468+ }
1469+ }
1470+ if (std::all_of(peer_offset_to_current_index.begin(), peer_offset_to_current_index.end(),
1471+ [](const size_t current_index) { return current_index == kInvalidIndex; })) {
1472+ return false;
1473+ }
1474+ 
1475+ aligned_insert_indexes.clear();
1476+ for (size_t peer_offset = 0U; peer_offset < peer_offset_to_current_index.size(); ++peer_offset) {
1477+ if (peer_offset_to_current_index[peer_offset] != kInvalidIndex) {
1478+ continue;
1479+ }
1480+ size_t insert_index = gap_start + current_gap_indexes.size();
1481+ for (size_t next_offset = peer_offset + 1U; next_offset < peer_offset_to_current_index.size(); ++next_offset) {
1482+ if (peer_offset_to_current_index[next_offset] != kInvalidIndex) {
1483+ insert_index = peer_offset_to_current_index[next_offset];
1484+ break;
1485+ }
1486+ }
1487+ aligned_insert_indexes.push_back(insert_index);
1488+ }
1489+ return true;
1490+}
1491+ 
1492+inline void AdjustInsertIndexesByAnchorAlignment(const NodePtr &node, const std::vector<int64_t> &axis,
1493+ const std::vector<Expression> &repeats, const bool search_forward,
1494+ const NodePtr &peer_node, const std::vector<int64_t> &peer_axis,
1495+ const std::vector<Expression> &peer_repeats,
1496+ const bool peer_search_forward, std::vector<size_t> &insert_indexes) {
1497+ std::vector<std::vector<size_t>> gap_indexes;
1498+ std::vector<size_t> gap_starts;
1499+ std::vector<std::vector<size_t>> peer_gap_indexes;
1500+ BuildUnitRepeatGapIndexes(repeats, gap_indexes, gap_starts);
1501+ BuildUnitRepeatGapIndexes(peer_repeats, peer_gap_indexes);
1502+ if (gap_indexes.size() != peer_gap_indexes.size()) {
1503+ return;
1504+ }
1505+ 
1506+ for (size_t gap_idx = 0U; gap_idx < gap_indexes.size(); ++gap_idx) {
1507+ if ((peer_gap_indexes[gap_idx].size() <= gap_indexes[gap_idx].size()) || (peer_gap_indexes[gap_idx].size() <= 1U)) {
1508+ continue;
1509+ }
1510+ std::vector<size_t> aligned_insert_indexes;
1511+ if (!CollectAnchorAlignedInsertIndexes(node, axis, gap_indexes[gap_idx], search_forward, peer_node, peer_axis,
1512+ peer_gap_indexes[gap_idx], peer_search_forward, gap_starts[gap_idx],
1513+ aligned_insert_indexes)) {
1514+ continue;
1515+ }
1516+ RemoveInsertIndexesInRange(gap_starts[gap_idx], gap_starts[gap_idx] + peer_gap_indexes[gap_idx].size(),
1517+ insert_indexes);
1518+ insert_indexes.insert(insert_indexes.end(), aligned_insert_indexes.begin(), aligned_insert_indexes.end());
1519+ }
1520+ std::sort(insert_indexes.begin(), insert_indexes.end());
1521+}
1522+ 
1523+inline Status CollectVerticalRelationInsertIndexes(const NodePtr &node1, const NodePtr &node2,
1524+ const NodeFuseInfo &fuse_info,
1525+ const std::vector<af::ReshapeAxisChangeInfo> &node1_axis_changes,
1526+ const std::vector<af::ReshapeAxisChangeInfo> &node2_axis_changes,
1527+ InsertIndexMergeState &node1_insert_index_state,
1528+ InsertIndexMergeState &node2_insert_index_state,
1529+ std::vector<size_t> &node1_insert_indexes,
1530+ std::vector<size_t> &node2_insert_indexes) {
1531+ AscGraphAxisMapping axis_mapping(false);
1532+ for (const auto &relation : fuse_info.GetNode1ToNode2LinkMap()) {
1533+ std::vector<Expression> node1_output_repeats;
1534+ std::vector<Expression> node2_input_repeats;
1535+ std::vector<Expression> dims;
1536+ std::vector<int64_t> node1_output_axis;
1537+ std::vector<int64_t> node2_input_axis;
1538+ std::vector<Expression> target_repeats;
1539+ std::vector<size_t> relation_node1_insert_indexes;
1540+ std::vector<size_t> relation_node2_insert_indexes;
1541+ GE_ASSERT_SUCCESS(
1542+ axis_mapping.GetPreNodeAttrs(node2, relation.second, dims, node1_output_axis, node1_output_repeats));
1543+ GE_ASSERT_SUCCESS(axis_mapping.GetCurNodeAttrs(node2, relation.second, node2_input_axis, node2_input_repeats));
1544+ 
1545+ GE_ASSERT_SUCCESS(BuildRelationTargetRepeats(node1_output_repeats, node2_input_repeats, node1_axis_changes,
1546+ node2_axis_changes, target_repeats));
1547+ GE_ASSERT_SUCCESS(
1548+ CollectInsertIndexesByTargetRepeats(node1_output_repeats, target_repeats, relation_node1_insert_indexes));
1549+ GE_ASSERT_SUCCESS(
1550+ CollectInsertIndexesByTargetRepeats(node2_input_repeats, target_repeats, relation_node2_insert_indexes));
1551+ AdjustInsertIndexesByAnchorAlignment(node1, node1_output_axis, node1_output_repeats, false, node2, node2_input_axis,
1552+ node2_input_repeats, true, relation_node1_insert_indexes);
1553+ AdjustInsertIndexesByAnchorAlignment(node2, node2_input_axis, node2_input_repeats, true, node1, node1_output_axis,
1554+ node1_output_repeats, false, relation_node2_insert_indexes);
1555+ GE_ASSERT_SUCCESS(MergeRelationInsertIndexes(node1_output_repeats.size(), relation_node1_insert_indexes,
1556+ node1_insert_index_state, node1_insert_indexes));
1557+ GE_ASSERT_SUCCESS(MergeRelationInsertIndexes(node2_input_repeats.size(), relation_node2_insert_indexes,
1558+ node2_insert_index_state, node2_insert_indexes));
1559+ GELOGD(
1560+ "collect vertical reshape insert indexes, node1 %s out %d repeats %s indexes %s, node2 %s in %d repeats %s "
1561+ "indexes %s, target repeats %s.",
1562+ node1->GetNamePtr(), relation.first, AutofuseUtils::VectorToStr(node1_output_repeats).c_str(),
1563+ AutofuseUtils::VectorToStr(node1_insert_indexes).c_str(), node2->GetNamePtr(), relation.second,
1564+ AutofuseUtils::VectorToStr(node2_input_repeats).c_str(),
1565+ AutofuseUtils::VectorToStr(node2_insert_indexes).c_str(), AutofuseUtils::VectorToStr(target_repeats).c_str());
1566+ }
1567+ return SUCCESS;
1568+}
1569+ 
1570+inline Status CollectCommonInputRelationInsertIndexes(const NodePtr &node1, const NodePtr &node2,
1571+ const NodeFuseInfo &fuse_info,
1572+ const std::vector<af::ReshapeAxisChangeInfo> &node1_axis_changes,
1573+ const std::vector<af::ReshapeAxisChangeInfo> &node2_axis_changes,
1574+ InsertIndexMergeState &node1_insert_index_state,
1575+ InsertIndexMergeState &node2_insert_index_state,
1576+ std::vector<size_t> &node1_insert_indexes,
1577+ std::vector<size_t> &node2_insert_indexes) {
1578+ AscGraphAxisMapping axis_mapping(false);
1579+ for (const auto &relation : fuse_info.GetSameInputMap()) {
1580+ std::vector<Expression> node1_input_repeats;
1581+ std::vector<Expression> node2_input_repeats;
1582+ std::vector<int64_t> node1_input_axis;
1583+ std::vector<int64_t> node2_input_axis;
1584+ std::vector<Expression> target_repeats;
1585+ std::vector<size_t> relation_node1_insert_indexes;
1586+ std::vector<size_t> relation_node2_insert_indexes;
1587+ GE_ASSERT_SUCCESS(axis_mapping.GetCurNodeAttrs(node1, relation.first, node1_input_axis, node1_input_repeats));
1588+ GE_ASSERT_SUCCESS(axis_mapping.GetCurNodeAttrs(node2, relation.second, node2_input_axis, node2_input_repeats));
1589+ 
1590+ GE_ASSERT_SUCCESS(BuildRelationTargetRepeats(node1_input_repeats, node2_input_repeats, node1_axis_changes,
1591+ node2_axis_changes, target_repeats));
1592+ GE_ASSERT_SUCCESS(
1593+ CollectInsertIndexesByTargetRepeats(node1_input_repeats, target_repeats, relation_node1_insert_indexes));
1594+ GE_ASSERT_SUCCESS(
1595+ CollectInsertIndexesByTargetRepeats(node2_input_repeats, target_repeats, relation_node2_insert_indexes));
1596+ AdjustInsertIndexesByAnchorAlignment(node1, node1_input_axis, node1_input_repeats, true, node2, node2_input_axis,
1597+ node2_input_repeats, true, relation_node1_insert_indexes);
1598+ AdjustInsertIndexesByAnchorAlignment(node2, node2_input_axis, node2_input_repeats, true, node1, node1_input_axis,
1599+ node1_input_repeats, true, relation_node2_insert_indexes);
1600+ GE_ASSERT_SUCCESS(MergeRelationInsertIndexes(node1_input_repeats.size(), relation_node1_insert_indexes,
1601+ node1_insert_index_state, node1_insert_indexes));
1602+ GE_ASSERT_SUCCESS(MergeRelationInsertIndexes(node2_input_repeats.size(), relation_node2_insert_indexes,
1603+ node2_insert_index_state, node2_insert_indexes));
1604+ GELOGD(
1605+ "collect common-input reshape insert indexes, node1 %s in %d repeats %s indexes %s, node2 %s in %d repeats "
1606+ "%s indexes %s, target repeats %s.",
1607+ node1->GetNamePtr(), relation.first, AutofuseUtils::VectorToStr(node1_input_repeats).c_str(),
1608+ AutofuseUtils::VectorToStr(node1_insert_indexes).c_str(), node2->GetNamePtr(), relation.second,
1609+ AutofuseUtils::VectorToStr(node2_input_repeats).c_str(),
1610+ AutofuseUtils::VectorToStr(node2_insert_indexes).c_str(), AutofuseUtils::VectorToStr(target_repeats).c_str());
1611+ }
1612+ return SUCCESS;
1613+}
1614+ 
1615+inline Status CollectRelationInsertIndexes(const NodePtr &node1, const NodePtr &node2, const NodeFuseInfo &fuse_info,
1616+ const std::vector<af::ReshapeAxisChangeInfo> &node1_axis_changes,
1617+ const std::vector<af::ReshapeAxisChangeInfo> &node2_axis_changes,
1618+ std::vector<size_t> &node1_insert_indexes,
1619+ std::vector<size_t> &node2_insert_indexes) {
1620+ node1_insert_indexes.clear();
1621+ node2_insert_indexes.clear();
1622+ InsertIndexMergeState node1_insert_index_state;
1623+ InsertIndexMergeState node2_insert_index_state;
1624+ GE_ASSERT_SUCCESS(CollectVerticalRelationInsertIndexes(
1625+ node1, node2, fuse_info, node1_axis_changes, node2_axis_changes, node1_insert_index_state,
1626+ node2_insert_index_state, node1_insert_indexes, node2_insert_indexes));
1627+ GE_ASSERT_SUCCESS(CollectCommonInputRelationInsertIndexes(
1628+ node1, node2, fuse_info, node1_axis_changes, node2_axis_changes, node1_insert_index_state,
1629+ node2_insert_index_state, node1_insert_indexes, node2_insert_indexes));
1630+ return SUCCESS;
1631+}
1632+ 
1633+// Backend can-fuse 前置处理接口:根据 node1/node2 的真实连接关系补齐 AscBackend/FusedAscBackend 的
1634+// reshape no-op 单位轴,避免后续比较或合并属性时使用不一致的轴空间。
1635+inline Status CompletePairReshapeAxes(const NodePtr &node1, const NodePtr &node2, const NodeFuseInfo &fuse_info) {
1636+ std::vector<af::ReshapeAxisChangeInfo> node1_axis_changes;
1637+ std::vector<af::ReshapeAxisChangeInfo> node2_axis_changes;
1638+ GE_ASSERT_SUCCESS(CollectNodeReshapeAxisChanges(node1, node1_axis_changes));
1639+ GE_ASSERT_SUCCESS(CollectNodeReshapeAxisChanges(node2, node2_axis_changes));
1640+ if (node1_axis_changes.empty() && node2_axis_changes.empty()) {
1641+ return SUCCESS;
1642+ }
1643+ 
1644+ std::vector<size_t> node1_insert_indexes;
1645+ std::vector<size_t> node2_insert_indexes;
1646+ GE_ASSERT_SUCCESS(CollectRelationInsertIndexes(node1, node2, fuse_info, node1_axis_changes, node2_axis_changes,
1647+ node1_insert_indexes, node2_insert_indexes));
1648+ GE_ASSERT_SUCCESS(PadNodeLeadingUnitAxisByInsertIndexesKeepOriginalAxisIds(node1, node1_insert_indexes));
1649+ GE_ASSERT_SUCCESS(PadNodeLeadingUnitAxisByInsertIndexesKeepOriginalAxisIds(node2, node2_insert_indexes));
1650+ std::vector<af::ReshapeAxisChangeInfo> merged_axis_changes;
1651+ GE_ASSERT_SUCCESS(CollectNodeReshapeAxisChanges(node1, merged_axis_changes));
1652+ GE_ASSERT_SUCCESS(CollectNodeReshapeAxisChanges(node2, merged_axis_changes));
1653+ GE_ASSERT_SUCCESS(SaveMergedReshapeAxisChanges(node1, merged_axis_changes));
1654+ GE_ASSERT_SUCCESS(SaveMergedReshapeAxisChanges(node2, merged_axis_changes));
1655+ return SUCCESS;
1656+}
1657+ 
1658+// Backend 融合属性继承接口:两个 backend 节点融合成新 backend 节点时,将两侧保存的 reshape 轴变化
1659+// 元数据继承到新节点。此处不重映射 axis id,后续由 FlushReshapeAxisChanges 统一刷新。
1660+inline void InheritReshapeAxisChanges(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,
1661+ const AutofuseInnerAttrs &attr2) {
1662+ attr_new.reshape_axis_changes.clear();
1663+ for (const auto &axis_change : attr1.reshape_axis_changes) {
1664+ AppendUniqueReshapeAxisChange(axis_change, attr_new.reshape_axis_changes);
1665+ }
1666+ for (const auto &axis_change : attr2.reshape_axis_changes) {
1667+ AppendUniqueReshapeAxisChange(axis_change, attr_new.reshape_axis_changes);
1668+ }
1669+}
1670+ 
1671+inline Status FlushReshapeAxisByRepeats(const NodePtr &node, const NodePtr &asc_node,
1672+ const std::vector<int64_t> &axis_before_Flush,
1673+ const std::vector<int64_t> &axis_after_Flush,
1674+ const std::vector<Expression> &reshape_repeats,
1675+ std::vector<int64_t> &reshape_axis, const char *info_name) {
1676+ if (axis_before_Flush.empty() || axis_after_Flush.empty() || reshape_axis.empty()) {
1677+ return SUCCESS;
1678+ }
1679+ 
1680+ GE_ASSERT_TRUE(axis_before_Flush.size() == axis_after_Flush.size(),
1681+ "axis_before_Flush size %zu must equal to axis_after_Flush size %zu", axis_before_Flush.size(),
1682+ axis_after_Flush.size());
1683+ GE_ASSERT_TRUE(reshape_axis.size() == reshape_repeats.size(), "reshape axis size %zu must equal repeats size %zu",
1684+ reshape_axis.size(), reshape_repeats.size());
1685+ 
1686+ std::unordered_map<int64_t, size_t> axis_before_to_index;
1687+ for (size_t i = 0U; i < axis_before_Flush.size(); ++i) {
1688+ axis_before_to_index[axis_before_Flush[i]] = i;
1689+ }
1690+ 
1691+ std::vector<int64_t> updated_axis;
1692+ updated_axis.reserve(reshape_axis.size());
1693+ for (size_t i = 0U; i < reshape_axis.size(); ++i) {
1694+ const auto axis = reshape_axis[i];
1695+ auto it = axis_before_to_index.find(axis);
1696+ if (it != axis_before_to_index.end()) {
1697+ updated_axis.push_back(axis_after_Flush[it->second]);
1698+ continue;
1699+ }
1700+ if (BackendUtils::IsEqOne(reshape_repeats[i]) && (reshape_axis.size() == axis_after_Flush.size())) {
1701+ updated_axis.push_back(axis_after_Flush[i]);
1702+ continue;
1703+ }
1704+ GELOGW("Axis %ld in %s not found in axis_before_Flush for asc_node %s, keep original value", axis, info_name,
1705+ asc_node->GetNamePtr());
1706+ updated_axis.push_back(axis);
1707+ }
1708+ 
1709+ GELOGD("Flush %s for node %s, asc_node %s, before: %s, after: %s", info_name, node->GetNamePtr(),
1710+ asc_node->GetNamePtr(), AutofuseUtils::VectorToStr(reshape_axis).c_str(),
1711+ AutofuseUtils::VectorToStr(updated_axis).c_str());
1712+ reshape_axis = updated_axis;
1713+ return SUCCESS;
1714+}
1715+ 
1716+// Backend reshape 轴元数据刷新接口:FlushAscSubGraphAxisInfo 转换 AscGraph 轴 id 后,同步刷新 backend
1717+// 节点中保存的 before_axis/after_axis,避免后续 can-fuse 或后处理读取到过期 axis id。
1718+inline Status FlushReshapeAxisChanges(const NodePtr &node, const NodePtr &asc_node,
1719+ const std::vector<int64_t> &axis_before_Flush,
1720+ const std::vector<int64_t> &axis_after_Flush) {
1721+ auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(node);
1722+ GE_ASSERT_NOTNULL(autofuse_attr);
1723+ auto reshape_axis_changes = autofuse_attr->GetReshapeAxisChanges();
1724+ if (reshape_axis_changes.empty()) {
1725+ return SUCCESS;
1726+ }
1727+ 
1728+ for (auto &change : reshape_axis_changes) {
1729+ GE_ASSERT_SUCCESS(FlushReshapeAxisByRepeats(node, asc_node, axis_before_Flush, axis_after_Flush,
1730+ change.before_repeats, change.before_axis, "reshape_before_axis"));
1731+ GE_ASSERT_SUCCESS(FlushReshapeAxisByRepeats(node, asc_node, axis_before_Flush, axis_after_Flush,
1732+ change.after_repeats, change.after_axis, "reshape_after_axis"));
1733+ }
1734+ autofuse_attr->SetReshapeAxisChanges(reshape_axis_changes);
1735+ 
1736+ return SUCCESS;
1737+}
1738+ 
1739+} // namespace asc_adapt
1740+} // namespace ge
1741+#endif // AUTOFUSE_POST_PROCESS_SCHEDULER_ADAPTER_ADAPTION_RESHAPE_AXIS_PADDING_H
@@ -52,6 +52,18 @@ enum class SplitFusionRatioRequirementState : uint32_t {
52 SATISFIED = 2U // 融合比例满足阈值要求52 SATISFIED = 2U // 融合比例满足阈值要求
53};53};
54 54 
55+struct ReshapeAxisChangeInfo {
56+ std::vector<int64_t> before_axis;
57+ std::vector<Expression> before_repeats;
58+ std::vector<int64_t> after_axis;
59+ std::vector<Expression> after_repeats;
60+};
61+ 
62+struct ReduceOriginalAxisInfo {
63+ std::vector<int64_t> axis;
64+ std::vector<Expression> repeats;
65+};
66+ 
55struct AutofuseInnerAttrs {67struct AutofuseInnerAttrs {
56 std::vector<const af::Node *> origin_nodes; // Asc节点对应的原始节点,用于Dfx打印、获取融合前ComputeGraph片段等68 std::vector<const af::Node *> origin_nodes; // Asc节点对应的原始节点,用于Dfx打印、获取融合前ComputeGraph片段等
57 std::vector<af::OutDataAnchor *> output_buffers; // Asc节点负责写入的原始输出anchor,用于lifting69 std::vector<af::OutDataAnchor *> output_buffers; // Asc节点负责写入的原始输出anchor,用于lifting
@@ -76,7 +88,9 @@ struct AutofuseInnerAttrs {
76 bool is_fuse_from_lowering = false; // 标识融合节点来自lowering还是can_fuse88 bool is_fuse_from_lowering = false; // 标识融合节点来自lowering还是can_fuse
77 std::vector<int64_t> reduce_original_axis; // reduce操作前的原始轴信息89 std::vector<int64_t> reduce_original_axis; // reduce操作前的原始轴信息
78 std::vector<Expression> reduce_original_repeats; // reduce操作前的原始repeats信息90 std::vector<Expression> reduce_original_repeats; // reduce操作前的原始repeats信息
79- int32_t is_reduce_all_load = REDUCE_ALL_LOAD_INIT; // 标识reduce是否所有load都是norm-like91+ std::map<std::string, ReduceOriginalAxisInfo> reduce_original_axis_infos; // 每个reduce节点操作前的原始轴信息
92+ std::vector<ReshapeAxisChangeInfo> reshape_axis_changes; // 每个reshape操作前后的轴变化信息
93+ int32_t is_reduce_all_load = REDUCE_ALL_LOAD_INIT; // 标识reduce是否所有load都是norm-like
80 94 
81 bool IsReduction() const {95 bool IsReduction() const {
82 return HasFuseType(loop::FuseType::kReduction);96 return HasFuseType(loop::FuseType::kReduction);
@@ -92,7 +106,12 @@ using AfAttrGroupsBase = af::AttrGroupsBase;
92class AutoFuseAttrs : public AfAttrGroupsBase {106class AutoFuseAttrs : public AfAttrGroupsBase {
93 public:107 public:
94 AutoFuseAttrs() = default;108 AutoFuseAttrs() = default;
95- AutoFuseAttrs(const AutoFuseAttrs &other) : fuse_type_(other.fuse_type_), asc_graph_(other.asc_graph_) {}109+ AutoFuseAttrs(const AutoFuseAttrs &other) : fuse_type_(other.fuse_type_), asc_graph_(other.asc_graph_) {
110+ inner_attrs_.reduce_original_axis = other.inner_attrs_.reduce_original_axis;
111+ inner_attrs_.reduce_original_repeats = other.inner_attrs_.reduce_original_repeats;
112+ inner_attrs_.reduce_original_axis_infos = other.inner_attrs_.reduce_original_axis_infos;
113+ inner_attrs_.reshape_axis_changes = other.inner_attrs_.reshape_axis_changes;
114+ }
96 AutoFuseAttrs &operator=(const AutoFuseAttrs &other) = delete;115 AutoFuseAttrs &operator=(const AutoFuseAttrs &other) = delete;
97 116 
98 [[nodiscard]] const std::shared_ptr<AscGraph> &GetAscGraph() const {117 [[nodiscard]] const std::shared_ptr<AscGraph> &GetAscGraph() const {
@@ -229,18 +248,66 @@ class AutoFuseAttrs : public AfAttrGroupsBase {
229 inner_attrs_.reduce_original_axis = axis;248 inner_attrs_.reduce_original_axis = axis;
230 }249 }
231 250 
251+ void SetReduceOriginalAxis(const std::string &node_name, const std::vector<int64_t> &axis) {
252+ inner_attrs_.reduce_original_axis_infos[node_name].axis = axis;
253+ SetReduceOriginalAxis(axis);
254+ }
255+ 
232 [[nodiscard]] const std::vector<int64_t> &GetReduceOriginalAxis() const {256 [[nodiscard]] const std::vector<int64_t> &GetReduceOriginalAxis() const {
233 return inner_attrs_.reduce_original_axis;257 return inner_attrs_.reduce_original_axis;
234 }258 }
235 259 
260+ [[nodiscard]] const std::vector<int64_t> &GetReduceOriginalAxis(const std::string &node_name) const {
261+ const auto it = inner_attrs_.reduce_original_axis_infos.find(node_name);
262+ if (it != inner_attrs_.reduce_original_axis_infos.end()) {
263+ return it->second.axis;
264+ }
265+ return GetReduceOriginalAxis();
266+ }
267+ 
236 void SetReduceOriginalRepeats(const std::vector<Expression> &repeats) {268 void SetReduceOriginalRepeats(const std::vector<Expression> &repeats) {
237 inner_attrs_.reduce_original_repeats = repeats;269 inner_attrs_.reduce_original_repeats = repeats;
238 }270 }
239 271 
272+ void SetReduceOriginalRepeats(const std::string &node_name, const std::vector<Expression> &repeats) {
273+ inner_attrs_.reduce_original_axis_infos[node_name].repeats = repeats;
274+ SetReduceOriginalRepeats(repeats);
275+ }
276+ 
240 [[nodiscard]] const std::vector<Expression> &GetReduceOriginalRepeats() const {277 [[nodiscard]] const std::vector<Expression> &GetReduceOriginalRepeats() const {
241 return inner_attrs_.reduce_original_repeats;278 return inner_attrs_.reduce_original_repeats;
242 }279 }
243 280 
281+ [[nodiscard]] const std::vector<Expression> &GetReduceOriginalRepeats(const std::string &node_name) const {
282+ const auto it = inner_attrs_.reduce_original_axis_infos.find(node_name);
283+ if (it != inner_attrs_.reduce_original_axis_infos.end()) {
284+ return it->second.repeats;
285+ }
286+ return GetReduceOriginalRepeats();
287+ }
288+ 
289+ void SetReduceOriginalAxisInfo(const std::string &node_name, const std::vector<int64_t> &axis,
290+ const std::vector<Expression> &repeats) {
291+ SetReduceOriginalAxis(node_name, axis);
292+ SetReduceOriginalRepeats(node_name, repeats);
293+ }
294+ 
295+ [[nodiscard]] const std::map<std::string, ReduceOriginalAxisInfo> &GetReduceOriginalAxisInfos() const {
296+ return inner_attrs_.reduce_original_axis_infos;
297+ }
298+ 
299+ void AddReshapeAxisChange(const ReshapeAxisChangeInfo &change) {
300+ inner_attrs_.reshape_axis_changes.push_back(change);
301+ }
302+ 
303+ void SetReshapeAxisChanges(const std::vector<ReshapeAxisChangeInfo> &changes) {
304+ inner_attrs_.reshape_axis_changes = changes;
305+ }
306+ 
307+ [[nodiscard]] const std::vector<ReshapeAxisChangeInfo> &GetReshapeAxisChanges() const {
308+ return inner_attrs_.reshape_axis_changes;
309+ }
310+ 
244 void SetReduceAllLoadState(const int32_t state) {311 void SetReduceAllLoadState(const int32_t state) {
245 inner_attrs_.is_reduce_all_load = state;312 inner_attrs_.is_reduce_all_load = state;
246 }313 }
@@ -27,6 +27,7 @@
27#include "attribute_group/attr_group_shape_env.h"27#include "attribute_group/attr_group_shape_env.h"
28#include "can_fuse/backend/asc_backend_fusion_decider.h"28#include "can_fuse/backend/asc_backend_fusion_decider.h"
29#include "post_process/scheduler_adapter/adaption_complete_node_attrs.h"29#include "post_process/scheduler_adapter/adaption_complete_node_attrs.h"
30+#include "post_process/scheduler_adapter/adaption_reshape_axis_padding.h"
30#include "graph/ascendc_ir/ascir_registry.h"31#include "graph/ascendc_ir/ascir_registry.h"
31#include "common/autofuse_platform_api.h"32#include "common/autofuse_platform_api.h"
32 33 
@@ -15632,6 +15633,245 @@ TEST_F(AscBackendPostProcessorTest, GatherInsertCastImproveprecision) {
15632 EXPECT_NE(cnt, 2);15633 EXPECT_NE(cnt, 2);
15633}15634}
15634 15635 
15636+struct ReshapeAxisPaddingCase {
15637+ ComputeGraphPtr outer_graph;
15638+ NodePtr asc_backend;
15639+ AutoFuseAttrs *attr = nullptr;
15640+};
15641+ 
15642+void BuildBestOverlapReshapeCase(ReshapeAxisPaddingCase &test_case) {
15643+ GraphBuilder builder("best_overlap_reshape_outer");
15644+ test_case.asc_backend =
15645+ builder.AddNode("best_overlap_reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {4, 15120});
15646+ ASSERT_NE(test_case.asc_backend, nullptr);
15647+ test_case.attr = GetOrCreateAutoFuseAttrs(test_case.asc_backend->GetOpDesc());
15648+ ASSERT_NE(test_case.attr, nullptr);
15649+ 
15650+ ge::AscGraph graph("best_overlap_reshape_graph");
15651+ const auto one = Symbol(1);
15652+ const auto size0 = Symbol(4);
15653+ const auto size1 = Symbol(15120);
15654+ auto z0 = graph.CreateAxis("z0", size0);
15655+ auto z1 = graph.CreateAxis("z1", size1);
15656+ const std::vector<int64_t> graph_axis = {z0.id, z1.id};
15657+ 
15658+ af::ascir_op::Data data("best_overlap_data", graph);
15659+ data.attr.sched.axis = graph_axis;
15660+ data.y.dtype = DT_FLOAT16;
15661+ *data.y.axis = graph_axis;
15662+ *data.y.repeats = {size0, size1};
15663+ *data.y.strides = {size1, one};
15664+ 
15665+ af::ascir_op::Load load("best_overlap_load");
15666+ load.x = data.y;
15667+ load.attr.sched.axis = graph_axis;
15668+ load.y.dtype = DT_FLOAT16;
15669+ *load.y.axis = graph_axis;
15670+ *load.y.repeats = {size0, size1};
15671+ *load.y.strides = {size1, one};
15672+ 
15673+ af::ascir_op::Store store("best_overlap_store");
15674+ store.x = load.y;
15675+ store.attr.sched.axis = graph_axis;
15676+ store.y.dtype = DT_FLOAT16;
15677+ *store.y.axis = graph_axis;
15678+ *store.y.repeats = {size0, size1};
15679+ *store.y.strides = {size1, one};
15680+ test_case.attr->SetAscGraph(std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph)), loop::FuseType::kPointwise);
15681+ 
15682+ af::ReshapeAxisChangeInfo change;
15683+ change.before_axis = {0, 1, 2};
15684+ change.before_repeats = {one, one, one};
15685+ change.after_axis = {0, 1};
15686+ change.after_repeats = {one, one};
15687+ test_case.attr->AddReshapeAxisChange(change);
15688+ test_case.outer_graph = builder.GetGraph();
15689+}
15690+ 
15691+void CheckBestOverlapReshapeResult(const std::shared_ptr<ge::AscGraph> &asc_graph) {
15692+ const auto completed_graph_attr = AscGraphUtils::GetComputeGraph(*asc_graph)->GetAttrsGroup<AscGraphAttr>();
15693+ ASSERT_NE(completed_graph_attr, nullptr);
15694+ ASSERT_EQ(completed_graph_attr->axis.size(), 3U);
15695+ EXPECT_EQ(completed_graph_attr->axis[0]->id, 0);
15696+ EXPECT_EQ(completed_graph_attr->axis[1]->id, 1);
15697+ EXPECT_EQ(completed_graph_attr->axis[2]->id, 2);
15698+ EXPECT_TRUE(BackendUtils::IsEqOne(completed_graph_attr->axis[0]->size));
15699+ EXPECT_EQ(std::string(completed_graph_attr->axis[1]->size.Str().get()), "4");
15700+ EXPECT_EQ(std::string(completed_graph_attr->axis[2]->size.Str().get()), "15120");
15701+ 
15702+ auto store_node = asc_graph->FindNode("best_overlap_store");
15703+ ASSERT_NE(store_node, nullptr);
15704+ AscTensorAttr *store_attr = nullptr;
15705+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store_node, store_attr), SUCCESS);
15706+ ASSERT_NE(store_attr, nullptr);
15707+ EXPECT_EQ(store_attr->axis, std::vector<int64_t>({0, 1, 2}));
15708+ ASSERT_EQ(store_attr->repeats.size(), 3U);
15709+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->repeats[0]));
15710+ EXPECT_EQ(std::string(store_attr->repeats[1].Str().get()), "4");
15711+ EXPECT_EQ(std::string(store_attr->repeats[2].Str().get()), "15120");
15712+ ASSERT_EQ(store_attr->strides.size(), 3U);
15713+ EXPECT_TRUE(BackendUtils::IsEqZero(store_attr->strides[0]));
15714+ EXPECT_EQ(std::string(store_attr->strides[1].Str().get()), "15120");
15715+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->strides[2]));
15716+}
15717+ 
15718+void BuildMultipleReshapeAxisChangesCase(ReshapeAxisPaddingCase &test_case) {
15719+ GraphBuilder builder("multi_reshape_outer");
15720+ test_case.asc_backend =
15721+ builder.AddNode("multi_reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {22, 15120, 1});
15722+ ASSERT_NE(test_case.asc_backend, nullptr);
15723+ test_case.attr = GetOrCreateAutoFuseAttrs(test_case.asc_backend->GetOpDesc());
15724+ ASSERT_NE(test_case.attr, nullptr);
15725+ 
15726+ ge::AscGraph graph("multi_reshape_axis_graph");
15727+ auto z0 = graph.CreateAxis("z0", Symbol(22));
15728+ auto z1 = graph.CreateAxis("z1", Symbol(15120));
15729+ auto z2 = graph.CreateAxis("z2", Symbol(1));
15730+ af::ascir_op::Data data("data", graph);
15731+ data.attr.sched.axis = {z0.id, z1.id, z2.id};
15732+ data.y.dtype = DT_FLOAT16;
15733+ *data.y.axis = {z0.id, z1.id, z2.id};
15734+ *data.y.repeats = {Symbol(22), Symbol(15120), Symbol(1)};
15735+ *data.y.strides = {Symbol(15120), Symbol(1), Symbol(0)};
15736+ 
15737+ af::ascir_op::Load load("load");
15738+ load.x = data.y;
15739+ load.attr.sched.axis = {z0.id, z1.id, z2.id};
15740+ load.y.dtype = DT_FLOAT16;
15741+ *load.y.axis = {z0.id, z1.id, z2.id};
15742+ *load.y.repeats = {Symbol(22), Symbol(15120), Symbol(1)};
15743+ *load.y.strides = {Symbol(15120), Symbol(1), Symbol(0)};
15744+ 
15745+ af::ascir_op::Store store("store");
15746+ store.x = load.y;
15747+ store.attr.sched.axis = {z0.id, z1.id, z2.id};
15748+ store.y.dtype = DT_FLOAT16;
15749+ *store.y.axis = {z0.id, z1.id, z2.id};
15750+ *store.y.repeats = {Symbol(22), Symbol(15120), Symbol(1)};
15751+ *store.y.strides = {Symbol(15120), Symbol(1), Symbol(0)};
15752+ test_case.attr->SetAscGraph(std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph)), loop::FuseType::kPointwise);
15753+ 
15754+ af::ReshapeAxisChangeInfo squeeze_change;
15755+ squeeze_change.before_axis = {0, 1, 2};
15756+ squeeze_change.before_repeats = {Symbol(1), Symbol(22), Symbol(15120)};
15757+ squeeze_change.after_axis = {0, 1};
15758+ squeeze_change.after_repeats = {Symbol(22), Symbol(15120)};
15759+ test_case.attr->AddReshapeAxisChange(squeeze_change);
15760+ 
15761+ af::ReshapeAxisChangeInfo unsqueeze_change;
15762+ unsqueeze_change.before_axis = {0, 1};
15763+ unsqueeze_change.before_repeats = {Symbol(22), Symbol(15120)};
15764+ unsqueeze_change.after_axis = {0, 1, 2};
15765+ unsqueeze_change.after_repeats = {Symbol(22), Symbol(15120), Symbol(1)};
15766+ test_case.attr->AddReshapeAxisChange(unsqueeze_change);
15767+ test_case.outer_graph = builder.GetGraph();
15768+}
15769+ 
15770+void CheckMultipleReshapeAxisChangesResult(const std::shared_ptr<ge::AscGraph> &asc_graph) {
15771+ const auto graph_attr = AscGraphUtils::GetComputeGraph(*asc_graph)->GetAttrsGroup<AscGraphAttr>();
15772+ ASSERT_NE(graph_attr, nullptr);
15773+ EXPECT_EQ(graph_attr->axis.size(), 4U);
15774+ 
15775+ std::vector<int64_t> graph_axis_after_second_pad;
15776+ for (const auto &axis : graph_attr->axis) {
15777+ ASSERT_NE(axis, nullptr);
15778+ graph_axis_after_second_pad.push_back(axis->id);
15779+ }
15780+ auto store_node = asc_graph->FindNode("store");
15781+ ASSERT_NE(store_node, nullptr);
15782+ AscTensorAttr *store_attr = nullptr;
15783+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store_node, store_attr), SUCCESS);
15784+ ASSERT_NE(store_attr, nullptr);
15785+ EXPECT_EQ(store_attr->axis, graph_axis_after_second_pad);
15786+ EXPECT_EQ(store_attr->axis.size(), 4U);
15787+ EXPECT_EQ(store_attr->repeats.size(), 4U);
15788+ EXPECT_EQ(store_attr->strides.size(), 4U);
15789+}
15790+ 
15791+void CheckKeepOriginalAxisIdsReshapeResult(const ReshapeAxisPaddingCase &test_case) {
15792+ const auto graph_attr =
15793+ AscGraphUtils::GetComputeGraph(*(test_case.attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
15794+ ASSERT_NE(graph_attr, nullptr);
15795+ ASSERT_EQ(graph_attr->axis.size(), 4U);
15796+ EXPECT_EQ(graph_attr->axis[0]->id, 0);
15797+ EXPECT_EQ(graph_attr->axis[1]->id, 3);
15798+ EXPECT_EQ(graph_attr->axis[2]->id, 1);
15799+ EXPECT_EQ(graph_attr->axis[3]->id, 2);
15800+ 
15801+ auto store_node = test_case.attr->GetAscGraph()->FindNode("store");
15802+ ASSERT_NE(store_node, nullptr);
15803+ AscTensorAttr *store_attr = nullptr;
15804+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store_node, store_attr), SUCCESS);
15805+ ASSERT_NE(store_attr, nullptr);
15806+ EXPECT_EQ(store_attr->axis, std::vector<int64_t>({0, 3, 1, 2}));
15807+ ASSERT_EQ(store_attr->repeats.size(), 4U);
15808+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->repeats[1]));
15809+ ASSERT_EQ(store_attr->strides.size(), 4U);
15810+ EXPECT_TRUE(BackendUtils::IsEqZero(store_attr->strides[1]));
15811+ 
15812+ const auto &reshape_axis_changes = test_case.attr->GetReshapeAxisChanges();
15813+ ASSERT_EQ(reshape_axis_changes.size(), 2U);
15814+ EXPECT_EQ(reshape_axis_changes[0].before_axis, std::vector<int64_t>({0, 1, 2}));
15815+ EXPECT_EQ(reshape_axis_changes[0].after_axis, std::vector<int64_t>({0, 1}));
15816+ EXPECT_EQ(reshape_axis_changes[1].before_axis, std::vector<int64_t>({0, 1}));
15817+ EXPECT_EQ(reshape_axis_changes[1].after_axis, std::vector<int64_t>({0, 1, 2}));
15818+ 
15819+ const auto &axis_group = GetInterAttrs(test_case.attr).axis_group;
15820+ EXPECT_EQ(axis_group.y_group, std::vector<int64_t>({0, 1, 2, 3}));
15821+ EXPECT_TRUE(axis_group.n_group.empty());
15822+ EXPECT_EQ(axis_group.axes_order, std::vector<size_t>({0U, 3U, 1U, 2U}));
15823+}
15824+ 
15825+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_RestoreReshapeAxisByBestOverlap) {
15826+ ReshapeAxisPaddingCase test_case;
15827+ ASSERT_NO_FATAL_FAILURE(BuildBestOverlapReshapeCase(test_case));
15828+ ASSERT_NE(test_case.outer_graph, nullptr);
15829+ ASSERT_EQ(asc_adapt::PadLeadingUnitAxisByInsertIndexesAndCompleteAttrs(*(test_case.attr->GetAscGraph()),
15830+ test_case.asc_backend, {0U}),
15831+ SUCCESS);
15832+ ASSERT_NO_FATAL_FAILURE(CheckBestOverlapReshapeResult(test_case.attr->GetAscGraph()));
15833+}
15834+ 
15835+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_RestoreMultipleReshapeAxisChangesByInsertIndexes) {
15836+ ReshapeAxisPaddingCase test_case;
15837+ ASSERT_NO_FATAL_FAILURE(BuildMultipleReshapeAxisChangesCase(test_case));
15838+ ASSERT_NE(test_case.outer_graph, nullptr);
15839+ ASSERT_EQ(asc_adapt::PadLeadingUnitAxisByInsertIndexesAndCompleteAttrs(*(test_case.attr->GetAscGraph()),
15840+ test_case.asc_backend, {0U}),
15841+ SUCCESS);
15842+ const auto &reshape_axis_changes = test_case.attr->GetReshapeAxisChanges();
15843+ ASSERT_EQ(reshape_axis_changes.size(), 2U);
15844+ EXPECT_EQ(reshape_axis_changes[0].before_axis, std::vector<int64_t>({1, 2, 3}));
15845+ EXPECT_EQ(reshape_axis_changes[0].after_axis, std::vector<int64_t>({1, 2}));
15846+ EXPECT_EQ(reshape_axis_changes[1].before_axis, std::vector<int64_t>({1, 2}));
15847+ EXPECT_EQ(reshape_axis_changes[1].after_axis, std::vector<int64_t>({1, 2, 3}));
15848+ auto graph_attr = AscGraphUtils::GetComputeGraph(*(test_case.attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
15849+ ASSERT_NE(graph_attr, nullptr);
15850+ ASSERT_EQ(graph_attr->axis.size(), 4U);
15851+ ASSERT_NO_FATAL_FAILURE(CheckMultipleReshapeAxisChangesResult(test_case.attr->GetAscGraph()));
15852+}
15853+ 
15854+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_RestoreReshapeAxisKeepOriginalAxisIds) {
15855+ ReshapeAxisPaddingCase test_case;
15856+ ASSERT_NO_FATAL_FAILURE(BuildMultipleReshapeAxisChangesCase(test_case));
15857+ ASSERT_NE(test_case.outer_graph, nullptr);
15858+ GetInterAttrs(test_case.attr).axis_group.y_group = {0, 1, 2};
15859+ GetInterAttrs(test_case.attr).axis_group.axes_order = {0U, 1U, 2U};
15860+ ASSERT_EQ(asc_adapt::PadLeadingUnitAxisByInsertIndexesAndCompleteAttrsKeepOriginalAxisIds(
15861+ *(test_case.attr->GetAscGraph()), test_case.asc_backend, {1U}),
15862+ SUCCESS);
15863+ ASSERT_NO_FATAL_FAILURE(CheckKeepOriginalAxisIdsReshapeResult(test_case));
15864+}
15865+ 
15866+TEST_F(AscBackendPostProcessorTest, CollectInsertIndexesByTargetRepeatsKeepsLaterGapPosition) {
15867+ std::vector<size_t> insert_indexes;
15868+ ASSERT_EQ(asc_adapt::CollectInsertIndexesByTargetRepeats(
15869+ {Symbol(2), Symbol(1024), Symbol(1024)}, {Symbol(2), Symbol(1024), Symbol(1), Symbol(1024), Symbol(1)},
15870+ insert_indexes),
15871+ SUCCESS);
15872+ EXPECT_EQ(insert_indexes, std::vector<size_t>({2U, 4U}));
15873+}
15874+ 
15635TEST_F(AscBackendPostProcessorTest, CompleteAttrWithGraphInvalidAxisNodeValidAxis) {15875TEST_F(AscBackendPostProcessorTest, CompleteAttrWithGraphInvalidAxisNodeValidAxis) {
15636 ComputeGraphPtr compute_graph = BuildGraph1("AscBackend");15876 ComputeGraphPtr compute_graph = BuildGraph1("AscBackend");
15637 EXPECT_EQ(compute_graph->GetAllNodesSize(), 5);15877 EXPECT_EQ(compute_graph->GetAllNodesSize(), 5);
@@ -1877,7 +1877,8 @@ TEST_F(AscGraphAxisMappingTest, AscBackendFusionDecider_CreateSubGraphAxisMapInf
1877 EXPECT_EQ(asc_graph_axis_map.CreateSubGraphAxisMapInfo(addn1, shape1, node_fuse_info), SUCCESS);1877 EXPECT_EQ(asc_graph_axis_map.CreateSubGraphAxisMapInfo(addn1, shape1, node_fuse_info), SUCCESS);
1878}1878}
1879 1879 
1880-TEST_F(AscGraphAxisMappingTest, AscBackendFusionDecider_CreateSubGraphAxisMapInfo_For_Reduce_Vertical_Merge_Fail) {1880+TEST_F(AscGraphAxisMappingTest,
1881+ AscBackendFusionDecider_CreateSubGraphAxisMapInfo_For_Reduce_Vertical_Merge_UnitAxisFailed) {
1881 AscBackendFusionDecider decider;1882 AscBackendFusionDecider decider;
1882 ComputeGraphPtr compute_graph = BuildGraph1("AscBackend");1883 ComputeGraphPtr compute_graph = BuildGraph1("AscBackend");
1883 ASSERT_NE(compute_graph, nullptr);1884 ASSERT_NE(compute_graph, nullptr);
@@ -43,6 +43,26 @@ class LoopNodeLoweringUT : public testing::Test {
43 std::unique_ptr<es::Graph> es_graph_;43 std::unique_ptr<es::Graph> es_graph_;
44};44};
45 45 
46+std::vector<std::string> ToExpressionStrings(const std::vector<Expression> &expressions) {
47+ std::vector<std::string> result;
48+ result.reserve(expressions.size());
49+ for (const auto &expression : expressions) {
50+ result.emplace_back(expression.Str().get());
51+ }
52+ return result;
53+}
54+ 
55+void ExpectReshapeAxisChange(loop::KernelBox &kernel, const std::vector<int64_t> &before_axis,
56+ const std::vector<std::string> &before_repeats, const std::vector<int64_t> &after_axis,
57+ const std::vector<std::string> &after_repeats) {
58+ const auto &axis_changes = kernel.GetReshapeAxisChanges();
59+ ASSERT_EQ(axis_changes.size(), 1U);
60+ EXPECT_EQ(axis_changes[0].before_axis, before_axis);
61+ EXPECT_EQ(ToExpressionStrings(axis_changes[0].before_repeats), before_repeats);
62+ EXPECT_EQ(axis_changes[0].after_axis, after_axis);
63+ EXPECT_EQ(ToExpressionStrings(axis_changes[0].after_repeats), after_repeats);
64+}
65+ 
46TEST_F(LoopNodeLoweringUT, In2Out1Lowering) {66TEST_F(LoopNodeLoweringUT, In2Out1Lowering) {
47 [this]() {67 [this]() {
48 auto data0 = es_graph_->CreateInput(0, "data0", nullptr);68 auto data0 = es_graph_->CreateInput(0, "data0", nullptr);
@@ -1763,6 +1783,7 @@ TEST_F(LoopNodeLoweringUT, LoweringUnsqueeze) {
1763 "tmp1 = ops.Unsqueeze(tmp0, 0)\n"1783 "tmp1 = ops.Unsqueeze(tmp0, 0)\n"
1764 "tmp2 = ops.Unsqueeze(tmp1, 1)\n"1784 "tmp2 = ops.Unsqueeze(tmp1, 1)\n"
1765 "tmp3 = ops.StoreReshape(\"Unsqueeze_0:0\", tmp2)\n");1785 "tmp3 = ops.StoreReshape(\"Unsqueeze_0:0\", tmp2)\n");
1786+ ExpectReshapeAxisChange(kernel, {0, 1}, {"s0", "2"}, {0, 1, 2, 3}, {"1", "1", "s0", "2"});
1766}1787}
1767 1788 
1768TEST_F(LoopNodeLoweringUT, LoweringSqueeze) {1789TEST_F(LoopNodeLoweringUT, LoweringSqueeze) {
@@ -1788,6 +1809,7 @@ TEST_F(LoopNodeLoweringUT, LoweringSqueeze) {
1788 "tmp2 = ops.Squeeze(tmp1, 2)\n"1809 "tmp2 = ops.Squeeze(tmp1, 2)\n"
1789 "tmp3 = ops.Squeeze(tmp2, 2)\n"1810 "tmp3 = ops.Squeeze(tmp2, 2)\n"
1790 "tmp4 = ops.Store(\"Squeeze_0:0\", tmp3)\n");1811 "tmp4 = ops.Store(\"Squeeze_0:0\", tmp3)\n");
1812+ ExpectReshapeAxisChange(kernel, {0, 1, 2, 3, 4}, {"s0", "1", "2", "1", "1"}, {0, 1}, {"s0", "2"});
1791}1813}
1792 1814 
1793TEST_F(LoopNodeLoweringUT, LoweringSqueezeLowerAxisIsNull) {1815TEST_F(LoopNodeLoweringUT, LoweringSqueezeLowerAxisIsNull) {
@@ -2279,6 +2301,8 @@ TEST_F(LoopNodeLoweringUT, LoweringExpandDims) {
2279 "tmp0 = ops.Load(\"data0:0\")\n"2301 "tmp0 = ops.Load(\"data0:0\")\n"
2280 "tmp1 = ops.Unsqueeze(tmp0, 2)\n"2302 "tmp1 = ops.Unsqueeze(tmp0, 2)\n"
2281 "tmp2 = ops.StoreReshape(\"ExpandDims_3:0\", tmp1)\n");2303 "tmp2 = ops.StoreReshape(\"ExpandDims_3:0\", tmp1)\n");
2304+ ExpectReshapeAxisChange(kernel, {0, 1}, {"s0", "2"}, {0, 1, 2}, {"s0", "2", "1"});
2305+ ExpectReshapeAxisChange(kernel1, {0, 1}, {"s0", "2"}, {0, 1, 2}, {"s0", "2", "1"});
2282 2306 
2283 auto kernel2 = ge::loop::GetKernelBox(expanddims2->GetOutDataAnchor(0));2307 auto kernel2 = ge::loop::GetKernelBox(expanddims2->GetOutDataAnchor(0));
2284 ASSERT_TRUE(kernel2.IsExternKernel());2308 ASSERT_TRUE(kernel2.IsExternKernel());
@@ -26,6 +26,7 @@
26#include "can_fuse/strategy/reduce_fusion_strategy.h"26#include "can_fuse/strategy/reduce_fusion_strategy.h"
27#include "post_process/asc_backend_post_processor.h"27#include "post_process/asc_backend_post_processor.h"
28#include "post_process/scheduler_adapter/adaption_fallback_load.h"28#include "post_process/scheduler_adapter/adaption_fallback_load.h"
29+#include "post_process/scheduler_adapter/adaption_reshape_axis_padding.h"
29#include "utils/auto_fuse_config.h"30#include "utils/auto_fuse_config.h"
30#include "fusion/autofuse_attrs.h"31#include "fusion/autofuse_attrs.h"
31#include "common/autofuse_backend_spec_api.h"32#include "common/autofuse_backend_spec_api.h"
@@ -108,6 +109,22 @@ NodePtr CreateReduceNodeWithOriginalAxis(const ComputeGraphPtr &graph, const std
108 attr->SetReduceOriginalRepeats(repeats);109 attr->SetReduceOriginalRepeats(repeats);
109 return node;110 return node;
110}111}
112+ 
113+NodePtr CreateNodeWithOutputAttr(const ComputeGraphPtr &graph, const std::string &name,
114+ const std::vector<int64_t> &axis, const std::vector<Expression> &repeats) {
115+ auto tensor_desc = std::make_shared<GeTensorDesc>();
116+ tensor_desc->SetShape(GeShape({1, 1, 1}));
117+ tensor_desc->SetFormat(FORMAT_ND);
118+ tensor_desc->SetDataType(DT_FLOAT);
119+ auto tensor_attr = tensor_desc->GetOrCreateAttrsGroup<AscTensorAttr>();
120+ tensor_attr->axis = axis;
121+ tensor_attr->repeats = repeats;
122+ 
123+ auto op_desc = std::make_shared<OpDesc>(name, kAscBackendType);
124+ op_desc->AddInputDesc(tensor_desc->Clone());
125+ op_desc->AddOutputDesc(tensor_desc->Clone());
126+ return graph->AddNode(op_desc);
127+}
111} // namespace128} // namespace
112 129 
113class LoweringAndCanfuseUT : public testing::Test {130class LoweringAndCanfuseUT : public testing::Test {
@@ -318,16 +335,13 @@ class LoweringAndCanfuseUT : public testing::Test {
318 }335 }
319 }336 }
320 337 
321- void VerifyAscNodeNoSizeOneAxis(const NodePtr &asc_node, bool is_concat) {338+ void VerifyAscNodeAxisAttrs(const NodePtr &asc_node) {
322 asc_adapt::TensorInfo tensor_desc;339 asc_adapt::TensorInfo tensor_desc;
323 ASSERT_EQ(asc_adapt::GetTensorInfo(asc_node, tensor_desc), SUCCESS);340 ASSERT_EQ(asc_adapt::GetTensorInfo(asc_node, tensor_desc), SUCCESS);
324 std::cout << " AscNode: " << asc_node->GetName() << ", Type: " << asc_node->GetType()341 std::cout << " AscNode: " << asc_node->GetName() << ", Type: " << asc_node->GetType()
325 << ", Repeats: " << AutofuseUtils::VectorToStr(tensor_desc.repeats) << std::endl;342 << ", Repeats: " << AutofuseUtils::VectorToStr(tensor_desc.repeats) << std::endl;
326- if (!is_concat) {343+ EXPECT_EQ(tensor_desc.axis.size(), tensor_desc.repeats.size());
327- for (size_t i = 0; i < tensor_desc.repeats.size(); ++i) {344+ EXPECT_EQ(tensor_desc.strides.size(), tensor_desc.repeats.size());
328- EXPECT_NE(tensor_desc.repeats[i], 1) << "Found size=1 axis in " << asc_node->GetName();
329- }
330- }
331 }345 }
332 346 
333 void VerifyAscBackendNode(const NodePtr &node) {347 void VerifyAscBackendNode(const NodePtr &node) {
@@ -342,7 +356,7 @@ class LoweringAndCanfuseUT : public testing::Test {
342 ASSERT_NE(attr->GetAscGraph(), nullptr);356 ASSERT_NE(attr->GetAscGraph(), nullptr);
343 357 
344 for (const auto &asc_node : attr->GetAscGraph()->GetAllNodes()) {358 for (const auto &asc_node : attr->GetAscGraph()->GetAllNodes()) {
345- VerifyAscNodeNoSizeOneAxis(asc_node, is_concat);359+ VerifyAscNodeAxisAttrs(asc_node);
346 }360 }
347 }361 }
348 362 
@@ -2088,20 +2102,20 @@ TEST_F(LoweringAndCanfuseUT, BroadcastToProdAxisProbe) {
2088 SetCurShapeEnvContext(nullptr);2102 SetCurShapeEnvContext(nullptr);
2089}2103}
2090 2104 
2091-TEST_F(LoweringAndCanfuseUT, ReduceOriginalAxisConflictCanNotFuse) {2105+TEST_F(LoweringAndCanfuseUT, ReduceOriginalAxisConflictCanFuse) {
2092 auto graph = std::make_shared<ComputeGraph>("reduce_original_axis_conflict_graph");2106 auto graph = std::make_shared<ComputeGraph>("reduce_original_axis_conflict_graph");
2093 const auto node1 = CreateReduceNodeWithOriginalAxis(graph, "reduce1", {0, 1}, {Symbol(64), Symbol(32)});2107 const auto node1 = CreateReduceNodeWithOriginalAxis(graph, "reduce1", {0, 1}, {Symbol(64), Symbol(32)});
2094 const auto node2 = CreateReduceNodeWithOriginalAxis(graph, "reduce2", {1, 2}, {Symbol(32), Symbol(16)});2108 const auto node2 = CreateReduceNodeWithOriginalAxis(graph, "reduce2", {1, 2}, {Symbol(32), Symbol(16)});
2095 2109 
2096- EXPECT_FALSE(ReduceFusionStrategy().CanFuse(node1, node2));2110+ EXPECT_TRUE(ReduceFusionStrategy().CanFuse(node1, node2));
2097}2111}
2098 2112 
2099-TEST_F(LoweringAndCanfuseUT, ReduceOriginalRepeatsConflictCanNotFuse) {2113+TEST_F(LoweringAndCanfuseUT, ReduceOriginalRepeatsConflictCanFuse) {
2100 auto graph = std::make_shared<ComputeGraph>("reduce_original_repeats_conflict_graph");2114 auto graph = std::make_shared<ComputeGraph>("reduce_original_repeats_conflict_graph");
2101 const auto node1 = CreateReduceNodeWithOriginalAxis(graph, "reduce1", {0, 1}, {Symbol(64), Symbol(32)});2115 const auto node1 = CreateReduceNodeWithOriginalAxis(graph, "reduce1", {0, 1}, {Symbol(64), Symbol(32)});
2102 const auto node2 = CreateReduceNodeWithOriginalAxis(graph, "reduce2", {0, 1}, {Symbol(64), Symbol(16)});2116 const auto node2 = CreateReduceNodeWithOriginalAxis(graph, "reduce2", {0, 1}, {Symbol(64), Symbol(16)});
2103 2117 
2104- EXPECT_FALSE(ReduceFusionStrategy().CanFuse(node1, node2));2118+ EXPECT_TRUE(ReduceFusionStrategy().CanFuse(node1, node2));
2105}2119}
2106 2120 
2107TEST_F(LoweringAndCanfuseUT, ReduceOriginalAxisCompatibleCanFuse) {2121TEST_F(LoweringAndCanfuseUT, ReduceOriginalAxisCompatibleCanFuse) {
@@ -2112,4 +2126,30 @@ TEST_F(LoweringAndCanfuseUT, ReduceOriginalAxisCompatibleCanFuse) {
2112 EXPECT_TRUE(ReduceFusionStrategy().CanFuse(node1, node2));2126 EXPECT_TRUE(ReduceFusionStrategy().CanFuse(node1, node2));
2113}2127}
2114 2128 
2129+TEST_F(LoweringAndCanfuseUT, ReshapePaddingAnchorAlignmentInsertBeforeExistingUnitAxis) {
2130+ auto graph = std::make_shared<ComputeGraph>("reshape_padding_anchor_alignment_graph");
2131+ const auto node1 = CreateNodeWithOutputAttr(graph, "node1", {0, 2}, {Symbol(4), Symbol(4)});
2132+ const auto node2 = CreateNodeWithOutputAttr(graph, "node2", {0, 1, 2}, {Symbol(1), Symbol(4), Symbol(4)});
2133+ std::vector<size_t> insert_indexes = {1U};
2134+ 
2135+ asc_adapt::AdjustInsertIndexesByAnchorAlignment(node1, {0, 2}, {Symbol(1), Symbol(4)}, false, node2, {0, 1, 2},
2136+ {Symbol(1), Symbol(1), Symbol(4)}, true, insert_indexes);
2137+ 
2138+ ASSERT_EQ(insert_indexes.size(), 1U);
2139+ EXPECT_EQ(insert_indexes[0], 0U);
2140+}
2141+ 
2142+TEST_F(LoweringAndCanfuseUT, ReshapePaddingAnchorAlignmentFallbackWhenNoAnchorMatched) {
2143+ auto graph = std::make_shared<ComputeGraph>("reshape_padding_anchor_fallback_graph");
2144+ const auto node1 = CreateNodeWithOutputAttr(graph, "node1", {0, 2}, {Symbol(1), Symbol(4)});
2145+ const auto node2 = CreateNodeWithOutputAttr(graph, "node2", {0, 1, 2}, {Symbol(1), Symbol(1), Symbol(4)});
2146+ std::vector<size_t> insert_indexes = {1U};
2147+ 
2148+ asc_adapt::AdjustInsertIndexesByAnchorAlignment(node1, {0, 2}, {Symbol(1), Symbol(4)}, false, node2, {0, 1, 2},
2149+ {Symbol(1), Symbol(1), Symbol(4)}, true, insert_indexes);
2150+ 
2151+ ASSERT_EQ(insert_indexes.size(), 1U);
2152+ EXPECT_EQ(insert_indexes[0], 1U);
2153+}
2154+ 
2115} // namespace ge2155} // namespace ge