已合并
fix:【 ABI约束】保证后端生成AutofuseTiling时使用前端的符号和顺序 #1753
fix:【 ABI约束】保证后端生成AutofuseTiling时使用前端的符号和顺序 #1753
已合并
zhang_shengjie创建于 8月15日
16 个文件变更+352-29
@@ -845,7 +845,7 @@ std::string TilingLib::TilingFuncDef(const ascir::FusedScheduledResult &fused_sc
845 << std::endl;845 << std::endl;
846 ss << kTilingHeadCceKtTestGuard << std::endl;846 ss << kTilingHeadCceKtTestGuard << std::endl;
847 // 生成判断是否为静态shape的接口847 // 生成判断是否为静态shape的接口
848- bool is_static = IsStaticSchedResult(elemwise_schedule_result);848+ bool is_static = IsFrontendStaticSchedResult(elemwise_schedule_result);
849 ss << GenCheckStaticShapeFunc(is_static);849 ss << GenCheckStaticShapeFunc(is_static);
850 if (ascgen_utils::CanUseTilingKey(elemwise_schedule_result)) {850 if (ascgen_utils::CanUseTilingKey(elemwise_schedule_result)) {
851 ss << this->GenFindBestTilingKeyFunc(elemwise_schedule_result, tiling_data_name);851 ss << this->GenFindBestTilingKeyFunc(elemwise_schedule_result, tiling_data_name);
@@ -1130,7 +1130,7 @@ std::string TilingLib::GenCubeFusionTilingBodyInductor(const ascir::FusedSchedul
1130void TilingLib::GenInductorShapeDim(const ascir::FusedScheduledResult &elemwise_schedule_result,1130void TilingLib::GenInductorShapeDim(const ascir::FusedScheduledResult &elemwise_schedule_result,
1131 codegen::PgoShapeStringStream &pgo_shape_dim,1131 codegen::PgoShapeStringStream &pgo_shape_dim,
1132 std::vector<std::string> &dynamic_shape_vars, const std::string &tiling_var) const {1132 std::vector<std::string> &dynamic_shape_vars, const std::string &tiling_var) const {
1133- for (auto vars : elemwise_schedule_result.origin_vars) {1133+ for (auto vars : GetFrontendShapeVars(elemwise_schedule_result)) {
1134 if (!(vars.IsConstExpr())) {1134 if (!(vars.IsConstExpr())) {
1135 std::string var_define = std::string(vars.Str().get());1135 std::string var_define = std::string(vars.Str().get());
1136 dynamic_shape_vars.push_back(var_define);1136 dynamic_shape_vars.push_back(var_define);
@@ -1283,7 +1283,7 @@ std::string TilingLib::GenTilingFunc(const std::map<std::string, std::string> &s
1283 std::stringstream ss;1283 std::stringstream ss;
1284 codegen::PgoShapeStringStream pgo_shape_dim;1284 codegen::PgoShapeStringStream pgo_shape_dim;
1285 std::string tiling_var = "tiling->";1285 std::string tiling_var = "tiling->";
1286- for (auto vars : fused_schedule_result.origin_vars) {1286+ for (auto vars : GetFrontendShapeVars(fused_schedule_result)) {
1287 if (!(vars.IsConstExpr())) {1287 if (!(vars.IsConstExpr())) {
1288 std::string var_define = std::string(vars.Str().get());1288 std::string var_define = std::string(vars.Str().get());
1289 auto it = shape_info.find(var_define);1289 auto it = shape_info.find(var_define);
@@ -1389,7 +1389,7 @@ static void GetTilingParse(std::string &tiling_parse, int &vector_core_num) {
1389static void FillShapeDimInfo(const ascir::FusedScheduledResult &fused_schedule_result,1389static void FillShapeDimInfo(const ascir::FusedScheduledResult &fused_schedule_result,
1390 const std::map<std::string, std::string> &shape_info, std::stringstream &shape_dim_def,1390 const std::map<std::string, std::string> &shape_info, std::stringstream &shape_dim_def,
1391 std::stringstream &shape_dim_param) {1391 std::stringstream &shape_dim_param) {
1392- for (const auto &vars : fused_schedule_result.origin_vars) {1392+ for (const auto &vars : GetFrontendShapeVars(fused_schedule_result)) {
1393 if (!vars.IsConstExpr()) {1393 if (!vars.IsConstExpr()) {
1394 std::string var_define = std::string(vars.Str().get());1394 std::string var_define = std::string(vars.Str().get());
1395 auto it = shape_info.find(var_define);1395 auto it = shape_info.find(var_define);
@@ -1780,7 +1780,7 @@ std::string TilingLib::GenTilingCacheFunc(const ascir::FusedScheduledResult &fus
1780 uint32_t index = 0U;1780 uint32_t index = 0U;
1781 std::stringstream ss_tmp;1781 std::stringstream ss_tmp;
1782 1782 
1783- for (const auto &vars : fused_schedule_result.origin_vars) {1783+ for (const auto &vars : GetFrontendShapeVars(fused_schedule_result)) {
1784 if (!(vars.IsConstExpr())) {1784 if (!(vars.IsConstExpr())) {
1785 std::string var_define = std::string(vars.Str().get());1785 std::string var_define = std::string(vars.Str().get());
1786 auto it = shape_info.find(var_define);1786 auto it = shape_info.find(var_define);
@@ -1822,7 +1822,7 @@ std::string TilingLib::GenDfxInputSymbolInfo(const ascir::FusedScheduledResult &
1822 << std::endl;1822 << std::endl;
1823 1823 
1824 bool first_sym = true;1824 bool first_sym = true;
1825- for (const auto &vars : fused_schedule_result.origin_vars) {1825+ for (const auto &vars : GetFrontendShapeVars(fused_schedule_result)) {
1826 if (!(vars.IsConstExpr())) {1826 if (!(vars.IsConstExpr())) {
1827 std::string var_define = std::string(vars.Str().get());1827 std::string var_define = std::string(vars.Str().get());
1828 auto it = shape_info.find(var_define);1828 auto it = shape_info.find(var_define);
@@ -496,7 +496,7 @@ std::map<std::string, std::string> TilingLib::GenerateCVFusionDynamic(
496 std::stringstream ss;496 std::stringstream ss;
497 std::stringstream call_cube_tiling;497 std::stringstream call_cube_tiling;
498 std::stringstream shape_symbol;498 std::stringstream shape_symbol;
499- for (auto vars : fused_schedule_result.origin_vars) {499+ for (auto vars : GetFrontendShapeVars(fused_schedule_result)) {
500 if (!(vars.IsConstExpr())) {500 if (!(vars.IsConstExpr())) {
501 std::string var_define = std::string(vars.Str().get());501 std::string var_define = std::string(vars.Str().get());
502 auto it = shape_info.find(var_define);502 auto it = shape_info.find(var_define);
@@ -356,7 +356,7 @@ std::string TilingLib::GenGetTopnSolutionsFuncForInductor(const ascir::FusedSche
356 std::stringstream ss;356 std::stringstream ss;
357 codegen::PgoShapeStringStream pgo_shape_dim;357 codegen::PgoShapeStringStream pgo_shape_dim;
358 int symbol_value_count = 0;358 int symbol_value_count = 0;
359- for (auto vars : fused_schedule_result.origin_vars) {359+ for (auto vars : GetFrontendShapeVars(fused_schedule_result)) {
360 if (!(vars.IsConstExpr())) {360 if (!(vars.IsConstExpr())) {
361 std::string var_define = std::string(vars.Str().get());361 std::string var_define = std::string(vars.Str().get());
362 pgo_shape_dim.shape_dim_def << "int64_t " << var_define << ", ";362 pgo_shape_dim.shape_dim_def << "int64_t " << var_define << ", ";
@@ -398,7 +398,7 @@ void TilingLib::GenTopnInitSearchTiling(std::stringstream &ss, const ascir::Fuse
398 ss << " search_tiling.set_ub_size(limit->ub_size - 256);" << std::endl;398 ss << " search_tiling.set_ub_size(limit->ub_size - 256);" << std::endl;
399 {399 {
400 int idx = 0;400 int idx = 0;
401- for (auto vars : fused_schedule_result.origin_vars) {401+ for (auto vars : GetFrontendShapeVars(fused_schedule_result)) {
402 if (!(vars.IsConstExpr())) {402 if (!(vars.IsConstExpr())) {
403 std::string var_define = std::string(vars.Str().get());403 std::string var_define = std::string(vars.Str().get());
404 ss << " const uint32_t " << var_define << " = static_cast<uint32_t>(request.symbol_values[" << idx << "]);"404 ss << " const uint32_t " << var_define << " = static_cast<uint32_t>(request.symbol_values[" << idx << "]);"
@@ -349,7 +349,7 @@ std::string TilingLib::ExternFunctionDeclare(const ascir::FusedScheduledResult &
349 std::stringstream ss;349 std::stringstream ss;
350 350 
351 // 生成判断是否为静态shape的接口351 // 生成判断是否为静态shape的接口
352- bool is_static = IsStaticSchedResult(fused_schedule_result);352+ bool is_static = IsFrontendStaticSchedResult(fused_schedule_result);
353 ss << GenCheckStaticShapeFunc(is_static);353 ss << GenCheckStaticShapeFunc(is_static);
354 return ss.str();354 return ss.str();
355}355}
@@ -9,8 +9,14 @@
9 */9 */
10 10 
11#include "ascgraph_info_complete.h"11#include "ascgraph_info_complete.h"
12+#include <algorithm>
13+#include <cctype>
14+#include <limits>
12#include <map>15#include <map>
13#include <queue>16#include <queue>
17+#include <set>
18+#include <string>
19+#include <utility>
14#include "ascir_ops.h"20#include "ascir_ops.h"
15#include "ascendc_ir_def.h"21#include "ascendc_ir_def.h"
16#include "graph/symbolizer/symbolic.h"22#include "graph/symbolizer/symbolic.h"
@@ -36,6 +42,26 @@ void InsertFreeSymbolsIntoVarSet(const af::Expression &exp, SizeVarSet &size_var
36 size_vars.insert(free_symbols.begin(), free_symbols.end());42 size_vars.insert(free_symbols.begin(), free_symbols.end());
37}43}
38 44 
45+bool ParseKsIndex(const std::string &name, uint64_t &index) {
46+ if (name.size() <= 2U || name[0] != 'k' || name[1] != 's') {
47+ return false;
48+ }
49+ uint64_t parsed = 0U;
50+ for (size_t i = 2U; i < name.size(); ++i) {
51+ const unsigned char ch = static_cast<unsigned char>(name[i]);
52+ if (!std::isdigit(ch)) {
53+ return false;
54+ }
55+ const uint64_t digit = static_cast<uint64_t>(ch - static_cast<unsigned char>('0'));
56+ if (parsed > (std::numeric_limits<uint64_t>::max() - digit) / 10U) {
57+ return false;
58+ }
59+ parsed = parsed * 10U + digit;
60+ }
61+ index = parsed;
62+ return true;
63+}
64+ 
39void CompleteDataApiInfo(af::AscNodePtr &node) {65void CompleteDataApiInfo(af::AscNodePtr &node) {
40 node->attr.api.type = af::ApiType::kAPITypeBuffer;66 node->attr.api.type = af::ApiType::kAPITypeBuffer;
41 node->attr.api.unit = af::ComputeUnit::kUnitNone;67 node->attr.api.unit = af::ComputeUnit::kUnitNone;
@@ -250,4 +276,66 @@ void AscGraphInfoComplete::AppendOriginalSizeVar(const af::AscGraph &graph, Size
250 }276 }
251 }277 }
252}278}
279+ 
280+Status AscGraphInfoComplete::CollectFrontendShapeVars(const af::AscGraph &graph,
281+ std::vector<af::Expression> &frontend_shape_vars) {
282+ frontend_shape_vars.clear();
283+ SizeVarSet all_shape_vars;
284+ for (const auto &size_var : graph.GetAllSizeVar()) {
285+ GE_ASSERT_NOTNULL(size_var);
286+ all_shape_vars.insert(size_var->expr);
287+ }
288+ // ASC graphs produced by the frontend may use Symbol("sN") directly in
289+ // axis/repeat/stride expressions without registering it as a SizeVar. The
290+ // original-symbol collector covers those expressions before optimization
291+ // removes unused axes or rewrites implementation graphs.
292+ AppendOriginalSizeVar(graph, all_shape_vars);
293+ for (const auto &expr : all_shape_vars) {
294+ if (!expr.IsConstExpr()) {
295+ frontend_shape_vars.emplace_back(expr);
296+ }
297+ }
298+ return af::SUCCESS;
299+}
300+ 
301+Status AscGraphInfoComplete::NormalizeFrontendShapeVars(std::vector<af::Expression> &frontend_shape_vars) {
302+ std::set<std::string> seen_names;
303+ std::vector<af::Expression> unique_vars;
304+ bool all_ks_names = true;
305+ std::vector<std::pair<uint64_t, af::Expression>> ks_vars;
306+ for (const auto &expr : frontend_shape_vars) {
307+ if (expr.IsConstExpr()) {
308+ continue;
309+ }
310+ const std::string name = af::SymbolicUtils::ToString(expr);
311+ if (!seen_names.insert(name).second) {
312+ continue;
313+ }
314+ unique_vars.emplace_back(expr);
315+ uint64_t index = 0U;
316+ if (!ParseKsIndex(name, index)) {
317+ all_ks_names = false;
318+ } else {
319+ ks_vars.emplace_back(index, expr);
320+ }
321+ }
322+ 
323+ if (!all_ks_names) {
324+ std::sort(unique_vars.begin(), unique_vars.end(), ExpressionComparator{});
325+ frontend_shape_vars = std::move(unique_vars);
326+ return af::SUCCESS;
327+ }
328+ 
329+ std::sort(ks_vars.begin(), ks_vars.end(), [](const auto &lhs, const auto &rhs) {
330+ if (lhs.first != rhs.first) {
331+ return lhs.first < rhs.first;
332+ }
333+ return af::SymbolicUtils::ToString(lhs.second) < af::SymbolicUtils::ToString(rhs.second);
334+ });
335+ frontend_shape_vars.clear();
336+ for (const auto &item : ks_vars) {
337+ frontend_shape_vars.emplace_back(item.second);
338+ }
339+ return af::SUCCESS;
340+}
253} // namespace optimize341} // namespace optimize
@@ -11,6 +11,9 @@
11#ifndef HINT_GRAPH_INFO_COMPLETE_H11#ifndef HINT_GRAPH_INFO_COMPLETE_H
12#define HINT_GRAPH_INFO_COMPLETE_H12#define HINT_GRAPH_INFO_COMPLETE_H
13 13 
14+#include <vector>
15+#include <string>
16+ 
14#include "ascendc_ir.h"17#include "ascendc_ir.h"
15#include "ascgen_log.h"18#include "ascgen_log.h"
16#include "graph/symbolizer/symbolic_utils.h"19#include "graph/symbolizer/symbolic_utils.h"
@@ -32,6 +35,15 @@ class AscGraphInfoComplete {
32 static Status CompleteApiInfo(const af::AscGraph &optimize_graph);35 static Status CompleteApiInfo(const af::AscGraph &optimize_graph);
33 36 
34 static void AppendOriginalSizeVar(const af::AscGraph &graph, SizeVarSet &size_vars);37 static void AppendOriginalSizeVar(const af::AscGraph &graph, SizeVarSet &size_vars);
38+ 
39+ // Capture the complete frontend shape ABI before optimization can remove or
40+ // rewrite size vars. This includes symbols embedded directly in ASC axis
41+ // and tensor expressions. For Inductor's ksN naming convention this restores
42+ // the frontend order using the numeric suffix; legacy/non-Inductor symbols
43+ // keep the existing deterministic expression order.
44+ static Status CollectFrontendShapeVars(const af::AscGraph &graph, std::vector<af::Expression> &frontend_shape_vars);
45+ 
46+ static Status NormalizeFrontendShapeVars(std::vector<af::Expression> &frontend_shape_vars);
35};47};
36} // namespace optimize48} // namespace optimize
37 49 
@@ -215,7 +215,7 @@ af::Expression CalculateWorkspaceSize(const std::vector<af::AscNodePtr> &workspa
215}215}
216 216 
217bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result) {217bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result) {
218- for (auto &var : fused_schedule_result.origin_vars) {218+ for (const auto &var : fused_schedule_result.origin_vars) {
219 GELOGD("var:%s, is_const:%d", var.Str().get(), static_cast<int32_t>(var.IsConstExpr()));219 GELOGD("var:%s, is_const:%d", var.Str().get(), static_cast<int32_t>(var.IsConstExpr()));
220 if (!var.IsConstExpr()) {220 if (!var.IsConstExpr()) {
221 return false;221 return false;
@@ -225,6 +225,22 @@ bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_resul
225 return true;225 return true;
226}226}
227 227 
228+const std::vector<af::Expression> &GetFrontendShapeVars(const ascir::FusedScheduledResult &fused_schedule_result) {
229+ if (fused_schedule_result.frontend_shape_vars_collected || !fused_schedule_result.frontend_shape_vars.empty()) {
230+ return fused_schedule_result.frontend_shape_vars;
231+ }
232+ return fused_schedule_result.origin_vars;
233+}
234+ 
235+bool IsFrontendStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result) {
236+ for (const auto &var : GetFrontendShapeVars(fused_schedule_result)) {
237+ if (!var.IsConstExpr()) {
238+ return false;
239+ }
240+ }
241+ return true;
242+}
243+ 
228af::Status ScalarValuePreProcess(const std::string &ori_value, const std::string &dtype,244af::Status ScalarValuePreProcess(const std::string &ori_value, const std::string &dtype,
229 std::string &after_pre_pro_value) {245 std::string &after_pre_pro_value) {
230 if (ori_value == "inf" || ori_value == "-inf") {246 if (ori_value == "inf" || ori_value == "-inf") {
@@ -162,6 +162,14 @@ void GetApiReservedBlockNum(const ascir::ImplGraph &graph, uint32_t &total_blk_n
162bool IsScalarNextNodeSupportBlkTensor(const af::AscNodePtr &node);162bool IsScalarNextNodeSupportBlkTensor(const af::AscNodePtr &node);
163bool IsUbScalarLoad(const af::AscNodePtr &node);163bool IsUbScalarLoad(const af::AscNodePtr &node);
164bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result);164bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result);
165+ 
166+// Return the frontend ABI symbol list. Results produced before the new field
167+// was introduced may only have origin_vars; keep that as a compatibility
168+// fallback for legacy callers and unit fixtures.
169+const std::vector<af::Expression> &GetFrontendShapeVars(const ascir::FusedScheduledResult &fused_schedule_result);
170+// Return the frontend static-shape judgment for the external ABI. Internal
171+// tiling-data generation must continue to use IsStaticSchedResult().
172+bool IsFrontendStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result);
165af::Status ScalarValuePreProcess(const std::string &ori_value, const std::string &dtype,173af::Status ScalarValuePreProcess(const std::string &ori_value, const std::string &dtype,
166 std::string &after_pre_pro_value);174 std::string &after_pre_pro_value);
167void MergeBrcAxisRepeats(const std::vector<af::Expression> &input0_repeats, // 输入0的vector_repeats, 带广播175void MergeBrcAxisRepeats(const std::vector<af::Expression> &input0_repeats, // 输入0的vector_repeats, 带广播
@@ -57,6 +57,14 @@ struct FusedScheduledResult {
57 std::vector<af::AscNodePtr> input_nodes;57 std::vector<af::AscNodePtr> input_nodes;
58 std::vector<af::AscNodePtr> output_nodes;58 std::vector<af::AscNodePtr> output_nodes;
59 std::vector<af::AscNodePtr> workspace_nodes;59 std::vector<af::AscNodePtr> workspace_nodes;
60+ // Symbols exposed by the frontend AutofuseTiling ABI. This list is captured
61+ // from the original ASC graph before graph optimization and must not be
62+ // rebuilt from impl graphs, since an impl graph may legitimately not use all
63+ // frontend shape symbols.
64+ std::vector<af::Expression> frontend_shape_vars;
65+ // Distinguish a captured empty frontend symbol list (static frontend graph)
66+ // from legacy results that predate frontend_shape_vars.
67+ bool frontend_shape_vars_collected{false};
60 std::vector<af::Expression> origin_vars;68 std::vector<af::Expression> origin_vars;
61 std::vector<std::vector<ScheduledResult>> node_idx_to_scheduled_results;69 std::vector<std::vector<ScheduledResult>> node_idx_to_scheduled_results;
62 GmTensorSizes gm_tensor_sizes;70 GmTensorSizes gm_tensor_sizes;
@@ -9,6 +9,7 @@
9 */9 */
10 10 
11#include "optimize.h"11#include "optimize.h"
12+#include <utility>
12#include <queue>13#include <queue>
13#include "attr_utils.h"14#include "attr_utils.h"
14#include "ascir_ops.h"15#include "ascir_ops.h"
@@ -552,18 +553,10 @@ Status Optimizer::ExpandReduceFirstStageResults(std::vector<autoschedule::AutoSc
552 553 
553Optimizer::Optimizer(const OptimizerOptions &options) : options_(options) {}554Optimizer::Optimizer(const OptimizerOptions &options) : options_(options) {}
554 555 
555-Status Optimizer::Optimize(const af::ComputeGraphPtr &fused_graph,556+Status Optimizer::DeserializeAscGraphNodes(const af::ComputeGraphPtr &fused_graph,
556- ascir::FusedScheduledResult &fused_scheduled_result) {557+ std::map<af::Node *, af::AscGraph> &asc_backend_to_ascgraph,
557- GELOGI("Fused graph optimize in, graph_name:[%s].", fused_graph->GetName().c_str());558+ SizeVarSet &original_var_set,
558- // RAII Guard,函数结束时自动清空 fused_graph_name559+ std::vector<af::Expression> &frontend_shape_vars) {
559- ascir::utils::FusedGraphNameGuard guard(fused_graph->GetName());
560- ascir::utils::DumpComputeGraph(fused_graph, "BaseFusedGraph");
561- if (options_.graph_type == GraphType::kFusedAscBackend) {
562- return OptimizeFusedAscBackend(fused_graph, fused_scheduled_result);
563- }
564- // deserialize ascgraph on ascgraph node
565- std::map<af::Node *, af::AscGraph> asc_backend_to_ascgraph;
566- SizeVarSet original_var_set;
567 for (auto &node : fused_graph->GetDirectNodePtr()) {560 for (auto &node : fused_graph->GetDirectNodePtr()) {
568 GE_ASSERT_NOTNULL(node);561 GE_ASSERT_NOTNULL(node);
569 if (node->GetType() == kAscGraphNodeType) {562 if (node->GetType() == kAscGraphNodeType) {
@@ -574,6 +567,10 @@ Status Optimizer::Optimize(const af::ComputeGraphPtr &fused_graph,
574 af::AscGraph ascgraph(graph_name.c_str());567 af::AscGraph ascgraph(graph_name.c_str());
575 GE_CHK_STATUS_RET(af::AscGraphUtils::DeserializeFromReadable(*serialized_ascgraph, ascgraph),568 GE_CHK_STATUS_RET(af::AscGraphUtils::DeserializeFromReadable(*serialized_ascgraph, ascgraph),
576 "DeserializeFromBinary failed, graph:[%s].", fused_graph->GetName().c_str());569 "DeserializeFromBinary failed, graph:[%s].", fused_graph->GetName().c_str());
570+ std::vector<af::Expression> graph_shape_vars;
571+ GE_CHK_STATUS_RET(AscGraphInfoComplete::CollectFrontendShapeVars(ascgraph, graph_shape_vars),
572+ "Collect frontend shape vars failed, graph:[%s].", ascgraph.GetName().c_str());
573+ frontend_shape_vars.insert(frontend_shape_vars.end(), graph_shape_vars.begin(), graph_shape_vars.end());
577 ascgraph.SetGraphType(af::AscGraphType::kImplGraph);574 ascgraph.SetGraphType(af::AscGraphType::kImplGraph);
578 GE_CHK_STATUS_RET(AscGraphInfoComplete::CompleteApiInfo(ascgraph), "CompleteApiInfo failed");575 GE_CHK_STATUS_RET(AscGraphInfoComplete::CompleteApiInfo(ascgraph), "CompleteApiInfo failed");
579 AscGraphInfoComplete::AppendOriginalSizeVar(ascgraph, original_var_set);576 AscGraphInfoComplete::AppendOriginalSizeVar(ascgraph, original_var_set);
@@ -583,7 +580,24 @@ Status Optimizer::Optimize(const af::ComputeGraphPtr &fused_graph,
583 }580 }
584 GE_ASSERT_TRUE(!asc_backend_to_ascgraph.empty(), "The fused graph [%s] is invalid, which has none AscBackend node.",581 GE_ASSERT_TRUE(!asc_backend_to_ascgraph.empty(), "The fused graph [%s] is invalid, which has none AscBackend node.",
585 fused_graph->GetName().c_str());582 fused_graph->GetName().c_str());
583+ return af::SUCCESS;
584+}
586 585 
586+Status Optimizer::Optimize(const af::ComputeGraphPtr &fused_graph,
587+ ascir::FusedScheduledResult &fused_scheduled_result) {
588+ GELOGI("Fused graph optimize in, graph_name:[%s].", fused_graph->GetName().c_str());
589+ // RAII Guard,函数结束时自动清空 fused_graph_name
590+ ascir::utils::FusedGraphNameGuard guard(fused_graph->GetName());
591+ ascir::utils::DumpComputeGraph(fused_graph, "BaseFusedGraph");
592+ if (options_.graph_type == GraphType::kFusedAscBackend) {
593+ return OptimizeFusedAscBackend(fused_graph, fused_scheduled_result);
594+ }
595+ std::map<af::Node *, af::AscGraph> asc_backend_to_ascgraph;
596+ SizeVarSet original_var_set;
597+ std::vector<af::Expression> frontend_shape_vars;
598+ GE_CHK_STATUS_RET(
599+ DeserializeAscGraphNodes(fused_graph, asc_backend_to_ascgraph, original_var_set, frontend_shape_vars),
600+ "Deserialize ascgraph nodes failed, graph:[%s].", fused_graph->GetName().c_str());
587 // If there is more than one Ascend backend on the fused graph, it is necessary to determine whether partial sub -601 // If there is more than one Ascend backend on the fused graph, it is necessary to determine whether partial sub -
588 // graphs can be merged based on the supported scenarios. If there are still more than one Ascend nodes after the602 // graphs can be merged based on the supported scenarios. If there are still more than one Ascend nodes after the
589 // merging, it should be converted into multiple schedule groups.603 // merging, it should be converted into multiple schedule groups.
@@ -594,22 +608,25 @@ Status Optimizer::Optimize(const af::ComputeGraphPtr &fused_graph,
594 } else {608 } else {
595 hint_graph = asc_backend_to_ascgraph.begin()->second;609 hint_graph = asc_backend_to_ascgraph.begin()->second;
596 }610 }
597- 
598 auto owner_graph = af::AscGraphUtils::GetComputeGraph(hint_graph);611 auto owner_graph = af::AscGraphUtils::GetComputeGraph(hint_graph);
599 GE_ASSERT_NOTNULL(owner_graph);612 GE_ASSERT_NOTNULL(owner_graph);
600 owner_graph->SetName(ascgen_utils::GenValidName(fused_graph->GetName()));613 owner_graph->SetName(ascgen_utils::GenValidName(fused_graph->GetName()));
601 GE_ASSERT_SUCCESS(Optimize(hint_graph, fused_scheduled_result), "optimize failed, graph:[%s].",614 GE_ASSERT_SUCCESS(Optimize(hint_graph, fused_scheduled_result), "optimize failed, graph:[%s].",
602 hint_graph.GetName().c_str());615 hint_graph.GetName().c_str());
616+ GE_CHK_STATUS_RET(AscGraphInfoComplete::NormalizeFrontendShapeVars(frontend_shape_vars),
617+ "Normalize frontend shape vars failed, graph:[%s].", fused_graph->GetName().c_str());
618+ fused_scheduled_result.frontend_shape_vars = std::move(frontend_shape_vars);
619+ fused_scheduled_result.frontend_shape_vars_collected = true;
603 // modify origin var and fused_graph620 // modify origin var and fused_graph
604 fused_scheduled_result.fused_graph_name = fused_graph->GetName().c_str();621 fused_scheduled_result.fused_graph_name = fused_graph->GetName().c_str();
605 fused_scheduled_result.origin_vars.assign(original_var_set.begin(), original_var_set.end());622 fused_scheduled_result.origin_vars.assign(original_var_set.begin(), original_var_set.end());
606 return af::SUCCESS;623 return af::SUCCESS;
607}624}
608 625 
609-Status Optimizer::OptimizeFusedAscBackend(const af::ComputeGraphPtr &fused_graph,626+Status Optimizer::CollectAscBackendNodes(const af::ComputeGraphPtr &fused_graph,
610- ascir::FusedScheduledResult &fused_scheduled_result) const {627+ std::map<af::Node *, af::AscGraph> &asc_backend_to_ascgraph,
611- std::map<af::Node *, af::AscGraph> asc_backend_to_ascgraph;628+ SizeVarSet &original_var_set,
612- SizeVarSet original_var_set;629+ std::vector<af::Expression> &frontend_shape_vars) const {
613 for (auto &node : fused_graph->GetDirectNodePtr()) {630 for (auto &node : fused_graph->GetDirectNodePtr()) {
614 GE_ASSERT_NOTNULL(node);631 GE_ASSERT_NOTNULL(node);
615 if (node->GetType() == kAscBackendType) {632 if (node->GetType() == kAscBackendType) {
@@ -618,6 +635,10 @@ Status Optimizer::OptimizeFusedAscBackend(const af::ComputeGraphPtr &fused_graph
618 auto fuse_asc_graph = fuse_attr->GetAscGraph();635 auto fuse_asc_graph = fuse_attr->GetAscGraph();
619 GE_ASSERT_NOTNULL(fuse_asc_graph, "Cannot get ascgraph from ascbc node:[%s].", node->GetNamePtr());636 GE_ASSERT_NOTNULL(fuse_asc_graph, "Cannot get ascgraph from ascbc node:[%s].", node->GetNamePtr());
620 ascir::utils::DumpGraph(*fuse_asc_graph, "AutoFuseBeforeRemoveDanglingNodes");637 ascir::utils::DumpGraph(*fuse_asc_graph, "AutoFuseBeforeRemoveDanglingNodes");
638+ std::vector<af::Expression> graph_shape_vars;
639+ GE_CHK_STATUS_RET(AscGraphInfoComplete::CollectFrontendShapeVars(*fuse_asc_graph, graph_shape_vars),
640+ "Collect frontend shape vars failed, graph:[%s].", fuse_asc_graph->GetName().c_str());
641+ frontend_shape_vars.insert(frontend_shape_vars.end(), graph_shape_vars.begin(), graph_shape_vars.end());
621 GE_CHK_STATUS_RET(RemoveDanglingNodes(*fuse_asc_graph), "Remove dangling nodes failed, graph:[%s].",642 GE_CHK_STATUS_RET(RemoveDanglingNodes(*fuse_asc_graph), "Remove dangling nodes failed, graph:[%s].",
622 fuse_asc_graph->GetName().c_str());643 fuse_asc_graph->GetName().c_str());
623 ::ascir::utils::DumpGraph(*fuse_asc_graph, "AutoFuseBeforeOptimize");644 ::ascir::utils::DumpGraph(*fuse_asc_graph, "AutoFuseBeforeOptimize");
@@ -627,6 +648,20 @@ Status Optimizer::OptimizeFusedAscBackend(const af::ComputeGraphPtr &fused_graph
627 }648 }
628 GE_ASSERT_TRUE(!asc_backend_to_ascgraph.empty(), "The fused graph [%s] is invalid, which has none AscBackend node.",649 GE_ASSERT_TRUE(!asc_backend_to_ascgraph.empty(), "The fused graph [%s] is invalid, which has none AscBackend node.",
629 fused_graph->GetName().c_str());650 fused_graph->GetName().c_str());
651+ GE_CHK_STATUS_RET(AscGraphInfoComplete::NormalizeFrontendShapeVars(frontend_shape_vars),
652+ "Normalize frontend shape vars failed, graph:[%s].", fused_graph->GetName().c_str());
653+ return af::SUCCESS;
654+}
655+ 
656+Status Optimizer::OptimizeFusedAscBackend(const af::ComputeGraphPtr &fused_graph,
657+ ascir::FusedScheduledResult &fused_scheduled_result) const {
658+ std::map<af::Node *, af::AscGraph> asc_backend_to_ascgraph;
659+ SizeVarSet original_var_set;
660+ std::vector<af::Expression> frontend_shape_vars;
661+ GE_CHK_STATUS_RET(CollectAscBackendNodes(fused_graph, asc_backend_to_ascgraph, original_var_set, frontend_shape_vars),
662+ "Collect ascbackend nodes failed, graph:[%s].", fused_graph->GetName().c_str());
663+ fused_scheduled_result.frontend_shape_vars = std::move(frontend_shape_vars);
664+ fused_scheduled_result.frontend_shape_vars_collected = true;
630 665 
631 GE_ASSERT_SUCCESS(FusedGraphModifier::SubgraphConnectionsToWorkspace(fused_graph, asc_backend_to_ascgraph),666 GE_ASSERT_SUCCESS(FusedGraphModifier::SubgraphConnectionsToWorkspace(fused_graph, asc_backend_to_ascgraph),
632 "Failed to add workspace between ascgraphs.");667 "Failed to add workspace between ascgraphs.");
@@ -965,6 +1000,12 @@ Status Optimizer::LoadOpSeqAdjust(const af::AscGraph &impl_graph) {
965 1000 
966Status Optimizer::Optimize(af::AscGraph &hint_graph, FusedScheduledResult &fused_scheduled_result) {1001Status Optimizer::Optimize(af::AscGraph &hint_graph, FusedScheduledResult &fused_scheduled_result) {
967 ascir::utils::DumpGraph(hint_graph, "AutoFuseBeforeRemoveDanglingNodes");1002 ascir::utils::DumpGraph(hint_graph, "AutoFuseBeforeRemoveDanglingNodes");
1003+ GE_CHK_STATUS_RET(
1004+ AscGraphInfoComplete::CollectFrontendShapeVars(hint_graph, fused_scheduled_result.frontend_shape_vars),
1005+ "Collect frontend shape vars failed, graph:[%s].", hint_graph.GetName().c_str());
1006+ fused_scheduled_result.frontend_shape_vars_collected = true;
1007+ GE_CHK_STATUS_RET(AscGraphInfoComplete::NormalizeFrontendShapeVars(fused_scheduled_result.frontend_shape_vars),
1008+ "Normalize frontend shape vars failed, graph:[%s].", hint_graph.GetName().c_str());
968 GE_CHK_STATUS_RET(RemoveDanglingNodes(hint_graph), "Remove dangling nodes failed, graph:[%s].",1009 GE_CHK_STATUS_RET(RemoveDanglingNodes(hint_graph), "Remove dangling nodes failed, graph:[%s].",
969 hint_graph.GetName().c_str());1010 hint_graph.GetName().c_str());
970 ascir::utils::DumpGraph(hint_graph, "AutoFuseBeforeOptimize");1011 ascir::utils::DumpGraph(hint_graph, "AutoFuseBeforeOptimize");
@@ -12,6 +12,7 @@
12#define OPTIMIZE_OPTIMIZE_H_12#define OPTIMIZE_OPTIMIZE_H_
13 13 
14#include "ascir.h"14#include "ascir.h"
15+#include "ascgraph_info_complete.h"
15#include "schedule_result.h"16#include "schedule_result.h"
16#include "ascgen_log.h"17#include "ascgen_log.h"
17 18 
@@ -79,6 +80,12 @@ class Optimizer {
79 */80 */
80 Status OptimizeFusedAscBackend(const af::ComputeGraphPtr &fused_graph,81 Status OptimizeFusedAscBackend(const af::ComputeGraphPtr &fused_graph,
81 ::ascir::FusedScheduledResult &fused_scheduled_result) const;82 ::ascir::FusedScheduledResult &fused_scheduled_result) const;
83+ Status DeserializeAscGraphNodes(const af::ComputeGraphPtr &fused_graph,
84+ std::map<af::Node *, af::AscGraph> &asc_backend_to_ascgraph,
85+ SizeVarSet &original_var_set, std::vector<af::Expression> &frontend_shape_vars);
86+ Status CollectAscBackendNodes(const af::ComputeGraphPtr &fused_graph,
87+ std::map<af::Node *, af::AscGraph> &asc_backend_to_ascgraph,
88+ SizeVarSet &original_var_set, std::vector<af::Expression> &frontend_shape_vars) const;
82 89 
83 /**90 /**
84 * Buf/Que 分配91 * Buf/Que 分配
@@ -149,7 +149,7 @@ add_subdirectory(concat_small_tail_dim)
149add_subdirectory(concat_inter_dim)149add_subdirectory(concat_inter_dim)
150add_subdirectory(concat_3d_last_dim)150add_subdirectory(concat_3d_last_dim)
151# add_subdirectory(concat_mult_inputs)151# add_subdirectory(concat_mult_inputs)
152-# add_subdirectory(dynamic_inputs_and_outputs)152+add_subdirectory(dynamic_inputs_and_outputs)
153add_subdirectory(load_max_min_store)153add_subdirectory(load_max_min_store)
154# add_subdirectory(load_rsum_store)154# add_subdirectory(load_rsum_store)
155add_subdirectory(load_rsum_block_store)155add_subdirectory(load_rsum_block_store)
@@ -15,6 +15,7 @@
15#include "codegen.h"15#include "codegen.h"
16#include "e2e_load_abs_store.h"16#include "e2e_load_abs_store.h"
17#include "e2e_common.h"17#include "e2e_common.h"
18+#include "ascgraph_info_complete.h"
18 19 
19#include <iostream>20#include <iostream>
20#include <vector>21#include <vector>
@@ -119,3 +120,38 @@ TEST_F(DynamicInputsAndOutputsST, DynamicInputsAndOutputsCodegen) {
119 120 
120 EXPECT_EQ(gen_success, true);121 EXPECT_EQ(gen_success, true);
121}122}
123+ 
124+TEST_F(DynamicInputsAndOutputsST, FrontendShapeAbiKeepsNaturalKsOrderWhenImplDropsSymbols) {
125+ auto fused_schedule_result = GenTestCase(1);
126+ fused_schedule_result.fused_graph_name = af::AscendString("dynamic_inputs_and_outputs_frontend_shape_abi");
127+ af::AscGraph original_asc_graph("dynamic_inputs_and_outputs_frontend_shape_abi_original");
128+ original_asc_graph.CreateSizeVar("ks10");
129+ original_asc_graph.CreateSizeVar("ks2");
130+ original_asc_graph.CreateSizeVar("ks0");
131+ original_asc_graph.CreateSizeVar("ks1");
132+ ASSERT_EQ(optimize::AscGraphInfoComplete::CollectFrontendShapeVars(original_asc_graph,
133+ fused_schedule_result.frontend_shape_vars),
134+ af::SUCCESS);
135+ ASSERT_EQ(optimize::AscGraphInfoComplete::NormalizeFrontendShapeVars(fused_schedule_result.frontend_shape_vars),
136+ af::SUCCESS);
137+ // The optimized implementation graph is intentionally modeled as retaining only one symbol.
138+ fused_schedule_result.origin_vars = {af::Symbol("ks0")};
139+ 
140+ codegen::Codegen codegen(codegen::CodegenOptions{});
141+ codegen::CodegenResult result;
142+ ASSERT_EQ(codegen.GenerateForInductor(fused_schedule_result, result), af::SUCCESS);
143+ 
144+ const auto signature_begin = result.tiling.find("extern \"C\" int64_t AutofuseTiling(");
145+ ASSERT_NE(signature_begin, std::string::npos);
146+ const auto signature_end = result.tiling.find(")", signature_begin);
147+ ASSERT_NE(signature_end, std::string::npos);
148+ const auto signature = result.tiling.substr(signature_begin, signature_end - signature_begin);
149+ 
150+ size_t previous = 0U;
151+ for (const auto &symbol : {std::string("ks0"), std::string("ks1"), std::string("ks2"), std::string("ks10")}) {
152+ const auto current = signature.find(symbol);
153+ ASSERT_NE(current, std::string::npos) << symbol << " missing from generated AutofuseTiling ABI";
154+ EXPECT_GE(current, previous) << "generated symbol order does not match frontend order";
155+ previous = current;
156+ }
157+}
@@ -47,6 +47,44 @@ TEST_F(CommonUtilsTest, IsStaticSchedResultTest) {
47 EXPECT_EQ(IsStaticSchedResult({static_result}), true);47 EXPECT_EQ(IsStaticSchedResult({static_result}), true);
48}48}
49 49 
50+TEST_F(CommonUtilsTest, FrontendShapeVarsTakePrecedenceOverImplVars) {
51+ ascir::FusedScheduledResult result;
52+ result.frontend_shape_vars = {af::Symbol("ks0"), af::Symbol("ks1"), af::Symbol("ks2"), af::Symbol("ks10")};
53+ result.frontend_shape_vars_collected = true;
54+ // Simulate an optimized impl graph that no longer retains the frontend
55+ // symbols and therefore remains static under the original internal rule.
56+ result.origin_vars = {af::Symbol(10)};
57+ 
58+ const auto &vars = GetFrontendShapeVars(result);
59+ ASSERT_EQ(vars.size(), 4U);
60+ EXPECT_EQ(af::SymbolicUtils::ToString(vars[0]), "ks0");
61+ EXPECT_EQ(af::SymbolicUtils::ToString(vars[1]), "ks1");
62+ EXPECT_EQ(af::SymbolicUtils::ToString(vars[2]), "ks2");
63+ EXPECT_EQ(af::SymbolicUtils::ToString(vars[3]), "ks10");
64+ EXPECT_TRUE(IsStaticSchedResult(result));
65+ EXPECT_FALSE(IsFrontendStaticSchedResult(result));
66+}
67+ 
68+TEST_F(CommonUtilsTest, FrontendShapeVarsFallbackToOriginVars) {
69+ ascir::FusedScheduledResult result;
70+ result.origin_vars = {af::Symbol(10), af::Symbol(20)};
71+ 
72+ const auto &vars = GetFrontendShapeVars(result);
73+ ASSERT_EQ(vars.size(), 2U);
74+ EXPECT_TRUE(vars[0].IsConstExpr());
75+ EXPECT_TRUE(IsStaticSchedResult(result));
76+}
77+ 
78+TEST_F(CommonUtilsTest, EmptyFrontendShapeVarsRemainStatic) {
79+ ascir::FusedScheduledResult result;
80+ result.frontend_shape_vars_collected = true;
81+ result.origin_vars = {af::Symbol("ks0")};
82+ 
83+ EXPECT_TRUE(GetFrontendShapeVars(result).empty());
84+ EXPECT_FALSE(IsStaticSchedResult(result));
85+ EXPECT_TRUE(IsFrontendStaticSchedResult(result));
86+}
87+ 
50TEST_F(CommonUtilsTest, ScalarValuePreProcessTest) {88TEST_F(CommonUtilsTest, ScalarValuePreProcessTest) {
51 std::string after_pre_pro_value;89 std::string after_pre_pro_value;
52 EXPECT_EQ(ScalarValuePreProcess("inf", "float", after_pre_pro_value), 0);90 EXPECT_EQ(ScalarValuePreProcess("inf", "float", after_pre_pro_value), 0);
@@ -0,0 +1,68 @@
1+/**
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <gtest/gtest.h>
12+ 
13+#include "ascgraph_info_complete.h"
14+#include "graph/symbolizer/symbolic_utils.h"
15+ 
16+namespace optimize {
17+namespace {
18+ 
19+std::vector<std::string> GetNames(const std::vector<af::Expression> &vars) {
20+ std::vector<std::string> names;
21+ names.reserve(vars.size());
22+ for (const auto &var : vars) {
23+ names.emplace_back(af::SymbolicUtils::ToString(var));
24+ }
25+ return names;
26+}
27+ 
28+TEST(FrontendShapeVarsTest, NormalizeKsNamesUsesNaturalOrder) {
29+ std::vector<af::Expression> vars = {af::Symbol("ks10"), af::Symbol("ks2"), af::Symbol("ks0"), af::Symbol("ks1"),
30+ af::Symbol("ks2")};
31+ 
32+ ASSERT_EQ(AscGraphInfoComplete::NormalizeFrontendShapeVars(vars), af::SUCCESS);
33+ EXPECT_EQ(GetNames(vars), (std::vector<std::string>{"ks0", "ks1", "ks2", "ks10"}));
34+}
35+ 
36+TEST(FrontendShapeVarsTest, NormalizeKsNamesAllowsSparseIndices) {
37+ std::vector<af::Expression> vars = {af::Symbol("ks0"), af::Symbol("ks2")};
38+ 
39+ ASSERT_EQ(AscGraphInfoComplete::NormalizeFrontendShapeVars(vars), af::SUCCESS);
40+ EXPECT_EQ(GetNames(vars), (std::vector<std::string>{"ks0", "ks2"}));
41+}
42+ 
43+TEST(FrontendShapeVarsTest, CollectsOriginalAscGraphSymbolsBeforeOptimization) {
44+ af::AscGraph graph("frontend_shape_vars");
45+ graph.CreateSizeVar("ks10");
46+ graph.CreateSizeVar("ks2");
47+ graph.CreateSizeVar("ks0");
48+ graph.CreateSizeVar(16);
49+ 
50+ std::vector<af::Expression> vars;
51+ ASSERT_EQ(AscGraphInfoComplete::CollectFrontendShapeVars(graph, vars), af::SUCCESS);
52+ ASSERT_EQ(AscGraphInfoComplete::NormalizeFrontendShapeVars(vars), af::SUCCESS);
53+ EXPECT_EQ(GetNames(vars), (std::vector<std::string>{"ks0", "ks2", "ks10"}));
54+}
55+ 
56+TEST(FrontendShapeVarsTest, CollectsSymbolsEmbeddedInAxisExpressions) {
57+ af::AscGraph graph("axis_shape_vars");
58+ const auto shape = af::Symbol("s0");
59+ graph.CreateAxis("z0", shape);
60+ 
61+ std::vector<af::Expression> vars;
62+ ASSERT_EQ(AscGraphInfoComplete::CollectFrontendShapeVars(graph, vars), af::SUCCESS);
63+ ASSERT_EQ(AscGraphInfoComplete::NormalizeFrontendShapeVars(vars), af::SUCCESS);
64+ EXPECT_EQ(GetNames(vars), (std::vector<std::string>{"s0"}));
65+}
66+ 
67+} // namespace
68+} // namespace optimize
@@ -586,6 +586,7 @@ codegen_e2e_st() {
586 concat_inter_dim_e2e \586 concat_inter_dim_e2e \
587 load_ub2ub_abs_store_expect_code_e2e \587 load_ub2ub_abs_store_expect_code_e2e \
588 concat_3d_last_dim_e2e \588 concat_3d_last_dim_e2e \
589+ dynamic_inputs_and_outputs_e2e \
589 load_isfinite_store_e2e \590 load_isfinite_store_e2e \
590 load_max_min_store_e2e \591 load_max_min_store_e2e \
591 load_rsum_block_store_e2e \592 load_rsum_block_store_e2e \