已开启
fix: restore reshape axes before autofuse can-fuse #1
fix: restore reshape axes before autofuse can-fuse #1
已开启
ling-DT创建于 7月28日
共 21 个文件变更+4190-1046
@@ -21,6 +21,7 @@
21#include "lowering/asc_ir_lowerer.h"21#include "lowering/asc_ir_lowerer.h"
22#include "can_fuse/fusion_strategy_solver.h"22#include "can_fuse/fusion_strategy_solver.h"
23#include "post_process/asc_backend_post_processor.h"23#include "post_process/asc_backend_post_processor.h"
24+#include "post_process/scheduler_adapter/adaption_complete_node_attrs.h"
24#include "utils/autofuse_utils.h"25#include "utils/autofuse_utils.h"
25#include "utils/auto_fuse_config.h"26#include "utils/auto_fuse_config.h"
26#include "autofuse_frame/autofuse_frames.h"27#include "autofuse_frame/autofuse_frames.h"
@@ -8,6 +8,7 @@
8 * See LICENSE in the root of the software repository for the full text of the License.8 * See LICENSE in the root of the software repository for the full text of the License.
9 */9 */
10 10 
11+#include <algorithm>
11#include <regex>12#include <regex>
12 13 
13#include "asc_backend_fusion_decider.h"14#include "asc_backend_fusion_decider.h"
@@ -27,6 +28,48 @@
27 28 
28namespace ge {29namespace ge {
29using namespace autofuse;30using namespace autofuse;
31+namespace {
32+bool HasAxisId(const std::vector<AxisPtr> &axis, const int64_t axis_id) {
33+ for (const auto &axis_info : axis) {
34+ if ((axis_info != nullptr) && (axis_info->id == axis_id)) {
35+ return true;
36+ }
37+ }
38+ return false;
39+}
40+ 
41+bool IsSameAxisIds(const std::vector<AxisPtr> &axis1, const std::vector<AxisPtr> &axis2) {
42+ if (axis1.size() != axis2.size()) {
43+ return false;
44+ }
45+ for (size_t i = 0U; i < axis1.size(); ++i) {
46+ if ((axis1[i] == nullptr) || (axis2[i] == nullptr) || (axis1[i]->id != axis2[i]->id)) {
47+ return false;
48+ }
49+ }
50+ return true;
51+}
52+ 
53+std::vector<AxisPtr> MergeAxisById(const std::vector<AxisPtr> &axis1, const std::vector<AxisPtr> &axis2) {
54+ std::vector<AxisPtr> merged_axis = axis1;
55+ for (const auto &axis_info : axis2) {
56+ if ((axis_info != nullptr) && !HasAxisId(merged_axis, axis_info->id)) {
57+ merged_axis.push_back(axis_info);
58+ }
59+ }
60+ std::sort(merged_axis.begin(), merged_axis.end(), [](const AxisPtr &lhs, const AxisPtr &rhs) {
61+ if (lhs == nullptr) {
62+ return false;
63+ }
64+ if (rhs == nullptr) {
65+ return true;
66+ }
67+ return lhs->id < rhs->id;
68+ });
69+ return merged_axis;
70+}
71+} // namespace
72+ 
30// 子图融合流程缓存dump图和缓存当前正在融合的节点名字73// 子图融合流程缓存dump图和缓存当前正在融合的节点名字
31Status CacheGraphBeforeSubGraphMerge(const NodePtr &node1, const NodePtr &node2, const ComputeGraphPtr &origin_graph) {74Status CacheGraphBeforeSubGraphMerge(const NodePtr &node1, const NodePtr &node2, const ComputeGraphPtr &origin_graph) {
32 if (!IsLogEnable(GE_MODULE_NAME, DLOG_DEBUG)) {75 if (!IsLogEnable(GE_MODULE_NAME, DLOG_DEBUG)) {
@@ -216,7 +259,9 @@ Status AscBackendFusionDecider::UpdateSubgraphAxisAttr(const NodePtr &new_node,
216 }259 }
217 }260 }
218 // 如果轴个数相同按照后序graph更新,否则用轴个数最多的子图作为新图的属性261 // 如果轴个数相同按照后序graph更新,否则用轴个数最多的子图作为新图的属性
219- if (graph_attr1->axis.size() == graph_attr2->axis.size()) {262+ if (!IsSameAxisIds(graph_attr1->axis, new_graph_attr2->axis)) {
263+ new_graph_attr->axis = MergeAxisById(graph_attr1->axis, new_graph_attr2->axis);
264+ } else if (graph_attr1->axis.size() == graph_attr2->axis.size()) {
220 new_graph_attr->axis = new_graph_attr2->axis;265 new_graph_attr->axis = new_graph_attr2->axis;
221 } else {266 } else {
222 if (graph_attr1->axis.size() > graph_attr2->axis.size()) {267 if (graph_attr1->axis.size() > graph_attr2->axis.size()) {
@@ -413,6 +458,8 @@ Status AscBackendFusionDecider::UpdateNewNodeAttr(const OpDescPtr op, const Node
413 GetInterAttrs(attr).fuse_type = fuse_type;458 GetInterAttrs(attr).fuse_type = fuse_type;
414 BackendUtils::SetReduceOriginalAxisInfo(GetInterAttrs(attr), GetInterAttrs(autofuse_attr1),459 BackendUtils::SetReduceOriginalAxisInfo(GetInterAttrs(attr), GetInterAttrs(autofuse_attr1),
415 GetInterAttrs(autofuse_attr2));460 GetInterAttrs(autofuse_attr2));
461+ BackendUtils::SetReshapeAxisChangeInfo(GetInterAttrs(attr), GetInterAttrs(autofuse_attr1),
462+ GetInterAttrs(autofuse_attr2));
416 463 
417 // 处理is_reduce_all_load属性:按照优先级设置融合后的值464 // 处理is_reduce_all_load属性:按照优先级设置融合后的值
418 // 优先级1:存在REDUCE_ALL_LOAD_NOT_ALL,则设置为REDUCE_ALL_LOAD_NOT_ALL465 // 优先级1:存在REDUCE_ALL_LOAD_NOT_ALL,则设置为REDUCE_ALL_LOAD_NOT_ALL
@@ -138,6 +138,98 @@ Status BuildAxisIndex(const AxisIndexMatchState &match_state, std::vector<uint32
138 }138 }
139 return SUCCESS;139 return SUCCESS;
140}140}
141+ 
142+bool IsCoveredBySequence(const size_t pos, const size_t offset, const size_t sequence_size) {
143+ return (pos >= offset) && (pos < (offset + sequence_size));
144+}
145+ 
146+bool CanPlaceRepeatSequences(const std::vector<Expression> &repeats1, const size_t offset1,
147+ const std::vector<Expression> &repeats2, const size_t offset2, const size_t common_size) {
148+ bool has_overlap = false;
149+ for (size_t pos = 0U; pos < common_size; ++pos) {
150+ const bool in_seq1 = IsCoveredBySequence(pos, offset1, repeats1.size());
151+ const bool in_seq2 = IsCoveredBySequence(pos, offset2, repeats2.size());
152+ if (in_seq1 && in_seq2) {
153+ has_overlap = true;
154+ if (repeats1[pos - offset1] != repeats2[pos - offset2]) {
155+ return false;
156+ }
157+ continue;
158+ }
159+ if (in_seq1 && !BackendUtils::IsEqOne(repeats1[pos - offset1])) {
160+ return false;
161+ }
162+ if (in_seq2 && !BackendUtils::IsEqOne(repeats2[pos - offset2])) {
163+ return false;
164+ }
165+ }
166+ return has_overlap;
167+}
168+ 
169+void BuildOffsetAxisMap(const std::vector<int64_t> &axis, const size_t offset, AxisPairSet &axis_map) {
170+ axis_map.clear();
171+ for (size_t i = 0U; i < axis.size(); ++i) {
172+ axis_map.insert(std::make_pair(axis[i], static_cast<int64_t>(offset + i)));
173+ }
174+}
175+ 
176+bool TryBuildExpandedAxisMap(const std::vector<int64_t> &axis1, const std::vector<Expression> &repeats1,
177+ const std::vector<int64_t> &axis2, const std::vector<Expression> &repeats2,
178+ AxisPairSet &axis_map1, AxisPairSet &axis_map2) {
179+ const auto min_common_size = std::max(repeats1.size(), repeats2.size());
180+ const auto max_common_size = repeats1.size() + repeats2.size();
181+ for (size_t common_size = min_common_size + 1U; common_size <= max_common_size; ++common_size) {
182+ for (size_t offset1 = 0U; offset1 + repeats1.size() <= common_size; ++offset1) {
183+ for (size_t offset2 = 0U; offset2 + repeats2.size() <= common_size; ++offset2) {
184+ if (!CanPlaceRepeatSequences(repeats1, offset1, repeats2, offset2, common_size)) {
185+ continue;
186+ }
187+ BuildOffsetAxisMap(axis1, offset1, axis_map1);
188+ BuildOffsetAxisMap(axis2, offset2, axis_map2);
189+ return true;
190+ }
191+ }
192+ }
193+ return false;
194+}
195+ 
196+bool IsOrderedBefore(const std::vector<int64_t> &axis, const int64_t lhs, const int64_t rhs) {
197+ auto lhs_pos = axis.end();
198+ auto rhs_pos = axis.end();
199+ for (auto it = axis.begin(); it != axis.end(); ++it) {
200+ if (*it == lhs) {
201+ lhs_pos = it;
202+ }
203+ if (*it == rhs) {
204+ rhs_pos = it;
205+ }
206+ }
207+ return (lhs_pos != axis.end()) && (rhs_pos != axis.end()) && (lhs_pos < rhs_pos);
208+}
209+ 
210+bool HasConsistentCommonAxisOrder(const std::vector<int64_t> &axis1, const std::vector<int64_t> &axis2) {
211+ for (size_t i = 0U; i < axis1.size(); ++i) {
212+ for (size_t j = i + 1U; j < axis1.size(); ++j) {
213+ const auto lhs = axis1[i];
214+ const auto rhs = axis1[j];
215+ if (std::find(axis2.begin(), axis2.end(), lhs) == axis2.end() ||
216+ std::find(axis2.begin(), axis2.end(), rhs) == axis2.end()) {
217+ continue;
218+ }
219+ if (!IsOrderedBefore(axis2, lhs, rhs)) {
220+ return false;
221+ }
222+ }
223+ }
224+ return true;
225+}
226+ 
227+Status ConvertLoopAxis(const AxisPairSet &node_map, int64_t &loop_axis, const bool need_flash) {
228+ if (loop_axis == af::kIdNone) {
229+ return SUCCESS;
230+ }
231+ return BackendUtils::ConvertAxis(node_map, loop_axis, need_flash);
232+}
141} // namespace233} // namespace
142 234 
143Status NodeFuseInfo::GetSubgraphSameInputIndex(const NodePtr &node1, const NodePtr &node2,235Status NodeFuseInfo::GetSubgraphSameInputIndex(const NodePtr &node1, const NodePtr &node2,
@@ -603,6 +695,30 @@ bool AscGraphAxisMapping::CanAxisMap(std::vector<int64_t> &node1_axis, std::vect
603 std::vector<int64_t> &node2_axis, std::vector<ge::Expression> &node2_repeats,695 std::vector<int64_t> &node2_axis, std::vector<ge::Expression> &node2_repeats,
604 AxisPairSet &node1_map, AxisPairSet &node2_map, AxisPairSet &temp_node1_map,696 AxisPairSet &node1_map, AxisPairSet &node2_map, AxisPairSet &temp_node1_map,
605 AxisPairSet &temp_node2_map) const {697 AxisPairSet &temp_node2_map) const {
698+ temp_node1_map.clear();
699+ temp_node2_map.clear();
700+ if (node1_repeats.size() == node2_repeats.size() && node1_repeats != node2_repeats) {
701+ std::vector<int64_t> mapped_node1_axis = node1_axis;
702+ std::vector<int64_t> mapped_node2_axis = node2_axis;
703+ if (!node1_map.empty() && (BackendUtils::ConvertAxis(node1_map, mapped_node1_axis) != SUCCESS)) {
704+ return false;
705+ }
706+ if (!node2_map.empty() && (BackendUtils::ConvertAxis(node2_map, mapped_node2_axis) != SUCCESS)) {
707+ return false;
708+ }
709+ if (TryBuildExpandedAxisMap(mapped_node1_axis, node1_repeats, mapped_node2_axis, node2_repeats, temp_node1_map,
710+ temp_node2_map)) {
711+ GELOGD_IF(open_log_,
712+ "find expanded axis map info: left axis(%s), repeats(%s), right axis(%s), repeats(%s), axis map1(%s), "
713+ "axis map2(%s).",
714+ AutofuseUtils::VectorToStr(node1_axis).c_str(), AutofuseUtils::VectorToStr(node1_repeats).c_str(),
715+ AutofuseUtils::VectorToStr(node2_axis).c_str(), AutofuseUtils::VectorToStr(node2_repeats).c_str(),
716+ AutofuseUtils::VectorPairToStr(temp_node1_map).c_str(),
717+ AutofuseUtils::VectorPairToStr(temp_node2_map).c_str());
718+ return true;
719+ }
720+ }
721+ 
606 if (node1_repeats.size() >= node2_repeats.size()) {722 if (node1_repeats.size() >= node2_repeats.size()) {
607 std::vector<uint32_t> axis_index;723 std::vector<uint32_t> axis_index;
608 if (FindAxisIndex(node2_repeats, node1_repeats, axis_index) != SUCCESS) {724 if (FindAxisIndex(node2_repeats, node1_repeats, axis_index) != SUCCESS) {
@@ -614,8 +730,6 @@ bool AscGraphAxisMapping::CanAxisMap(std::vector<int64_t> &node1_axis, std::vect
614 return false;730 return false;
615 }731 }
616 }732 }
617- temp_node1_map.clear();
618- temp_node2_map.clear();
619 for (auto i = 0U; i < axis_index.size(); i++) {733 for (auto i = 0U; i < axis_index.size(); i++) {
620 GE_ASSERT_TRUE(static_cast<size_t>(axis_index[i]) < node1_axis.size());734 GE_ASSERT_TRUE(static_cast<size_t>(axis_index[i]) < node1_axis.size());
621 temp_node2_map.insert(std::pair<int64_t, int64_t>(node2_axis[i], node1_axis[axis_index[i]]));735 temp_node2_map.insert(std::pair<int64_t, int64_t>(node2_axis[i], node1_axis[axis_index[i]]));
@@ -634,8 +748,6 @@ bool AscGraphAxisMapping::CanAxisMap(std::vector<int64_t> &node1_axis, std::vect
634 return false;748 return false;
635 }749 }
636 }750 }
637- temp_node1_map.clear();
638- temp_node2_map.clear();
639 for (auto i = 0U; i < axis_index.size(); i++) {751 for (auto i = 0U; i < axis_index.size(); i++) {
640 GE_ASSERT_TRUE(static_cast<size_t>(axis_index[i]) < node2_axis.size());752 GE_ASSERT_TRUE(static_cast<size_t>(axis_index[i]) < node2_axis.size());
641 temp_node1_map.insert(std::pair<int64_t, int64_t>(node1_axis[i], node2_axis[axis_index[i]]));753 temp_node1_map.insert(std::pair<int64_t, int64_t>(node1_axis[i], node2_axis[axis_index[i]]));
@@ -680,35 +792,35 @@ bool AscGraphAxisMapping::IsSameMapAxis(AxisPairSet &map1, AxisPairSet &map2) co
680}792}
681 793 
682Status AscGraphAxisMapping::FlashContinueAxisId() {794Status AscGraphAxisMapping::FlashContinueAxisId() {
683- AxisPairSet *max_map;
684- AxisPairSet *min_map;
685 GELOGD_IF(open_log_, "flash continue axis before, node1 map(%s) and node2 map(%s).",795 GELOGD_IF(open_log_, "flash continue axis before, node1 map(%s) and node2 map(%s).",
686 AutofuseUtils::VectorPairToStr(node1_map_).c_str(), AutofuseUtils::VectorPairToStr(node2_map_).c_str());796 AutofuseUtils::VectorPairToStr(node1_map_).c_str(), AutofuseUtils::VectorPairToStr(node2_map_).c_str());
687- if (node1_map_.size() >= node2_map_.size()) {797+ 
688- max_map = &node1_map_;798+ std::set<int64_t> axis_values;
689- min_map = &node2_map_;799+ for (const auto &pair : node1_map_) {
690- } else {800+ axis_values.insert(pair.second);
691- max_map = &node2_map_;801+ }
692- min_map = &node1_map_;802+ for (const auto &pair : node2_map_) {
803+ axis_values.insert(pair.second);
693 }804 }
694 std::unordered_map<int64_t, int64_t> value_map;805 std::unordered_map<int64_t, int64_t> value_map;
695- AxisPairSet temp_map;
696 int64_t i = 0;806 int64_t i = 0;
697- for (auto &pair : *max_map) {807+ for (const auto axis_value : axis_values) {
698- value_map[pair.second] = i;808+ value_map[axis_value] = i++;
699- temp_map.insert(std::pair<int64_t, int64_t>(pair.first, i));
700- i++;
701 }809 }
702- *max_map = temp_map;
703- GE_ASSERT_TRUE(value_map.size() == (*max_map).size());
704 810 
705- temp_map.clear();811+ auto flush_map = [&value_map](AxisPairSet &node_map) -> Status {
706- for (auto &pair : *min_map) {812+ AxisPairSet temp_map;
707- auto it = value_map.find(pair.second);813+ for (const auto &pair : node_map) {
708- GE_ASSERT_TRUE(it != value_map.end());814+ const auto it = value_map.find(pair.second);
709- temp_map.insert(std::pair<int64_t, int64_t>(pair.first, it->second));815+ GE_ASSERT_TRUE(it != value_map.end());
710- }816+ temp_map.insert(std::make_pair(pair.first, it->second));
711- *min_map = temp_map;817+ }
818+ node_map = std::move(temp_map);
819+ return SUCCESS;
820+ };
821+ GE_ASSERT_SUCCESS(flush_map(node1_map_));
822+ GE_ASSERT_SUCCESS(flush_map(node2_map_));
823+ 
712 GELOGD_IF(open_log_, "flash continue axis after, node1 map(%s) and node2 map(%s).",824 GELOGD_IF(open_log_, "flash continue axis after, node1 map(%s) and node2 map(%s).",
713 AutofuseUtils::VectorPairToStr(node1_map_).c_str(), AutofuseUtils::VectorPairToStr(node2_map_).c_str());825 AutofuseUtils::VectorPairToStr(node1_map_).c_str(), AutofuseUtils::VectorPairToStr(node2_map_).c_str());
714 return SUCCESS;826 return SUCCESS;
@@ -822,14 +934,26 @@ Status AscGraphAxisMapping::GetVerticalAxisMapInfo(const NodePtr &node, const in
822 934 
823Status AscGraphAxisMapping::FlushAscSubGraphAxisInfo(const NodePtr &node, const ComputeGraphPtr &graph,935Status AscGraphAxisMapping::FlushAscSubGraphAxisInfo(const NodePtr &node, const ComputeGraphPtr &graph,
824 const AxisPairSet &node_map, bool need_flash) const {936 const AxisPairSet &node_map, bool need_flash) const {
937+ auto graph_attr = graph->GetAttrsGroup<AscGraphAttr>();
938+ GE_ASSERT_NOTNULL(graph_attr);
825 for (auto &asc_node : graph->GetAllNodes()) {939 for (auto &asc_node : graph->GetAllNodes()) {
826 GE_ASSERT_NOTNULL(asc_node);940 GE_ASSERT_NOTNULL(asc_node);
827 auto asc_node_op_desc = asc_node->GetOpDesc();941 auto asc_node_op_desc = asc_node->GetOpDesc();
828 GE_ASSERT_NOTNULL(asc_node_op_desc);942 GE_ASSERT_NOTNULL(asc_node_op_desc);
829 AscNodeAttr *asc_node_attr = asc_node_op_desc->GetAttrsGroup<AscNodeAttr>();943 AscNodeAttr *asc_node_attr = asc_node_op_desc->GetAttrsGroup<AscNodeAttr>();
830 GE_ASSERT_NOTNULL(asc_node_attr);944 GE_ASSERT_NOTNULL(asc_node_attr);
831- if (BackendUtils::ConvertAxis(node_map, asc_node_attr->sched.axis, need_flash) != SUCCESS) {945+ GE_ASSERT_SUCCESS(BackendUtils::ConvertAxis(node_map, asc_node_attr->sched.axis, need_flash));
832- return FAILED;946+ GE_ASSERT_SUCCESS(ConvertLoopAxis(node_map, asc_node_attr->sched.loop_axis, need_flash));
947+ 
948+ for (size_t i = 0U; i < asc_node->GetAllInDataAnchorsSize(); ++i) {
949+ const auto input_desc = asc_node_op_desc->MutableInputDesc(i);
950+ GE_ASSERT_NOTNULL(input_desc);
951+ auto input_desc_tensor_attr = input_desc->GetAttrsGroup<AscTensorAttr>();
952+ if (input_desc_tensor_attr == nullptr) {
953+ continue;
954+ }
955+ GE_ASSERT_SUCCESS(BackendUtils::ConvertAxis(node_map, input_desc_tensor_attr->axis, need_flash));
956+ GE_ASSERT_SUCCESS(BackendUtils::ConvertAxis(node_map, input_desc_tensor_attr->vectorized_axis, need_flash));
833 }957 }
834 958 
835 for (auto &output_desc : asc_node_op_desc->GetAllOutputsDescPtr()) {959 for (auto &output_desc : asc_node_op_desc->GetAllOutputsDescPtr()) {
@@ -837,19 +961,16 @@ Status AscGraphAxisMapping::FlushAscSubGraphAxisInfo(const NodePtr &node, const
837 auto output_desc_tensor_attr = output_desc->GetAttrsGroup<AscTensorAttr>();961 auto output_desc_tensor_attr = output_desc->GetAttrsGroup<AscTensorAttr>();
838 GE_ASSERT_NOTNULL(output_desc_tensor_attr);962 GE_ASSERT_NOTNULL(output_desc_tensor_attr);
839 auto axis_before_Flush = output_desc_tensor_attr->axis;963 auto axis_before_Flush = output_desc_tensor_attr->axis;
840- if (BackendUtils::ConvertAxis(node_map, output_desc_tensor_attr->axis, need_flash) != SUCCESS) {964+ GE_ASSERT_SUCCESS(BackendUtils::ConvertAxis(node_map, output_desc_tensor_attr->axis, need_flash));
841- return FAILED;965+ GE_ASSERT_SUCCESS(BackendUtils::ConvertAxis(node_map, output_desc_tensor_attr->vectorized_axis, need_flash));
842- }
843 GE_ASSERT_SUCCESS(BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(node, asc_node, axis_before_Flush,966 GE_ASSERT_SUCCESS(BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(node, asc_node, axis_before_Flush,
844 output_desc_tensor_attr->axis));967 output_desc_tensor_attr->axis));
968+ GE_ASSERT_SUCCESS(
969+ BackendUtils::FlushReshapeAxisChanges(node, asc_node, axis_before_Flush, output_desc_tensor_attr->axis));
845 }970 }
846 }971 }
847- auto graph_attr = graph->GetAttrsGroup<AscGraphAttr>();
848- GE_ASSERT_NOTNULL(graph_attr);
849 for (auto &axis_info : graph_attr->axis) {972 for (auto &axis_info : graph_attr->axis) {
850- if (BackendUtils::ConvertAxis(node_map, axis_info->id, need_flash) != SUCCESS) {973+ GE_ASSERT_SUCCESS(BackendUtils::ConvertAxis(node_map, axis_info->id, need_flash));
851- return FAILED;
852- }
853 GELOGD_IF(open_log_, " \nflash graph axis info: axis name(%s), axis id(%ld), axis size(%s), graph name(%s).",974 GELOGD_IF(open_log_, " \nflash graph axis info: axis name(%s), axis id(%ld), axis size(%s), graph name(%s).",
854 axis_info->name.c_str(), axis_info->id, std::string(axis_info->size.Str().get()).c_str(),975 axis_info->name.c_str(), axis_info->id, std::string(axis_info->size.Str().get()).c_str(),
855 graph->GetName().c_str());976 graph->GetName().c_str());
@@ -918,7 +1039,7 @@ bool AscGraphAxisMapping::CanLoopMerge(const NodePtr &node1, const NodePtr &node
918 1039 
919 if (axis1 != axis2) {1040 if (axis1 != axis2) {
920 // 判断轴是否是顺序子集关系,子集关系认为也是可以循环合并的,后期schedue adapter补轴实现1041 // 判断轴是否是顺序子集关系,子集关系认为也是可以循环合并的,后期schedue adapter补轴实现
921- if (!BackendUtils::CheckAxisSubsetRelation(axis1, axis2)) {1042+ if (!BackendUtils::CheckAxisSubsetRelation(axis1, axis2) && !HasConsistentCommonAxisOrder(axis1, axis2)) {
922 GELOGI_IF(open_log_, "sched axis different and not subset relation, can't merge.");1043 GELOGI_IF(open_log_, "sched axis different and not subset relation, can't merge.");
923 return false;1044 return false;
924 }1045 }
@@ -49,6 +49,55 @@ size_t FindIndex(const Container &container, const ValueType &value) {
49 return std::distance(container.begin(), it);49 return std::distance(container.begin(), it);
50}50}
51 51 
52+bool IsOnlyUnitRepeatAxisOrderChange(const TensorAttrInfo &in_attr, const TensorAttrInfo &out_attr) {
53+ if (in_attr.axis == out_attr.axis) {
54+ return false;
55+ }
56+ if ((in_attr.axis.size() != in_attr.repeats.size()) || (out_attr.axis.size() != out_attr.repeats.size())) {
57+ return false;
58+ }
59+ if (in_attr.repeats.empty() || out_attr.repeats.empty()) {
60+ return false;
61+ }
62+ 
63+ std::vector<int64_t> in_non_unit_axis;
64+ std::vector<int64_t> out_non_unit_axis;
65+ std::vector<Expression> in_non_unit_repeats;
66+ std::vector<Expression> out_non_unit_repeats;
67+ in_non_unit_axis.reserve(in_attr.axis.size());
68+ out_non_unit_axis.reserve(out_attr.axis.size());
69+ in_non_unit_repeats.reserve(in_attr.repeats.size());
70+ out_non_unit_repeats.reserve(out_attr.repeats.size());
71+ for (size_t i = 0U; i < in_attr.repeats.size(); ++i) {
72+ if (!BackendUtils::IsEqOne(in_attr.repeats[i])) {
73+ in_non_unit_axis.push_back(in_attr.axis[i]);
74+ in_non_unit_repeats.push_back(in_attr.repeats[i]);
75+ }
76+ }
77+ for (size_t i = 0U; i < out_attr.repeats.size(); ++i) {
78+ if (!BackendUtils::IsEqOne(out_attr.repeats[i])) {
79+ out_non_unit_axis.push_back(out_attr.axis[i]);
80+ out_non_unit_repeats.push_back(out_attr.repeats[i]);
81+ }
82+ }
83+ if ((in_non_unit_repeats.size() == in_attr.repeats.size()) &&
84+ (out_non_unit_repeats.size() == out_attr.repeats.size())) {
85+ return false;
86+ }
87+ if (in_non_unit_axis != out_non_unit_axis) {
88+ return false;
89+ }
90+ if (in_non_unit_repeats.size() != out_non_unit_repeats.size()) {
91+ return false;
92+ }
93+ for (size_t i = 0U; i < in_non_unit_repeats.size(); ++i) {
94+ if (SymbolicUtils::StaticCheckEq(in_non_unit_repeats[i], out_non_unit_repeats[i]) != TriBool::kTrue) {
95+ return false;
96+ }
97+ }
98+ return true;
99+}
100+ 
52bool IsLoadConnectedToSplit(const NodePtr &load_node) {101bool IsLoadConnectedToSplit(const NodePtr &load_node) {
53 const auto load_out_anchor = load_node->GetOutDataAnchor(0);102 const auto load_out_anchor = load_node->GetOutDataAnchor(0);
54 GE_ASSERT_NOTNULL(load_out_anchor);103 GE_ASSERT_NOTNULL(load_out_anchor);
@@ -394,6 +443,11 @@ Status BackendUtils::FusedBackSteppingViewOpTranspose(TensorAttrInfo &temp_graph
394 const auto &graph_axis = temp_graph_attr.axis;443 const auto &graph_axis = temp_graph_attr.axis;
395 const auto &load_axis = temp_load_attr.axis;444 const auto &load_axis = temp_load_attr.axis;
396 445 
446+ if (IsOnlyUnitRepeatAxisOrderChange(temp_graph_attr, temp_load_attr)) {
447+ GELOGD("Fused back stepping view op only has reshape unit axis change, skip transpose.");
448+ return SUCCESS;
449+ }
450+ 
397 // 计算将load轴变为graph轴所需的最小交换次数,并记录每次交换的axis id451 // 计算将load轴变为graph轴所需的最小交换次数,并记录每次交换的axis id
398 int64_t swap_count = 0;452 int64_t swap_count = 0;
399 GE_ASSERT_SUCCESS(MinSwapCount(graph_axis, load_axis, swap_count, transpose_info));453 GE_ASSERT_SUCCESS(MinSwapCount(graph_axis, load_axis, swap_count, transpose_info));
@@ -525,6 +579,10 @@ Status BackendUtils::PostProBackSteppingViewOpTranspose(TensorAttrInfo &temp_gra
525 const auto &graph_axis = temp_graph_attr.axis;579 const auto &graph_axis = temp_graph_attr.axis;
526 auto &cur_axis = temp_load_attr.axis;580 auto &cur_axis = temp_load_attr.axis;
527 // 反推出 transpose_info 并 根据反推结果还原临时 attr_info ,为下一次反推处理准备attr_info581 // 反推出 transpose_info 并 根据反推结果还原临时 attr_info ,为下一次反推处理准备attr_info
582+ if (IsOnlyUnitRepeatAxisOrderChange(temp_graph_attr, temp_load_attr)) {
583+ GELOGD("post process back stepping view op only has reshape unit axis change, skip transpose.");
584+ return SUCCESS;
585+ }
528 int64_t swap_count = 0;586 int64_t swap_count = 0;
529 if ((cur_node_type == kLoadType) || (cur_node_type == kGatherType)) {587 if ((cur_node_type == kLoadType) || (cur_node_type == kGatherType)) {
530 GE_ASSERT_SUCCESS(MinSwapCount(cur_axis, graph_axis, swap_count, transpose_info));588 GE_ASSERT_SUCCESS(MinSwapCount(cur_axis, graph_axis, swap_count, transpose_info));
@@ -2704,6 +2762,17 @@ Status BackendUtils::UpdateTransposeBeforeMerge(const NodePtr &node2, const Comp
2704 return SUCCESS;2762 return SUCCESS;
2705}2763}
2706 2764 
2765+Status BackendUtils::CompleteNodeAttrsBeforeCanFuse(const NodePtr &node1, const NodePtr &node2) {
2766+ GE_ASSERT_SUCCESS(asc_adapt::PadPairLeadingUnitAxisBeforeCompleteAttrs(node1, node2));
2767+ auto asc_graph1 = BackendUtils::GetNodeFusedAscGraph(node1);
2768+ GE_ASSERT_NOTNULL(asc_graph1);
2769+ GE_ASSERT_SUCCESS(asc_adapt::CompleteNodeAttrsOnAscGraph(*asc_graph1, node1));
2770+ auto asc_graph2 = BackendUtils::GetNodeFusedAscGraph(node2);
2771+ GE_ASSERT_NOTNULL(asc_graph2);
2772+ GE_ASSERT_SUCCESS(asc_adapt::CompleteNodeAttrsOnAscGraph(*asc_graph2, node2));
2773+ return SUCCESS;
2774+}
2775+ 
2707Status CompleteNodeAttrsBeforeMerge(const NodePtr &node1, const NodePtr &node2) {2776Status CompleteNodeAttrsBeforeMerge(const NodePtr &node1, const NodePtr &node2) {
2708 auto asc_graph1 = BackendUtils::GetNodeFusedAscGraph(node1);2777 auto asc_graph1 = BackendUtils::GetNodeFusedAscGraph(node1);
2709 GE_ASSERT_NOTNULL(asc_graph1);2778 GE_ASSERT_NOTNULL(asc_graph1);
@@ -3263,15 +3332,17 @@ void BackendUtils::SetReduceOriginalAxisInfo(AutofuseInnerAttrs &attr_new, const
3263 }3332 }
3264}3333}
3265 3334 
3266-// 融合存在轴映射之后index对应的axis变化的场景,则记录的reduce的原始axis也要相应变化3335+void BackendUtils::SetReshapeAxisChangeInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,
3267-Status BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node, const NodePtr &asc_node,3336+ const AutofuseInnerAttrs &attr2) {
3268- const std::vector<int64_t> axis_before_Flush,3337+ attr_new.reshape_axis_changes = attr1.reshape_axis_changes;
3269- const std::vector<int64_t> axis_after_Flush) {3338+ attr_new.reshape_axis_changes.insert(attr_new.reshape_axis_changes.end(), attr2.reshape_axis_changes.begin(),
3270- if (!asc_adapt::IsReduceNode(asc_node)) {3339+ attr2.reshape_axis_changes.end());
3271- return SUCCESS;3340+}
3272- }
3273 3341 
3274- if (axis_before_Flush.empty() || axis_after_Flush.empty()) {3342+Status FlushOriginalAxis(const NodePtr &node, const NodePtr &asc_node, const std::vector<int64_t> &axis_before_Flush,
3343+ const std::vector<int64_t> &axis_after_Flush, std::vector<int64_t> &original_axis,
3344+ const char *info_name) {
3345+ if (axis_before_Flush.empty() || axis_after_Flush.empty() || original_axis.empty()) {
3275 return SUCCESS;3346 return SUCCESS;
3276 }3347 }
3277 3348 
@@ -3285,36 +3356,112 @@ Status BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node,
3285 return SUCCESS;3356 return SUCCESS;
3286 }3357 }
3287 3358 
3288- auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(node);3359+ std::unordered_map<int64_t, size_t> axis_before_to_index;
3289- GE_ASSERT_NOTNULL(autofuse_attr);3360+ for (size_t i = 0U; i < axis_before_Flush.size(); ++i) {
3361+ axis_before_to_index[axis_before_Flush[i]] = i;
3362+ }
3290 3363 
3291- auto reduce_original_axis = autofuse_attr->GetReduceOriginalAxis();3364+ std::vector<int64_t> updated_axis;
3292- if (reduce_original_axis.empty()) {3365+ updated_axis.reserve(original_axis.size());
3366+ for (const auto &axis : original_axis) {
3367+ auto it = axis_before_to_index.find(axis);
3368+ if (it != axis_before_to_index.end()) {
3369+ updated_axis.push_back(axis_after_Flush[it->second]);
3370+ } else {
3371+ GELOGW("Axis %ld in %s not found in axis_before_Flush for asc_node %s, keep original value", axis, info_name,
3372+ asc_node->GetName().c_str());
3373+ updated_axis.push_back(axis);
3374+ }
3375+ }
3376+ 
3377+ GELOGD("Flush %s for node %s, asc_node %s, before: %s, after: %s", info_name, node->GetName().c_str(),
3378+ asc_node->GetName().c_str(), AutofuseUtils::VectorToStr(original_axis).c_str(),
3379+ AutofuseUtils::VectorToStr(updated_axis).c_str());
3380+ original_axis = updated_axis;
3381+ return SUCCESS;
3382+}
3383+ 
3384+Status FlushReshapeAxisByRepeats(const NodePtr &node, const NodePtr &asc_node,
3385+ const std::vector<int64_t> &axis_before_Flush,
3386+ const std::vector<int64_t> &axis_after_Flush,
3387+ const std::vector<Expression> &reshape_repeats, std::vector<int64_t> &reshape_axis,
3388+ const char *info_name) {
3389+ if (axis_before_Flush.empty() || axis_after_Flush.empty() || reshape_axis.empty()) {
3293 return SUCCESS;3390 return SUCCESS;
3294 }3391 }
3295 3392 
3393+ GE_ASSERT_TRUE(axis_before_Flush.size() == axis_after_Flush.size(),
3394+ "axis_before_Flush size %zu must equal to axis_after_Flush size %zu", axis_before_Flush.size(),
3395+ axis_after_Flush.size());
3396+ GE_ASSERT_TRUE(reshape_axis.size() == reshape_repeats.size(), "reshape axis size %zu must equal repeats size %zu",
3397+ reshape_axis.size(), reshape_repeats.size());
3398+ 
3296 std::unordered_map<int64_t, size_t> axis_before_to_index;3399 std::unordered_map<int64_t, size_t> axis_before_to_index;
3297 for (size_t i = 0U; i < axis_before_Flush.size(); ++i) {3400 for (size_t i = 0U; i < axis_before_Flush.size(); ++i) {
3298 axis_before_to_index[axis_before_Flush[i]] = i;3401 axis_before_to_index[axis_before_Flush[i]] = i;
3299 }3402 }
3300 3403 
3301 std::vector<int64_t> updated_axis;3404 std::vector<int64_t> updated_axis;
3302- updated_axis.reserve(reduce_original_axis.size());3405+ updated_axis.reserve(reshape_axis.size());
3303- for (const auto &axis : reduce_original_axis) {3406+ for (size_t i = 0U; i < reshape_axis.size(); ++i) {
3407+ const auto axis = reshape_axis[i];
3304 auto it = axis_before_to_index.find(axis);3408 auto it = axis_before_to_index.find(axis);
3305 if (it != axis_before_to_index.end()) {3409 if (it != axis_before_to_index.end()) {
3306- size_t index = it->second;3410+ updated_axis.push_back(axis_after_Flush[it->second]);
3307- updated_axis.push_back(axis_after_Flush[index]);3411+ continue;
3308- } else {
3309- GELOGW("Axis %ld in reduce_original_axis not found in axis_before_Flush for asc_node %s, keep original value",
3310- axis, asc_node->GetName().c_str());
3311- updated_axis.push_back(axis);
3312 }3412 }
3413+ if (BackendUtils::IsEqOne(reshape_repeats[i]) && (reshape_axis.size() == axis_after_Flush.size())) {
3414+ updated_axis.push_back(axis_after_Flush[i]);
3415+ continue;
3416+ }
3417+ GELOGW("Axis %ld in %s not found in axis_before_Flush for asc_node %s, keep original value", axis, info_name,
3418+ asc_node->GetName().c_str());
3419+ updated_axis.push_back(axis);
3313 }3420 }
3314 3421 
3315- autofuse_attr->SetReduceOriginalAxis(updated_axis);3422+ GELOGD("Flush %s for node %s, asc_node %s, before: %s, after: %s", info_name, node->GetName().c_str(),
3316- GELOGD("Flush reduce original axis for asc_node %s, before: %s, after: %s", asc_node->GetName().c_str(),3423+ asc_node->GetName().c_str(), AutofuseUtils::VectorToStr(reshape_axis).c_str(),
3317- AutofuseUtils::VectorToStr(reduce_original_axis).c_str(), AutofuseUtils::VectorToStr(updated_axis).c_str());3424+ AutofuseUtils::VectorToStr(updated_axis).c_str());
3425+ reshape_axis = updated_axis;
3426+ return SUCCESS;
3427+}
3428+ 
3429+// 融合存在轴映射之后index对应的axis变化的场景,则记录的reduce的原始axis也要相应变化
3430+Status BackendUtils::FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node, const NodePtr &asc_node,
3431+ const std::vector<int64_t> axis_before_Flush,
3432+ const std::vector<int64_t> axis_after_Flush) {
3433+ if (!asc_adapt::IsReduceNode(asc_node)) {
3434+ return SUCCESS;
3435+ }
3436+ 
3437+ auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(node);
3438+ GE_ASSERT_NOTNULL(autofuse_attr);
3439+ 
3440+ auto reduce_original_axis = autofuse_attr->GetReduceOriginalAxis();
3441+ GE_ASSERT_SUCCESS(FlushOriginalAxis(node, asc_node, axis_before_Flush, axis_after_Flush, reduce_original_axis,
3442+ "reduce_original_axis"));
3443+ autofuse_attr->SetReduceOriginalAxis(reduce_original_axis);
3444+ 
3445+ return SUCCESS;
3446+}
3447+ 
3448+Status BackendUtils::FlushReshapeAxisChanges(const NodePtr &node, const NodePtr &asc_node,
3449+ const std::vector<int64_t> axis_before_Flush,
3450+ const std::vector<int64_t> axis_after_Flush) {
3451+ auto autofuse_attr = BackendUtils::GetNodeAutoFuseAttr(node);
3452+ GE_ASSERT_NOTNULL(autofuse_attr);
3453+ auto reshape_axis_changes = autofuse_attr->GetReshapeAxisChanges();
3454+ if (reshape_axis_changes.empty()) {
3455+ return SUCCESS;
3456+ }
3457+ 
3458+ for (auto &change : reshape_axis_changes) {
3459+ GE_ASSERT_SUCCESS(FlushReshapeAxisByRepeats(node, asc_node, axis_before_Flush, axis_after_Flush,
3460+ change.before_repeats, change.before_axis, "reshape_before_axis"));
3461+ GE_ASSERT_SUCCESS(FlushReshapeAxisByRepeats(node, asc_node, axis_before_Flush, axis_after_Flush,
3462+ change.after_repeats, change.after_axis, "reshape_after_axis"));
3463+ }
3464+ autofuse_attr->SetReshapeAxisChanges(reshape_axis_changes);
3318 3465 
3319 return SUCCESS;3466 return SUCCESS;
3320}3467}
@@ -3327,6 +3474,14 @@ Status GetNodeTransposeInfo(const NodePtr &node, const TensorAttrInfo &temp_grap
3327 GE_ASSERT_NOTNULL(cur_output_desc);3474 GE_ASSERT_NOTNULL(cur_output_desc);
3328 const auto cur_output_attr = cur_output_desc->GetAttrsGroup<AscTensorAttr>();3475 const auto cur_output_attr = cur_output_desc->GetAttrsGroup<AscTensorAttr>();
3329 GE_ASSERT_NOTNULL(cur_output_attr);3476 GE_ASSERT_NOTNULL(cur_output_attr);
3477+ TensorAttrInfo cur_output_attr_info;
3478+ cur_output_attr_info.axis = cur_output_attr->axis;
3479+ cur_output_attr_info.repeats = cur_output_attr->repeats;
3480+ if (IsOnlyUnitRepeatAxisOrderChange(temp_graph_attr, cur_output_attr_info)) {
3481+ GELOGI("node %s(%s) only has reshape unit axis change in graph attr compare, skip transpose.",
3482+ node->GetName().c_str(), node->GetType().c_str());
3483+ return SUCCESS;
3484+ }
3330 int64_t swap = 0;3485 int64_t swap = 0;
3331 if ((node->GetType() == kLoadType) || (node->GetType() == kGatherType)) {3486 if ((node->GetType() == kLoadType) || (node->GetType() == kGatherType)) {
3332 GE_ASSERT_SUCCESS(BackendUtils::MinSwapCount(cur_output_attr->axis, temp_graph_attr.axis, swap, transpose_info));3487 GE_ASSERT_SUCCESS(BackendUtils::MinSwapCount(cur_output_attr->axis, temp_graph_attr.axis, swap, transpose_info));
@@ -670,6 +670,7 @@ 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 CompleteNodeAttrsBeforeCanFuse(const NodePtr &node1, const NodePtr &node2);
673 static Status TuningSubgraphBeforeMerge(const NodePtr &node1, const NodePtr &node2, const ComputeGraphPtr &graph1,674 static Status TuningSubgraphBeforeMerge(const NodePtr &node1, const NodePtr &node2, const ComputeGraphPtr &graph1,
674 const ComputeGraphPtr &graph2, const NodeFuseInfo &fuse_info);675 const ComputeGraphPtr &graph2, const NodeFuseInfo &fuse_info);
675 static Status GetPreNodeAndAnchor(const NodePtr &node, const int32_t index, NodePtr &peer_node,676 static Status GetPreNodeAndAnchor(const NodePtr &node, const int32_t index, NodePtr &peer_node,
@@ -850,9 +851,14 @@ class BackendUtils {
850 static bool OnlyHasTypesInAscgraph(const NodePtr &node, const std::vector<std::string> &target_types);851 static bool OnlyHasTypesInAscgraph(const NodePtr &node, const std::vector<std::string> &target_types);
851 static void SetReduceOriginalAxisInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,852 static void SetReduceOriginalAxisInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,
852 const AutofuseInnerAttrs &attr2);853 const AutofuseInnerAttrs &attr2);
854+ static void SetReshapeAxisChangeInfo(AutofuseInnerAttrs &attr_new, const AutofuseInnerAttrs &attr1,
855+ const AutofuseInnerAttrs &attr2);
853 static Status FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node, const NodePtr &asc_node,856 static Status FlushReduceOriginalAxisIfIsReduceNode(const NodePtr &node, const NodePtr &asc_node,
854 const std::vector<int64_t> axis_before_Flush,857 const std::vector<int64_t> axis_before_Flush,
855 const std::vector<int64_t> axis_after_Flush);858 const std::vector<int64_t> axis_after_Flush);
859+ static Status FlushReshapeAxisChanges(const NodePtr &node, const NodePtr &asc_node,
860+ const std::vector<int64_t> axis_before_Flush,
861+ const std::vector<int64_t> axis_after_Flush);
856 static Status GetTransposeInfos(862 static Status GetTransposeInfos(
857 AscGraph &asc_graph, bool &has_only_one_transpose,863 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);864 std::unordered_map<NodePtr, std::vector<std::pair<int64_t, int64_t>>> &fallback_node_to_transpose_info);
@@ -603,6 +603,14 @@ bool FusionStrategySolver::CanFuse(const ComputeGraphPtr &graph, const FusingNod
603 return false;603 return false;
604 }604 }
605 605 
606+ if (BackendUtils::CompleteNodeAttrsBeforeCanFuse(node1->GetOrgNode(), node2->GetOrgNode()) != SUCCESS) {
607+ GELOGI("node1 %s(%s) and node2 %s(%s) cannot fuse, complete node attrs before can-fuse failed.",
608+ node1->GetNamePtr(), node1->GetOrgNode()->GetType().c_str(), node2->GetNamePtr(),
609+ node2->GetOrgNode()->GetType().c_str());
610+ can_not_fuse_nodes.insert({node1.get(), node2.get()});
611+ return false;
612+ }
613+ 
606 // node1是node2的祖先节点,判断纵向融合,否则判断横向融合614 // node1是node2的祖先节点,判断纵向融合,否则判断横向融合
607 if (node2->IsAncestor(node1)) {615 if (node2->IsAncestor(node1)) {
608 if (!GetBackEnd(graph)->CanFuseVertical(node1->GetOrgNode(), node2->GetOrgNode())) {616 if (!GetBackEnd(graph)->CanFuseVertical(node1->GetOrgNode(), node2->GetOrgNode())) {
@@ -85,15 +85,6 @@ bool ConcatFusionStrategy::CanFuse(const NodePtr &node1, const NodePtr &node2) {
85 graph_attr2->axis.size());85 graph_attr2->axis.size());
86 return false;86 return false;
87 }87 }
88- if (attr2->HasFuseType(loop::FuseType::kConcat) && graph_attr2->axis.size() < graph_attr1->axis.size()) {
89- GELOGI(
90- "node1 %s(%s) and node2 %s(%s) cannot fuse, the reason is [%s][In concat fusion occasion, node1 sched axis "
91- "size(%zu) more than node2 sched axis size(%zu)]",
92- node1->GetNamePtr(), node1->GetType().c_str(), node2->GetNamePtr(), node2->GetType().c_str(),
93- ge::NotFuseReasonCode(ge::NotFuseReason::kConcatNodeSchedAxisSizeNotEqual), graph_attr1->axis.size(),
94- graph_attr2->axis.size());
95- return false;
96- }
97 return true;88 return true;
98}89}
99 90 
@@ -52,6 +52,13 @@ 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+ 
55struct AutofuseInnerAttrs {62struct AutofuseInnerAttrs {
56 std::vector<const af::Node *> origin_nodes; // Asc节点对应的原始节点,用于Dfx打印、获取融合前ComputeGraph片段等63 std::vector<const af::Node *> origin_nodes; // Asc节点对应的原始节点,用于Dfx打印、获取融合前ComputeGraph片段等
57 std::vector<af::OutDataAnchor *> output_buffers; // Asc节点负责写入的原始输出anchor,用于lifting64 std::vector<af::OutDataAnchor *> output_buffers; // Asc节点负责写入的原始输出anchor,用于lifting
@@ -71,12 +78,13 @@ struct AutofuseInnerAttrs {
71 size_t reduce_fused_elementwise_node_num = 0U; // reduce节点向后融合的elementwise节点数量78 size_t reduce_fused_elementwise_node_num = 0U; // reduce节点向后融合的elementwise节点数量
72 int64_t split_global_id = kNonSplitGlobalId; // split op 在 lowering 之前的全局编号,不是split节点的话,这个编号为-179 int64_t split_global_id = kNonSplitGlobalId; // split op 在 lowering 之前的全局编号,不是split节点的话,这个编号为-1
73 SplitFusionRatioRequirementState split_fusion_ratio_requirement_state =80 SplitFusionRatioRequirementState split_fusion_ratio_requirement_state =
74- SplitFusionRatioRequirementState::NOT_DETERMINED; // 缓存对split融合比例是否超过阈值的预测结果81+ SplitFusionRatioRequirementState::NOT_DETERMINED; // 缓存对split融合比例是否超过阈值的预测结果
75- bool is_split_complete = false; // 缓存原split节点是否完全恢复的判断结果82+ bool is_split_complete = false; // 缓存原split节点是否完全恢复的判断结果
76- bool is_fuse_from_lowering = false; // 标识融合节点来自lowering还是can_fuse83+ bool is_fuse_from_lowering = false; // 标识融合节点来自lowering还是can_fuse
77- std::vector<int64_t> reduce_original_axis; // reduce操作前的原始轴信息84+ std::vector<int64_t> reduce_original_axis; // reduce操作前的原始轴信息
78- std::vector<Expression> reduce_original_repeats; // reduce操作前的原始repeats信息85+ std::vector<Expression> reduce_original_repeats; // reduce操作前的原始repeats信息
79- int32_t is_reduce_all_load = REDUCE_ALL_LOAD_INIT; // 标识reduce是否所有load都是norm-like86+ std::vector<ReshapeAxisChangeInfo> reshape_axis_changes; // 每个reshape操作前后的轴变化信息
87+ int32_t is_reduce_all_load = REDUCE_ALL_LOAD_INIT; // 标识reduce是否所有load都是norm-like
80 88 
81 bool IsReduction() const {89 bool IsReduction() const {
82 return HasFuseType(loop::FuseType::kReduction);90 return HasFuseType(loop::FuseType::kReduction);
@@ -241,6 +249,18 @@ class AutoFuseAttrs : public AfAttrGroupsBase {
241 return inner_attrs_.reduce_original_repeats;249 return inner_attrs_.reduce_original_repeats;
242 }250 }
243 251 
252+ void AddReshapeAxisChange(const ReshapeAxisChangeInfo &change) {
253+ inner_attrs_.reshape_axis_changes.push_back(change);
254+ }
255+ 
256+ void SetReshapeAxisChanges(const std::vector<ReshapeAxisChangeInfo> &changes) {
257+ inner_attrs_.reshape_axis_changes = changes;
258+ }
259+ 
260+ [[nodiscard]] const std::vector<ReshapeAxisChangeInfo> &GetReshapeAxisChanges() const {
261+ return inner_attrs_.reshape_axis_changes;
262+ }
263+ 
244 void SetReduceAllLoadState(const int32_t state) {264 void SetReduceAllLoadState(const int32_t state) {
245 inner_attrs_.is_reduce_all_load = state;265 inner_attrs_.is_reduce_all_load = state;
246 }266 }
@@ -37,6 +37,9 @@ struct ExtraKernelBoxMeta {
37 std::set<const ge::OutDataAnchor *> used_ascend_buffers;37 std::set<const ge::OutDataAnchor *> used_ascend_buffers;
38 std::set<const ge::OutDataAnchor *> optimized_ascend_buffers;38 std::set<const ge::OutDataAnchor *> optimized_ascend_buffers;
39 std::set<loop::Edge> concrete_edges; // edges consumed by this fused kernel39 std::set<loop::Edge> concrete_edges; // edges consumed by this fused kernel
40+ std::vector<ReshapeAxisChangeInfo> reshape_axis_changes;
41+ std::vector<int64_t> reshape_before_axis;
42+ std::vector<Expression> reshape_before_repeats;
40 std::string stream_label;43 std::string stream_label;
41 std::string stream_priority;44 std::string stream_priority;
42 static ExtraKernelBoxMeta &Default() {45 static ExtraKernelBoxMeta &Default() {
@@ -86,6 +89,9 @@ struct KernelBoxMeta {
86 if (op->Type() == "ops.StoreStridedSlice") {89 if (op->Type() == "ops.StoreStridedSlice") {
87 extra->num_slices++;90 extra->num_slices++;
88 }91 }
92+ const auto &reshape_axis_changes = op->GetReshapeAxisChanges();
93+ extra->reshape_axis_changes.insert(extra->reshape_axis_changes.end(), reshape_axis_changes.begin(),
94+ reshape_axis_changes.end());
89 const auto node = op->GetAscendIrNode();95 const auto node = op->GetAscendIrNode();
90 if (node != nullptr && seen_nodes.insert(node).second) {96 if (node != nullptr && seen_nodes.insert(node).second) {
91 if (extra->stream_label.empty()) {97 if (extra->stream_label.empty()) {
@@ -350,6 +356,32 @@ class KernelBox {
350 return GetExtraMeta().optimized_ascend_buffers;356 return GetExtraMeta().optimized_ascend_buffers;
351 }357 }
352 358 
359+ void SetReshapeBeforeRepeats(const std::vector<Expression> &repeats) {
360+ if (meta_ == nullptr || IsExternKernel()) {
361+ return;
362+ }
363+ meta_->Extra().reshape_before_repeats = repeats;
364+ }
365+ 
366+ void SetReshapeBeforeAxis(const std::vector<int64_t> &axis) {
367+ if (meta_ == nullptr || IsExternKernel()) {
368+ return;
369+ }
370+ meta_->Extra().reshape_before_axis = axis;
371+ }
372+ 
373+ const std::vector<Expression> &GetReshapeBeforeRepeats() {
374+ return GetExtraMeta().reshape_before_repeats;
375+ }
376+ 
377+ const std::vector<int64_t> &GetReshapeBeforeAxis() {
378+ return GetExtraMeta().reshape_before_axis;
379+ }
380+ 
381+ const std::vector<ReshapeAxisChangeInfo> &GetReshapeAxisChanges() {
382+ return GetExtraMeta().reshape_axis_changes;
383+ }
384+ 
353 size_t NumOps() {385 size_t NumOps() {
354 return GetExtraMeta().num_ops;386 return GetExtraMeta().num_ops;
355 }387 }
@@ -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) {
@@ -682,10 +704,12 @@ LoopVar Reshape(const LoopVar &op, const std::vector<Expression> &src_dims, cons
682 // -i为后续减轴,index维度有变化需要更新704 // -i为后续减轴,index维度有变化需要更新
683 reshape = loop::Squeeze(reshape, dims_new[i] - static_cast<int64_t>(i));705 reshape = loop::Squeeze(reshape, dims_new[i] - static_cast<int64_t>(i));
684 }706 }
707+ AddReshapeAxisChange(reshape, src_dims, dst_dims);
685 return reshape;708 return reshape;
686 }709 }
687 if (AutofuseUtils::CheckAndMulDetect(src_dims, dst_dims, short_idx, mul_idx)) {710 if (AutofuseUtils::CheckAndMulDetect(src_dims, dst_dims, short_idx, mul_idx)) {
688 reshape = LoopVar(std::make_shared<ReshapeOp>(op.Op(), src_dims, dst_dims, short_idx, mul_idx));711 reshape = LoopVar(std::make_shared<ReshapeOp>(op.Op(), src_dims, dst_dims, short_idx, mul_idx));
712+ AddReshapeAxisChange(reshape, src_dims, dst_dims);
689 return reshape;713 return reshape;
690 }714 }
691 } else {715 } else {
@@ -693,10 +717,12 @@ LoopVar Reshape(const LoopVar &op, const std::vector<Expression> &src_dims, cons
693 for (const auto &new_dim : dims_new) {717 for (const auto &new_dim : dims_new) {
694 reshape = loop::Unsqueeze(reshape, new_dim);718 reshape = loop::Unsqueeze(reshape, new_dim);
695 }719 }
720+ AddReshapeAxisChange(reshape, src_dims, dst_dims);
696 return reshape;721 return reshape;
697 }722 }
698 if (AutofuseUtils::CheckAndMulDetect(dst_dims, src_dims, short_idx, mul_idx)) {723 if (AutofuseUtils::CheckAndMulDetect(dst_dims, src_dims, short_idx, mul_idx)) {
699 reshape = LoopVar(std::make_shared<ReshapeOp>(op.Op(), src_dims, dst_dims, short_idx, mul_idx));724 reshape = LoopVar(std::make_shared<ReshapeOp>(op.Op(), src_dims, dst_dims, short_idx, mul_idx));
725+ AddReshapeAxisChange(reshape, src_dims, dst_dims);
700 return reshape;726 return reshape;
701 }727 }
702 }728 }
@@ -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,6 +114,14 @@ 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();
119 for (size_t i = 0U; i < inputs_.size(); ++i) {127 for (size_t i = 0U; i < inputs_.size(); ++i) {
@@ -132,6 +140,7 @@ class LoopOp {
132 140 
133 private:141 private:
134 static std::atomic<int64_t> global_id_;142 static std::atomic<int64_t> global_id_;
143+ std::vector<ReshapeAxisChangeInfo> reshape_axis_changes_;
135};144};
136 145 
137class LoopVar {146class LoopVar {
@@ -243,6 +243,57 @@ 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+ const auto &reshape_axis_changes = kernel_box.GetReshapeAxisChanges();
249+ if (!reshape_axis_changes.empty()) {
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+ 
261+ const auto &before_axis = kernel_box.GetReshapeBeforeAxis();
262+ const auto &before_repeats = kernel_box.GetReshapeBeforeRepeats();
263+ if (before_axis.empty() && before_repeats.empty()) {
264+ return SUCCESS;
265+ }
266+ GE_ASSERT_NOTNULL(asc_graph);
267+ const auto graph_attr = af::AscGraphUtils::GetComputeGraph(*asc_graph)->GetAttrsGroup<AscGraphAttr>();
268+ GE_ASSERT_NOTNULL(graph_attr);
269+ 
270+ af::ReshapeAxisChangeInfo change;
271+ change.before_repeats = before_repeats;
272+ for (const auto &axis : graph_attr->axis) {
273+ GE_ASSERT_NOTNULL(axis);
274+ change.after_axis.push_back(axis->id);
275+ change.after_repeats.push_back(axis->size);
276+ }
277+ if (!before_axis.empty()) {
278+ change.before_axis = before_axis;
279+ } else {
280+ int64_t next_axis_id =
281+ change.after_axis.empty() ? 0 : (*std::max_element(change.after_axis.begin(), change.after_axis.end()) + 1);
282+ size_t after_idx = 0U;
283+ for (const auto &repeat : before_repeats) {
284+ if ((after_idx < change.after_repeats.size()) &&
285+ (SymbolicUtils::StaticCheckEq(repeat, change.after_repeats[after_idx]) == TriBool::kTrue)) {
286+ change.before_axis.push_back(change.after_axis[after_idx++]);
287+ continue;
288+ }
289+ GE_ASSERT_TRUE(SymbolicUtils::StaticCheckEq(repeat, Symbol(1)) == TriBool::kTrue);
290+ change.before_axis.push_back(next_axis_id++);
291+ }
292+ }
293+ fuse_attrs->AddReshapeAxisChange(change);
294+ return SUCCESS;
295+}
296+ 
246graphStatus BuildOpForKernelBox(loop::KernelBox &kernel_box, CounterPtr counter,297graphStatus BuildOpForKernelBox(loop::KernelBox &kernel_box, CounterPtr counter,
247 shared_ptr<loop::AscOverrides> asc_graph, af::Operator &asc_op) {298 shared_ptr<loop::AscOverrides> asc_graph, af::Operator &asc_op) {
248 std::string asc_op_name = CreateAscbackendName(kernel_box, counter);299 std::string asc_op_name = CreateAscbackendName(kernel_box, counter);
@@ -424,6 +475,7 @@ OpDescPtr LoweringManager::BuildOpDescForKernelBox(loop::KernelBox &kernel_box,
424 GE_ASSERT_NOTNULL(fuse_attrs);475 GE_ASSERT_NOTNULL(fuse_attrs);
425 GE_ASSERT_NOTNULL(asc_graph->SharedGraph());476 GE_ASSERT_NOTNULL(asc_graph->SharedGraph());
426 fuse_attrs->SetAscGraph(asc_graph->SharedGraph(), kernel_box.Type());477 fuse_attrs->SetAscGraph(asc_graph->SharedGraph(), kernel_box.Type());
478+ GE_ASSERT_SUCCESS(SaveReshapeAxisChangeInfo(kernel_box, asc_graph->SharedGraph(), fuse_attrs));
427 fuse_attrs->SetOriginOutputBuffers({anchor});479 fuse_attrs->SetOriginOutputBuffers({anchor});
428 fuse_attrs->SetOriginNodes(kernel_box.GetAscendIrNodes());480 fuse_attrs->SetOriginNodes(kernel_box.GetAscendIrNodes());
429 fuse_attrs->SetOptimizedInputBuffers(kernel_box.GetOptimizedInputAscendBuffers());481 fuse_attrs->SetOptimizedInputBuffers(kernel_box.GetOptimizedInputAscendBuffers());
@@ -2025,6 +2025,7 @@ REGISTER_LOWERING(Log) {
2025 GE_ASSERT_NOTNULL(node->GetInDataAnchor(0));2025 GE_ASSERT_NOTNULL(node->GetInDataAnchor(0));
2026 auto src = node->GetInDataAnchor(0)->GetPeerOutAnchor();2026 auto src = node->GetInDataAnchor(0)->GetPeerOutAnchor();
2027 GE_ASSERT_NOTNULL(src);2027 GE_ASSERT_NOTNULL(src);
2028+ loop::GetKernelBox(src).Realize();
2028 auto desc = src->GetOwnerNode()->GetOpDesc()->GetOutputDescPtr(src->GetIdx());2029 auto desc = src->GetOwnerNode()->GetOpDesc()->GetOutputDescPtr(src->GetIdx());
2029 GE_ASSERT_NOTNULL(desc);2030 GE_ASSERT_NOTNULL(desc);
2030 auto dtype = desc->GetDataType();2031 auto dtype = desc->GetDataType();
@@ -2139,7 +2140,14 @@ REGISTER_LOWERING(Reshape) {
2139 auto x = loop::Load(node->GetInDataAnchor(0));2140 auto x = loop::Load(node->GetInDataAnchor(0));
2140 auto reshape = loop::Reshape(x, dims, output_dims);2141 auto reshape = loop::Reshape(x, dims, output_dims);
2141 LOWERING_WARN_RECORD_REASON(reshape.IsValid(), node, "no specific reshape pattern matched");2142 LOWERING_WARN_RECORD_REASON(reshape.IsValid(), node, "no specific reshape pattern matched");
2142- loop::StoreReshape(node->GetOutDataAnchor(0), reshape);2143+ auto kernel_box = loop::Store(node->GetOutDataAnchor(0), reshape);
2144+ if (dims.size() > output_dims.size()) {
2145+ const auto tensor_attr = desc->GetAttrsGroup<AscTensorAttr>();
2146+ if ((tensor_attr != nullptr) && (tensor_attr->axis.size() == dims.size())) {
2147+ kernel_box.SetReshapeBeforeAxis(tensor_attr->axis);
2148+ }
2149+ kernel_box.SetReshapeBeforeRepeats(dims);
2150+ }
2143 return GRAPH_SUCCESS;2151 return GRAPH_SUCCESS;
2144}2152}
2145 2153 
@@ -10,7 +10,11 @@
10 10 
11#ifndef AUTOFUSE_POST_PROCESS_SCHEDULER_ADAPTER_ADAPTION_COMPLETE_NODE_ATTRS_H11#ifndef AUTOFUSE_POST_PROCESS_SCHEDULER_ADAPTER_ADAPTION_COMPLETE_NODE_ATTRS_H
12#define AUTOFUSE_POST_PROCESS_SCHEDULER_ADAPTER_ADAPTION_COMPLETE_NODE_ATTRS_H12#define AUTOFUSE_POST_PROCESS_SCHEDULER_ADAPTER_ADAPTION_COMPLETE_NODE_ATTRS_H
13+#include <unordered_map>
13#include "common/checker.h"14#include "common/checker.h"
15+#include "graph/symbolizer/symbolic_utils.h"
16+#include "fusion/autofuse_attrs.h"
17+#include "lowering/asc_lowerer/loop_common.h"
14#include "post_process/post_process_util.h"18#include "post_process/post_process_util.h"
15 19 
16namespace ge {20namespace ge {
@@ -68,6 +72,10 @@ inline Status UpdateTensorAttrsIfEmpty(const NodePtr &node, AscTensorAttr *tenso
68 return SUCCESS;72 return SUCCESS;
69}73}
70 74 
75+inline bool ContainsAxisId(const std::vector<int64_t> &axis, const int64_t axis_id) {
76+ return std::find(axis.begin(), axis.end(), axis_id) != axis.end();
77+}
78+ 
71inline Status UpdateTensorAttrsIfNotEmpty(const NodePtr &node, const std::vector<int64_t> &axis,79inline Status UpdateTensorAttrsIfNotEmpty(const NodePtr &node, const std::vector<int64_t> &axis,
72 const std::vector<Expression> &repeats, AscTensorAttr *tensor_attr) {80 const std::vector<Expression> &repeats, AscTensorAttr *tensor_attr) {
73 (void)repeats;81 (void)repeats;
@@ -154,6 +162,451 @@ inline Status UpdateTensorAttrs(const NodePtr &node, const std::vector<int64_t>
154 return SUCCESS;162 return SUCCESS;
155}163}
156 164 
165+inline bool IsSameRepeat(const Expression &lhs, const Expression &rhs) {
166+ return SymbolicUtils::StaticCheckEq(lhs, rhs) == TriBool::kTrue;
167+}
168+ 
169+inline bool ContainsRepeatsByOrder(const std::vector<AxisPtr> &axis, const std::vector<Expression> &repeats) {
170+ if (repeats.empty()) {
171+ return true;
172+ }
173+ size_t repeat_idx = 0U;
174+ for (const auto &axis_info : axis) {
175+ if (axis_info == nullptr) {
176+ continue;
177+ }
178+ if (IsSameRepeat(axis_info->size, repeats[repeat_idx])) {
179+ ++repeat_idx;
180+ if (repeat_idx == repeats.size()) {
181+ return true;
182+ }
183+ }
184+ }
185+ return false;
186+}
187+ 
188+inline void MergeNoOpReshapeRepeats(const std::vector<Expression> &candidate_repeats,
189+ std::vector<Expression> &target_repeats) {
190+ if (candidate_repeats.empty()) {
191+ return;
192+ }
193+ if (target_repeats.empty()) {
194+ target_repeats = candidate_repeats;
195+ return;
196+ }
197+ size_t target_idx = 0U;
198+ for (const auto &repeat : candidate_repeats) {
199+ size_t matched_idx = target_repeats.size();
200+ for (size_t i = target_idx; i < target_repeats.size(); ++i) {
201+ if (SymbolicUtils::StaticCheckEq(target_repeats[i], repeat) == TriBool::kTrue) {
202+ matched_idx = i;
203+ break;
204+ }
205+ }
206+ if (matched_idx != target_repeats.size()) {
207+ target_idx = matched_idx + 1U;
208+ continue;
209+ }
210+ target_repeats.insert(target_repeats.begin() + static_cast<ptrdiff_t>(target_idx), repeat);
211+ ++target_idx;
212+ }
213+}
214+ 
215+inline std::vector<Expression> BuildNoOpReshapeRepeats(const std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
216+ std::vector<Expression> target_repeats;
217+ for (const auto &change : axis_changes) {
218+ MergeNoOpReshapeRepeats(change.before_repeats, target_repeats);
219+ MergeNoOpReshapeRepeats(change.after_repeats, target_repeats);
220+ }
221+ return target_repeats;
222+}
223+ 
224+inline Status CollectSplitCoveredUnitAxes(const AscGraph &asc_graph, const AscGraphAttr &graph_attr,
225+ std::vector<int64_t> &split_covered_axis) {
226+ split_covered_axis.clear();
227+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
228+ if (node->GetType() != kSplitType) {
229+ continue;
230+ }
231+ const auto &op_desc = node->GetOpDesc();
232+ GE_ASSERT_NOTNULL(op_desc);
233+ for (size_t output_idx = 0U; output_idx < node->GetAllOutDataAnchorsSize(); ++output_idx) {
234+ const auto output_tensor_desc = op_desc->MutableOutputDesc(output_idx);
235+ GE_ASSERT_NOTNULL(output_tensor_desc);
236+ const auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
237+ if ((tensor_attr == nullptr) || (tensor_attr->axis.size() != tensor_attr->repeats.size()) ||
238+ (tensor_attr->axis.size() != tensor_attr->strides.size())) {
239+ continue;
240+ }
241+ for (size_t i = 0U; i < tensor_attr->axis.size(); ++i) {
242+ const auto graph_axis_it = std::find_if(graph_attr.axis.begin(), graph_attr.axis.end(),
243+ [axis_id = tensor_attr->axis[i]](const AxisPtr &axis_info) {
244+ return (axis_info != nullptr) && (axis_info->id == axis_id);
245+ });
246+ if (graph_axis_it == graph_attr.axis.end()) {
247+ continue;
248+ }
249+ const auto &graph_axis = *graph_axis_it;
250+ if (BackendUtils::IsEqOne(graph_axis->size) || !BackendUtils::IsEqOne(tensor_attr->repeats[i]) ||
251+ !BackendUtils::IsEqZero(tensor_attr->strides[i]) ||
252+ ContainsAxisId(split_covered_axis, tensor_attr->axis[i])) {
253+ continue;
254+ }
255+ split_covered_axis.push_back(tensor_attr->axis[i]);
256+ }
257+ }
258+ }
259+ return SUCCESS;
260+}
261+ 
262+inline Status CollectConcatCoveredUnitAxes(const AscGraph &asc_graph, const AscGraphAttr &graph_attr,
263+ std::vector<int64_t> &covered_axis) {
264+ const auto compute_graph = AscGraphUtils::GetComputeGraph(asc_graph);
265+ GE_ASSERT_NOTNULL(compute_graph);
266+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
267+ if (node->GetType() != kConcatType) {
268+ continue;
269+ }
270+ const auto &op_desc = node->GetOpDesc();
271+ GE_ASSERT_NOTNULL(op_desc);
272+ if (node->GetAllOutDataAnchorsSize() == 0U) {
273+ continue;
274+ }
275+ const auto output_tensor_desc = op_desc->MutableOutputDesc(0U);
276+ GE_ASSERT_NOTNULL(output_tensor_desc);
277+ const auto output_tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
278+ if ((output_tensor_attr == nullptr) || (output_tensor_attr->axis.size() != output_tensor_attr->repeats.size())) {
279+ continue;
280+ }
281+ for (size_t input_idx = 0U; input_idx < node->GetAllInDataAnchorsSize(); ++input_idx) {
282+ const auto input_tensor_desc = op_desc->MutableInputDesc(input_idx);
283+ GE_ASSERT_NOTNULL(input_tensor_desc);
284+ const auto input_tensor_attr = input_tensor_desc->GetAttrsGroup<AscTensorAttr>();
285+ if ((input_tensor_attr == nullptr) || (input_tensor_attr->axis.size() != input_tensor_attr->repeats.size()) ||
286+ (input_tensor_attr->axis.size() != input_tensor_attr->strides.size())) {
287+ continue;
288+ }
289+ for (size_t i = 0U; i < input_tensor_attr->axis.size(); ++i) {
290+ const auto output_axis_it =
291+ std::find(output_tensor_attr->axis.begin(), output_tensor_attr->axis.end(), input_tensor_attr->axis[i]);
292+ if (output_axis_it == output_tensor_attr->axis.end()) {
293+ continue;
294+ }
295+ const auto output_axis_idx =
296+ static_cast<size_t>(std::distance(output_tensor_attr->axis.begin(), output_axis_it));
297+ if (output_axis_idx >= output_tensor_attr->repeats.size()) {
298+ continue;
299+ }
300+ const auto graph_axis_it = std::find_if(graph_attr.axis.begin(), graph_attr.axis.end(),
301+ [axis_id = input_tensor_attr->axis[i]](const AxisPtr &axis_info) {
302+ return (axis_info != nullptr) && (axis_info->id == axis_id);
303+ });
304+ if (graph_axis_it == graph_attr.axis.end()) {
305+ continue;
306+ }
307+ const auto &graph_axis = *graph_axis_it;
308+ if (BackendUtils::IsEqOne(graph_axis->size) || !BackendUtils::IsEqOne(input_tensor_attr->repeats[i]) ||
309+ !BackendUtils::IsEqZero(input_tensor_attr->strides[i]) ||
310+ BackendUtils::IsEqOne(output_tensor_attr->repeats[output_axis_idx]) ||
311+ !IsSameRepeat(graph_axis->size, output_tensor_attr->repeats[output_axis_idx]) ||
312+ ContainsAxisId(covered_axis, input_tensor_attr->axis[i])) {
313+ continue;
314+ }
315+ covered_axis.push_back(input_tensor_attr->axis[i]);
316+ }
317+ }
318+ for (size_t output_axis_idx = 0U; output_axis_idx < output_tensor_attr->axis.size(); ++output_axis_idx) {
319+ const auto axis_id = output_tensor_attr->axis[output_axis_idx];
320+ const auto graph_axis_it = std::find_if(
321+ graph_attr.axis.begin(), graph_attr.axis.end(),
322+ [axis_id](const AxisPtr &axis_info) { return (axis_info != nullptr) && (axis_info->id == axis_id); });
323+ if ((graph_axis_it == graph_attr.axis.end()) || BackendUtils::IsEqOne((*graph_axis_it)->size) ||
324+ BackendUtils::IsEqOne(output_tensor_attr->repeats[output_axis_idx]) ||
325+ !IsSameRepeat((*graph_axis_it)->size, output_tensor_attr->repeats[output_axis_idx]) ||
326+ ContainsAxisId(covered_axis, axis_id)) {
327+ continue;
328+ }
329+ for (const auto &producer_node : compute_graph->GetAllNodes()) {
330+ if ((producer_node == node) || (producer_node->GetType() == kConcatType)) {
331+ continue;
332+ }
333+ const auto &producer_op_desc = producer_node->GetOpDesc();
334+ GE_ASSERT_NOTNULL(producer_op_desc);
335+ bool is_covered = false;
336+ for (size_t output_idx = 0U; output_idx < producer_node->GetAllOutDataAnchorsSize(); ++output_idx) {
337+ const auto producer_output_desc = producer_op_desc->MutableOutputDesc(output_idx);
338+ GE_ASSERT_NOTNULL(producer_output_desc);
339+ const auto producer_tensor_attr = producer_output_desc->GetAttrsGroup<AscTensorAttr>();
340+ if ((producer_tensor_attr == nullptr) ||
341+ (producer_tensor_attr->axis.size() != producer_tensor_attr->repeats.size()) ||
342+ (producer_tensor_attr->axis.size() != producer_tensor_attr->strides.size())) {
343+ continue;
344+ }
345+ const auto producer_axis_it =
346+ std::find(producer_tensor_attr->axis.begin(), producer_tensor_attr->axis.end(), axis_id);
347+ if (producer_axis_it == producer_tensor_attr->axis.end()) {
348+ continue;
349+ }
350+ const auto producer_axis_idx =
351+ static_cast<size_t>(std::distance(producer_tensor_attr->axis.begin(), producer_axis_it));
352+ if (BackendUtils::IsEqOne(producer_tensor_attr->repeats[producer_axis_idx]) &&
353+ BackendUtils::IsEqZero(producer_tensor_attr->strides[producer_axis_idx])) {
354+ covered_axis.push_back(axis_id);
355+ is_covered = true;
356+ break;
357+ }
358+ }
359+ if (is_covered) {
360+ break;
361+ }
362+ }
363+ }
364+ }
365+ return SUCCESS;
366+}
367+ 
368+inline Status CollectCoveredUnitAxes(const AscGraph &asc_graph, const AscGraphAttr &graph_attr,
369+ std::vector<int64_t> &covered_axis) {
370+ GE_ASSERT_SUCCESS(CollectSplitCoveredUnitAxes(asc_graph, graph_attr, covered_axis));
371+ GE_ASSERT_SUCCESS(CollectConcatCoveredUnitAxes(asc_graph, graph_attr, covered_axis));
372+ return SUCCESS;
373+}
374+ 
375+inline AxisPtr MakeNoOpReshapeAxis(const int64_t axis_id, const Expression &repeat) {
376+ auto axis_info = ComGraphMakeShared<Axis>();
377+ GE_ASSERT_NOTNULL(axis_info);
378+ axis_info->id = axis_id;
379+ axis_info->name = "reshape_axis_optimized_" + std::to_string(axis_id);
380+ axis_info->type = Axis::kAxisTypeOriginal;
381+ axis_info->size = repeat;
382+ return axis_info;
383+}
384+ 
385+inline int64_t GetNextNoOpReshapeAxisId(const std::vector<AxisPtr> &axis) {
386+ int64_t max_axis_id = -1;
387+ for (const auto &axis_info : axis) {
388+ if (axis_info == nullptr) {
389+ continue;
390+ }
391+ max_axis_id = std::max(max_axis_id, axis_info->id);
392+ }
393+ return max_axis_id + 1;
394+}
395+ 
396+inline void ShiftAxisIdFrom(const int64_t insert_axis_id, int64_t &axis_id) {
397+ if (axis_id >= insert_axis_id) {
398+ ++axis_id;
399+ }
400+}
401+ 
402+inline void ShiftAxisIdsFrom(const int64_t insert_axis_id, std::vector<int64_t> &axis) {
403+ for (auto &axis_id : axis) {
404+ ShiftAxisIdFrom(insert_axis_id, axis_id);
405+ }
406+}
407+ 
408+inline Status ShiftAscGraphAxisIdsFrom(const AscGraph &asc_graph, const int64_t insert_axis_id) {
409+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
410+ const auto &op_desc = node->GetOpDesc();
411+ GE_ASSERT_NOTNULL(op_desc);
412+ auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();
413+ if (node_attr != nullptr) {
414+ ShiftAxisIdsFrom(insert_axis_id, node_attr->sched.axis);
415+ ShiftAxisIdFrom(insert_axis_id, node_attr->sched.loop_axis);
416+ }
417+ for (size_t i = 0U; i < node->GetAllInDataAnchorsSize(); ++i) {
418+ const auto input_tensor_desc = op_desc->MutableInputDesc(i);
419+ GE_ASSERT_NOTNULL(input_tensor_desc);
420+ auto tensor_attr = input_tensor_desc->GetAttrsGroup<AscTensorAttr>();
421+ if (tensor_attr == nullptr) {
422+ continue;
423+ }
424+ ShiftAxisIdsFrom(insert_axis_id, tensor_attr->axis);
425+ ShiftAxisIdsFrom(insert_axis_id, tensor_attr->vectorized_axis);
426+ }
427+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
428+ const auto output_tensor_desc = op_desc->MutableOutputDesc(i);
429+ GE_ASSERT_NOTNULL(output_tensor_desc);
430+ auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
431+ if (tensor_attr == nullptr) {
432+ continue;
433+ }
434+ ShiftAxisIdsFrom(insert_axis_id, tensor_attr->axis);
435+ ShiftAxisIdsFrom(insert_axis_id, tensor_attr->vectorized_axis);
436+ }
437+ }
438+ return SUCCESS;
439+}
440+ 
441+inline int64_t FindInsertAxisIdByNextRepeat(const std::vector<AxisPtr> &axis, const size_t graph_axis_begin,
442+ const std::vector<Expression> &target_repeats,
443+ const size_t target_repeat_index) {
444+ for (size_t i = target_repeat_index + 1U; i < target_repeats.size(); ++i) {
445+ if (BackendUtils::IsEqOne(target_repeats[i])) {
446+ continue;
447+ }
448+ for (size_t j = graph_axis_begin; j < axis.size(); ++j) {
449+ if ((axis[j] != nullptr) && IsSameRepeat(axis[j]->size, target_repeats[i])) {
450+ return axis[j]->id;
451+ }
452+ }
453+ }
454+ return GetNextNoOpReshapeAxisId(axis);
455+}
456+ 
457+template <typename ScoreFunc>
458+inline std::vector<size_t> BuildBestOverlapTargetIndexes(const size_t source_size, const size_t target_size,
459+ const ScoreFunc &score_func) {
460+ if ((source_size == 0U) || (source_size > target_size)) {
461+ return {};
462+ }
463+ constexpr int32_t kInvalidScore = -1000000;
464+ std::vector<std::vector<int32_t>> dp(source_size + 1U, std::vector<int32_t>(target_size + 1U, kInvalidScore));
465+ for (size_t target_idx = 0U; target_idx <= target_size; ++target_idx) {
466+ dp[source_size][target_idx] = 0;
467+ }
468+ for (size_t source_idx = source_size; source_idx > 0U; --source_idx) {
469+ for (size_t target_idx = target_size; target_idx > 0U; --target_idx) {
470+ const auto source_pos = source_idx - 1U;
471+ const auto target_pos = target_idx - 1U;
472+ if ((source_size - source_pos) > (target_size - target_pos)) {
473+ continue;
474+ }
475+ const auto match_score = score_func(source_pos, target_pos) + dp[source_pos + 1U][target_pos + 1U];
476+ const auto skip_score = dp[source_pos][target_pos + 1U];
477+ dp[source_pos][target_pos] = std::max(match_score, skip_score);
478+ }
479+ }
480+ 
481+ std::vector<size_t> target_indexes(source_size, target_size);
482+ size_t source_idx = 0U;
483+ size_t target_idx = 0U;
484+ while ((source_idx < source_size) && (target_idx < target_size)) {
485+ const auto match_score = score_func(source_idx, target_idx) + dp[source_idx + 1U][target_idx + 1U];
486+ const auto skip_score = dp[source_idx][target_idx + 1U];
487+ if (((target_size - target_idx - 1U) >= (source_size - source_idx)) && (skip_score >= match_score)) {
488+ ++target_idx;
489+ continue;
490+ }
491+ target_indexes[source_idx++] = target_idx++;
492+ }
493+ return target_indexes;
494+}
495+ 
496+inline void ShiftInsertedTargetAxesFrom(const std::vector<AxisPtr> &graph_axis, const int64_t insert_axis_id,
497+ std::vector<AxisPtr> &target_axis) {
498+ for (const auto &axis_info : target_axis) {
499+ const auto is_graph_axis = std::find(graph_axis.begin(), graph_axis.end(), axis_info) != graph_axis.end();
500+ if ((axis_info != nullptr) && !is_graph_axis) {
501+ ShiftAxisIdFrom(insert_axis_id, axis_info->id);
502+ }
503+ }
504+}
505+ 
506+inline int64_t GetNextNoOpReshapeAxisId(const std::vector<AxisPtr> &graph_axis,
507+ const std::vector<AxisPtr> &target_axis) {
508+ int64_t max_axis_id = -1;
509+ for (const auto &axis_info : graph_axis) {
510+ if (axis_info != nullptr) {
511+ max_axis_id = std::max(max_axis_id, axis_info->id);
512+ }
513+ }
514+ for (const auto &axis_info : target_axis) {
515+ if (axis_info != nullptr) {
516+ max_axis_id = std::max(max_axis_id, axis_info->id);
517+ }
518+ }
519+ return max_axis_id + 1;
520+}
521+ 
522+inline Status RestoreNoOpReshapeAxisWithSplitCoveredAxes(AscGraph &asc_graph,
523+ const std::vector<Expression> &target_repeats,
524+ const std::vector<int64_t> &split_covered_axis,
525+ AscGraphAttr *graph_attr) {
526+ GE_ASSERT_NOTNULL(graph_attr);
527+ if (graph_attr->axis.size() == target_repeats.size()) {
528+ GELOGD("graph %s axis size %zu equals no-op reshape target repeats size %zu, skip restore before complete attrs.",
529+ asc_graph.GetName().c_str(), graph_attr->axis.size(), target_repeats.size());
530+ return SUCCESS;
531+ }
532+ if (graph_attr->axis.size() > target_repeats.size()) {
533+ GELOGD(
534+ "graph %s axis size %zu is greater than no-op reshape target repeats size %zu, skip restore before "
535+ "complete attrs.",
536+ asc_graph.GetName().c_str(), graph_attr->axis.size(), target_repeats.size());
537+ return SUCCESS;
538+ }
539+ 
540+ const auto matched_target_indexes = BuildBestOverlapTargetIndexes(
541+ graph_attr->axis.size(), target_repeats.size(),
542+ [&graph_attr, &target_repeats](size_t source_idx, size_t target_idx) -> int32_t {
543+ if (graph_attr->axis[source_idx] == nullptr) {
544+ return 0;
545+ }
546+ return IsSameRepeat(graph_attr->axis[source_idx]->size, target_repeats[target_idx]) ? 1 : 0;
547+ });
548+ GE_ASSERT_TRUE(matched_target_indexes.size() == graph_attr->axis.size());
549+ 
550+ const size_t kInvalidIndex = target_repeats.size();
551+ std::vector<size_t> target_to_graph_index(target_repeats.size(), kInvalidIndex);
552+ for (size_t graph_axis_idx = 0U; graph_axis_idx < matched_target_indexes.size(); ++graph_axis_idx) {
553+ GE_ASSERT_TRUE(matched_target_indexes[graph_axis_idx] < target_to_graph_index.size());
554+ target_to_graph_index[matched_target_indexes[graph_axis_idx]] = graph_axis_idx;
555+ }
556+ 
557+ std::vector<AxisPtr> target_axis;
558+ target_axis.reserve(target_repeats.size());
559+ std::vector<int64_t> inserted_axis_ids;
560+ std::vector<Expression> inserted_axis_repeats;
561+ for (size_t target_repeat_idx = 0U; target_repeat_idx < target_repeats.size(); ++target_repeat_idx) {
562+ if (target_to_graph_index[target_repeat_idx] != kInvalidIndex) {
563+ target_axis.push_back(graph_attr->axis[target_to_graph_index[target_repeat_idx]]);
564+ continue;
565+ }
566+ 
567+ int64_t insert_axis_id = GetNextNoOpReshapeAxisId(graph_attr->axis, target_axis);
568+ for (size_t next_target_idx = target_repeat_idx + 1U; next_target_idx < target_to_graph_index.size();
569+ ++next_target_idx) {
570+ if (target_to_graph_index[next_target_idx] != kInvalidIndex) {
571+ const auto next_graph_axis = graph_attr->axis[target_to_graph_index[next_target_idx]];
572+ GE_ASSERT_NOTNULL(next_graph_axis);
573+ insert_axis_id = next_graph_axis->id;
574+ break;
575+ }
576+ }
577+ for (const auto &axis_info : graph_attr->axis) {
578+ GE_ASSERT_NOTNULL(axis_info);
579+ ShiftAxisIdFrom(insert_axis_id, axis_info->id);
580+ }
581+ ShiftInsertedTargetAxesFrom(graph_attr->axis, insert_axis_id, target_axis);
582+ GE_ASSERT_SUCCESS(ShiftAscGraphAxisIdsFrom(asc_graph, insert_axis_id));
583+ target_axis.push_back(MakeNoOpReshapeAxis(insert_axis_id, kSymbolOne));
584+ inserted_axis_ids.push_back(insert_axis_id);
585+ inserted_axis_repeats.push_back(kSymbolOne);
586+ GELOGD("graph %s restore no-op reshape axis id %ld repeat %s at target repeat idx %zu before complete attrs.",
587+ asc_graph.GetName().c_str(), insert_axis_id, kSymbolOne.Str().get(), target_repeat_idx);
588+ }
589+ const auto old_axis_size = graph_attr->axis.size();
590+ graph_attr->axis = std::move(target_axis);
591+ GELOGD(
592+ "graph %s restore no-op reshape axes by target repeats %s, covered axes %s, inserted axis ids %s, inserted "
593+ "repeats "
594+ "%s before complete attrs.",
595+ asc_graph.GetName().c_str(), AutofuseUtils::VectorToStr(target_repeats).c_str(),
596+ AutofuseUtils::VectorToStr(split_covered_axis).c_str(), AutofuseUtils::VectorToStr(inserted_axis_ids).c_str(),
597+ AutofuseUtils::VectorToStr(inserted_axis_repeats).c_str());
598+ GELOGI(
599+ "graph %s restore no-op reshape axes with split-covered unit axes, graph axis size from %zu to %zu "
600+ "before complete attrs.",
601+ asc_graph.GetName().c_str(), old_axis_size, graph_attr->axis.size());
602+ return SUCCESS;
603+}
604+ 
605+inline bool IsReshapePaddingAxis(const AxisPtr &axis) {
606+ return (axis != nullptr) && BackendUtils::IsEqOne(axis->size) &&
607+ (axis->name.rfind("reshape_axis_padding_", 0U) == 0U);
608+}
609+ 
157inline Status CompleteNodeAttrsOnAscGraph(AscGraph &asc_graph, [[maybe_unused]] const NodePtr &asc_node) {610inline Status CompleteNodeAttrsOnAscGraph(AscGraph &asc_graph, [[maybe_unused]] const NodePtr &asc_node) {
158 TensorAttrInfo graph_attr;611 TensorAttrInfo graph_attr;
159 GE_ASSERT_SUCCESS(BackendUtils::GetGraphAttrInfo(asc_graph, graph_attr));612 GE_ASSERT_SUCCESS(BackendUtils::GetGraphAttrInfo(asc_graph, graph_attr));
@@ -201,6 +654,496 @@ inline Status CompleteNodeAttrsOnAscGraph(AscGraph &asc_graph, [[maybe_unused]]
201 return SUCCESS;654 return SUCCESS;
202}655}
203 656 
657+inline void CopyTensorAttrs(const AscTensorAttr &src_attr, AscTensorAttr &dst_attr) {
658+ dst_attr.axis = src_attr.axis;
659+ dst_attr.repeats = src_attr.repeats;
660+ dst_attr.strides = src_attr.strides;
661+ dst_attr.vectorized_axis = src_attr.vectorized_axis;
662+}
663+ 
664+inline void ReorderGraphAxesToOriginalOrder(std::vector<AxisPtr> &axis) {
665+ std::vector<AxisPtr> sorted_original_axis;
666+ sorted_original_axis.reserve(axis.size());
667+ for (const auto &axis_info : axis) {
668+ if (!IsReshapePaddingAxis(axis_info)) {
669+ sorted_original_axis.push_back(axis_info);
670+ }
671+ }
672+ std::stable_sort(sorted_original_axis.begin(), sorted_original_axis.end(),
673+ [](const AxisPtr &lhs, const AxisPtr &rhs) {
674+ if ((lhs == nullptr) || (rhs == nullptr)) {
675+ return lhs != nullptr;
676+ }
677+ return lhs->id < rhs->id;
678+ });
679+ size_t original_axis_index = 0U;
680+ for (auto &axis_info : axis) {
681+ if (IsReshapePaddingAxis(axis_info)) {
682+ continue;
683+ }
684+ axis_info = sorted_original_axis[original_axis_index++];
685+ }
686+}
687+ 
688+inline void ReorderAxisIdsByGraphOrder(const std::vector<int64_t> &graph_axis_order, std::vector<int64_t> &axis) {
689+ std::vector<int64_t> reordered_axis;
690+ for (const auto graph_axis_id : graph_axis_order) {
691+ auto it = std::find(axis.begin(), axis.end(), graph_axis_id);
692+ if (it != axis.end()) {
693+ reordered_axis.push_back(graph_axis_id);
694+ }
695+ }
696+ for (const auto axis_id : axis) {
697+ if (std::find(graph_axis_order.begin(), graph_axis_order.end(), axis_id) == graph_axis_order.end()) {
698+ reordered_axis.push_back(axis_id);
699+ }
700+ }
701+ axis = reordered_axis;
702+}
703+ 
704+inline void ReorderTensorAttrsByGraphOrder(const std::vector<int64_t> &graph_axis_order, AscTensorAttr &tensor_attr) {
705+ if (tensor_attr.axis.empty()) {
706+ return;
707+ }
708+ if ((tensor_attr.repeats.size() != tensor_attr.axis.size()) ||
709+ (tensor_attr.strides.size() != tensor_attr.axis.size())) {
710+ return;
711+ }
712+ AscTensorAttr reordered_attr = tensor_attr;
713+ reordered_attr.axis.clear();
714+ reordered_attr.repeats.clear();
715+ reordered_attr.strides.clear();
716+ for (const auto graph_axis_id : graph_axis_order) {
717+ auto it = std::find(tensor_attr.axis.begin(), tensor_attr.axis.end(), graph_axis_id);
718+ if (it == tensor_attr.axis.end()) {
719+ continue;
720+ }
721+ const auto idx = static_cast<size_t>(std::distance(tensor_attr.axis.begin(), it));
722+ reordered_attr.axis.push_back(tensor_attr.axis[idx]);
723+ reordered_attr.repeats.push_back(tensor_attr.repeats[idx]);
724+ reordered_attr.strides.push_back(tensor_attr.strides[idx]);
725+ }
726+ for (size_t i = 0U; i < tensor_attr.axis.size(); ++i) {
727+ if (std::find(graph_axis_order.begin(), graph_axis_order.end(), tensor_attr.axis[i]) != graph_axis_order.end()) {
728+ continue;
729+ }
730+ reordered_attr.axis.push_back(tensor_attr.axis[i]);
731+ reordered_attr.repeats.push_back(tensor_attr.repeats[i]);
732+ reordered_attr.strides.push_back(tensor_attr.strides[i]);
733+ }
734+ CopyTensorAttrs(reordered_attr, tensor_attr);
735+}
736+ 
737+inline Status ReorderAscGraphAttrsByGraphOrder(const AscGraph &asc_graph,
738+ const std::vector<int64_t> &graph_axis_order) {
739+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
740+ const auto &op_desc = node->GetOpDesc();
741+ GE_ASSERT_NOTNULL(op_desc);
742+ auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();
743+ if (node_attr != nullptr) {
744+ ReorderAxisIdsByGraphOrder(graph_axis_order, node_attr->sched.axis);
745+ }
746+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
747+ const auto output_tensor_desc = op_desc->MutableOutputDesc(i);
748+ GE_ASSERT_NOTNULL(output_tensor_desc);
749+ auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
750+ if (tensor_attr == nullptr) {
751+ continue;
752+ }
753+ ReorderTensorAttrsByGraphOrder(graph_axis_order, *tensor_attr);
754+ }
755+ }
756+ return SUCCESS;
757+}
758+ 
759+inline Status ReorderAscGraphAttrsByCurrentGraphOrder(const AscGraph &asc_graph, const AscGraphAttr &graph_attr) {
760+ std::vector<int64_t> graph_axis_order;
761+ graph_axis_order.reserve(graph_attr.axis.size());
762+ for (const auto &axis_info : graph_attr.axis) {
763+ GE_ASSERT_NOTNULL(axis_info);
764+ graph_axis_order.push_back(axis_info->id);
765+ }
766+ GE_ASSERT_SUCCESS(ReorderAscGraphAttrsByGraphOrder(asc_graph, graph_axis_order));
767+ return SUCCESS;
768+}
769+ 
770+inline void CompleteTensorAttrsByGraphOrderPreserveStrides(const NodePtr &node, const size_t output_idx,
771+ const std::vector<int64_t> &graph_axis_order,
772+ AscTensorAttr &tensor_attr) {
773+ const auto old_axis = tensor_attr.axis;
774+ std::vector<int64_t> inserted_axis_ids;
775+ if (tensor_attr.axis.size() >= graph_axis_order.size()) {
776+ return;
777+ }
778+ 
779+ const auto matched_target_indexes =
780+ BuildBestOverlapTargetIndexes(tensor_attr.axis.size(), graph_axis_order.size(),
781+ [&tensor_attr, &graph_axis_order](size_t source_idx, size_t target_idx) -> int32_t {
782+ return tensor_attr.axis[source_idx] == graph_axis_order[target_idx] ? 1 : 0;
783+ });
784+ if (matched_target_indexes.size() != tensor_attr.axis.size()) {
785+ return;
786+ }
787+ 
788+ const size_t kInvalidIndex = graph_axis_order.size();
789+ std::vector<size_t> target_to_tensor_index(graph_axis_order.size(), kInvalidIndex);
790+ for (size_t tensor_axis_idx = 0U; tensor_axis_idx < matched_target_indexes.size(); ++tensor_axis_idx) {
791+ target_to_tensor_index[matched_target_indexes[tensor_axis_idx]] = tensor_axis_idx;
792+ }
793+ 
794+ AscTensorAttr completed_attr = tensor_attr;
795+ completed_attr.axis.clear();
796+ if (!tensor_attr.repeats.empty()) {
797+ completed_attr.repeats.clear();
798+ }
799+ if (!tensor_attr.strides.empty()) {
800+ completed_attr.strides.clear();
801+ }
802+ for (size_t i = 0U; i < graph_axis_order.size(); ++i) {
803+ const auto tensor_idx = target_to_tensor_index[i];
804+ if (tensor_idx != kInvalidIndex) {
805+ completed_attr.axis.push_back(tensor_attr.axis[tensor_idx]);
806+ if (!tensor_attr.repeats.empty()) {
807+ completed_attr.repeats.push_back(tensor_attr.repeats[tensor_idx]);
808+ }
809+ if (!tensor_attr.strides.empty()) {
810+ completed_attr.strides.push_back(tensor_attr.strides[tensor_idx]);
811+ }
812+ continue;
813+ }
814+ const auto graph_axis_id = graph_axis_order[i];
815+ completed_attr.axis.push_back(graph_axis_id);
816+ if (!tensor_attr.repeats.empty()) {
817+ completed_attr.repeats.push_back(kSymbolOne);
818+ }
819+ if (!tensor_attr.strides.empty()) {
820+ completed_attr.strides.push_back(kSymbolZero);
821+ }
822+ inserted_axis_ids.push_back(graph_axis_id);
823+ GELOGD("node %s(%s) output %zu complete preserve tensor attrs with reshape axis id %ld at graph axis idx %zu.",
824+ node->GetName().c_str(), node->GetType().c_str(), output_idx, graph_axis_id, i);
825+ }
826+ CopyTensorAttrs(completed_attr, tensor_attr);
827+ if (!inserted_axis_ids.empty()) {
828+ GELOGD("node %s(%s) output %zu complete preserve tensor attrs with reshape axes %s, axis from %s to %s.",
829+ node->GetName().c_str(), node->GetType().c_str(), output_idx,
830+ AutofuseUtils::VectorToStr(inserted_axis_ids).c_str(), AutofuseUtils::VectorToStr(old_axis).c_str(),
831+ AutofuseUtils::VectorToStr(tensor_attr.axis).c_str());
832+ }
833+}
834+ 
835+inline Status UpdateTensorAttrsPreserveStrides(const NodePtr &node, const std::vector<int64_t> &axis,
836+ const std::vector<Expression> &repeats) {
837+ const auto &op_desc = node->GetOpDesc();
838+ GE_ASSERT_NOTNULL(op_desc);
839+ for (size_t i = 0U; i < node->GetAllOutDataAnchorsSize(); ++i) {
840+ const auto output_tensor_desc = op_desc->MutableOutputDesc(i);
841+ GE_ASSERT_NOTNULL(output_tensor_desc);
842+ auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
843+ GE_ASSERT_NOTNULL(tensor_attr);
844+ if (node->GetType() == kScalarType) {
845+ tensor_attr->axis = axis;
846+ tensor_attr->repeats.assign(axis.size(), kSymbolOne);
847+ tensor_attr->strides.assign(axis.size(), kSymbolZero);
848+ continue;
849+ }
850+ if ((tensor_attr->axis.empty()) && (node->GetType() != kDataType)) {
851+ GE_ASSERT_SUCCESS(UpdateTensorAttrsIfEmpty(node, tensor_attr, axis, repeats));
852+ continue;
853+ }
854+ CompleteTensorAttrsByGraphOrderPreserveStrides(node, i, axis, *tensor_attr);
855+ GELOGD("after preserve attrs: node %s(%s), axis:%s, repeats:%s stride:%s.", node->GetName().c_str(),
856+ node->GetType().c_str(), AutofuseUtils::VectorToStr(tensor_attr->axis).c_str(),
857+ AutofuseUtils::VectorToStr(tensor_attr->repeats).c_str(),
858+ AutofuseUtils::VectorToStr(tensor_attr->strides).c_str());
859+ }
860+ return SUCCESS;
861+}
862+ 
863+inline Status CompleteNodeAttrsOnAscGraphPreserveStrides(AscGraph &asc_graph, const NodePtr &asc_node) {
864+ (void)asc_node;
865+ TensorAttrInfo graph_attr;
866+ GE_ASSERT_SUCCESS(BackendUtils::GetGraphAttrInfo(asc_graph, graph_attr));
867+ GELOGI("max sched axis %s in graph %s, preserve tensor strides.", AutofuseUtils::VectorToStr(graph_attr.axis).c_str(),
868+ asc_graph.GetName().c_str());
869+ 
870+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
871+ if (IsTorchDataType(node)) {
872+ GELOGI("torch node %s(%s) not complete node attr.", node->GetName().c_str(), node->GetType().c_str());
873+ continue;
874+ }
875+ if (IsCubeRelatedAscNode(node)) {
876+ GELOGI("cube related node %s(%s) not complete node attr.", node->GetName().c_str(), node->GetType().c_str());
877+ continue;
878+ }
879+ if ((!IsGatherData(node)) && (!BackendUtils::IsOutputNode(node))) {
880+ GE_ASSERT_SUCCESS(UpdateTensorAttrsPreserveStrides(node, graph_attr.axis, graph_attr.repeats));
881+ }
882+ const auto &op_desc = node->GetOpDesc();
883+ GE_ASSERT_NOTNULL(op_desc);
884+ auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();
885+ GE_ASSERT_NOTNULL(node_attr);
886+ GELOGI("node %s(%s) before complete sched axis %s to %s in graph %s, preserve tensor strides.",
887+ node->GetName().c_str(), node->GetType().c_str(), AutofuseUtils::VectorToStr(node_attr->sched.axis).c_str(),
888+ AutofuseUtils::VectorToStr(graph_attr.axis).c_str(), asc_graph.GetName().c_str());
889+ node_attr->sched.axis = graph_attr.axis;
890+ GELOGI("node %s(%s) after complete sched axis %s to %s in graph %s, preserve tensor strides.",
891+ node->GetName().c_str(), node->GetType().c_str(), AutofuseUtils::VectorToStr(node_attr->sched.axis).c_str(),
892+ AutofuseUtils::VectorToStr(graph_attr.axis).c_str(), asc_graph.GetName().c_str());
893+ }
894+ return SUCCESS;
895+}
896+ 
897+inline Status HasLoadFeedingSplit(const AscGraph &asc_graph, bool &has_load_feeding_split) {
898+ has_load_feeding_split = false;
899+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
900+ if (node->GetType() != kLoadType) {
901+ continue;
902+ }
903+ std::vector<NodePtr> peer_in_nodes;
904+ GE_ASSERT_SUCCESS(asc_adapt::GetPeerInNodes(node, peer_in_nodes, 0));
905+ for (const auto &peer_in_node : peer_in_nodes) {
906+ if (peer_in_node->GetType() == kSplitType) {
907+ has_load_feeding_split = true;
908+ return SUCCESS;
909+ }
910+ }
911+ }
912+ return SUCCESS;
913+}
914+ 
915+inline Status CompleteSplitInputTensorAttrs(const AscTensorAttr &src_attr, const AscTensorAttr &split_output_attr,
916+ AscTensorAttr &dst_attr) {
917+ dst_attr.axis = split_output_attr.axis;
918+ dst_attr.repeats.clear();
919+ dst_attr.strides.clear();
920+ dst_attr.vectorized_axis = split_output_attr.vectorized_axis;
921+ 
922+ size_t src_start = 0U;
923+ if ((!src_attr.axis.empty()) && (!src_attr.repeats.empty()) && (!src_attr.strides.empty()) &&
924+ BackendUtils::IsEqOne(src_attr.repeats.front()) && BackendUtils::IsEqZero(src_attr.strides.front())) {
925+ src_start = 1U;
926+ }
927+ for (size_t i = src_start; i < src_attr.repeats.size(); ++i) {
928+ dst_attr.repeats.push_back(src_attr.repeats[i]);
929+ }
930+ while (dst_attr.repeats.size() < dst_attr.axis.size()) {
931+ dst_attr.repeats.push_back(kSymbolOne);
932+ }
933+ if (dst_attr.repeats.size() > dst_attr.axis.size()) {
934+ dst_attr.repeats.resize(dst_attr.axis.size());
935+ }
936+ GE_ASSERT_SUCCESS(UpdateStridesByReapeats(dst_attr.repeats, dst_attr.strides));
937+ return SUCCESS;
938+}
939+ 
940+inline Status UpdateLoadAndInputAttrsFromSplitOutput(const NodePtr &load_node, const AscTensorAttr &split_output_attr) {
941+ auto load_output_desc = load_node->GetOpDesc()->MutableOutputDesc(0U);
942+ GE_ASSERT_NOTNULL(load_output_desc);
943+ auto load_tensor_attr = load_output_desc->GetAttrsGroup<AscTensorAttr>();
944+ GE_ASSERT_NOTNULL(load_tensor_attr);
945+ AscTensorAttr completed_load_attr = *load_tensor_attr;
946+ GE_ASSERT_SUCCESS(CompleteSplitInputTensorAttrs(*load_tensor_attr, split_output_attr, completed_load_attr));
947+ CopyTensorAttrs(completed_load_attr, *load_tensor_attr);
948+ 
949+ std::vector<NodePtr> peer_out_nodes;
950+ GE_ASSERT_SUCCESS(asc_adapt::GetPeerOutNodes(load_node, peer_out_nodes));
951+ for (const auto &peer_out_node : peer_out_nodes) {
952+ GeTensorDescPtr peer_output_desc;
953+ GE_ASSERT_SUCCESS(asc_adapt::GetOutputTensorDesc(peer_out_node, peer_output_desc));
954+ auto peer_tensor_attr = peer_output_desc->GetAttrsGroup<AscTensorAttr>();
955+ GE_ASSERT_NOTNULL(peer_tensor_attr);
956+ CopyTensorAttrs(completed_load_attr, *peer_tensor_attr);
957+ }
958+ return SUCCESS;
959+}
960+ 
961+inline Status UpdateLoadAttrsFromSplitOutputs(const AscGraph &asc_graph) {
962+ bool has_load_feeding_split = false;
963+ GE_ASSERT_SUCCESS(HasLoadFeedingSplit(asc_graph, has_load_feeding_split));
964+ if (!has_load_feeding_split) {
965+ return SUCCESS;
966+ }
967+ for (const auto &node : AscGraphUtils::GetComputeGraph(asc_graph)->GetAllNodes()) {
968+ if (node->GetType() != kLoadType) {
969+ continue;
970+ }
971+ std::vector<NodePtr> peer_in_nodes;
972+ GE_ASSERT_SUCCESS(asc_adapt::GetPeerInNodes(node, peer_in_nodes, 0));
973+ for (const auto &peer_in_node : peer_in_nodes) {
974+ if (peer_in_node->GetType() != kSplitType) {
975+ continue;
976+ }
977+ AscTensorAttr *split_output_attr = nullptr;
978+ GE_ASSERT_SUCCESS(asc_adapt::GetOutputTensorAttr(peer_in_node, split_output_attr));
979+ GE_ASSERT_NOTNULL(split_output_attr);
980+ if (split_output_attr->axis.empty()) {
981+ continue;
982+ }
983+ GE_ASSERT_SUCCESS(UpdateLoadAndInputAttrsFromSplitOutput(node, *split_output_attr));
984+ GELOGI("load node %s(%s) update tensor attrs from split output %s(%s).", node->GetName().c_str(),
985+ node->GetType().c_str(), peer_in_node->GetName().c_str(), peer_in_node->GetType().c_str());
986+ break;
987+ }
988+ }
989+ return SUCCESS;
990+}
991+ 
992+inline Status DumpPadLeadingUnitAxisResult(const AscGraph &asc_graph, const NodePtr &asc_node, const char *process_name,
993+ const ComputeGraphPtr &fused_graph) {
994+ GELOGI("AscBackendPostProcessor: End to run the process(%s) on the graph, graph: %s, parent node: %s(%s).",
995+ process_name, fused_graph->GetName().c_str(), asc_node->GetNamePtr(), asc_node->GetType().c_str());
996+ GELOGD("dump node:%s(%s) asc graph info(with tensor attr info):", asc_node->GetNamePtr(),
997+ asc_node->GetType().c_str());
998+ (void)asc_graph;
999+ BackendUtils::DumpAscGraph(asc_node);
1000+ return SUCCESS;
1001+}
1002+ 
1003+inline Status PadLeadingUnitAxisByReshapeAxisChanges(AscGraph &asc_graph, const NodePtr &asc_node,
1004+ const std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
1005+ if (axis_changes.empty()) {
1006+ return SUCCESS;
1007+ }
1008+ constexpr const char *kPadLeadingUnitAxisProcName = "pad_leading_unit_axis";
1009+ const auto fused_graph = AscGraphUtils::GetComputeGraph(asc_graph);
1010+ GE_ASSERT_NOTNULL(fused_graph);
1011+ GE_ASSERT_SUCCESS(BackendUtils::AddInputOutputNodesForAscGraph(fused_graph));
1012+ GE_ASSERT_SUCCESS(CacheGraphBeforePostProcess(asc_node, kPadLeadingUnitAxisProcName, fused_graph));
1013+ const auto graph_attr = AscGraphUtils::GetComputeGraph(asc_graph)->GetAttrsGroup<AscGraphAttr>();
1014+ GE_ASSERT_NOTNULL(graph_attr);
1015+ ReorderGraphAxesToOriginalOrder(graph_attr->axis);
1016+ const auto target_repeats = BuildNoOpReshapeRepeats(axis_changes);
1017+ if (target_repeats.empty()) {
1018+ return SUCCESS;
1019+ }
1020+ GELOGD("node %s(%s) graph %s start to pad leading unit axes by %zu reshape axis changes, target repeats %s.",
1021+ asc_node->GetName().c_str(), asc_node->GetType().c_str(), asc_graph.GetName().c_str(), axis_changes.size(),
1022+ AutofuseUtils::VectorToStr(target_repeats).c_str());
1023+ std::vector<int64_t> covered_axis;
1024+ GE_ASSERT_SUCCESS(CollectCoveredUnitAxes(asc_graph, *graph_attr, covered_axis));
1025+ GE_ASSERT_SUCCESS(RestoreNoOpReshapeAxisWithSplitCoveredAxes(asc_graph, target_repeats, covered_axis, graph_attr));
1026+ GE_ASSERT_SUCCESS(ReorderAscGraphAttrsByCurrentGraphOrder(asc_graph, *graph_attr));
1027+ GELOGI("graph %s restore fused reshape axes by changes from fused AscBackend, covered axes %s before complete attrs.",
1028+ asc_graph.GetName().c_str(), AutofuseUtils::VectorToStr(covered_axis).c_str());
1029+ GE_ASSERT_SUCCESS(UpdateLoadAttrsFromSplitOutputs(asc_graph));
1030+ return SUCCESS;
1031+}
1032+ 
1033+inline Status PadLeadingUnitAxisAndCompleteAttrs(AscGraph &asc_graph, const NodePtr &asc_node,
1034+ const std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
1035+ GE_ASSERT_SUCCESS(PadLeadingUnitAxisByReshapeAxisChanges(asc_graph, asc_node, axis_changes));
1036+ if (axis_changes.empty()) {
1037+ return SUCCESS;
1038+ }
1039+ GE_ASSERT_SUCCESS(CompleteNodeAttrsOnAscGraphPreserveStrides(asc_graph, asc_node));
1040+ const auto fused_graph = AscGraphUtils::GetComputeGraph(asc_graph);
1041+ GE_ASSERT_NOTNULL(fused_graph);
1042+ GE_ASSERT_SUCCESS(DumpPadLeadingUnitAxisResult(asc_graph, asc_node, "pad_leading_unit_axis", fused_graph));
1043+ return SUCCESS;
1044+}
1045+ 
1046+inline bool IsSameReshapeAxisChange(const af::ReshapeAxisChangeInfo &lhs, const af::ReshapeAxisChangeInfo &rhs) {
1047+ return (lhs.before_axis == rhs.before_axis) && (lhs.after_axis == rhs.after_axis) &&
1048+ (lhs.before_repeats.size() == rhs.before_repeats.size()) &&
1049+ (lhs.after_repeats.size() == rhs.after_repeats.size()) &&
1050+ std::equal(lhs.before_repeats.begin(), lhs.before_repeats.end(), rhs.before_repeats.begin(), IsSameRepeat) &&
1051+ std::equal(lhs.after_repeats.begin(), lhs.after_repeats.end(), rhs.after_repeats.begin(), IsSameRepeat);
1052+}
1053+ 
1054+inline void AppendUniqueReshapeAxisChange(const af::ReshapeAxisChangeInfo &axis_change,
1055+ std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
1056+ const auto it = std::find_if(axis_changes.begin(), axis_changes.end(), [&axis_change](const auto &saved_change) {
1057+ return IsSameReshapeAxisChange(axis_change, saved_change);
1058+ });
1059+ if (it == axis_changes.end()) {
1060+ axis_changes.push_back(axis_change);
1061+ }
1062+}
1063+ 
1064+inline Status CollectNodeReshapeAxisChanges(const NodePtr &node, std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
1065+ if (!BackendUtils::IsBackendFuseNode(node)) {
1066+ return SUCCESS;
1067+ }
1068+ const auto attr = node->GetOpDescBarePtr()->GetAttrsGroup<AutoFuseAttrs>();
1069+ GE_ASSERT_NOTNULL(attr);
1070+ if (node->GetType() == kAscBackendType) {
1071+ for (const auto &axis_change : attr->GetReshapeAxisChanges()) {
1072+ AppendUniqueReshapeAxisChange(axis_change, axis_changes);
1073+ }
1074+ return SUCCESS;
1075+ }
1076+ if (node->GetType() != kFusedAscBackendType) {
1077+ return SUCCESS;
1078+ }
1079+ GE_ASSERT_NOTNULL(attr->GetFuseComputeGraph());
1080+ for (const auto &inner_node : attr->GetFuseComputeGraph()->GetAllNodes()) {
1081+ if ((inner_node == nullptr) || !BackendUtils::IsBackendFuseNode(inner_node) ||
1082+ (inner_node->GetType() != kAscBackendType)) {
1083+ continue;
1084+ }
1085+ GE_ASSERT_SUCCESS(CollectNodeReshapeAxisChanges(inner_node, axis_changes));
1086+ }
1087+ return SUCCESS;
1088+}
1089+ 
1090+inline Status PadNodeLeadingUnitAxisByReshapeAxisChanges(const NodePtr &node,
1091+ const std::vector<af::ReshapeAxisChangeInfo> &axis_changes) {
1092+ if (axis_changes.empty() || !BackendUtils::IsBackendFuseNode(node)) {
1093+ return SUCCESS;
1094+ }
1095+ const auto attr = node->GetOpDescBarePtr()->GetAttrsGroup<AutoFuseAttrs>();
1096+ GE_ASSERT_NOTNULL(attr);
1097+ if (node->GetType() == kAscBackendType) {
1098+ GE_ASSERT_NOTNULL(attr->GetAscGraph());
1099+ GE_ASSERT_SUCCESS(PadLeadingUnitAxisByReshapeAxisChanges(*(attr->GetAscGraph()), node, axis_changes));
1100+ return SUCCESS;
1101+ }
1102+ if (node->GetType() != kFusedAscBackendType) {
1103+ return SUCCESS;
1104+ }
1105+ GE_ASSERT_NOTNULL(attr->GetFuseComputeGraph());
1106+ for (const auto &inner_node : attr->GetFuseComputeGraph()->GetAllNodes()) {
1107+ if ((inner_node == nullptr) || !BackendUtils::IsBackendFuseNode(inner_node) ||
1108+ (inner_node->GetType() != kAscBackendType)) {
1109+ continue;
1110+ }
1111+ GE_ASSERT_SUCCESS(PadNodeLeadingUnitAxisByReshapeAxisChanges(inner_node, axis_changes));
1112+ }
1113+ return SUCCESS;
1114+}
1115+ 
1116+inline Status PadPairLeadingUnitAxisBeforeCompleteAttrs(const NodePtr &node1, const NodePtr &node2) {
1117+ std::vector<af::ReshapeAxisChangeInfo> axis_changes;
1118+ GE_ASSERT_SUCCESS(CollectNodeReshapeAxisChanges(node1, axis_changes));
1119+ GE_ASSERT_SUCCESS(CollectNodeReshapeAxisChanges(node2, axis_changes));
1120+ GE_ASSERT_SUCCESS(PadNodeLeadingUnitAxisByReshapeAxisChanges(node1, axis_changes));
1121+ GE_ASSERT_SUCCESS(PadNodeLeadingUnitAxisByReshapeAxisChanges(node2, axis_changes));
1122+ return SUCCESS;
1123+}
1124+ 
1125+inline bool IsInnerAscBackendNode(const NodePtr &node) {
1126+ return (node != nullptr) && BackendUtils::IsBackendFuseNode(node) && (node->GetType() == kAscBackendType);
1127+}
1128+ 
1129+inline Status KeepPaddedLeadingUnitAxis(const AscGraph &asc_graph, std::vector<int64_t> &graph_invalid_axis_id) {
1130+ const auto graph_attr = AscGraphUtils::GetComputeGraph(asc_graph)->GetAttrsGroup<AscGraphAttr>();
1131+ GE_ASSERT_NOTNULL(graph_attr);
1132+ auto padded_axis_it = std::find_if(graph_attr->axis.begin(), graph_attr->axis.end(), [](const AxisPtr &axis_info) {
1133+ return (axis_info != nullptr) && (axis_info->name.rfind("axis_padding_", 0U) == 0U);
1134+ });
1135+ if (padded_axis_it == graph_attr->axis.end()) {
1136+ return SUCCESS;
1137+ }
1138+ const auto padded_axis_id = (*padded_axis_it)->id;
1139+ auto it = std::find(graph_invalid_axis_id.begin(), graph_invalid_axis_id.end(), padded_axis_id);
1140+ if (it != graph_invalid_axis_id.end()) {
1141+ GELOGI("graph %s keep padded leading unit axis id %ld.", asc_graph.GetName().c_str(), padded_axis_id);
1142+ graph_invalid_axis_id.erase(it);
1143+ }
1144+ return SUCCESS;
1145+}
1146+ 
204inline Status UpdateInvalidIndices(const NodePtr &node, std::vector<int64_t> &graph_invalid_axis_id) {1147inline Status UpdateInvalidIndices(const NodePtr &node, std::vector<int64_t> &graph_invalid_axis_id) {
205 const auto &op_desc = node->GetOpDesc();1148 const auto &op_desc = node->GetOpDesc();
206 GE_ASSERT_NOTNULL(op_desc);1149 GE_ASSERT_NOTNULL(op_desc);
@@ -290,6 +1233,26 @@ inline Status FlashContinueGraphAxis(std::vector<AxisPtr> &axis, const std::vect
290 return SUCCESS;1233 return SUCCESS;
291}1234}
292 1235 
1236+inline Status FlashContinueAxisId(const std::vector<int64_t> &graph_invalid_axis_id, int64_t &axis_id) {
1237+ if (axis_id == af::kIdNone) {
1238+ return SUCCESS;
1239+ }
1240+ if (std::find(graph_invalid_axis_id.begin(), graph_invalid_axis_id.end(), axis_id) != graph_invalid_axis_id.end()) {
1241+ axis_id = af::kIdNone;
1242+ return SUCCESS;
1243+ }
1244+ const auto less_axis_count = std::count_if(graph_invalid_axis_id.begin(), graph_invalid_axis_id.end(),
1245+ [axis_id](int64_t id) { return id < axis_id; });
1246+ axis_id -= static_cast<int64_t>(less_axis_count);
1247+ return SUCCESS;
1248+}
1249+ 
1250+inline void RemoveAxisIds(std::vector<int64_t> &axis, const std::vector<int64_t> &graph_invalid_axis_id) {
1251+ for (const auto axis_id : graph_invalid_axis_id) {
1252+ axis.erase(std::remove(axis.begin(), axis.end(), axis_id), axis.end());
1253+ }
1254+}
1255+ 
293inline Status RemoveReduceOriginalInvalidAxis(const NodePtr &asc_node,1256inline Status RemoveReduceOriginalInvalidAxis(const NodePtr &asc_node,
294 const std::vector<int64_t> &graph_invalid_axis_id) {1257 const std::vector<int64_t> &graph_invalid_axis_id) {
295 auto attr = BackendUtils::GetNodeAutoFuseAttr(asc_node);1258 auto attr = BackendUtils::GetNodeAutoFuseAttr(asc_node);
@@ -341,6 +1304,8 @@ inline Status RemoveNodeInvalidAxis(const NodePtr &node, const std::vector<int64
341 GE_ASSERT_NOTNULL(op_desc);1304 GE_ASSERT_NOTNULL(op_desc);
342 auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();1305 auto node_attr = op_desc->GetAttrsGroup<AscNodeAttr>();
343 GE_ASSERT_NOTNULL(node_attr);1306 GE_ASSERT_NOTNULL(node_attr);
1307+ const bool loop_axis_removed = std::find(graph_invalid_axis_id.begin(), graph_invalid_axis_id.end(),
1308+ node_attr->sched.loop_axis) != graph_invalid_axis_id.end();
344 1309 
345 for (auto it = graph_invalid_axis_id.begin(); it != graph_invalid_axis_id.end(); ++it) {1310 for (auto it = graph_invalid_axis_id.begin(); it != graph_invalid_axis_id.end(); ++it) {
346 auto axis_id = *it;1311 auto axis_id = *it;
@@ -374,10 +1339,16 @@ inline Status RemoveNodeInvalidAxis(const NodePtr &node, const std::vector<int64
374 tensor_attr->repeats.erase(tensor_attr->repeats.begin() + axis_idx);1339 tensor_attr->repeats.erase(tensor_attr->repeats.begin() + axis_idx);
375 tensor_attr->strides.erase(tensor_attr->strides.begin() + axis_idx);1340 tensor_attr->strides.erase(tensor_attr->strides.begin() + axis_idx);
376 }1341 }
1342+ RemoveAxisIds(tensor_attr->vectorized_axis, graph_invalid_axis_id);
377 }1343 }
378 }1344 }
379 // 后端有连续轴约束,需要把删除后的剩余的轴从0开始重新变连续(但是轴的相对位置不变)1345 // 后端有连续轴约束,需要把删除后的剩余的轴从0开始重新变连续(但是轴的相对位置不变)
380 GE_ASSERT_SUCCESS(FlashContinueNodeAxis(node_attr->sched.axis, graph_invalid_axis_id));1346 GE_ASSERT_SUCCESS(FlashContinueNodeAxis(node_attr->sched.axis, graph_invalid_axis_id));
1347+ if (loop_axis_removed) {
1348+ node_attr->sched.loop_axis = node_attr->sched.axis.empty() ? af::kIdNone : node_attr->sched.axis.back();
1349+ } else {
1350+ GE_ASSERT_SUCCESS(FlashContinueAxisId(graph_invalid_axis_id, node_attr->sched.loop_axis));
1351+ }
381 if (BackendUtils::IsOutputNode(node)) {1352 if (BackendUtils::IsOutputNode(node)) {
382 return SUCCESS;1353 return SUCCESS;
383 }1354 }
@@ -387,6 +1358,7 @@ inline Status RemoveNodeInvalidAxis(const NodePtr &node, const std::vector<int64
387 auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();1358 auto tensor_attr = output_tensor_desc->GetAttrsGroup<AscTensorAttr>();
388 GE_ASSERT_NOTNULL(tensor_attr);1359 GE_ASSERT_NOTNULL(tensor_attr);
389 GE_ASSERT_SUCCESS(FlashContinueNodeAxis(tensor_attr->axis, graph_invalid_axis_id));1360 GE_ASSERT_SUCCESS(FlashContinueNodeAxis(tensor_attr->axis, graph_invalid_axis_id));
1361+ GE_ASSERT_SUCCESS(FlashContinueNodeAxis(tensor_attr->vectorized_axis, graph_invalid_axis_id));
390 }1362 }
391 return SUCCESS;1363 return SUCCESS;
392}1364}
@@ -612,6 +1584,7 @@ inline Status GetAndRemoveInvalidAxis(AscGraph &asc_graph, const NodePtr &asc_no
612 GE_ASSERT_SUCCESS(GetInvalidAxis(asc_graph, graph_invalid_axis_id));1584 GE_ASSERT_SUCCESS(GetInvalidAxis(asc_graph, graph_invalid_axis_id));
613 // 3、gather data2如果全是无效轴需要保留一根轴1585 // 3、gather data2如果全是无效轴需要保留一根轴
614 GE_ASSERT_SUCCESS(UpdateInvalidAxis(asc_graph, graph_invalid_axis_id, gather_data2_nodes));1586 GE_ASSERT_SUCCESS(UpdateInvalidAxis(asc_graph, graph_invalid_axis_id, gather_data2_nodes));
1587+ GE_ASSERT_SUCCESS(KeepPaddedLeadingUnitAxis(asc_graph, graph_invalid_axis_id));
615 // 4、根据需要删除的无效轴处理gather的替换轴index和gather data1588 // 4、根据需要删除的无效轴处理gather的替换轴index和gather data
616 GE_ASSERT_SUCCESS(RemoveGatherInvalidAxis(asc_graph, graph_invalid_axis_id));1589 GE_ASSERT_SUCCESS(RemoveGatherInvalidAxis(asc_graph, graph_invalid_axis_id));
617 // 5、删除和刷新无效轴(使用 std::greater<int64_t>1590 // 5、删除和刷新无效轴(使用 std::greater<int64_t>
@@ -648,9 +1621,7 @@ inline Status RemoveInvalidAxisOnAscGraph(const ComputeGraphPtr &graph, bool is_
648 GELOGD("after remove invalid axis, dump node:%s(%s) asc graph info(with tensor attr info):", node->GetNamePtr(),1621 GELOGD("after remove invalid axis, dump node:%s(%s) asc graph info(with tensor attr info):", node->GetNamePtr(),
649 node->GetType().c_str());1622 node->GetType().c_str());
650 BackendUtils::DumpAscGraph(node);1623 BackendUtils::DumpAscGraph(node);
651- } else if (1624+ } else if (node->GetType() == kFusedAscBackendType) {
652- node->GetType() ==
653- kFusedAscBackendType) { // FusedAscBackend无效轴删除解决输出多引用给两个reshape,分别在不同的位置加size为1的轴,再后融合concat场景,会反推出transpose,需要删除无效轴
654 GELOGI("FusedAscbackend node: %s(%s) start to run the process(%s).", node->GetName().c_str(),1625 GELOGI("FusedAscbackend node: %s(%s) start to run the process(%s).", node->GetName().c_str(),
655 node->GetType().c_str(), proc_name.c_str());1626 node->GetType().c_str(), proc_name.c_str());
656 GE_ASSERT_NOTNULL(node->GetOpDescBarePtr());1627 GE_ASSERT_NOTNULL(node->GetOpDescBarePtr());
@@ -213,6 +213,7 @@ GE 的融合优化走两条路线:
213**路线二:自动融合**(`compiler/graph/optimize/autofuse/`)213**路线二:自动融合**(`compiler/graph/optimize/autofuse/`)
214 214 
215基于算子分类和依赖分析,自动识别可融合的算子组合。这个子系统(`AutofuseOptimize`)在 `AfterPrecisionRefine` 阶段被调用。215基于算子分类和依赖分析,自动识别可融合的算子组合。这个子系统(`AutofuseOptimize`)在 `AfterPrecisionRefine` 阶段被调用。
216+AutoFuse 会为 reshape 记录多组 before/after axis change,后续补轴流程按 `repeat` 相对位置恢复 reshape-only 的 `repeat=1` 轴,避免将纯 reshape 轴变化误判为 transpose。
216 217 
217### 3.2 Pattern Matcher 融合框架218### 3.2 Pattern Matcher 融合框架
218 219 
@@ -316,6 +317,8 @@ Python 层会自动创建 ES `GraphBuilder`、图输入、图输出和 pattern c
316 317 
317自动融合子系统(`compiler/graph/optimize/autofuse/`)包含完整的子目录结构:`ascendc/`(AscendC 算子融合)、`ascir/`、`att/`、`codegen/`、`compiler/`、`optimize/` 等,表明它不仅做融合决策,还涉及融合后算子的代码生成——这是一条从算子分类到代码生成的完整路径。318自动融合子系统(`compiler/graph/optimize/autofuse/`)包含完整的子目录结构:`ascendc/`(AscendC 算子融合)、`ascir/`、`att/`、`codegen/`、`compiler/`、`optimize/` 等,表明它不仅做融合决策,还涉及融合后算子的代码生成——这是一条从算子分类到代码生成的完整路径。
318 319 
320+AutoFuse 后处理会在 `AscBackendSchedulerAdapter::DoBeforePass()` 中补齐 `AscGraph` 节点调度轴和 tensor 轴。对于同一个 `FusedAscBackend` 内由 reshape 减轴/加轴连接的多个 `AscBackend`,轴补齐只在该 fused 容器内传播并迭代到收敛,确保相连 `AscBackend` 的 axis 数量一致;传播不能跨不同 `FusedAscBackend`,也不能退回通用 `complete_attrs` 兜底逻辑中处理。
321+ 
319## 4. 引擎分区322## 4. 引擎分区
320 323 
321### 4.1 引擎分区的必要性324### 4.1 引擎分区的必要性
@@ -9,6 +9,7 @@
9 */9 */
10#include <gtest/gtest.h>10#include <gtest/gtest.h>
11#include <functional>11#include <functional>
12+#include "../../../../compiler/graph/optimize/autofuse/autofuse/fusion/autofuse_attrs.h"
12#include "graph/utils/graph_utils_ex.h"13#include "graph/utils/graph_utils_ex.h"
13#include "graph/attribute_group/attr_group_symbolic_desc.h"14#include "graph/attribute_group/attr_group_symbolic_desc.h"
14#include "graph/compute_graph.h"15#include "graph/compute_graph.h"
@@ -23,7 +24,6 @@
23#include "post_process/scheduler_adapter/adaption_fallback_scalar.h"24#include "post_process/scheduler_adapter/adaption_fallback_scalar.h"
24#include "post_process/asc_backend_post_processor.h"25#include "post_process/asc_backend_post_processor.h"
25#include "post_process/pass/cube_fixpip_pass.h"26#include "post_process/pass/cube_fixpip_pass.h"
26-#include "fusion/autofuse_attrs.h"
27#include "ascgen_log.h"27#include "ascgen_log.h"
28#include "attribute_group/attr_group_shape_env.h"28#include "attribute_group/attr_group_shape_env.h"
29#include "can_fuse/backend/asc_backend_fusion_decider.h"29#include "can_fuse/backend/asc_backend_fusion_decider.h"
@@ -206,6 +206,128 @@ std::shared_ptr<AscGraph> CreatAddAscGraph(ge::AscGraph &graph) {
206 compute_graph->SetGraphOutNodesInfo(output_nodes);206 compute_graph->SetGraphOutNodesInfo(output_nodes);
207 return std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph));207 return std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph));
208}208}
209+ 
210+std::shared_ptr<AscGraph> CreateReshapeAxisChangeAscGraph(ge::AscGraph &graph, std::vector<int64_t> &original_axis,
211+ std::vector<Expression> &original_repeats) {
212+ const auto one = Symbol(1);
213+ const Expression A = graph.CreateSizeVar("A");
214+ const Expression C = graph.CreateSizeVar("C");
215+ 
216+ auto a = graph.CreateAxis("A", A);
217+ auto b = graph.CreateAxis("B", one);
218+ auto c = graph.CreateAxis("C", C);
219+ original_axis = {a.id, b.id, c.id};
220+ original_repeats = {A, one, C};
221+ 
222+ auto graph_attr = AscGraphUtils::GetComputeGraph(graph)->GetAttrsGroup<AscGraphAttr>();
223+ GE_ASSERT_NOTNULL(graph_attr);
224+ graph_attr->axis.erase(std::remove_if(graph_attr->axis.begin(), graph_attr->axis.end(),
225+ [&b](const AxisPtr &axis) { return (axis != nullptr) && (axis->id == b.id); }),
226+ graph_attr->axis.end());
227+ 
228+ af::ascir_op::Data x("x", graph);
229+ x.attr.sched.axis = {a.id, c.id};
230+ x.attr.sched.loop_axis = c.id;
231+ x.y.dtype = DT_FLOAT16;
232+ *x.y.axis = {a.id, c.id};
233+ *x.y.repeats = {A, C};
234+ *x.y.strides = {C, one};
235+ 
236+ af::ascir_op::Load x_local("x_local");
237+ x_local.x = x.y;
238+ x_local.attr.sched.axis = {a.id, c.id};
239+ x_local.y.dtype = DT_FLOAT16;
240+ *x_local.y.axis = {a.id, c.id};
241+ *x_local.y.repeats = {A, C};
242+ *x_local.y.strides = {C, one};
243+ 
244+ af::ascir_op::Store x_out("x_out");
245+ x_out.x = x_local.y;
246+ x_out.attr.sched.axis = {a.id, c.id};
247+ x_out.attr.sched.loop_axis = c.id;
248+ x_out.y.dtype = DT_FLOAT16;
249+ *x_out.y.axis = {a.id, c.id};
250+ *x_out.y.repeats = {A, C};
251+ *x_out.y.strides = {C, one};
252+ 
253+ af::ascir_op::Output output("output");
254+ output.x = x_out.y;
255+ output.attr.sched.axis = {a.id, c.id};
256+ output.attr.sched.loop_axis = c.id;
257+ output.y.dtype = DT_FLOAT16;
258+ *output.y.axis = {a.id, c.id};
259+ *output.y.repeats = {A, C};
260+ *output.y.strides = {C, one};
261+ 
262+ auto output_node = graph.FindNode("output");
263+ auto compute_graph = output_node->GetOwnerComputeGraph();
264+ std::vector<std::pair<NodePtr, int32_t>> output_nodes{{output_node, 0}};
265+ compute_graph->SetOutputSize(1U);
266+ compute_graph->SetGraphOutNodesInfo(output_nodes);
267+ return std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph));
268+}
269+ 
270+std::shared_ptr<AscGraph> CreateRestoredLeadingReshapeAxisGraph(ge::AscGraph &graph) {
271+ const auto one = Symbol(1);
272+ const auto size0 = Symbol(22);
273+ const auto size1 = Symbol(15120);
274+ auto z0 = graph.CreateAxis("z0", size0);
275+ auto z1 = graph.CreateAxis("z1", size1);
276+ 
277+ auto reshape_padding = ComGraphMakeShared<Axis>();
278+ GE_ASSERT_NOTNULL(reshape_padding);
279+ reshape_padding->id = 2;
280+ reshape_padding->name = "reshape_axis_padding_2";
281+ reshape_padding->type = Axis::kAxisTypeOriginal;
282+ reshape_padding->size = one;
283+ auto graph_attr = AscGraphUtils::GetComputeGraph(graph)->GetAttrsGroup<AscGraphAttr>();
284+ GE_ASSERT_NOTNULL(graph_attr);
285+ graph_attr->axis = {reshape_padding, graph_attr->axis[0], graph_attr->axis[1]};
286+ 
287+ const std::vector<int64_t> axis = {reshape_padding->id, z0.id, z1.id};
288+ af::ascir_op::Data x("x", graph);
289+ x.attr.sched.axis = axis;
290+ x.attr.sched.loop_axis = z1.id;
291+ x.y.dtype = DT_FLOAT16;
292+ *x.y.axis = axis;
293+ *x.y.repeats = {one, size0, size1};
294+ *x.y.strides = {Symbol(0), size1, one};
295+ 
296+ af::ascir_op::Load x_local("x_local");
297+ x_local.x = x.y;
298+ x_local.attr.sched.axis = axis;
299+ x_local.attr.sched.loop_axis = z1.id;
300+ x_local.y.dtype = DT_FLOAT16;
301+ *x_local.y.axis = axis;
302+ *x_local.y.repeats = {one, size0, size1};
303+ *x_local.y.strides = {Symbol(0), size1, one};
304+ 
305+ af::ascir_op::Store x_out("x_out");
306+ x_out.x = x_local.y;
307+ x_out.attr.sched.axis = axis;
308+ x_out.attr.sched.loop_axis = z1.id;
309+ x_out.y.dtype = DT_FLOAT16;
310+ *x_out.y.axis = axis;
311+ *x_out.y.repeats = {one, size0, size1};
312+ *x_out.y.strides = {Symbol(0), size1, one};
313+ 
314+ af::ascir_op::Output output("output");
315+ output.x = x_out.y;
316+ output.attr.sched.axis = axis;
317+ output.attr.sched.loop_axis = z1.id;
318+ output.y.dtype = DT_FLOAT16;
319+ *output.y.axis = {};
320+ *output.y.repeats = {};
321+ *output.y.strides = {};
322+ 
323+ auto output_node = graph.FindNode("output");
324+ auto compute_graph = output_node->GetOwnerComputeGraph();
325+ std::vector<std::pair<NodePtr, int32_t>> output_nodes{{output_node, 0}};
326+ compute_graph->SetOutputSize(1U);
327+ compute_graph->SetGraphOutNodesInfo(output_nodes);
328+ return std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph));
329+}
330+ 
209/*331/*
210 * data332 * data
211 * / \333 * / \
@@ -15862,6 +15984,595 @@ TEST_F(AscBackendPostProcessorTest, GatherInsertCastImproveprecision) {
15862 EXPECT_NE(cnt, 2);15984 EXPECT_NE(cnt, 2);
15863}15985}
15864 15986 
15987+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_RestoreReshapeAxisChangeInfo) {
15988+ GraphBuilder builder("reshape_outer");
15989+ auto asc_backend = builder.AddNode("reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {2, 3});
15990+ ASSERT_NE(asc_backend, nullptr);
15991+ const auto attr = GetOrCreateAutoFuseAttrs(asc_backend->GetOpDesc());
15992+ ASSERT_NE(attr, nullptr);
15993+ 
15994+ ge::AscGraph reshape_graph("reshape_reduced_axis");
15995+ std::vector<int64_t> original_axis;
15996+ std::vector<Expression> original_repeats;
15997+ attr->SetAscGraph(CreateReshapeAxisChangeAscGraph(reshape_graph, original_axis, original_repeats),
15998+ loop::FuseType::kReshape);
15999+ af::ReshapeAxisChangeInfo change;
16000+ change.before_axis = original_axis;
16001+ change.before_repeats = original_repeats;
16002+ change.after_axis = {original_axis[0], original_axis[2]};
16003+ change.after_repeats = {original_repeats[0], original_repeats[2]};
16004+ attr->AddReshapeAxisChange(change);
16005+ 
16006+ const auto graph_attr = AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
16007+ ASSERT_NE(graph_attr, nullptr);
16008+ ASSERT_EQ(graph_attr->axis.size(), 2U);
16009+ 
16010+ EXPECT_EQ(
16011+ asc_adapt::PadLeadingUnitAxisAndCompleteAttrs(*(attr->GetAscGraph()), asc_backend, attr->GetReshapeAxisChanges()),
16012+ SUCCESS);
16013+ 
16014+ std::vector<int64_t> graph_axis;
16015+ for (const auto &axis : graph_attr->axis) {
16016+ ASSERT_NE(axis, nullptr);
16017+ graph_axis.push_back(axis->id);
16018+ }
16019+ ASSERT_EQ(graph_axis.size(), original_axis.size());
16020+ EXPECT_EQ(graph_axis[0], original_axis[0]);
16021+ EXPECT_EQ(graph_axis[1], original_axis[1]);
16022+ EXPECT_EQ(graph_axis[2], original_axis[2]);
16023+ 
16024+ const auto store = AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->FindNode("x_out");
16025+ ASSERT_NE(store, nullptr);
16026+ AscTensorAttr *store_attr = nullptr;
16027+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store, store_attr), SUCCESS);
16028+ ASSERT_NE(store_attr, nullptr);
16029+ EXPECT_EQ(store_attr->axis, graph_axis);
16030+ ASSERT_EQ(store_attr->repeats.size(), original_repeats.size());
16031+ ASSERT_EQ(store_attr->strides.size(), original_repeats.size());
16032+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->repeats[1]));
16033+ EXPECT_TRUE(BackendUtils::IsEqZero(store_attr->strides[1]));
16034+}
16035+ 
16036+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_RestoreSingleLeadingUnitReshapeAsNoOp) {
16037+ GraphBuilder builder("single_leading_unit_reshape_outer");
16038+ auto asc_backend =
16039+ builder.AddNode("single_leading_unit_reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {22, 15120});
16040+ ASSERT_NE(asc_backend, nullptr);
16041+ const auto attr = GetOrCreateAutoFuseAttrs(asc_backend->GetOpDesc());
16042+ ASSERT_NE(attr, nullptr);
16043+ 
16044+ ge::AscGraph graph("single_leading_unit_reshape_graph");
16045+ const auto one = Symbol(1);
16046+ const auto size0 = Symbol(22);
16047+ const auto size1 = Symbol(15120);
16048+ auto z0 = graph.CreateAxis("z0", size0);
16049+ auto z1 = graph.CreateAxis("z1", size1);
16050+ const std::vector<int64_t> graph_axis = {z0.id, z1.id};
16051+ 
16052+ af::ascir_op::Data data("single_data", graph);
16053+ data.attr.sched.axis = graph_axis;
16054+ data.y.dtype = DT_FLOAT16;
16055+ *data.y.axis = graph_axis;
16056+ *data.y.repeats = {size0, size1};
16057+ *data.y.strides = {size1, one};
16058+ 
16059+ af::ascir_op::Load load("single_load");
16060+ load.x = data.y;
16061+ load.attr.sched.axis = graph_axis;
16062+ load.y.dtype = DT_FLOAT16;
16063+ *load.y.axis = graph_axis;
16064+ *load.y.repeats = {size0, size1};
16065+ *load.y.strides = {size1, one};
16066+ 
16067+ af::ascir_op::Store store("single_store");
16068+ store.x = load.y;
16069+ store.attr.sched.axis = graph_axis;
16070+ store.y.dtype = DT_FLOAT16;
16071+ *store.y.axis = graph_axis;
16072+ *store.y.repeats = {size0, size1};
16073+ *store.y.strides = {size1, one};
16074+ 
16075+ af::ascir_op::Output output("single_output");
16076+ output.x = store.y;
16077+ output.attr.sched.axis = graph_axis;
16078+ auto output_node = graph.FindNode("single_output");
16079+ ASSERT_NE(output_node, nullptr);
16080+ auto compute_graph = output_node->GetOwnerComputeGraph();
16081+ std::vector<std::pair<NodePtr, int32_t>> output_nodes{{output_node, 0}};
16082+ compute_graph->SetOutputSize(1U);
16083+ compute_graph->SetGraphOutNodesInfo(output_nodes);
16084+ attr->SetAscGraph(std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph)), loop::FuseType::kPointwise);
16085+ 
16086+ af::ReshapeAxisChangeInfo change;
16087+ change.before_axis = {0, 1, 2};
16088+ change.before_repeats = {one, size0, size1};
16089+ change.after_axis = {0, 1};
16090+ change.after_repeats = {size0, size1};
16091+ attr->AddReshapeAxisChange(change);
16092+ 
16093+ ASSERT_EQ(
16094+ asc_adapt::PadLeadingUnitAxisAndCompleteAttrs(*(attr->GetAscGraph()), asc_backend, attr->GetReshapeAxisChanges()),
16095+ SUCCESS);
16096+ 
16097+ const auto completed_graph_attr =
16098+ AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
16099+ ASSERT_NE(completed_graph_attr, nullptr);
16100+ std::vector<int64_t> completed_graph_axis;
16101+ for (const auto &axis : completed_graph_attr->axis) {
16102+ ASSERT_NE(axis, nullptr);
16103+ completed_graph_axis.push_back(axis->id);
16104+ }
16105+ ASSERT_EQ(completed_graph_attr->axis.size(), 3U);
16106+ EXPECT_EQ(completed_graph_axis, std::vector<int64_t>({0, 1, 2}));
16107+ EXPECT_TRUE(BackendUtils::IsEqOne(completed_graph_attr->axis[0]->size));
16108+ EXPECT_EQ(std::string(completed_graph_attr->axis[1]->size.Str().get()), "22");
16109+ EXPECT_EQ(std::string(completed_graph_attr->axis[2]->size.Str().get()), "15120");
16110+ 
16111+ auto load_node = attr->GetAscGraph()->FindNode("single_load");
16112+ ASSERT_NE(load_node, nullptr);
16113+ AscTensorAttr *load_attr = nullptr;
16114+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(load_node, load_attr), SUCCESS);
16115+ ASSERT_NE(load_attr, nullptr);
16116+ EXPECT_EQ(load_attr->axis, completed_graph_axis);
16117+ ASSERT_EQ(load_attr->repeats.size(), 3U);
16118+ EXPECT_TRUE(BackendUtils::IsEqOne(load_attr->repeats[0]));
16119+ EXPECT_EQ(std::string(load_attr->repeats[1].Str().get()), "22");
16120+ EXPECT_EQ(std::string(load_attr->repeats[2].Str().get()), "15120");
16121+ 
16122+ auto store_node = attr->GetAscGraph()->FindNode("single_store");
16123+ ASSERT_NE(store_node, nullptr);
16124+ AscTensorAttr *store_attr = nullptr;
16125+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store_node, store_attr), SUCCESS);
16126+ ASSERT_NE(store_attr, nullptr);
16127+ EXPECT_EQ(store_attr->axis, completed_graph_axis);
16128+ ASSERT_EQ(store_attr->repeats.size(), 3U);
16129+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->repeats[0]));
16130+ EXPECT_EQ(std::string(store_attr->repeats[1].Str().get()), "22");
16131+ EXPECT_EQ(std::string(store_attr->repeats[2].Str().get()), "15120");
16132+}
16133+ 
16134+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_RestoreReshapeAxisByBestOverlap) {
16135+ GraphBuilder builder("best_overlap_reshape_outer");
16136+ auto asc_backend =
16137+ builder.AddNode("best_overlap_reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {4, 15120});
16138+ ASSERT_NE(asc_backend, nullptr);
16139+ const auto attr = GetOrCreateAutoFuseAttrs(asc_backend->GetOpDesc());
16140+ ASSERT_NE(attr, nullptr);
16141+ 
16142+ ge::AscGraph graph("best_overlap_reshape_graph");
16143+ const auto one = Symbol(1);
16144+ const auto size0 = Symbol(4);
16145+ const auto size1 = Symbol(15120);
16146+ auto z0 = graph.CreateAxis("z0", size0);
16147+ auto z1 = graph.CreateAxis("z1", size1);
16148+ const std::vector<int64_t> graph_axis = {z0.id, z1.id};
16149+ 
16150+ af::ascir_op::Data data("best_overlap_data", graph);
16151+ data.attr.sched.axis = graph_axis;
16152+ data.y.dtype = DT_FLOAT16;
16153+ *data.y.axis = graph_axis;
16154+ *data.y.repeats = {size0, size1};
16155+ *data.y.strides = {size1, one};
16156+ 
16157+ af::ascir_op::Load load("best_overlap_load");
16158+ load.x = data.y;
16159+ load.attr.sched.axis = graph_axis;
16160+ load.y.dtype = DT_FLOAT16;
16161+ *load.y.axis = graph_axis;
16162+ *load.y.repeats = {size0, size1};
16163+ *load.y.strides = {size1, one};
16164+ 
16165+ af::ascir_op::Store store("best_overlap_store");
16166+ store.x = load.y;
16167+ store.attr.sched.axis = graph_axis;
16168+ store.y.dtype = DT_FLOAT16;
16169+ *store.y.axis = graph_axis;
16170+ *store.y.repeats = {size0, size1};
16171+ *store.y.strides = {size1, one};
16172+ attr->SetAscGraph(std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph)), loop::FuseType::kPointwise);
16173+ 
16174+ af::ReshapeAxisChangeInfo change;
16175+ change.before_axis = {0, 1, 2};
16176+ change.before_repeats = {one, one, one};
16177+ change.after_axis = {0, 1};
16178+ change.after_repeats = {one, one};
16179+ attr->AddReshapeAxisChange(change);
16180+ 
16181+ ASSERT_EQ(
16182+ asc_adapt::PadLeadingUnitAxisAndCompleteAttrs(*(attr->GetAscGraph()), asc_backend, attr->GetReshapeAxisChanges()),
16183+ SUCCESS);
16184+ 
16185+ const auto completed_graph_attr =
16186+ AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
16187+ ASSERT_NE(completed_graph_attr, nullptr);
16188+ ASSERT_EQ(completed_graph_attr->axis.size(), 3U);
16189+ EXPECT_EQ(completed_graph_attr->axis[0]->id, 0);
16190+ EXPECT_EQ(completed_graph_attr->axis[1]->id, 1);
16191+ EXPECT_EQ(completed_graph_attr->axis[2]->id, 2);
16192+ EXPECT_TRUE(BackendUtils::IsEqOne(completed_graph_attr->axis[0]->size));
16193+ EXPECT_EQ(std::string(completed_graph_attr->axis[1]->size.Str().get()), "4");
16194+ EXPECT_EQ(std::string(completed_graph_attr->axis[2]->size.Str().get()), "15120");
16195+ 
16196+ auto store_node = attr->GetAscGraph()->FindNode("best_overlap_store");
16197+ ASSERT_NE(store_node, nullptr);
16198+ AscTensorAttr *store_attr = nullptr;
16199+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store_node, store_attr), SUCCESS);
16200+ ASSERT_NE(store_attr, nullptr);
16201+ EXPECT_EQ(store_attr->axis, std::vector<int64_t>({0, 1, 2}));
16202+ ASSERT_EQ(store_attr->repeats.size(), 3U);
16203+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->repeats[0]));
16204+ EXPECT_EQ(std::string(store_attr->repeats[1].Str().get()), "4");
16205+ EXPECT_EQ(std::string(store_attr->repeats[2].Str().get()), "15120");
16206+ ASSERT_EQ(store_attr->strides.size(), 3U);
16207+ EXPECT_TRUE(BackendUtils::IsEqZero(store_attr->strides[0]));
16208+ EXPECT_EQ(std::string(store_attr->strides[1].Str().get()), "15120");
16209+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->strides[2]));
16210+}
16211+ 
16212+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_RestoreMultipleReshapeAxisChangesIdempotently) {
16213+ GraphBuilder builder("multi_reshape_outer");
16214+ auto asc_backend =
16215+ builder.AddNode("multi_reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {22, 15120, 1});
16216+ ASSERT_NE(asc_backend, nullptr);
16217+ const auto attr = GetOrCreateAutoFuseAttrs(asc_backend->GetOpDesc());
16218+ ASSERT_NE(attr, nullptr);
16219+ 
16220+ ge::AscGraph graph("multi_reshape_axis_graph");
16221+ auto z0 = graph.CreateAxis("z0", Symbol(22));
16222+ auto z1 = graph.CreateAxis("z1", Symbol(15120));
16223+ auto z2 = graph.CreateAxis("z2", Symbol(1));
16224+ af::ascir_op::Data data("data", graph);
16225+ data.attr.sched.axis = {z0.id, z1.id, z2.id};
16226+ data.y.dtype = DT_FLOAT16;
16227+ *data.y.axis = {z0.id, z1.id, z2.id};
16228+ *data.y.repeats = {Symbol(22), Symbol(15120), Symbol(1)};
16229+ *data.y.strides = {Symbol(15120), Symbol(1), Symbol(0)};
16230+ 
16231+ af::ascir_op::Load load("load");
16232+ load.x = data.y;
16233+ load.attr.sched.axis = {z0.id, z1.id, z2.id};
16234+ load.y.dtype = DT_FLOAT16;
16235+ *load.y.axis = {z0.id, z1.id, z2.id};
16236+ *load.y.repeats = {Symbol(22), Symbol(15120), Symbol(1)};
16237+ *load.y.strides = {Symbol(15120), Symbol(1), Symbol(0)};
16238+ 
16239+ af::ascir_op::Store store("store");
16240+ store.x = load.y;
16241+ store.attr.sched.axis = {z0.id, z1.id, z2.id};
16242+ store.y.dtype = DT_FLOAT16;
16243+ *store.y.axis = {z0.id, z1.id, z2.id};
16244+ *store.y.repeats = {Symbol(22), Symbol(15120), Symbol(1)};
16245+ *store.y.strides = {Symbol(15120), Symbol(1), Symbol(0)};
16246+ attr->SetAscGraph(std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph)), loop::FuseType::kPointwise);
16247+ 
16248+ af::ReshapeAxisChangeInfo squeeze_change;
16249+ squeeze_change.before_axis = {0, 1, 2};
16250+ squeeze_change.before_repeats = {Symbol(1), Symbol(22), Symbol(15120)};
16251+ squeeze_change.after_axis = {0, 1};
16252+ squeeze_change.after_repeats = {Symbol(22), Symbol(15120)};
16253+ attr->AddReshapeAxisChange(squeeze_change);
16254+ 
16255+ af::ReshapeAxisChangeInfo unsqueeze_change;
16256+ unsqueeze_change.before_axis = {0, 1};
16257+ unsqueeze_change.before_repeats = {Symbol(22), Symbol(15120)};
16258+ unsqueeze_change.after_axis = {0, 1, 2};
16259+ unsqueeze_change.after_repeats = {Symbol(22), Symbol(15120), Symbol(1)};
16260+ attr->AddReshapeAxisChange(unsqueeze_change);
16261+ 
16262+ ASSERT_EQ(
16263+ asc_adapt::PadLeadingUnitAxisAndCompleteAttrs(*(attr->GetAscGraph()), asc_backend, attr->GetReshapeAxisChanges()),
16264+ SUCCESS);
16265+ auto graph_attr = AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
16266+ ASSERT_NE(graph_attr, nullptr);
16267+ ASSERT_EQ(graph_attr->axis.size(), 4U);
16268+ 
16269+ ASSERT_EQ(
16270+ asc_adapt::PadLeadingUnitAxisAndCompleteAttrs(*(attr->GetAscGraph()), asc_backend, attr->GetReshapeAxisChanges()),
16271+ SUCCESS);
16272+ graph_attr = AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
16273+ ASSERT_NE(graph_attr, nullptr);
16274+ EXPECT_EQ(graph_attr->axis.size(), 4U);
16275+ 
16276+ std::vector<int64_t> graph_axis_after_second_pad;
16277+ for (const auto &axis : graph_attr->axis) {
16278+ ASSERT_NE(axis, nullptr);
16279+ graph_axis_after_second_pad.push_back(axis->id);
16280+ }
16281+ auto store_node = attr->GetAscGraph()->FindNode("store");
16282+ ASSERT_NE(store_node, nullptr);
16283+ AscTensorAttr *store_attr = nullptr;
16284+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store_node, store_attr), SUCCESS);
16285+ ASSERT_NE(store_attr, nullptr);
16286+ EXPECT_EQ(store_attr->axis, graph_axis_after_second_pad);
16287+ EXPECT_EQ(store_attr->axis.size(), 4U);
16288+ EXPECT_EQ(store_attr->repeats.size(), 4U);
16289+ EXPECT_EQ(store_attr->strides.size(), 4U);
16290+}
16291+ 
16292+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_RestoreMixedReshapeDoesNotDuplicateTensorAxis) {
16293+ GraphBuilder builder("mixed_reshape_outer");
16294+ auto asc_backend =
16295+ builder.AddNode("mixed_reshape_backend", kAscBackendType, 2, 1, FORMAT_ND, DT_FLOAT16, {22, 15120, 1});
16296+ ASSERT_NE(asc_backend, nullptr);
16297+ const auto attr = GetOrCreateAutoFuseAttrs(asc_backend->GetOpDesc());
16298+ ASSERT_NE(attr, nullptr);
16299+ 
16300+ ge::AscGraph graph("mixed_reshape_axis_graph");
16301+ const auto one = Symbol(1);
16302+ const auto size0 = Symbol(22);
16303+ const auto size1 = Symbol(15120);
16304+ auto z0 = graph.CreateAxis("z0", size0);
16305+ auto z1 = graph.CreateAxis("z1", size1);
16306+ auto z2 = graph.CreateAxis("z2", one);
16307+ const std::vector<int64_t> graph_axis = {z0.id, z1.id, z2.id};
16308+ 
16309+ af::ascir_op::Data data0("mixed_data0", graph);
16310+ data0.attr.sched.axis = graph_axis;
16311+ data0.y.dtype = DT_FLOAT16;
16312+ *data0.y.axis = graph_axis;
16313+ *data0.y.repeats = {size0, size1, one};
16314+ *data0.y.strides = {size1, one, Symbol(0)};
16315+ 
16316+ af::ascir_op::Load load0("mixed_load0");
16317+ load0.x = data0.y;
16318+ load0.attr.sched.axis = graph_axis;
16319+ load0.y.dtype = DT_FLOAT16;
16320+ *load0.y.axis = graph_axis;
16321+ *load0.y.repeats = {size0, size1, one};
16322+ *load0.y.strides = {size1, one, Symbol(0)};
16323+ 
16324+ af::ascir_op::Data data1("mixed_data1", graph);
16325+ data1.attr.sched.axis = graph_axis;
16326+ data1.y.dtype = DT_FLOAT16;
16327+ *data1.y.axis = graph_axis;
16328+ *data1.y.repeats = {one, size1, one};
16329+ *data1.y.strides = {Symbol(0), one, Symbol(0)};
16330+ 
16331+ af::ascir_op::Load load1("mixed_load1");
16332+ load1.x = data1.y;
16333+ load1.attr.sched.axis = graph_axis;
16334+ load1.y.dtype = DT_FLOAT16;
16335+ *load1.y.axis = graph_axis;
16336+ *load1.y.repeats = {one, size1, one};
16337+ *load1.y.strides = {Symbol(0), one, Symbol(0)};
16338+ 
16339+ af::ascir_op::Add add("mixed_add");
16340+ add.x1 = load1.y;
16341+ add.x2 = load0.y;
16342+ add.attr.sched.axis = graph_axis;
16343+ add.y.dtype = DT_FLOAT16;
16344+ *add.y.axis = {};
16345+ *add.y.repeats = {};
16346+ *add.y.strides = {};
16347+ 
16348+ af::ascir_op::Store store("mixed_store");
16349+ store.x = add.y;
16350+ store.attr.sched.axis = graph_axis;
16351+ store.y.dtype = DT_FLOAT16;
16352+ *store.y.axis = graph_axis;
16353+ *store.y.repeats = {size0, size1, one};
16354+ *store.y.strides = {size1, one, Symbol(0)};
16355+ 
16356+ af::ascir_op::Output output("mixed_output");
16357+ output.x = store.y;
16358+ output.attr.sched.axis = graph_axis;
16359+ *output.y.axis = {};
16360+ *output.y.repeats = {};
16361+ *output.y.strides = {};
16362+ auto output_node = graph.FindNode("mixed_output");
16363+ ASSERT_NE(output_node, nullptr);
16364+ auto compute_graph = output_node->GetOwnerComputeGraph();
16365+ std::vector<std::pair<NodePtr, int32_t>> output_nodes{{output_node, 0}};
16366+ compute_graph->SetOutputSize(1U);
16367+ compute_graph->SetGraphOutNodesInfo(output_nodes);
16368+ attr->SetAscGraph(std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph)), loop::FuseType::kPointwise);
16369+ 
16370+ af::ReshapeAxisChangeInfo squeeze_change;
16371+ squeeze_change.before_axis = {0, 1, 2};
16372+ squeeze_change.before_repeats = {one, size0, size1};
16373+ squeeze_change.after_axis = {0, 1};
16374+ squeeze_change.after_repeats = {size0, size1};
16375+ attr->AddReshapeAxisChange(squeeze_change);
16376+ 
16377+ af::ReshapeAxisChangeInfo unsqueeze_change;
16378+ unsqueeze_change.before_axis = {0, 1};
16379+ unsqueeze_change.before_repeats = {size0, size1};
16380+ unsqueeze_change.after_axis = {0, 1, 2};
16381+ unsqueeze_change.after_repeats = {size0, size1, one};
16382+ attr->AddReshapeAxisChange(unsqueeze_change);
16383+ 
16384+ ASSERT_EQ(
16385+ asc_adapt::PadLeadingUnitAxisAndCompleteAttrs(*(attr->GetAscGraph()), asc_backend, attr->GetReshapeAxisChanges()),
16386+ SUCCESS);
16387+ ASSERT_EQ(asc_adapt::CompleteNodeAttrsOnAscGraph(*(attr->GetAscGraph()), asc_backend), SUCCESS);
16388+ 
16389+ const auto completed_graph_attr =
16390+ AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
16391+ ASSERT_NE(completed_graph_attr, nullptr);
16392+ std::vector<int64_t> completed_graph_axis;
16393+ for (const auto &axis : completed_graph_attr->axis) {
16394+ ASSERT_NE(axis, nullptr);
16395+ completed_graph_axis.push_back(axis->id);
16396+ }
16397+ ASSERT_EQ(completed_graph_attr->axis.size(), 4U);
16398+ EXPECT_TRUE(BackendUtils::IsEqOne(completed_graph_attr->axis[0]->size));
16399+ EXPECT_EQ(std::string(completed_graph_attr->axis[1]->size.Str().get()), "22");
16400+ EXPECT_EQ(std::string(completed_graph_attr->axis[2]->size.Str().get()), "15120");
16401+ EXPECT_TRUE(BackendUtils::IsEqOne(completed_graph_attr->axis[3]->size));
16402+ 
16403+ auto load_node = attr->GetAscGraph()->FindNode("mixed_load0");
16404+ ASSERT_NE(load_node, nullptr);
16405+ AscTensorAttr *load_attr = nullptr;
16406+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(load_node, load_attr), SUCCESS);
16407+ ASSERT_NE(load_attr, nullptr);
16408+ EXPECT_EQ(load_attr->axis, completed_graph_axis);
16409+ EXPECT_EQ(load_attr->axis.size(), load_attr->repeats.size());
16410+ EXPECT_EQ(load_attr->axis.size(), load_attr->strides.size());
16411+ ASSERT_EQ(load_attr->repeats.size(), 4U);
16412+ EXPECT_TRUE(BackendUtils::IsEqOne(load_attr->repeats[0]));
16413+ EXPECT_EQ(std::string(load_attr->repeats[1].Str().get()), "22");
16414+ EXPECT_EQ(std::string(load_attr->repeats[2].Str().get()), "15120");
16415+ EXPECT_TRUE(BackendUtils::IsEqOne(load_attr->repeats[3]));
16416+ 
16417+ auto add_node = attr->GetAscGraph()->FindNode("mixed_add");
16418+ ASSERT_NE(add_node, nullptr);
16419+ AscTensorAttr *add_attr = nullptr;
16420+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(add_node, add_attr), SUCCESS);
16421+ ASSERT_NE(add_attr, nullptr);
16422+ EXPECT_EQ(add_attr->axis, completed_graph_axis);
16423+ EXPECT_EQ(add_attr->axis.size(), add_attr->repeats.size());
16424+ EXPECT_EQ(add_attr->axis.size(), add_attr->strides.size());
16425+ ASSERT_EQ(add_attr->repeats.size(), 4U);
16426+ EXPECT_TRUE(BackendUtils::IsEqOne(add_attr->repeats[0]));
16427+ EXPECT_EQ(std::string(add_attr->repeats[1].Str().get()), "22");
16428+ EXPECT_EQ(std::string(add_attr->repeats[2].Str().get()), "15120");
16429+ EXPECT_TRUE(BackendUtils::IsEqOne(add_attr->repeats[3]));
16430+}
16431+ 
16432+TEST_F(AscBackendPostProcessorTest, FlushSubGraphAxisInfo_MapsReshapePaddingAxisId) {
16433+ GraphBuilder builder("reshape_padding_flush_outer");
16434+ auto asc_backend = builder.AddNode("reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {22, 15120});
16435+ ASSERT_NE(asc_backend, nullptr);
16436+ const auto attr = GetOrCreateAutoFuseAttrs(asc_backend->GetOpDesc());
16437+ ASSERT_NE(attr, nullptr);
16438+ 
16439+ ge::AscGraph graph("reshape_padding_flush_graph");
16440+ const auto one = Symbol(1);
16441+ const auto size0 = Symbol(22);
16442+ const auto size1 = Symbol(15120);
16443+ auto z0 = graph.CreateAxis("z0", size0);
16444+ auto z1 = graph.CreateAxis("z1", size1);
16445+ const int64_t reshape_padding_id = 3;
16446+ auto reshape_padding = ComGraphMakeShared<Axis>();
16447+ ASSERT_NE(reshape_padding, nullptr);
16448+ reshape_padding->id = reshape_padding_id;
16449+ reshape_padding->name = "reshape_axis_padding_3";
16450+ reshape_padding->type = Axis::kAxisTypeOriginal;
16451+ reshape_padding->size = one;
16452+ auto graph_attr = AscGraphUtils::GetComputeGraph(graph)->GetAttrsGroup<AscGraphAttr>();
16453+ ASSERT_NE(graph_attr, nullptr);
16454+ graph_attr->axis = {reshape_padding, graph_attr->axis[0], graph_attr->axis[1]};
16455+ const std::vector<int64_t> reshape_axis = {reshape_padding->id, z0.id, z1.id};
16456+ 
16457+ af::ascir_op::Data data("data", graph);
16458+ data.attr.sched.axis = reshape_axis;
16459+ data.attr.sched.loop_axis = reshape_padding->id;
16460+ data.y.dtype = DT_FLOAT16;
16461+ *data.y.axis = reshape_axis;
16462+ *data.y.repeats = {one, size0, size1};
16463+ *data.y.strides = {Symbol(0), size1, one};
16464+ *data.y.vectorized_axis = reshape_axis;
16465+ 
16466+ af::ascir_op::Load load("load");
16467+ load.x = data.y;
16468+ load.attr.sched.axis = reshape_axis;
16469+ load.attr.sched.loop_axis = reshape_padding->id;
16470+ load.y.dtype = DT_FLOAT16;
16471+ *load.y.axis = reshape_axis;
16472+ *load.y.repeats = {one, size0, size1};
16473+ *load.y.strides = {Symbol(0), size1, one};
16474+ *load.y.vectorized_axis = reshape_axis;
16475+ 
16476+ af::ascir_op::Store store("store");
16477+ store.x = load.y;
16478+ store.attr.sched.axis = reshape_axis;
16479+ store.attr.sched.loop_axis = reshape_padding->id;
16480+ store.y.dtype = DT_FLOAT16;
16481+ *store.y.axis = reshape_axis;
16482+ *store.y.repeats = {one, size0, size1};
16483+ *store.y.strides = {Symbol(0), size1, one};
16484+ *store.y.vectorized_axis = reshape_axis;
16485+ 
16486+ af::ascir_op::Output output("output");
16487+ output.x = store.y;
16488+ output.attr.sched.axis = reshape_axis;
16489+ output.attr.sched.loop_axis = reshape_padding->id;
16490+ output.y.dtype = DT_FLOAT16;
16491+ auto output_node = graph.FindNode("output");
16492+ ASSERT_NE(output_node, nullptr);
16493+ auto compute_graph = output_node->GetOwnerComputeGraph();
16494+ std::vector<std::pair<NodePtr, int32_t>> output_nodes{{output_node, 0}};
16495+ compute_graph->SetOutputSize(1U);
16496+ compute_graph->SetGraphOutNodesInfo(output_nodes);
16497+ attr->SetAscGraph(std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph)), loop::FuseType::kReshape);
16498+ 
16499+ AxisPairSet node_map;
16500+ node_map.insert({reshape_padding->id, 2});
16501+ node_map.insert({z0.id, z0.id});
16502+ node_map.insert({z1.id, z1.id});
16503+ AscGraphAxisMapping graph_axis_map;
16504+ ASSERT_EQ(graph_axis_map.FlushSubGraphAxisInfo(asc_backend, node_map, true), SUCCESS);
16505+ 
16506+ graph_attr = AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
16507+ ASSERT_NE(graph_attr, nullptr);
16508+ ASSERT_EQ(graph_attr->axis.size(), 3U);
16509+ EXPECT_EQ(graph_attr->axis[0]->id, 2);
16510+ EXPECT_EQ(graph_attr->axis[0]->name, "reshape_axis_padding_3");
16511+ 
16512+ auto load_node = attr->GetAscGraph()->FindNode("load");
16513+ ASSERT_NE(load_node, nullptr);
16514+ const auto load_node_attr = load_node->GetOpDesc()->GetAttrsGroup<AscNodeAttr>();
16515+ ASSERT_NE(load_node_attr, nullptr);
16516+ EXPECT_EQ(load_node_attr->sched.axis, std::vector<int64_t>({2, 0, 1}));
16517+ EXPECT_EQ(load_node_attr->sched.loop_axis, 2);
16518+ AscTensorAttr *load_attr = nullptr;
16519+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(load_node, load_attr), SUCCESS);
16520+ ASSERT_NE(load_attr, nullptr);
16521+ EXPECT_EQ(load_attr->axis, std::vector<int64_t>({2, 0, 1}));
16522+ EXPECT_EQ(load_attr->vectorized_axis, std::vector<int64_t>({2, 0, 1}));
16523+}
16524+ 
16525+TEST_F(AscBackendPostProcessorTest, FlushReshapeAxisChanges_RemapMissingUnitAxisByPosition) {
16526+ GraphBuilder builder("reshape_flush_outer");
16527+ auto asc_backend = builder.AddNode("reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {22, 15120});
16528+ ASSERT_NE(asc_backend, nullptr);
16529+ const auto attr = GetOrCreateAutoFuseAttrs(asc_backend->GetOpDesc());
16530+ ASSERT_NE(attr, nullptr);
16531+ 
16532+ af::ReshapeAxisChangeInfo change;
16533+ change.before_axis = {2, 0, 1};
16534+ change.before_repeats = {Symbol(1), Symbol(22), Symbol(15120)};
16535+ change.after_axis = {0, 1};
16536+ change.after_repeats = {Symbol(22), Symbol(15120)};
16537+ attr->AddReshapeAxisChange(change);
16538+ 
16539+ ASSERT_EQ(BackendUtils::FlushReshapeAxisChanges(asc_backend, asc_backend, {3, 0, 1}, {4, 0, 1}), SUCCESS);
16540+ 
16541+ const auto &changes = attr->GetReshapeAxisChanges();
16542+ ASSERT_EQ(changes.size(), 1U);
16543+ EXPECT_EQ(changes[0].before_axis, std::vector<int64_t>({4, 0, 1}));
16544+ EXPECT_EQ(changes[0].after_axis, std::vector<int64_t>({0, 1}));
16545+}
16546+ 
16547+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_KeepsLeadingReshapePaddingAfterConcatPadding) {
16548+ GraphBuilder builder("reshape_padding_outer");
16549+ auto asc_backend = builder.AddNode("reshape_backend", kAscBackendType, 1, 1, FORMAT_ND, DT_FLOAT16, {22, 15120});
16550+ ASSERT_NE(asc_backend, nullptr);
16551+ const auto attr = GetOrCreateAutoFuseAttrs(asc_backend->GetOpDesc());
16552+ ASSERT_NE(attr, nullptr);
16553+ 
16554+ ge::AscGraph graph("reshape_padding_graph");
16555+ attr->SetAscGraph(CreateRestoredLeadingReshapeAxisGraph(graph), loop::FuseType::kReshape);
16556+ af::ReshapeAxisChangeInfo change;
16557+ change.before_axis = {2, 0, 1};
16558+ change.before_repeats = {Symbol(1), Symbol(22), Symbol(15120)};
16559+ change.after_axis = {0, 1};
16560+ change.after_repeats = {Symbol(22), Symbol(15120)};
16561+ attr->AddReshapeAxisChange(change);
16562+ 
16563+ ASSERT_EQ(
16564+ asc_adapt::PadLeadingUnitAxisAndCompleteAttrs(*(attr->GetAscGraph()), asc_backend, attr->GetReshapeAxisChanges()),
16565+ SUCCESS);
16566+ ASSERT_EQ(asc_adapt::CompleteNodeAttrsOnAscGraph(*(attr->GetAscGraph()), asc_backend), SUCCESS);
16567+ 
16568+ const auto graph_attr = AscGraphUtils::GetComputeGraph(*(attr->GetAscGraph()))->GetAttrsGroup<AscGraphAttr>();
16569+ ASSERT_NE(graph_attr, nullptr);
16570+ ASSERT_EQ(graph_attr->axis.size(), 3U);
16571+ EXPECT_TRUE(BackendUtils::IsEqOne(graph_attr->axis[0]->size));
16572+ EXPECT_EQ(std::string(graph_attr->axis[1]->size.Str().get()), "22");
16573+ EXPECT_EQ(std::string(graph_attr->axis[2]->size.Str().get()), "15120");
16574+}
16575+ 
15865TEST_F(AscBackendPostProcessorTest, CompleteAttrWithGraphInvalidAxisNodeValidAxis) {16576TEST_F(AscBackendPostProcessorTest, CompleteAttrWithGraphInvalidAxisNodeValidAxis) {
15866 ComputeGraphPtr compute_graph = BuildGraph1("AscBackend");16577 ComputeGraphPtr compute_graph = BuildGraph1("AscBackend");
15867 EXPECT_EQ(compute_graph->GetAllNodesSize(), 5);16578 EXPECT_EQ(compute_graph->GetAllNodesSize(), 5);
@@ -20079,4 +20790,390 @@ TEST_F(AscBackendPostProcessorTest, Adaption_CyclicExternalLiftPass_DtypeNotSupp
20079 // 确保Broadcast节点数量符合预期20790 // 确保Broadcast节点数量符合预期
20080 ASSERT_EQ(broadcast_cnt, 2);20791 ASSERT_EQ(broadcast_cnt, 2);
20081}20792}
20793+ 
20794+static std::shared_ptr<ge::AscGraph> CreatConcatGraphWithSqueezedLeadingAxis(ge::AscGraph &graph) {
20795+ const auto one = Symbol(1);
20796+ const auto axis0_size = Symbol(4);
20797+ const auto axis1_size = Symbol(22);
20798+ const auto axis2_size = Symbol(15120);
20799+ auto axis0 = graph.CreateAxis("A", axis0_size);
20800+ auto axis1 = graph.CreateAxis("B", axis1_size);
20801+ auto axis2 = graph.CreateAxis("C", axis2_size);
20802+ 
20803+ std::vector<af::ascir_op::Load> loads;
20804+ loads.reserve(4U);
20805+ std::vector<ge::AscOpOutput> load_outputs;
20806+ for (size_t i = 0U; i < 4U; ++i) {
20807+ const auto data_name = "data" + std::to_string(i);
20808+ af::ascir_op::Data data(data_name.c_str(), graph);
20809+ data.attr.sched.axis = {axis1.id, axis2.id, axis0.id};
20810+ data.y.dtype = DT_FLOAT16;
20811+ *data.y.axis = {axis1.id, axis2.id, axis0.id};
20812+ *data.y.repeats = {axis1_size, axis2_size, one};
20813+ *data.y.strides = {axis2_size, one, Symbol(0)};
20814+ 
20815+ const auto load_name = "load" + std::to_string(i);
20816+ loads.emplace_back(load_name.c_str());
20817+ loads.back().x = data.y;
20818+ loads.back().attr.sched.axis = {axis1.id, axis2.id, axis0.id};
20819+ loads.back().attr.sched.loop_axis = axis0.id;
20820+ loads.back().y.dtype = DT_FLOAT16;
20821+ *loads.back().y.axis = {axis1.id, axis2.id, axis0.id};
20822+ *loads.back().y.repeats = {axis1_size, axis2_size, one};
20823+ *loads.back().y.strides = {axis2_size, one, Symbol(0)};
20824+ *loads.back().y.vectorized_axis = {axis1.id, axis2.id, axis0.id};
20825+ load_outputs.emplace_back(loads.back().y);
20826+ }
20827+ 
20828+ af::ascir_op::Concat concat("concat");
20829+ concat.x = load_outputs;
20830+ concat.attr.sched.axis = {axis1.id, axis2.id, axis0.id};
20831+ concat.attr.sched.loop_axis = axis0.id;
20832+ concat.y.dtype = DT_FLOAT16;
20833+ *concat.y.axis = {axis1.id, axis2.id, axis0.id};
20834+ *concat.y.repeats = {axis1_size, axis2_size, axis0_size};
20835+ *concat.y.strides = {axis2_size * axis0_size, axis0_size, one};
20836+ *concat.y.vectorized_axis = {axis1.id, axis2.id, axis0.id};
20837+ 
20838+ af::ascir_op::Store store("store");
20839+ store.x = concat.y;
20840+ store.attr.sched.axis = {axis1.id, axis2.id, axis0.id};
20841+ store.attr.sched.loop_axis = axis0.id;
20842+ store.y.dtype = DT_FLOAT16;
20843+ *store.y.axis = {axis1.id, axis2.id, axis0.id};
20844+ *store.y.repeats = {axis1_size, axis2_size, axis0_size};
20845+ *store.y.strides = {axis2_size * axis0_size, axis0_size, one};
20846+ *store.y.vectorized_axis = {axis1.id, axis2.id, axis0.id};
20847+ 
20848+ af::ascir_op::Output output("output");
20849+ output.x = store.y;
20850+ output.attr.sched.axis = {axis1.id, axis2.id, axis0.id};
20851+ *output.y.axis = {};
20852+ *output.y.repeats = {};
20853+ *output.y.strides = {};
20854+ 
20855+ auto output_node = graph.FindNode("output");
20856+ auto compute_graph = output_node->GetOwnerComputeGraph();
20857+ std::vector<std::pair<NodePtr, int32_t>> output_nodes{{output_node, 0}};
20858+ compute_graph->SetOutputSize(1U);
20859+ compute_graph->SetGraphOutNodesInfo(output_nodes);
20860+ auto graph_attr = compute_graph->GetAttrsGroup<AscGraphAttr>();
20861+ graph_attr->axis = {graph_attr->axis[1], graph_attr->axis[2], graph_attr->axis[0]};
20862+ return std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph));
20863+}
20864+ 
20865+static std::shared_ptr<ge::AscGraph> CreatSplitGraphWithSqueezedLeadingAxis(ge::AscGraph &graph) {
20866+ const auto one = Symbol(1);
20867+ const auto axis0_size = Symbol(4);
20868+ const auto axis1_size = Symbol(22);
20869+ const auto axis2_size = Symbol(15120);
20870+ auto axis0 = graph.CreateAxis("A", axis0_size);
20871+ auto axis1 = graph.CreateAxis("B", axis1_size);
20872+ auto axis2 = graph.CreateAxis("C", axis2_size);
20873+ 
20874+ af::ascir_op::Data data("split_data", graph);
20875+ data.attr.sched.axis = {axis0.id, axis1.id, axis2.id};
20876+ data.y.dtype = DT_FLOAT16;
20877+ *data.y.axis = {axis0.id, axis1.id, axis2.id};
20878+ *data.y.repeats = {axis0_size, axis1_size, axis2_size};
20879+ *data.y.strides = {axis1_size * axis2_size, axis2_size, one};
20880+ 
20881+ af::ascir_op::Load load("split_load");
20882+ load.x = data.y;
20883+ load.attr.sched.axis = {axis0.id, axis1.id, axis2.id};
20884+ load.attr.sched.loop_axis = axis2.id;
20885+ load.y.dtype = DT_FLOAT16;
20886+ *load.y.axis = {axis0.id, axis1.id, axis2.id};
20887+ *load.y.repeats = {axis0_size, axis1_size, axis2_size};
20888+ *load.y.strides = {axis1_size * axis2_size, axis2_size, one};
20889+ 
20890+ af::ascir_op::Split split("split");
20891+ split.InstanceOutputy(1);
20892+ split.ir_attr.SetIndex(0);
20893+ split.x = load.y;
20894+ split.attr.sched.axis = {axis1.id, axis2.id, axis0.id};
20895+ split.attr.sched.loop_axis = axis0.id;
20896+ split.y[0].dtype = DT_FLOAT16;
20897+ AscOutputAttrDataType split_output_data_type(&split, 0);
20898+ split_output_data_type = ge::DT_FLOAT16;
20899+ *split.y[0].axis = {axis1.id, axis2.id, axis0.id};
20900+ *split.y[0].repeats = {axis1_size, axis2_size, one};
20901+ *split.y[0].strides = {axis2_size, one, Symbol(0)};
20902+ 
20903+ af::ascir_op::Store store("split_store");
20904+ store.x = split.y[0];
20905+ store.attr.sched.axis = {axis1.id, axis2.id, axis0.id};
20906+ store.attr.sched.loop_axis = axis0.id;
20907+ store.y.dtype = DT_FLOAT16;
20908+ *store.y.axis = {axis1.id, axis2.id, axis0.id};
20909+ *store.y.repeats = {axis1_size, axis2_size, one};
20910+ *store.y.strides = {axis2_size, one, Symbol(0)};
20911+ 
20912+ af::ascir_op::Output output("split_output");
20913+ output.x = store.y;
20914+ output.attr.sched.axis = {axis1.id, axis2.id, axis0.id};
20915+ *output.y.axis = {};
20916+ *output.y.repeats = {};
20917+ *output.y.strides = {};
20918+ 
20919+ auto output_node = graph.FindNode("split_output");
20920+ auto compute_graph = output_node->GetOwnerComputeGraph();
20921+ std::vector<std::pair<NodePtr, int32_t>> output_nodes{{output_node, 0}};
20922+ compute_graph->SetOutputSize(1U);
20923+ compute_graph->SetGraphOutNodesInfo(output_nodes);
20924+ auto graph_attr = compute_graph->GetAttrsGroup<AscGraphAttr>();
20925+ graph_attr->axis = {graph_attr->axis[1], graph_attr->axis[2], graph_attr->axis[0]};
20926+ return std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph));
20927+}
20928+ 
20929+static std::shared_ptr<ge::AscGraph> CreatConcatGraphWithInsertedAxisNotConcatAxis(ge::AscGraph &graph) {
20930+ const auto one = Symbol(1);
20931+ const auto concat_axis_size = Symbol(4);
20932+ const auto axis1_size = Symbol(22);
20933+ const auto axis2_size = Symbol(15120);
20934+ auto axis1 = graph.CreateAxis("B", axis1_size);
20935+ auto concat_axis = graph.CreateAxis("A", concat_axis_size);
20936+ auto inserted_axis = graph.CreateAxis("D", one);
20937+ auto axis2 = graph.CreateAxis("C", axis2_size);
20938+ const std::vector<int64_t> axis = {axis1.id, concat_axis.id, inserted_axis.id, axis2.id};
20939+ 
20940+ std::vector<af::ascir_op::Load> loads;
20941+ loads.reserve(4U);
20942+ std::vector<ge::AscOpOutput> load_outputs;
20943+ for (size_t i = 0U; i < 4U; ++i) {
20944+ const auto data_name = "data_not_tail" + std::to_string(i);
20945+ af::ascir_op::Data data(data_name.c_str(), graph);
20946+ data.attr.sched.axis = axis;
20947+ data.y.dtype = DT_FLOAT16;
20948+ *data.y.axis = axis;
20949+ *data.y.repeats = {axis1_size, one, one, axis2_size};
20950+ *data.y.strides = {axis2_size, Symbol(0), Symbol(0), one};
20951+ 
20952+ const auto load_name = "load_not_tail" + std::to_string(i);
20953+ loads.emplace_back(load_name.c_str());
20954+ loads.back().x = data.y;
20955+ loads.back().attr.sched.axis = axis;
20956+ loads.back().y.dtype = DT_FLOAT16;
20957+ *loads.back().y.axis = axis;
20958+ *loads.back().y.repeats = {axis1_size, one, one, axis2_size};
20959+ *loads.back().y.strides = {axis2_size, Symbol(0), Symbol(0), one};
20960+ load_outputs.emplace_back(loads.back().y);
20961+ }
20962+ 
20963+ af::ascir_op::Concat concat("concat_not_tail");
20964+ concat.x = load_outputs;
20965+ concat.attr.sched.axis = axis;
20966+ concat.y.dtype = DT_FLOAT16;
20967+ *concat.y.axis = axis;
20968+ *concat.y.repeats = {axis1_size, concat_axis_size, one, axis2_size};
20969+ *concat.y.strides = {concat_axis_size * axis2_size, axis2_size, Symbol(0), one};
20970+ 
20971+ af::ascir_op::Store store("store_not_tail");
20972+ store.x = concat.y;
20973+ store.attr.sched.axis = axis;
20974+ store.y.dtype = DT_FLOAT16;
20975+ *store.y.axis = axis;
20976+ *store.y.repeats = {axis1_size, concat_axis_size, one, axis2_size};
20977+ *store.y.strides = {concat_axis_size * axis2_size, axis2_size, Symbol(0), one};
20978+ 
20979+ af::ascir_op::Output output("output_not_tail");
20980+ output.x = store.y;
20981+ output.attr.sched.axis = axis;
20982+ *output.y.axis = {};
20983+ *output.y.repeats = {};
20984+ *output.y.strides = {};
20985+ 
20986+ auto output_node = graph.FindNode("output_not_tail");
20987+ auto compute_graph = output_node->GetOwnerComputeGraph();
20988+ std::vector<std::pair<NodePtr, int32_t>> output_nodes{{output_node, 0}};
20989+ compute_graph->SetOutputSize(1U);
20990+ compute_graph->SetGraphOutNodesInfo(output_nodes);
20991+ return std::shared_ptr<ge::AscGraph>(new ge::AscGraph(graph));
20992+}
20993+ 
20994+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_FusedConcatKeepsSqueezedLeadingAxis) {
20995+ ge::AscGraph concat_graph("concat_axis_padding");
20996+ auto asc_graph = CreatConcatGraphWithSqueezedLeadingAxis(concat_graph);
20997+ ASSERT_NE(asc_graph, nullptr);
20998+ 
20999+ GraphBuilder inner_builder("fused_inner");
21000+ auto concat_backend = inner_builder.AddNode("concat_backend", kAscBackendType, 0, 1);
21001+ auto concat_backend_attr = GetOrCreateAutoFuseAttrs(concat_backend->GetOpDescBarePtr());
21002+ ASSERT_NE(concat_backend_attr, nullptr);
21003+ concat_backend_attr->SetAscGraph(asc_graph, loop::FuseType::kConcat);
21004+ auto inner_graph = inner_builder.GetGraph();
21005+ 
21006+ GraphBuilder root_builder("root");
21007+ auto fused_node = root_builder.AddNode("fused", kFusedAscBackendType, 0, 1);
21008+ auto fused_attr = GetOrCreateAutoFuseAttrs(fused_node->GetOpDescBarePtr());
21009+ ASSERT_NE(fused_attr, nullptr);
21010+ fused_attr->SetFuseComputeGraph(inner_graph);
21011+ auto root_graph = root_builder.GetGraph();
21012+ 
21013+ EXPECT_EQ(asc_adapt::CompleteNodeAttrsOnAscGraphForSched(root_graph), SUCCESS);
21014+ 
21015+ const auto graph_attr = AscGraphUtils::GetComputeGraph(*asc_graph)->GetAttrsGroup<AscGraphAttr>();
21016+ ASSERT_NE(graph_attr, nullptr);
21017+ ASSERT_EQ(graph_attr->axis.size(), 4U);
21018+ EXPECT_EQ(std::string(graph_attr->axis[0]->size.Str().get()), "4");
21019+ EXPECT_EQ(std::string(graph_attr->axis[1]->size.Str().get()), "22");
21020+ EXPECT_EQ(std::string(graph_attr->axis[2]->size.Str().get()), "15120");
21021+ EXPECT_TRUE(BackendUtils::IsEqOne(graph_attr->axis[3]->size));
21022+ 
21023+ AscTensorAttr *concat_attr = nullptr;
21024+ auto concat_node = asc_graph->FindNode("concat");
21025+ ASSERT_NE(concat_node, nullptr);
21026+ const auto concat_node_attr = concat_node->GetOpDesc()->GetAttrsGroup<AscNodeAttr>();
21027+ ASSERT_NE(concat_node_attr, nullptr);
21028+ EXPECT_EQ(concat_node_attr->sched.loop_axis, 0);
21029+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(concat_node, concat_attr), SUCCESS);
21030+ EXPECT_EQ(concat_attr->axis, std::vector<int64_t>({0, 1, 2, 3}));
21031+ EXPECT_EQ(concat_attr->vectorized_axis, std::vector<int64_t>({1, 2, 0}));
21032+ ASSERT_EQ(concat_attr->repeats.size(), 4U);
21033+ EXPECT_EQ(std::string(concat_attr->repeats[0].Str().get()), "4");
21034+ EXPECT_EQ(std::string(concat_attr->repeats[1].Str().get()), "22");
21035+ EXPECT_EQ(std::string(concat_attr->repeats[2].Str().get()), "15120");
21036+ EXPECT_TRUE(BackendUtils::IsEqOne(concat_attr->repeats[3]));
21037+ ASSERT_EQ(concat_attr->strides.size(), 4U);
21038+ EXPECT_TRUE(BackendUtils::IsEqOne(concat_attr->strides[0]));
21039+ EXPECT_EQ(std::string(concat_attr->strides[1].Str().get()), "60480");
21040+ EXPECT_EQ(std::string(concat_attr->strides[2].Str().get()), "4");
21041+ EXPECT_TRUE(BackendUtils::IsEqZero(concat_attr->strides[3]));
21042+ 
21043+ AscTensorAttr *store_attr = nullptr;
21044+ auto store_node = asc_graph->FindNode("store");
21045+ ASSERT_NE(store_node, nullptr);
21046+ const auto store_node_attr = store_node->GetOpDesc()->GetAttrsGroup<AscNodeAttr>();
21047+ ASSERT_NE(store_node_attr, nullptr);
21048+ EXPECT_EQ(store_node_attr->sched.loop_axis, 0);
21049+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store_node, store_attr), SUCCESS);
21050+ EXPECT_EQ(store_attr->axis, std::vector<int64_t>({0, 1, 2, 3}));
21051+ EXPECT_EQ(store_attr->vectorized_axis, std::vector<int64_t>({1, 2, 0}));
21052+ ASSERT_EQ(store_attr->repeats.size(), 4U);
21053+ EXPECT_EQ(std::string(store_attr->repeats[0].Str().get()), "4");
21054+ EXPECT_EQ(std::string(store_attr->repeats[1].Str().get()), "22");
21055+ EXPECT_EQ(std::string(store_attr->repeats[2].Str().get()), "15120");
21056+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->repeats[3]));
21057+ ASSERT_EQ(store_attr->strides.size(), 4U);
21058+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->strides[0]));
21059+ EXPECT_EQ(std::string(store_attr->strides[1].Str().get()), "60480");
21060+ EXPECT_EQ(std::string(store_attr->strides[2].Str().get()), "4");
21061+ EXPECT_TRUE(BackendUtils::IsEqZero(store_attr->strides[3]));
21062+}
21063+ 
21064+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_FusedConcatCompletesSplitLoadSqueezedAxis) {
21065+ ge::AscGraph split_graph("split_axis_padding");
21066+ auto split_asc_graph = CreatSplitGraphWithSqueezedLeadingAxis(split_graph);
21067+ ASSERT_NE(split_asc_graph, nullptr);
21068+ ge::AscGraph concat_graph("concat_axis_padding_for_split");
21069+ auto concat_asc_graph = CreatConcatGraphWithSqueezedLeadingAxis(concat_graph);
21070+ ASSERT_NE(concat_asc_graph, nullptr);
21071+ 
21072+ GraphBuilder inner_builder("fused_inner_with_split");
21073+ auto split_backend = inner_builder.AddNode("split_backend", kAscBackendType, 0, 1);
21074+ auto split_backend_attr = GetOrCreateAutoFuseAttrs(split_backend->GetOpDescBarePtr());
21075+ ASSERT_NE(split_backend_attr, nullptr);
21076+ split_backend_attr->SetAscGraph(split_asc_graph, loop::FuseType::kSplit);
21077+ auto concat_backend = inner_builder.AddNode("concat_backend_for_split", kAscBackendType, 0, 1);
21078+ auto concat_backend_attr = GetOrCreateAutoFuseAttrs(concat_backend->GetOpDescBarePtr());
21079+ ASSERT_NE(concat_backend_attr, nullptr);
21080+ concat_backend_attr->SetAscGraph(concat_asc_graph, loop::FuseType::kConcat);
21081+ auto inner_graph = inner_builder.GetGraph();
21082+ 
21083+ GraphBuilder root_builder("root_with_split");
21084+ auto fused_node = root_builder.AddNode("fused_with_split", kFusedAscBackendType, 0, 1);
21085+ auto fused_attr = GetOrCreateAutoFuseAttrs(fused_node->GetOpDescBarePtr());
21086+ ASSERT_NE(fused_attr, nullptr);
21087+ fused_attr->SetFuseComputeGraph(inner_graph);
21088+ auto root_graph = root_builder.GetGraph();
21089+ 
21090+ EXPECT_EQ(asc_adapt::CompleteNodeAttrsOnAscGraphForSched(root_graph), SUCCESS);
21091+ 
21092+ AscTensorAttr *load_attr = nullptr;
21093+ auto load_node = split_asc_graph->FindNode("split_load");
21094+ ASSERT_NE(load_node, nullptr);
21095+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(load_node, load_attr), SUCCESS);
21096+ EXPECT_EQ(load_attr->axis, std::vector<int64_t>({0, 1, 2, 3}));
21097+ ASSERT_EQ(load_attr->repeats.size(), 4U);
21098+ EXPECT_EQ(std::string(load_attr->repeats[0].Str().get()), "4");
21099+ EXPECT_EQ(std::string(load_attr->repeats[1].Str().get()), "22");
21100+ EXPECT_EQ(std::string(load_attr->repeats[2].Str().get()), "15120");
21101+ EXPECT_TRUE(BackendUtils::IsEqOne(load_attr->repeats[3]));
21102+ 
21103+ AscTensorAttr *data_attr = nullptr;
21104+ auto data_node = split_asc_graph->FindNode("split_data");
21105+ ASSERT_NE(data_node, nullptr);
21106+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(data_node, data_attr), SUCCESS);
21107+ EXPECT_EQ(data_attr->axis, load_attr->axis);
21108+ ASSERT_EQ(data_attr->repeats.size(), load_attr->repeats.size());
21109+ for (size_t i = 0U; i < data_attr->repeats.size(); ++i) {
21110+ EXPECT_EQ(std::string(data_attr->repeats[i].Str().get()), std::string(load_attr->repeats[i].Str().get()));
21111+ }
21112+ 
21113+ AscTensorAttr *split_attr = nullptr;
21114+ auto split_node = split_asc_graph->FindNode("split");
21115+ ASSERT_NE(split_node, nullptr);
21116+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(split_node, split_attr), SUCCESS);
21117+ EXPECT_EQ(split_attr->axis, std::vector<int64_t>({0, 1, 2, 3}));
21118+ ASSERT_EQ(split_attr->repeats.size(), 4U);
21119+ EXPECT_TRUE(BackendUtils::IsEqOne(split_attr->repeats[0]));
21120+ EXPECT_EQ(std::string(split_attr->repeats[1].Str().get()), "22");
21121+ EXPECT_EQ(std::string(split_attr->repeats[2].Str().get()), "15120");
21122+ EXPECT_TRUE(BackendUtils::IsEqOne(split_attr->repeats[3]));
21123+}
21124+ 
21125+TEST_F(AscBackendPostProcessorTest, CompleteAttrs_FusedConcatKeepsInsertedAxisNotConcatAxis) {
21126+ ge::AscGraph concat_graph("concat_axis_padding_not_tail");
21127+ auto asc_graph = CreatConcatGraphWithInsertedAxisNotConcatAxis(concat_graph);
21128+ ASSERT_NE(asc_graph, nullptr);
21129+ 
21130+ GraphBuilder inner_builder("fused_inner_not_tail");
21131+ auto concat_backend = inner_builder.AddNode("concat_backend_not_tail", kAscBackendType, 0, 1);
21132+ auto concat_backend_attr = GetOrCreateAutoFuseAttrs(concat_backend->GetOpDescBarePtr());
21133+ ASSERT_NE(concat_backend_attr, nullptr);
21134+ concat_backend_attr->SetAscGraph(asc_graph, loop::FuseType::kConcat);
21135+ auto inner_graph = inner_builder.GetGraph();
21136+ 
21137+ GraphBuilder root_builder("root_not_tail");
21138+ auto fused_node = root_builder.AddNode("fused_not_tail", kFusedAscBackendType, 0, 1);
21139+ auto fused_attr = GetOrCreateAutoFuseAttrs(fused_node->GetOpDescBarePtr());
21140+ ASSERT_NE(fused_attr, nullptr);
21141+ fused_attr->SetFuseComputeGraph(inner_graph);
21142+ auto root_graph = root_builder.GetGraph();
21143+ 
21144+ EXPECT_EQ(asc_adapt::CompleteNodeAttrsOnAscGraphForSched(root_graph), SUCCESS);
21145+ 
21146+ const auto graph_attr = AscGraphUtils::GetComputeGraph(*asc_graph)->GetAttrsGroup<AscGraphAttr>();
21147+ ASSERT_NE(graph_attr, nullptr);
21148+ ASSERT_EQ(graph_attr->axis.size(), 5U);
21149+ EXPECT_EQ(graph_attr->axis[0]->id, 0);
21150+ EXPECT_EQ(graph_attr->axis[1]->id, 1);
21151+ EXPECT_EQ(graph_attr->axis[2]->id, 2);
21152+ EXPECT_EQ(graph_attr->axis[3]->id, 3);
21153+ EXPECT_EQ(graph_attr->axis[4]->id, 4);
21154+ 
21155+ AscTensorAttr *concat_attr = nullptr;
21156+ auto concat_node = asc_graph->FindNode("concat_not_tail");
21157+ ASSERT_NE(concat_node, nullptr);
21158+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(concat_node, concat_attr), SUCCESS);
21159+ EXPECT_EQ(concat_attr->axis, std::vector<int64_t>({0, 1, 2, 3, 4}));
21160+ ASSERT_EQ(concat_attr->repeats.size(), 5U);
21161+ EXPECT_EQ(std::string(concat_attr->repeats[0].Str().get()), "22");
21162+ EXPECT_EQ(std::string(concat_attr->repeats[1].Str().get()), "4");
21163+ EXPECT_TRUE(BackendUtils::IsEqOne(concat_attr->repeats[2]));
21164+ EXPECT_EQ(std::string(concat_attr->repeats[3].Str().get()), "15120");
21165+ EXPECT_TRUE(BackendUtils::IsEqOne(concat_attr->repeats[4]));
21166+ 
21167+ AscTensorAttr *store_attr = nullptr;
21168+ auto store_node = asc_graph->FindNode("store_not_tail");
21169+ ASSERT_NE(store_node, nullptr);
21170+ ASSERT_EQ(asc_adapt::GetOutputTensorAttr(store_node, store_attr), SUCCESS);
21171+ EXPECT_EQ(store_attr->axis, std::vector<int64_t>({0, 1, 2, 3, 4}));
21172+ ASSERT_EQ(store_attr->repeats.size(), 5U);
21173+ EXPECT_EQ(std::string(store_attr->repeats[0].Str().get()), "22");
21174+ EXPECT_EQ(std::string(store_attr->repeats[1].Str().get()), "4");
21175+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->repeats[2]));
21176+ EXPECT_EQ(std::string(store_attr->repeats[3].Str().get()), "15120");
21177+ EXPECT_TRUE(BackendUtils::IsEqOne(store_attr->repeats[4]));
21178+}
20082} // namespace ge21179} // namespace ge