已合并
fix:【 ABI约束】保证后端生成AutofuseTiling时使用前端的符号和顺序 #1753
zhang_shengjie创建于 8月15日
fix:【 ABI约束】保证后端生成AutofuseTiling时使用前端的符号和顺序 #1753
已合并
共 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 | |||
| 1130 | void TilingLib::GenInductorShapeDim(const ascir::FusedScheduledResult &elemwise_schedule_result, | 1130 | void 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) { | |||
| 1389 | static void FillShapeDimInfo(const ascir::FusedScheduledResult &fused_schedule_result, | 1389 | static 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 | 11 | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 12 | 15 | ||
| 13 | 16 | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 14 | 20 | ||
| 15 | 21 | ||
| 16 | 22 | ||
| @@ -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 | + | ||
| 39 | void CompleteDataApiInfo(af::AscNodePtr &node) { | 65 | void 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 optimize | 341 | } // namespace optimize |
| @@ -11,6 +11,9 @@ | |||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 14 | 17 | ||
| 15 | 18 | ||
| 16 | 19 | ||
| @@ -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 optimize | 48 | } // namespace optimize |
| 37 | 49 | ||
| @@ -215,7 +215,7 @@ af::Expression CalculateWorkspaceSize(const std::vector<af::AscNodePtr> &workspa | |||
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result) { | 217 | bool 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 | + | ||
| 228 | af::Status ScalarValuePreProcess(const std::string &ori_value, const std::string &dtype, | 244 | af::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 | |||
| 162 | bool IsScalarNextNodeSupportBlkTensor(const af::AscNodePtr &node); | 162 | bool IsScalarNextNodeSupportBlkTensor(const af::AscNodePtr &node); |
| 163 | bool IsUbScalarLoad(const af::AscNodePtr &node); | 163 | bool IsUbScalarLoad(const af::AscNodePtr &node); |
| 164 | bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result); | 164 | bool 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); | ||
| 165 | af::Status ScalarValuePreProcess(const std::string &ori_value, const std::string &dtype, | 173 | af::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); |
| 167 | void MergeBrcAxisRepeats(const std::vector<af::Expression> &input0_repeats, // 输入0的vector_repeats, 带广播 | 175 | void 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 | 11 | ||
| 12 | + | ||
| 12 | 13 | ||
| 13 | 14 | ||
| 14 | 15 | ||
| @@ -552,18 +553,10 @@ Status Optimizer::ExpandReduceFirstStageResults(std::vector<autoschedule::AutoSc | |||
| 552 | 553 | ||
| 553 | Optimizer::Optimizer(const OptimizerOptions &options) : options_(options) {} | 554 | Optimizer::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_name | 559 | + 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 the | 602 | // 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_graph | 620 | // 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 | ||
| 966 | Status Optimizer::Optimize(af::AscGraph &hint_graph, FusedScheduledResult &fused_scheduled_result) { | 1001 | Status 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 | 12 | ||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | + | ||
| 15 | 16 | ||
| 16 | 17 | ||
| 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) | |||
| 149 | add_subdirectory(concat_inter_dim) | 149 | add_subdirectory(concat_inter_dim) |
| 150 | add_subdirectory(concat_3d_last_dim) | 150 | add_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) |
| 153 | add_subdirectory(load_max_min_store) | 153 | add_subdirectory(load_max_min_store) |
| 154 | # add_subdirectory(load_rsum_store) | 154 | # add_subdirectory(load_rsum_store) |
| 155 | add_subdirectory(load_rsum_block_store) | 155 | add_subdirectory(load_rsum_block_store) |
Mautofuse/tests/st/codegen/e2e/dynamic_inputs_and_outputs/dynamic_inputs_and_outputs_codegen.cpp+36-0
| @@ -15,6 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | + | ||
| 18 | 19 | ||
| 19 | 20 | ||
| 20 | 21 | ||
| @@ -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 | + | ||
| 50 | TEST_F(CommonUtilsTest, ScalarValuePreProcessTest) { | 88 | TEST_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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 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 \ |