已合并
feat: 完善 IndirectLoad SIMD 和 SIMT 支持 #1542
xiebangrui2025创建于 7月28日
feat: 完善 IndirectLoad SIMD 和 SIMT 支持 #1542
已合并
共 31 个文件变更+1293-593
| @@ -878,7 +878,7 @@ af::Status AscendGraphParser::ConvertToTuningSpace(const af::AscGraph &graph) { | |||
| 878 | continue; | 878 | continue; |
| 879 | } | 879 | } |
| 880 | const auto indirect_load_behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node); | 880 | const auto indirect_load_behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node); |
| 881 | - if (indirect_load_behavior.uses_direct_gm_pipeline || indirect_load_behavior.skips_api_emit) { | 881 | + if (indirect_load_behavior.uses_direct_gm_pipeline) { |
| 882 | GELOGD("[IndirectLoad] Skip tuning-space node info for node[%s], direct_gm[%d], skips_emit[%d].", | 882 | GELOGD("[IndirectLoad] Skip tuning-space node info for node[%s], direct_gm[%d], skips_emit[%d].", |
| 883 | node->GetNamePtr(), static_cast<int32_t>(indirect_load_behavior.uses_direct_gm_pipeline), | 883 | node->GetNamePtr(), static_cast<int32_t>(indirect_load_behavior.uses_direct_gm_pipeline), |
| 884 | static_cast<int32_t>(indirect_load_behavior.skips_api_emit)); | 884 | static_cast<int32_t>(indirect_load_behavior.skips_api_emit)); |
| @@ -28,7 +28,6 @@ | |||
| 28 | #include "indirect_load_utils.h" | 28 | #include "indirect_load_utils.h" |
| 29 | #include "optimize/platform/platform_factory.h" | 29 | #include "optimize/platform/platform_factory.h" |
| 30 | #include "optimize/schedule_utils.h" | 30 | #include "optimize/schedule_utils.h" |
| 31 | -#include "v35/codegen/simt_scalar_call/simt_scalar_emitter.h" | ||
| 32 | #include "common/platform_context.h" | 31 | #include "common/platform_context.h" |
| 33 | #include "codegen_graph_check.h" | 32 | #include "codegen_graph_check.h" |
| 34 | 33 | ||
| @@ -67,10 +66,7 @@ Status AllocateQues(TPipe &tpipe, const QueCollection &collection) { | |||
| 67 | const auto new_que = tpipe.ques.emplace(iter.first, TQue{iter.first, iter.second, position}); | 66 | const auto new_que = tpipe.ques.emplace(iter.first, TQue{iter.first, iter.second, position}); |
| 68 | GE_CHK_BOOL_RET_STATUS(new_que.second, af::FAILED, "Codegen emplace que [%ld] failed", iter.first); | 67 | GE_CHK_BOOL_RET_STATUS(new_que.second, af::FAILED, "Codegen emplace que [%ld] failed", iter.first); |
| 69 | } | 68 | } |
| 70 | - const auto skip_iter = collection.direct_gm_ques.find(iter.first); | 69 | + tpipe.ques.at(iter.first).skip_init_for_simt_direct_gm = collection.direct_gm_ques.at(iter.first); |
| 71 | - if (skip_iter != collection.direct_gm_ques.end()) { | ||
| 72 | - tpipe.ques.at(iter.first).skip_init_for_simt_direct_gm = skip_iter->second; | ||
| 73 | - } | ||
| 74 | } | 70 | } |
| 75 | for (auto &[id, que] : tpipe.ques) { | 71 | for (auto &[id, que] : tpipe.ques) { |
| 76 | if (id != tpipe.cube_output_que_id) { | 72 | if (id != tpipe.cube_output_que_id) { |
| @@ -2215,8 +2211,7 @@ Status Kernel::ParseGraph(const ascir::ImplGraph &graph, const ascir::FusedSched | |||
| 2215 | continue; | 2211 | continue; |
| 2216 | } | 2212 | } |
| 2217 | const auto indirect_load_behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node); | 2213 | const auto indirect_load_behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node); |
| 2218 | - if (indirect_load_behavior.skips_api_emit && indirect_load_behavior.uses_direct_gm_pipeline && | 2214 | + if (indirect_load_behavior.skips_api_emit && !IsOps<Store>(node)) { |
| 2219 | - !IsOps<Store>(node)) { | ||
| 2220 | continue; | 2215 | continue; |
| 2221 | } | 2216 | } |
| 2222 | 2217 | ||
| @@ -19,7 +19,6 @@ | |||
| 19 | #include "api_call/utils/api_call_factory.h" | 19 | #include "api_call/utils/api_call_factory.h" |
| 20 | #include "graph/ascendc_ir/utils/asc_tensor_utils.h" | 20 | #include "graph/ascendc_ir/utils/asc_tensor_utils.h" |
| 21 | #include "indirect_load_utils.h" | 21 | #include "indirect_load_utils.h" |
| 22 | -#include "v35/codegen/simt_scalar_call/simt_scalar_emitter.h" | ||
| 23 | 22 | ||
| 24 | using namespace std; | 23 | using namespace std; |
| 25 | using namespace af::ops; | 24 | using namespace af::ops; |
| @@ -305,7 +304,7 @@ Status Loop::ConstructFromNodes(ascir::NodeViewVisitorConst nodes, const Tiler & | |||
| 305 | TraverseGraphForReduceNodes(nodes, current_loop->is_graph_has_reduce_node, current_loop->is_ar); | 304 | TraverseGraphForReduceNodes(nodes, current_loop->is_graph_has_reduce_node, current_loop->is_ar); |
| 306 | auto lifecycle_edge = GetLifecycleEdge(nodes, tpipe); | 305 | auto lifecycle_edge = GetLifecycleEdge(nodes, tpipe); |
| 307 | for (auto node : nodes) { | 306 | for (auto node : nodes) { |
| 308 | - if (IsSkippedApiEmitProcessNode(node)) { | 307 | + if (ascgen_utils::indirect_load::GetTemplateBehavior(std::dynamic_pointer_cast<af::AscNode>(node)).skips_api_emit) { |
| 309 | GE_CHK_STATUS_RET(AddSkippedApiEmitProcessCall(node, current_loop, current_axis, tensor_calls)); | 308 | GE_CHK_STATUS_RET(AddSkippedApiEmitProcessCall(node, current_loop, current_axis, tensor_calls)); |
| 310 | continue; | 309 | continue; |
| 311 | } | 310 | } |
| @@ -716,9 +715,7 @@ Status Loop::GenerateLoop(const Tiler &tiler, const TPipe &tpipe, std::vector<as | |||
| 716 | } | 715 | } |
| 717 | ss << "for (" << axis.AsArg() << " = 0; " << axis << " < " << axis.loop_size.Str() << "; " << axis << "++) " | 716 | ss << "for (" << axis.AsArg() << " = 0; " << axis << " < " << axis.loop_size.Str() << "; " << axis << "++) " |
| 718 | << "{" << std::endl; | 717 | << "{" << std::endl; |
| 719 | - const bool skip_calc_from_axis_for_indirect_load_simt = | 718 | + if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) { |
| 720 | - axis.type == Axis::Type::kAxisTypeTileInner && FindIndirectLoadOpCall(this, true) != nullptr; | ||
| 721 | - if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse && !skip_calc_from_axis_for_indirect_load_simt) { | ||
| 722 | ss << tiler.CalcFromAxis(axis.id); | 719 | ss << tiler.CalcFromAxis(axis.id); |
| 723 | } | 720 | } |
| 724 | GenerateEnCacheCondition(tiler, tpipe, axis, ss); | 721 | GenerateEnCacheCondition(tiler, tpipe, axis, ss); |
| @@ -14,7 +14,6 @@ | |||
| 14 | 14 | ||
| 15 | #include "ascir_ops.h" | 15 | #include "ascir_ops.h" |
| 16 | #include "ascir_ops_utils.h" | 16 | #include "ascir_ops_utils.h" |
| 17 | -#include "common_utils.h" | ||
| 18 | #include "schedule_result.h" | 17 | #include "schedule_result.h" |
| 19 | 18 | ||
| 20 | namespace ascgen_utils::indirect_load { | 19 | namespace ascgen_utils::indirect_load { |
| @@ -39,30 +38,24 @@ TemplateBehavior GetBehavior(TemplateRole role) { | |||
| 39 | TemplateBehavior behavior; | 38 | TemplateBehavior behavior; |
| 40 | switch (role) { | 39 | switch (role) { |
| 41 | case TemplateRole::kSimdInputPre: | 40 | case TemplateRole::kSimdInputPre: |
| 42 | - behavior.skips_main_schedule_tiling = true; | 41 | + behavior.excludes_tiling_group = true; |
| 43 | - behavior.skips_api_emit = true; | ||
| 44 | behavior.preserves_vectorized_axis = true; | 42 | behavior.preserves_vectorized_axis = true; |
| 45 | break; | 43 | break; |
| 46 | - case TemplateRole::kSimdOp: | ||
| 47 | - break; | ||
| 48 | case TemplateRole::kSimtInputBoundary: | 44 | case TemplateRole::kSimtInputBoundary: |
| 49 | behavior.skips_main_schedule_tiling = true; | 45 | behavior.skips_main_schedule_tiling = true; |
| 50 | behavior.skips_api_emit = true; | 46 | behavior.skips_api_emit = true; |
| 51 | behavior.uses_direct_gm_pipeline = true; | 47 | behavior.uses_direct_gm_pipeline = true; |
| 52 | - behavior.skips_ub_expr = true; | ||
| 53 | behavior.preserves_vectorized_axis = true; | 48 | behavior.preserves_vectorized_axis = true; |
| 54 | break; | 49 | break; |
| 55 | case TemplateRole::kSimtDirectGmBoundary: | 50 | case TemplateRole::kSimtDirectGmBoundary: |
| 56 | case TemplateRole::kSimtInlineTransform: | 51 | case TemplateRole::kSimtInlineTransform: |
| 57 | behavior.skips_api_emit = true; | 52 | behavior.skips_api_emit = true; |
| 58 | behavior.uses_direct_gm_pipeline = true; | 53 | behavior.uses_direct_gm_pipeline = true; |
| 59 | - behavior.skips_ub_expr = true; | ||
| 60 | behavior.preserves_vectorized_axis = true; | 54 | behavior.preserves_vectorized_axis = true; |
| 61 | break; | 55 | break; |
| 62 | case TemplateRole::kSimtOp: | 56 | case TemplateRole::kSimtOp: |
| 63 | behavior.uses_direct_gm_pipeline = true; | 57 | behavior.uses_direct_gm_pipeline = true; |
| 64 | behavior.skips_ub_lifecycle = true; | 58 | behavior.skips_ub_lifecycle = true; |
| 65 | - behavior.skips_ub_expr = true; | ||
| 66 | behavior.preserves_vectorized_axis = true; | 59 | behavior.preserves_vectorized_axis = true; |
| 67 | break; | 60 | break; |
| 68 | case TemplateRole::kNone: | 61 | case TemplateRole::kNone: |
| @@ -82,8 +75,7 @@ TemplateBehavior GetTemplateBehavior(const af::AscNodePtr &node) { | |||
| 82 | 75 | ||
| 83 | af::Status InheritTemplateRoleIfIL(af::AscGraph &graph, const std::string &vf_node_name, const af::AscNodePtr &src) { | 76 | af::Status InheritTemplateRoleIfIL(af::AscGraph &graph, const std::string &vf_node_name, const af::AscNodePtr &src) { |
| 84 | GE_ASSERT_NOTNULL(src); | 77 | GE_ASSERT_NOTNULL(src); |
| 85 | - const auto &behavior = GetTemplateBehavior(src); | 78 | + if (GetTemplateRole(src) == TemplateRole::kNone) { |
| 86 | - if (!behavior.skips_api_emit && !behavior.uses_direct_gm_pipeline) { | ||
| 87 | return af::SUCCESS; | 79 | return af::SUCCESS; |
| 88 | } | 80 | } |
| 89 | auto vf_node = graph.FindNode(vf_node_name.c_str()); | 81 | auto vf_node = graph.FindNode(vf_node_name.c_str()); |
| @@ -157,9 +149,7 @@ bool ShouldApplyInputInnerVectorization(const af::AscNodePtr &node) { | |||
| 157 | } | 149 | } |
| 158 | 150 | ||
| 159 | bool ShouldDisableRegularVectorFunc(const af::AscNodePtr &node) { | 151 | bool ShouldDisableRegularVectorFunc(const af::AscNodePtr &node) { |
| 160 | - const TemplateRole role = GetTemplateRole(node); | 152 | + return GetTemplateBehavior(node).uses_direct_gm_pipeline; |
| 161 | - return role == TemplateRole::kSimtInputBoundary || role == TemplateRole::kSimtDirectGmBoundary || | ||
| 162 | - role == TemplateRole::kSimtInlineTransform || role == TemplateRole::kSimtOp; | ||
| 163 | } | 153 | } |
| 164 | 154 | ||
| 165 | af::AscNodePtr GetInputProducer(const af::AscNodePtr &node, size_t input_index) { | 155 | af::AscNodePtr GetInputProducer(const af::AscNodePtr &node, size_t input_index) { |
| @@ -21,7 +21,6 @@ namespace ascgen_utils::indirect_load { | |||
| 21 | enum class TemplateRole : int64_t { | 21 | enum class TemplateRole : int64_t { |
| 22 | kNone, | 22 | kNone, |
| 23 | kSimdInputPre, | 23 | kSimdInputPre, |
| 24 | - kSimdOp, | ||
| 25 | kSimtInputBoundary, | 24 | kSimtInputBoundary, |
| 26 | kSimtDirectGmBoundary, | 25 | kSimtDirectGmBoundary, |
| 27 | kSimtInlineTransform, | 26 | kSimtInlineTransform, |
| @@ -29,11 +28,11 @@ enum class TemplateRole : int64_t { | |||
| 29 | }; | 28 | }; |
| 30 | 29 | ||
| 31 | struct TemplateBehavior { | 30 | struct TemplateBehavior { |
| 31 | + bool excludes_tiling_group = false; | ||
| 32 | bool skips_main_schedule_tiling = false; | 32 | bool skips_main_schedule_tiling = false; |
| 33 | bool skips_api_emit = false; | 33 | bool skips_api_emit = false; |
| 34 | bool uses_direct_gm_pipeline = false; | 34 | bool uses_direct_gm_pipeline = false; |
| 35 | bool skips_ub_lifecycle = false; | 35 | bool skips_ub_lifecycle = false; |
| 36 | - bool skips_ub_expr = false; | ||
| 37 | bool preserves_vectorized_axis = false; | 36 | bool preserves_vectorized_axis = false; |
| 38 | }; | 37 | }; |
| 39 | 38 | ||
| @@ -307,7 +307,7 @@ af::Status AscGraphUbExprBuilder::Build(const af::AscGraph &graph, UbExprContext | |||
| 307 | std::map<int64_t, ContainerState> buffer_bytes; | 307 | std::map<int64_t, ContainerState> buffer_bytes; |
| 308 | for (const auto &node : graph.GetAllNodes()) { | 308 | for (const auto &node : graph.GetAllNodes()) { |
| 309 | GE_ASSERT_NOTNULL(node); | 309 | GE_ASSERT_NOTNULL(node); |
| 310 | - if (ascgen_utils::indirect_load::GetTemplateBehavior(node).skips_ub_expr) { | 310 | + if (ascgen_utils::indirect_load::GetTemplateBehavior(node).uses_direct_gm_pipeline) { |
| 311 | continue; | 311 | continue; |
| 312 | } | 312 | } |
| 313 | for (const auto &output : node->outputs()) { | 313 | for (const auto &output : node->outputs()) { |
| @@ -188,19 +188,6 @@ class AscIrCodegen { | |||
| 188 | (void)node; | 188 | (void)node; |
| 189 | return true; | 189 | return true; |
| 190 | } | 190 | } |
| 191 | - | ||
| 192 | - virtual bool IsSimtScalarSupported(const AscNode &node) const { | ||
| 193 | - (void)node; | ||
| 194 | - return false; | ||
| 195 | - } | ||
| 196 | - | ||
| 197 | - virtual ge::graphStatus GenerateSimtScalarExpr(const AscNode &node, const std::vector<std::string> &inputs, | ||
| 198 | - std::string &expr) const { | ||
| 199 | - (void)node; | ||
| 200 | - (void)inputs; | ||
| 201 | - (void)expr; | ||
| 202 | - return af::FAILED; | ||
| 203 | - } | ||
| 204 | }; | 191 | }; |
| 205 | 192 | ||
| 206 | class AscIrAtt { | 193 | class AscIrAtt { |
| @@ -520,7 +520,8 @@ Status AddIndirectLoadSyntheticOuterAxis(const af::AscNodePtr &node, ascir::Axis | |||
| 520 | return af::SUCCESS; | 520 | return af::SUCCESS; |
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | -Status ApplyIndirectLoadTemplateMerge(ascir::ImplGraph &graph, const af::AscNodePtr &node, ascir::AxisId axis_id) { | 523 | +Status ApplyIndirectLoadTemplateMerge(ascir::ImplGraph &graph, const af::AscNodePtr &node, ascir::AxisId axis_id, |
| 524 | + bool merge_tensor_axis = true) { | ||
| 524 | if (axis_id == af::kIdNone) { | 525 | if (axis_id == af::kIdNone) { |
| 525 | return af::SUCCESS; | 526 | return af::SUCCESS; |
| 526 | } | 527 | } |
| @@ -531,15 +532,19 @@ Status ApplyIndirectLoadTemplateMerge(ascir::ImplGraph &graph, const af::AscNode | |||
| 531 | node->GetNamePtr()); | 532 | node->GetNamePtr()); |
| 532 | GE_ASSERT_TRUE(graph.ApplySchedAxisMerge(node, axis_id), "Failed to merge schedule axis[%ld] for node[%s].", | 533 | GE_ASSERT_TRUE(graph.ApplySchedAxisMerge(node, axis_id), "Failed to merge schedule axis[%ld] for node[%s].", |
| 533 | axis_id, node->GetNamePtr()); | 534 | axis_id, node->GetNamePtr()); |
| 534 | - GE_ASSERT_TRUE(graph.ApplyTensorAxisMerge(node, axis_id), "Failed to merge tensor axis[%ld] for node[%s].", axis_id, | 535 | + if (merge_tensor_axis) { |
| 535 | - node->GetNamePtr()); | 536 | + GE_ASSERT_TRUE(graph.ApplyTensorAxisMerge(node, axis_id), "Failed to merge tensor axis[%ld] for node[%s].", |
| 537 | + axis_id, node->GetNamePtr()); | ||
| 538 | + } | ||
| 536 | } else { | 539 | } else { |
| 537 | GELOGD("[IndirectLoad] Graph[%s] apply single-axis template merge axis[%ld] for node[%s].", graph.GetName().c_str(), | 540 | GELOGD("[IndirectLoad] Graph[%s] apply single-axis template merge axis[%ld] for node[%s].", graph.GetName().c_str(), |
| 538 | axis_id, node->GetNamePtr()); | 541 | axis_id, node->GetNamePtr()); |
| 539 | GE_ASSERT_TRUE(graph.ApplySchedAxisMerge(node, axis_id, {axis_id}), | 542 | GE_ASSERT_TRUE(graph.ApplySchedAxisMerge(node, axis_id, {axis_id}), |
| 540 | "Failed to merge schedule axis[%ld] for node[%s].", axis_id, node->GetNamePtr()); | 543 | "Failed to merge schedule axis[%ld] for node[%s].", axis_id, node->GetNamePtr()); |
| 541 | - GE_ASSERT_TRUE(graph.ApplyTensorAxisMerge(node, axis_id, {axis_id}), | 544 | + if (merge_tensor_axis) { |
| 542 | - "Failed to merge tensor axis[%ld] for node[%s].", axis_id, node->GetNamePtr()); | 545 | + GE_ASSERT_TRUE(graph.ApplyTensorAxisMerge(node, axis_id, {axis_id}), |
| 546 | + "Failed to merge tensor axis[%ld] for node[%s].", axis_id, node->GetNamePtr()); | ||
| 547 | + } | ||
| 543 | } | 548 | } |
| 544 | return af::SUCCESS; | 549 | return af::SUCCESS; |
| 545 | } | 550 | } |
| @@ -598,8 +603,10 @@ Status Scheduler::ApplyIndirectLoadNodeAxes(const af::AscNodePtr &node, bool &sk | |||
| 598 | return af::SUCCESS; | 603 | return af::SUCCESS; |
| 599 | } | 604 | } |
| 600 | if (ascgen_utils::indirect_load::ShouldApplyInputInnerVectorization(node)) { | 605 | if (ascgen_utils::indirect_load::ShouldApplyInputInnerVectorization(node)) { |
| 601 | - skip_main_tiling = true; | ||
| 602 | GE_ASSERT_SUCCESS(ApplyInputInnerVectorizedAxis(graph_, node, indirect_load_axes_.input_inner_axis)); | 606 | GE_ASSERT_SUCCESS(ApplyInputInnerVectorizedAxis(graph_, node, indirect_load_axes_.input_inner_axis)); |
| 607 | + GE_ASSERT_SUCCESS(AddIndirectLoadSyntheticOuterAxis(node, indirect_load_axes_.outer_axis, | ||
| 608 | + has_indirect_load_synthetic_outer_axis_)); | ||
| 609 | + GE_ASSERT_SUCCESS(ApplyIndirectLoadTemplateMerge(graph_, node, indirect_load_axes_.outer_axis, false)); | ||
| 603 | return af::SUCCESS; | 610 | return af::SUCCESS; |
| 604 | } | 611 | } |
| 605 | if (ascgen_utils::indirect_load::ShouldSkipMainScheduleTiling(node)) { | 612 | if (ascgen_utils::indirect_load::ShouldSkipMainScheduleTiling(node)) { |
| @@ -484,8 +484,8 @@ Status TilingGroup::GenTilingGroup(const ascir::ImplGraph &impl_graph, AxisGroup | |||
| 484 | std::vector<std::pair<std::string, AxisGroup>> node_name_to_tiling_group; | 484 | std::vector<std::pair<std::string, AxisGroup>> node_name_to_tiling_group; |
| 485 | std::set<af::AxisId> n_groupset; | 485 | std::set<af::AxisId> n_groupset; |
| 486 | for (const auto &node : impl_graph.GetAllNodes()) { | 486 | for (const auto &node : impl_graph.GetAllNodes()) { |
| 487 | - if (ScheduleUtils::IsBuffer(node) || | 487 | + const auto behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node); |
| 488 | - ascgen_utils::indirect_load::GetTemplateBehavior(node).skips_main_schedule_tiling) { | 488 | + if (ScheduleUtils::IsBuffer(node) || behavior.skips_main_schedule_tiling || behavior.excludes_tiling_group) { |
| 489 | continue; | 489 | continue; |
| 490 | } | 490 | } |
| 491 | AxisGroup single_node_axes_group; | 491 | AxisGroup single_node_axes_group; |
| @@ -386,8 +386,7 @@ af::Status BaseAlignmentStrategy::AlignVectorizedStrides(ascir::ImplGraph &impl_ | |||
| 386 | for (const auto &node : impl_graph.GetAllNodes()) { | 386 | for (const auto &node : impl_graph.GetAllNodes()) { |
| 387 | GE_ASSERT_NOTNULL(node); | 387 | GE_ASSERT_NOTNULL(node); |
| 388 | const auto indirect_load_behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node); | 388 | const auto indirect_load_behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node); |
| 389 | - if (ScheduleUtils::IsBuffer(node) || indirect_load_behavior.uses_direct_gm_pipeline || | 389 | + if (ScheduleUtils::IsBuffer(node) || indirect_load_behavior.uses_direct_gm_pipeline) { |
| 390 | - indirect_load_behavior.skips_api_emit) { | ||
| 391 | continue; | 390 | continue; |
| 392 | } | 391 | } |
| 393 | GE_ASSERT_SUCCESS(SetVectorizedStridesForOneNode(node)); | 392 | GE_ASSERT_SUCCESS(SetVectorizedStridesForOneNode(node)); |
| @@ -12,12 +12,12 @@ | |||
| 12 | 12 | ||
| 13 | #include "ascir_ops.h" | 13 | #include "ascir_ops.h" |
| 14 | #include "ascir_ops_utils.h" | 14 | #include "ascir_ops_utils.h" |
| 15 | +#include "v35/ascir/ascir_codegen_v2.h" | ||
| 15 | #include "common_utils.h" | 16 | #include "common_utils.h" |
| 16 | #include "graph_utils.h" | 17 | #include "graph_utils.h" |
| 17 | #include "graph/symbolizer/symbolic.h" | 18 | #include "graph/symbolizer/symbolic.h" |
| 18 | #include "indirect_load_utils.h" | 19 | #include "indirect_load_utils.h" |
| 19 | #include "schedule_result.h" | 20 | #include "schedule_result.h" |
| 20 | -#include "schedule_utils.h" | ||
| 21 | 21 | ||
| 22 | #include <algorithm> | 22 | #include <algorithm> |
| 23 | #include <sstream> | 23 | #include <sstream> |
| @@ -76,15 +76,25 @@ bool HasExp2(const af::AscGraph &graph) { | |||
| 76 | return false; | 76 | return false; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | -bool IsTemplateCandidateLegal(ascir::TemplateId template_id, const IndirectLoadGraphPaths &paths) { | 79 | +af::Status ValidateTemplateCandidate(ascir::TemplateId template_id, const IndirectLoadGraphPaths &paths, |
| 80 | + bool &is_candidate_legal) { | ||
| 81 | + is_candidate_legal = true; | ||
| 80 | if (template_id != ascir::TemplateId::kIndirectLoadSimt) { | 82 | if (template_id != ascir::TemplateId::kIndirectLoadSimt) { |
| 81 | - return true; | 83 | + return af::SUCCESS; |
| 82 | } | 84 | } |
| 85 | + is_candidate_legal = false; | ||
| 83 | if (paths.data_input.empty()) { | 86 | if (paths.data_input.empty()) { |
| 84 | - return false; | 87 | + return af::SUCCESS; |
| 85 | } | 88 | } |
| 86 | const auto &input_node = paths.data_input.front(); | 89 | const auto &input_node = paths.data_input.front(); |
| 87 | - return af::ops::IsOps<af::ascir_op::Data>(input_node) || af::ops::IsOps<af::ascir_op::Load>(input_node); | 90 | + if (af::ops::IsOps<af::ascir_op::Data>(input_node)) { |
| 91 | + is_candidate_legal = true; | ||
| 92 | + } else if (af::ops::IsOps<af::ascir_op::Load>(input_node)) { | ||
| 93 | + GE_ASSERT_SUCCESS(ascgen_utils::indirect_load::SetTemplateRole( | ||
| 94 | + input_node, ascgen_utils::indirect_load::TemplateRole::kSimtInputBoundary)); | ||
| 95 | + is_candidate_legal = true; | ||
| 96 | + } | ||
| 97 | + return af::SUCCESS; | ||
| 88 | } | 98 | } |
| 89 | 99 | ||
| 90 | af::Status GetIndirectLoadAxis(const af::AscNodePtr &node, int64_t &axis) { | 100 | af::Status GetIndirectLoadAxis(const af::AscNodePtr &node, int64_t &axis) { |
| @@ -142,12 +152,12 @@ af::Status MergeAxesForTemplate(af::AscGraph &graph, const std::vector<af::AxisI | |||
| 142 | return af::SUCCESS; | 152 | return af::SUCCESS; |
| 143 | } | 153 | } |
| 144 | 154 | ||
| 145 | -af::Status CreateFixedTileSplit(af::AscGraph &graph, af::AxisId axis_id, af::AxisId &outer_id, af::AxisId &inner_id) { | 155 | +af::Status CreateFixedTileSplit(af::AscGraph &graph, af::AxisId axis_id) { |
| 146 | const auto *axis = graph.FindAxis(axis_id); | 156 | const auto *axis = graph.FindAxis(axis_id); |
| 147 | GE_ASSERT_NOTNULL(axis, "IndirectLoad fixed tile axis %ld is not found.", axis_id); | 157 | GE_ASSERT_NOTNULL(axis, "IndirectLoad fixed tile axis %ld is not found.", axis_id); |
| 148 | - outer_id = | 158 | + const af::AxisId outer_id = |
| 149 | graph.CreateAxis(axis->name + "T", ascir::Axis::Type::kAxisTypeTileOuter, axis->size, {axis_id}, af::kIdNone).id; | 159 | graph.CreateAxis(axis->name + "T", ascir::Axis::Type::kAxisTypeTileOuter, axis->size, {axis_id}, af::kIdNone).id; |
| 150 | - inner_id = | 160 | + const af::AxisId inner_id = |
| 151 | graph | 161 | graph |
| 152 | .CreateAxis(axis->name + "t", ascir::Axis::Type::kAxisTypeTileInner, af::sym::kSymbolOne, {axis_id}, outer_id) | 162 | .CreateAxis(axis->name + "t", ascir::Axis::Type::kAxisTypeTileInner, af::sym::kSymbolOne, {axis_id}, outer_id) |
| 153 | .id; | 163 | .id; |
| @@ -168,12 +178,11 @@ af::Status BuildSimdInputInnerAxis(af::AscGraph &graph, const af::AscNodePtr &in | |||
| 168 | return af::SUCCESS; | 178 | return af::SUCCESS; |
| 169 | } | 179 | } |
| 170 | af::Status BuildAxisViewByBoundary(af::AscGraph &graph, const std::vector<af::AxisId> &axes, size_t boundary, | 180 | af::Status BuildAxisViewByBoundary(af::AscGraph &graph, const std::vector<af::AxisId> &axes, size_t boundary, |
| 171 | - af::AxisId &outer_axis, af::AxisId &inner_axis, std::vector<af::AxisId> &outer_axes, | 181 | + af::AxisId &outer_axis, af::AxisId &inner_axis) { |
| 172 | - std::vector<af::AxisId> &inner_axes) { | ||
| 173 | GE_ASSERT_TRUE(!axes.empty(), "IndirectLoad output axis is empty."); | 182 | GE_ASSERT_TRUE(!axes.empty(), "IndirectLoad output axis is empty."); |
| 174 | const size_t split = std::min(boundary, axes.size()); | 183 | const size_t split = std::min(boundary, axes.size()); |
| 175 | - outer_axes.assign(axes.begin(), axes.begin() + static_cast<int64_t>(split)); | 184 | + const std::vector<af::AxisId> outer_axes(axes.begin(), axes.begin() + static_cast<int64_t>(split)); |
| 176 | - inner_axes.assign(axes.begin() + static_cast<int64_t>(split), axes.end()); | 185 | + const std::vector<af::AxisId> inner_axes(axes.begin() + static_cast<int64_t>(split), axes.end()); |
| 177 | if (outer_axes.empty()) { | 186 | if (outer_axes.empty()) { |
| 178 | outer_axis = graph.CreateAxis("indirect_load_single_outer", af::sym::kSymbolOne).id; | 187 | outer_axis = graph.CreateAxis("indirect_load_single_outer", af::sym::kSymbolOne).id; |
| 179 | } else { | 188 | } else { |
| @@ -192,13 +201,8 @@ af::Status NormalizeAxesForTemplate(af::AscGraph &graph, const af::AscNodePtr &i | |||
| 192 | const size_t boundary = static_cast<size_t>(axis < 0L ? axis + rank : axis); | 201 | const size_t boundary = static_cast<size_t>(axis < 0L ? axis + rank : axis); |
| 193 | ascir::AxisId outer_axis = af::kIdNone; | 202 | ascir::AxisId outer_axis = af::kIdNone; |
| 194 | ascir::AxisId inner_axis = af::kIdNone; | 203 | ascir::AxisId inner_axis = af::kIdNone; |
| 195 | - std::vector<ascir::AxisId> outer_axes; | 204 | + GE_ASSERT_SUCCESS(BuildAxisViewByBoundary(graph, output_axes, boundary, outer_axis, inner_axis)); |
| 196 | - std::vector<ascir::AxisId> inner_axes; | 205 | + GE_ASSERT_SUCCESS(CreateFixedTileSplit(graph, outer_axis)); |
| 197 | - GE_ASSERT_SUCCESS( | ||
| 198 | - BuildAxisViewByBoundary(graph, output_axes, boundary, outer_axis, inner_axis, outer_axes, inner_axes)); | ||
| 199 | - ascir::AxisId fixed_tile_outer_axis = af::kIdNone; | ||
| 200 | - ascir::AxisId fixed_tile_inner_axis = af::kIdNone; | ||
| 201 | - GE_ASSERT_SUCCESS(CreateFixedTileSplit(graph, outer_axis, fixed_tile_outer_axis, fixed_tile_inner_axis)); | ||
| 202 | GE_ASSERT_SUCCESS( | 206 | GE_ASSERT_SUCCESS( |
| 203 | ascgen_utils::indirect_load::SetTemplateAxes(indirect_load, {outer_axis, inner_axis, input_inner_axis})); | 207 | ascgen_utils::indirect_load::SetTemplateAxes(indirect_load, {outer_axis, inner_axis, input_inner_axis})); |
| 204 | return af::SUCCESS; | 208 | return af::SUCCESS; |
| @@ -217,6 +221,22 @@ af::Status NormalizeSimdAxesForTemplate(af::AscGraph &graph, const af::AscNodePt | |||
| 217 | if (input_producer != nullptr && !af::ops::IsOps<af::ascir_op::Data>(input_producer)) { | 221 | if (input_producer != nullptr && !af::ops::IsOps<af::ascir_op::Data>(input_producer)) { |
| 218 | GE_ASSERT_SUCCESS(BuildSimdInputInnerAxis(graph, input_producer, axis_index, input_inner_axis)); | 222 | GE_ASSERT_SUCCESS(BuildSimdInputInnerAxis(graph, input_producer, axis_index, input_inner_axis)); |
| 219 | } | 223 | } |
| 224 | + for (const auto &node : paths.data_input) { | ||
| 225 | + if (af::ops::IsOps<af::ascir_op::Data>(node)) { | ||
| 226 | + for (const auto &output : node->outputs()) { | ||
| 227 | + std::copy_n(output_axes.begin(), axis_index, output->attr.axis.begin()); | ||
| 228 | + } | ||
| 229 | + break; | ||
| 230 | + } | ||
| 231 | + if (ascgen_utils::indirect_load::GetTemplateRole(node) != | ||
| 232 | + ascgen_utils::indirect_load::TemplateRole::kSimdInputPre) { | ||
| 233 | + break; | ||
| 234 | + } | ||
| 235 | + std::copy_n(output_axes.begin(), axis_index, node->attr.sched.axis.begin()); | ||
| 236 | + for (const auto &output : node->outputs()) { | ||
| 237 | + std::copy_n(output_axes.begin(), axis_index, output->attr.axis.begin()); | ||
| 238 | + } | ||
| 239 | + } | ||
| 220 | return NormalizeAxesForTemplate(graph, indirect_load, axis, rank, input_inner_axis); | 240 | return NormalizeAxesForTemplate(graph, indirect_load, axis, rank, input_inner_axis); |
| 221 | } | 241 | } |
| 222 | 242 | ||
| @@ -232,7 +252,8 @@ bool CanEmitSimtScalar(const af::AscNodePtr &node) { | |||
| 232 | return false; | 252 | return false; |
| 233 | } | 253 | } |
| 234 | const auto impl = ascgen_utils::GetAscIrCodegenImpl(node->GetType()); | 254 | const auto impl = ascgen_utils::GetAscIrCodegenImpl(node->GetType()); |
| 235 | - return impl != nullptr && impl->IsSimtScalarSupported(*node); | 255 | + const auto *v2_impl = impl == nullptr ? nullptr : dynamic_cast<af::ascir::AscIrCodegenV2 *>(impl.get()); |
| 256 | + return v2_impl != nullptr && v2_impl->IsSimtScalarSupported(*node); | ||
| 236 | } | 257 | } |
| 237 | 258 | ||
| 238 | bool CollectMovableSimtInputPreNodes(const af::AscNodePtr &indirect_load, const NodePath &data_input, NodePath &nodes) { | 259 | bool CollectMovableSimtInputPreNodes(const af::AscNodePtr &indirect_load, const NodePath &data_input, NodePath &nodes) { |
| @@ -252,7 +273,34 @@ bool CollectMovableSimtInputPreNodes(const af::AscNodePtr &indirect_load, const | |||
| 252 | return false; | 273 | return false; |
| 253 | } | 274 | } |
| 254 | 275 | ||
| 255 | -af::Status MoveSimtInputPreNode(const af::AscNodePtr &node, const af::AscNodePtr &indirect_load) { | 276 | +bool IsSimdInputShapeEnlarged(const af::AscNodePtr &indirect_load) { |
| 277 | + af::Expression input_numel = af::sym::kSymbolOne; | ||
| 278 | + for (const af::Expression &repeat : indirect_load->inputs()[0]->attr.repeats) { | ||
| 279 | + input_numel = input_numel * repeat; | ||
| 280 | + } | ||
| 281 | + af::Expression output_numel = af::sym::kSymbolOne; | ||
| 282 | + for (const af::Expression &repeat : indirect_load->outputs()[0]->attr.repeats) { | ||
| 283 | + output_numel = output_numel * repeat; | ||
| 284 | + } | ||
| 285 | + return af::SymbolicUtils::StaticCheckGt(output_numel, input_numel) == af::TriBool::kTrue; | ||
| 286 | +} | ||
| 287 | + | ||
| 288 | +void CollectMovableSimdInputPreNodes(const af::AscNodePtr &indirect_load, const NodePath &data_input, NodePath &nodes) { | ||
| 289 | + af::AscNodePtr consumer = indirect_load; | ||
| 290 | + for (const auto ¤t : data_input) { | ||
| 291 | + if (af::ops::IsOps<af::ascir_op::Data>(current) || af::ops::IsOps<af::ascir_op::Load>(current) || | ||
| 292 | + current->inputs.Size() != 1UL || current->outputs().size() != 1UL || | ||
| 293 | + current->attr.api.compute_type != af::ComputeType::kComputeElewise || current->GetInControlNodesSize() != 0UL || | ||
| 294 | + current->GetOutControlNodesSize() != 0UL || | ||
| 295 | + ascgen_utils::indirect_load::GetOnlyOutputConsumer(current) != consumer) { | ||
| 296 | + return; | ||
| 297 | + } | ||
| 298 | + nodes.emplace_back(current); | ||
| 299 | + consumer = current; | ||
| 300 | + } | ||
| 301 | +} | ||
| 302 | + | ||
| 303 | +af::Status MoveInputPreNode(const af::AscNodePtr &node, const af::AscNodePtr &indirect_load) { | ||
| 256 | const auto producer = ascgen_utils::indirect_load::GetInputProducer(node, 0UL); | 304 | const auto producer = ascgen_utils::indirect_load::GetInputProducer(node, 0UL); |
| 257 | GE_ASSERT_NOTNULL(producer); | 305 | GE_ASSERT_NOTNULL(producer); |
| 258 | const auto producer_out = producer->GetOutDataAnchor(0UL); | 306 | const auto producer_out = producer->GetOutDataAnchor(0UL); |
| @@ -281,7 +329,7 @@ af::Status MoveSimtInputPreNode(const af::AscNodePtr &node, const af::AscNodePtr | |||
| 281 | node_output->attr.repeats = indirect_output->attr.repeats; | 329 | node_output->attr.repeats = indirect_output->attr.repeats; |
| 282 | node_output->attr.strides = indirect_output->attr.strides; | 330 | node_output->attr.strides = indirect_output->attr.strides; |
| 283 | indirect_output->attr.dtype = producer->outputs()[0]->attr.dtype; | 331 | indirect_output->attr.dtype = producer->outputs()[0]->attr.dtype; |
| 284 | - GELOGD("[IndirectLoad] Move SIMT input pre node[%s] after IndirectLoad[%s].", node->GetNamePtr(), | 332 | + GELOGD("[IndirectLoad] Move input pre node[%s] after IndirectLoad[%s].", node->GetNamePtr(), |
| 285 | indirect_load->GetNamePtr()); | 333 | indirect_load->GetNamePtr()); |
| 286 | return af::SUCCESS; | 334 | return af::SUCCESS; |
| 287 | } | 335 | } |
| @@ -295,7 +343,23 @@ af::Status MoveSimtInputPreNodes(const af::AscNodePtr &indirect_load, IndirectLo | |||
| 295 | return af::SUCCESS; | 343 | return af::SUCCESS; |
| 296 | } | 344 | } |
| 297 | for (const auto &node : nodes) { | 345 | for (const auto &node : nodes) { |
| 298 | - GE_ASSERT_SUCCESS(MoveSimtInputPreNode(node, indirect_load)); | 346 | + GE_ASSERT_SUCCESS(MoveInputPreNode(node, indirect_load)); |
| 347 | + } | ||
| 348 | + paths.data_input.erase(paths.data_input.begin(), paths.data_input.begin() + static_cast<int64_t>(nodes.size())); | ||
| 349 | + paths.output.insert(paths.output.begin(), nodes.rbegin(), nodes.rend()); | ||
| 350 | + return af::SUCCESS; | ||
| 351 | +} | ||
| 352 | + | ||
| 353 | +af::Status MoveSimdInputPreNodes(const af::AscNodePtr &indirect_load, IndirectLoadGraphPaths &paths) { | ||
| 354 | + if (IsSimdInputShapeEnlarged(indirect_load) || indirect_load->GetInControlNodesSize() != 0UL || | ||
| 355 | + indirect_load->GetOutControlNodesSize() != 0UL || | ||
| 356 | + ascgen_utils::indirect_load::GetOnlyOutputConsumer(indirect_load) == nullptr) { | ||
| 357 | + return af::SUCCESS; | ||
| 358 | + } | ||
| 359 | + NodePath nodes; | ||
| 360 | + CollectMovableSimdInputPreNodes(indirect_load, paths.data_input, nodes); | ||
| 361 | + for (const auto &node : nodes) { | ||
| 362 | + GE_ASSERT_SUCCESS(MoveInputPreNode(node, indirect_load)); | ||
| 299 | } | 363 | } |
| 300 | paths.data_input.erase(paths.data_input.begin(), paths.data_input.begin() + static_cast<int64_t>(nodes.size())); | 364 | paths.data_input.erase(paths.data_input.begin(), paths.data_input.begin() + static_cast<int64_t>(nodes.size())); |
| 301 | paths.output.insert(paths.output.begin(), nodes.rbegin(), nodes.rend()); | 365 | paths.output.insert(paths.output.begin(), nodes.rbegin(), nodes.rend()); |
| @@ -346,24 +410,22 @@ af::Status RecordTemplateLogicalView(const af::AscNodePtr &indirect_load) { | |||
| 346 | af::Status PrepareCandidateGraph(const af::AscNodePtr &indirect_load, ascir::TemplateId template_id, | 410 | af::Status PrepareCandidateGraph(const af::AscNodePtr &indirect_load, ascir::TemplateId template_id, |
| 347 | IndirectLoadGraphPaths &paths, bool &is_candidate_legal) { | 411 | IndirectLoadGraphPaths &paths, bool &is_candidate_legal) { |
| 348 | paths = CollectGraphPaths(indirect_load); | 412 | paths = CollectGraphPaths(indirect_load); |
| 349 | - if (template_id == ascir::TemplateId::kIndirectLoadSimt) { | 413 | + if (template_id == ascir::TemplateId::kIndirectLoadSimd) { |
| 414 | + GE_ASSERT_SUCCESS(MoveSimdInputPreNodes(indirect_load, paths)); | ||
| 415 | + } else if (template_id == ascir::TemplateId::kIndirectLoadSimt) { | ||
| 350 | GE_ASSERT_SUCCESS(MoveSimtInputPreNodes(indirect_load, paths)); | 416 | GE_ASSERT_SUCCESS(MoveSimtInputPreNodes(indirect_load, paths)); |
| 351 | } | 417 | } |
| 352 | - is_candidate_legal = IsTemplateCandidateLegal(template_id, paths); | 418 | + GE_ASSERT_SUCCESS(ValidateTemplateCandidate(template_id, paths, is_candidate_legal)); |
| 353 | if (!is_candidate_legal) { | 419 | if (!is_candidate_legal) { |
| 354 | return af::SUCCESS; | 420 | return af::SUCCESS; |
| 355 | } | 421 | } |
| 356 | GE_ASSERT_SUCCESS(PropagateInputTensorAttrs(paths)); | 422 | GE_ASSERT_SUCCESS(PropagateInputTensorAttrs(paths)); |
| 357 | GE_ASSERT_SUCCESS(RecordTemplateLogicalView(indirect_load)); | 423 | GE_ASSERT_SUCCESS(RecordTemplateLogicalView(indirect_load)); |
| 358 | - GE_ASSERT_SUCCESS(::ascir::SetTemplateId(indirect_load, template_id)); | ||
| 359 | return af::SUCCESS; | 424 | return af::SUCCESS; |
| 360 | } | 425 | } |
| 361 | 426 | ||
| 362 | af::Status AnnotateSimdTemplateRoles(const af::AscNodePtr &indirect_load, const IndirectLoadGraphPaths &paths) { | 427 | af::Status AnnotateSimdTemplateRoles(const af::AscNodePtr &indirect_load, const IndirectLoadGraphPaths &paths) { |
| 363 | GE_ASSERT_NOTNULL(indirect_load); | 428 | GE_ASSERT_NOTNULL(indirect_load); |
| 364 | - GE_ASSERT_SUCCESS( | ||
| 365 | - ascgen_utils::indirect_load::SetTemplateRole(indirect_load, ascgen_utils::indirect_load::TemplateRole::kSimdOp)); | ||
| 366 | - | ||
| 367 | for (const auto &node : paths.data_input) { | 429 | for (const auto &node : paths.data_input) { |
| 368 | if (af::ops::IsOps<af::ascir_op::Data>(node)) { | 430 | if (af::ops::IsOps<af::ascir_op::Data>(node)) { |
| 369 | break; | 431 | break; |
| @@ -375,7 +437,7 @@ af::Status AnnotateSimdTemplateRoles(const af::AscNodePtr &indirect_load, const | |||
| 375 | } | 437 | } |
| 376 | break; | 438 | break; |
| 377 | } | 439 | } |
| 378 | - if (!ascgen_utils::IsNodeSupportsVectorFunction(node) && !af::ops::IsOps<af::ascir_op::Load>(node)) { | 440 | + if (node->inputs.Size() != 1UL || node->outputs().size() != 1UL) { |
| 379 | break; | 441 | break; |
| 380 | } | 442 | } |
| 381 | GE_ASSERT_SUCCESS( | 443 | GE_ASSERT_SUCCESS( |
| @@ -384,24 +446,6 @@ af::Status AnnotateSimdTemplateRoles(const af::AscNodePtr &indirect_load, const | |||
| 384 | return af::SUCCESS; | 446 | return af::SUCCESS; |
| 385 | } | 447 | } |
| 386 | 448 | ||
| 387 | -af::Status AnnotateSimtInputRoles(const NodePath &path, bool &is_candidate_legal) { | ||
| 388 | - is_candidate_legal = false; | ||
| 389 | - for (const auto &node : path) { | ||
| 390 | - if (af::ops::IsOps<af::ascir_op::Data>(node)) { | ||
| 391 | - is_candidate_legal = true; | ||
| 392 | - return af::SUCCESS; | ||
| 393 | - } | ||
| 394 | - if (af::ops::IsOps<af::ascir_op::Load>(node)) { | ||
| 395 | - GE_ASSERT_SUCCESS(ascgen_utils::indirect_load::SetTemplateRole( | ||
| 396 | - node, ascgen_utils::indirect_load::TemplateRole::kSimtInputBoundary)); | ||
| 397 | - is_candidate_legal = true; | ||
| 398 | - return af::SUCCESS; | ||
| 399 | - } | ||
| 400 | - return af::SUCCESS; | ||
| 401 | - } | ||
| 402 | - return af::SUCCESS; | ||
| 403 | -} | ||
| 404 | - | ||
| 405 | af::Status AnnotateSimtTransformRoles(const NodePath &path, const std::string &terminal_type, | 449 | af::Status AnnotateSimtTransformRoles(const NodePath &path, const std::string &terminal_type, |
| 406 | const std::string &direct_gm_boundary_type, bool &is_candidate_legal) { | 450 | const std::string &direct_gm_boundary_type, bool &is_candidate_legal) { |
| 407 | is_candidate_legal = false; | 451 | is_candidate_legal = false; |
| @@ -431,10 +475,6 @@ af::Status AnnotateSimtTemplateRoles(const af::AscNodePtr &indirect_load, const | |||
| 431 | is_candidate_legal = false; | 475 | is_candidate_legal = false; |
| 432 | GE_ASSERT_SUCCESS( | 476 | GE_ASSERT_SUCCESS( |
| 433 | ascgen_utils::indirect_load::SetTemplateRole(indirect_load, ascgen_utils::indirect_load::TemplateRole::kSimtOp)); | 477 | ascgen_utils::indirect_load::SetTemplateRole(indirect_load, ascgen_utils::indirect_load::TemplateRole::kSimtOp)); |
| 434 | - GE_ASSERT_SUCCESS(AnnotateSimtInputRoles(paths.data_input, is_candidate_legal)); | ||
| 435 | - if (!is_candidate_legal) { | ||
| 436 | - return af::SUCCESS; | ||
| 437 | - } | ||
| 438 | GE_ASSERT_SUCCESS(AnnotateSimtTransformRoles(paths.index_input, af::ascir_op::Data::Type, af::ascir_op::Load::Type, | 478 | GE_ASSERT_SUCCESS(AnnotateSimtTransformRoles(paths.index_input, af::ascir_op::Data::Type, af::ascir_op::Load::Type, |
| 439 | is_candidate_legal)); | 479 | is_candidate_legal)); |
| 440 | if (!is_candidate_legal) { | 480 | if (!is_candidate_legal) { |
| @@ -452,8 +492,9 @@ af::Status ApplySimdGraphPass(af::AscGraph &graph, const af::AscNodePtr &indirec | |||
| 452 | if (!is_candidate_legal) { | 492 | if (!is_candidate_legal) { |
| 453 | return af::SUCCESS; | 493 | return af::SUCCESS; |
| 454 | } | 494 | } |
| 455 | - GE_ASSERT_SUCCESS(NormalizeSimdAxesForTemplate(graph, indirect_load, paths)); | ||
| 456 | GE_ASSERT_SUCCESS(AnnotateSimdTemplateRoles(indirect_load, paths)); | 495 | GE_ASSERT_SUCCESS(AnnotateSimdTemplateRoles(indirect_load, paths)); |
| 496 | + GE_ASSERT_SUCCESS(NormalizeSimdAxesForTemplate(graph, indirect_load, paths)); | ||
| 497 | + GE_ASSERT_SUCCESS(::ascir::SetTemplateId(indirect_load, ascir::TemplateId::kIndirectLoadSimd)); | ||
| 457 | return af::SUCCESS; | 498 | return af::SUCCESS; |
| 458 | } | 499 | } |
| 459 | 500 | ||
| @@ -472,6 +513,7 @@ af::Status ApplySimtGraphPass(af::AscGraph &graph, const af::AscNodePtr &indirec | |||
| 472 | } | 513 | } |
| 473 | GE_ASSERT_SUCCESS(::ascir::SetDcacheSize(indirect_load, kIndirectLoadSimtDcacheSize)); | 514 | GE_ASSERT_SUCCESS(::ascir::SetDcacheSize(indirect_load, kIndirectLoadSimtDcacheSize)); |
| 474 | GE_ASSERT_SUCCESS(NormalizeSimtAxesForTemplate(graph, indirect_load)); | 515 | GE_ASSERT_SUCCESS(NormalizeSimtAxesForTemplate(graph, indirect_load)); |
| 516 | + GE_ASSERT_SUCCESS(::ascir::SetTemplateId(indirect_load, ascir::TemplateId::kIndirectLoadSimt)); | ||
| 475 | return af::SUCCESS; | 517 | return af::SUCCESS; |
| 476 | } | 518 | } |
| 477 | 519 | ||
| @@ -297,26 +297,6 @@ TEST(IndirectLoadScheduleCaseGeneratorTest, DoesNotStoreFixedTileAxesAsTemplateM | |||
| 297 | af::kIdNone); | 297 | af::kIdNone); |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | -TEST(IndirectLoadScheduleCaseGeneratorTest, StoresInputVectorizedAxisAsTemplateMetadata) { | ||
| 301 | - auto graph = BuildIndirectLoadGraph(2, true); | ||
| 302 | - optimize::IndirectLoadScheduleCaseGenerator generator; | ||
| 303 | - std::vector<af::AscGraph> graphs; | ||
| 304 | - std::vector<std::string> score_functions; | ||
| 305 | - ASSERT_EQ(generator.Generate(graph, graphs, score_functions), af::SUCCESS); | ||
| 306 | - auto &simd_graph = FindGeneratedGraphByTemplate(graphs, ascir::TemplateId::kIndirectLoadSimd); | ||
| 307 | - const auto indirect_load = simd_graph.FindNode("indirect_load"); | ||
| 308 | - const auto pre_abs = simd_graph.FindNode("pre_abs"); | ||
| 309 | - ASSERT_NE(indirect_load, nullptr); | ||
| 310 | - ASSERT_NE(pre_abs, nullptr); | ||
| 311 | - | ||
| 312 | - ascgen_utils::indirect_load::TemplateAxes axes; | ||
| 313 | - ASSERT_EQ(ascgen_utils::indirect_load::GetTemplateAxes(indirect_load, axes), af::SUCCESS); | ||
| 314 | - ExpectAxisNames(simd_graph, pre_abs->attr.sched.axis, {"z0", "z1", "z2", "z3"}); | ||
| 315 | - ExpectAxisNames(simd_graph, pre_abs->outputs()[0]->attr.axis, {"z0", "z1", "z2", "z3"}); | ||
| 316 | - EXPECT_TRUE(pre_abs->outputs()[0]->attr.vectorized_axis.empty()); | ||
| 317 | - ExpectAxisNames(simd_graph, {axes.input_inner_axis}, {"indirect_load_input_inner"}); | ||
| 318 | -} | ||
| 319 | - | ||
| 320 | TEST(IndirectLoadScheduleCaseGeneratorTest, GeneratedSimdCandidateKeepsPublicBehavior) { | 300 | TEST(IndirectLoadScheduleCaseGeneratorTest, GeneratedSimdCandidateKeepsPublicBehavior) { |
| 321 | auto graph = BuildIndirectLoadGraph(2, true); | 301 | auto graph = BuildIndirectLoadGraph(2, true); |
| 322 | optimize::IndirectLoadScheduleCaseGenerator generator; | 302 | optimize::IndirectLoadScheduleCaseGenerator generator; |
| @@ -332,7 +312,6 @@ TEST(IndirectLoadScheduleCaseGeneratorTest, GeneratedSimdCandidateKeepsPublicBeh | |||
| 332 | EXPECT_FALSE(il_behavior.skips_api_emit); | 312 | EXPECT_FALSE(il_behavior.skips_api_emit); |
| 333 | EXPECT_FALSE(il_behavior.uses_direct_gm_pipeline); | 313 | EXPECT_FALSE(il_behavior.uses_direct_gm_pipeline); |
| 334 | EXPECT_FALSE(il_behavior.skips_ub_lifecycle); | 314 | EXPECT_FALSE(il_behavior.skips_ub_lifecycle); |
| 335 | - EXPECT_FALSE(il_behavior.skips_ub_expr); | ||
| 336 | EXPECT_FALSE(il_behavior.preserves_vectorized_axis); | 315 | EXPECT_FALSE(il_behavior.preserves_vectorized_axis); |
| 337 | EXPECT_FALSE(ascgen_utils::indirect_load::ShouldDisableRegularVectorFunc(indirect_load)); | 316 | EXPECT_FALSE(ascgen_utils::indirect_load::ShouldDisableRegularVectorFunc(indirect_load)); |
| 338 | } | 317 | } |
| @@ -348,7 +327,6 @@ TEST(IndirectLoadScheduleCaseGeneratorTest, GeneratedSimtCandidateKeepsPublicBeh | |||
| 348 | EXPECT_FALSE(behavior.skips_api_emit); | 327 | EXPECT_FALSE(behavior.skips_api_emit); |
| 349 | EXPECT_TRUE(behavior.uses_direct_gm_pipeline); | 328 | EXPECT_TRUE(behavior.uses_direct_gm_pipeline); |
| 350 | EXPECT_TRUE(behavior.skips_ub_lifecycle); | 329 | EXPECT_TRUE(behavior.skips_ub_lifecycle); |
| 351 | - EXPECT_TRUE(behavior.skips_ub_expr); | ||
| 352 | EXPECT_TRUE(behavior.preserves_vectorized_axis); | 330 | EXPECT_TRUE(behavior.preserves_vectorized_axis); |
| 353 | EXPECT_FALSE(ascgen_utils::indirect_load::ShouldApplyInputInnerVectorization(indirect_load)); | 331 | EXPECT_FALSE(ascgen_utils::indirect_load::ShouldApplyInputInnerVectorization(indirect_load)); |
| 354 | EXPECT_FALSE(ascgen_utils::indirect_load::ShouldSkipMainScheduleTiling(indirect_load)); | 332 | EXPECT_FALSE(ascgen_utils::indirect_load::ShouldSkipMainScheduleTiling(indirect_load)); |
| @@ -356,7 +334,26 @@ TEST(IndirectLoadScheduleCaseGeneratorTest, GeneratedSimtCandidateKeepsPublicBeh | |||
| 356 | EXPECT_TRUE(ascgen_utils::indirect_load::ShouldDisableRegularVectorFunc(indirect_load)); | 334 | EXPECT_TRUE(ascgen_utils::indirect_load::ShouldDisableRegularVectorFunc(indirect_load)); |
| 357 | } | 335 | } |
| 358 | 336 | ||
| 359 | -TEST(IndirectLoadScheduleCaseGeneratorTest, SimtMovesInputPrecisionCastAfterIndirectLoad) { | 337 | +TEST(IndirectLoadScheduleCaseGeneratorTest, SimdMovesInputPreAfterIndirectLoad) { |
| 338 | + auto graph = BuildIndirectLoadGraph(2, true); | ||
| 339 | + optimize::IndirectLoadScheduleCaseGenerator generator; | ||
| 340 | + std::vector<af::AscGraph> graphs; | ||
| 341 | + std::vector<std::string> score_functions; | ||
| 342 | + ASSERT_EQ(generator.Generate(graph, graphs, score_functions), af::SUCCESS); | ||
| 343 | + auto &simd_graph = FindGeneratedGraphByTemplate(graphs, ascir::TemplateId::kIndirectLoadSimd); | ||
| 344 | + const auto indirect_load = simd_graph.FindNode("indirect_load"); | ||
| 345 | + const auto pre_abs = simd_graph.FindNode("pre_abs"); | ||
| 346 | + ASSERT_NE(indirect_load, nullptr); | ||
| 347 | + ASSERT_NE(pre_abs, nullptr); | ||
| 348 | + | ||
| 349 | + EXPECT_EQ(ascgen_utils::indirect_load::GetInputProducer(indirect_load, 0UL)->GetName(), "x"); | ||
| 350 | + EXPECT_EQ(ascgen_utils::indirect_load::GetInputProducer(pre_abs, 0UL), indirect_load); | ||
| 351 | + EXPECT_EQ(ascgen_utils::indirect_load::GetOnlyOutputConsumer(indirect_load), pre_abs); | ||
| 352 | + ExpectAxisNames(simd_graph, pre_abs->attr.sched.axis, {"z4", "z5", "z6", "z7"}); | ||
| 353 | + ExpectAxisNames(simd_graph, pre_abs->outputs()[0]->attr.axis, {"z4", "z5", "z6", "z7"}); | ||
| 354 | +} | ||
| 355 | + | ||
| 356 | +TEST(IndirectLoadScheduleCaseGeneratorTest, MovesInputPrecisionCastAfterIndirectLoad) { | ||
| 360 | auto graph = BuildIndirectLoadPrecisionCastGraph(); | 357 | auto graph = BuildIndirectLoadPrecisionCastGraph(); |
| 361 | optimize::IndirectLoadScheduleCaseGenerator generator; | 358 | optimize::IndirectLoadScheduleCaseGenerator generator; |
| 362 | std::vector<af::AscGraph> graphs; | 359 | std::vector<af::AscGraph> graphs; |
| @@ -372,8 +369,14 @@ TEST(IndirectLoadScheduleCaseGeneratorTest, SimtMovesInputPrecisionCastAfterIndi | |||
| 372 | EXPECT_NE(simd_graph.FindNode("output_cast"), nullptr); | 369 | EXPECT_NE(simd_graph.FindNode("output_cast"), nullptr); |
| 373 | ASSERT_NE(simd_graph.FindNode("indirect_load"), nullptr); | 370 | ASSERT_NE(simd_graph.FindNode("indirect_load"), nullptr); |
| 374 | ASSERT_NE(simd_graph.FindNode("output_exp"), nullptr); | 371 | ASSERT_NE(simd_graph.FindNode("output_exp"), nullptr); |
| 375 | - EXPECT_EQ(simd_graph.FindNode("indirect_load")->outputs()[0]->attr.dtype, af::DT_FLOAT); | 372 | + EXPECT_EQ(simd_graph.FindNode("indirect_load")->outputs()[0]->attr.dtype, af::DT_FLOAT16); |
| 376 | EXPECT_EQ(simd_graph.FindNode("output_exp")->outputs()[0]->attr.dtype, af::DT_FLOAT); | 373 | EXPECT_EQ(simd_graph.FindNode("output_exp")->outputs()[0]->attr.dtype, af::DT_FLOAT); |
| 374 | + EXPECT_EQ(ascgen_utils::indirect_load::GetInputProducer(simd_graph.FindNode("indirect_load"), 0UL)->GetName(), | ||
| 375 | + "input_load"); | ||
| 376 | + EXPECT_EQ(ascgen_utils::indirect_load::GetInputProducer(simd_graph.FindNode("input_cast"), 0UL), | ||
| 377 | + simd_graph.FindNode("indirect_load")); | ||
| 378 | + EXPECT_EQ(ascgen_utils::indirect_load::GetOnlyOutputConsumer(simd_graph.FindNode("input_cast"))->GetName(), | ||
| 379 | + "output_exp"); | ||
| 377 | 380 | ||
| 378 | auto &simt_graph = FindGeneratedGraphByTemplate(graphs, ascir::TemplateId::kIndirectLoadSimt); | 381 | auto &simt_graph = FindGeneratedGraphByTemplate(graphs, ascir::TemplateId::kIndirectLoadSimt); |
| 379 | const auto input_cast = simt_graph.FindNode("input_cast"); | 382 | const auto input_cast = simt_graph.FindNode("input_cast"); |
| @@ -1,4 +1,4 @@ | |||
| 1 | -function(add_indirect_load_e2e_case test_name rank axis use_exp2 tiling_key x0 x1 x2 x3 index0 index1 index2 index3) | 1 | +function(add_indirect_load_e2e_case test_name rank axis input_pre_type use_exp2 tiling_key x0 x1 x2 x3 index0 index1 index2 index3) |
| 2 | set(case_workdir ${CMAKE_CURRENT_BINARY_DIR}/${test_name}) | 2 | set(case_workdir ${CMAKE_CURRENT_BINARY_DIR}/${test_name}) |
| 3 | file(MAKE_DIRECTORY ${case_workdir}) | 3 | file(MAKE_DIRECTORY ${case_workdir}) |
| 4 | do_backend_e2e_st_test(${test_name} | 4 | do_backend_e2e_st_test(${test_name} |
| @@ -14,7 +14,7 @@ function(add_indirect_load_e2e_case test_name rank axis use_exp2 tiling_key x0 x | |||
| 14 | set(case_definitions | 14 | set(case_definitions |
| 15 | IL_RANK=${rank} | 15 | IL_RANK=${rank} |
| 16 | IL_AXIS=${axis} | 16 | IL_AXIS=${axis} |
| 17 | - IL_HAS_INPUT_PRE=1 | 17 | + IL_INPUT_PRE_TYPE=${input_pre_type} |
| 18 | IL_USE_EXP2=${use_exp2} | 18 | IL_USE_EXP2=${use_exp2} |
| 19 | IL_TILING_KEY=${tiling_key} | 19 | IL_TILING_KEY=${tiling_key} |
| 20 | IL_X_S0=${x0} | 20 | IL_X_S0=${x0} |
| @@ -29,13 +29,89 @@ function(add_indirect_load_e2e_case test_name rank axis use_exp2 tiling_key x0 x | |||
| 29 | target_compile_definitions(${test_name}_e2e_v2 PRIVATE ${case_definitions}) | 29 | target_compile_definitions(${test_name}_e2e_v2 PRIVATE ${case_definitions}) |
| 30 | endfunction() | 30 | endfunction() |
| 31 | 31 | ||
| 32 | -add_indirect_load_e2e_case(indirect_load_rank2_axis1_simt 2 1 0 1 5 8 1 1 4 6 1 1) | 32 | +function(mark_indirect_load_static_shape test_name) |
| 33 | -add_indirect_load_e2e_case(indirect_load_rank2_axis1_simd 2 1 1 0 5 8 1 1 4 6 1 1) | 33 | + target_compile_definitions(${test_name}_codegen_v2 PRIVATE IL_STATIC_SHAPE) |
| 34 | -add_indirect_load_e2e_case(indirect_load_rank2_axis0_simt 2 0 0 1 4 9 1 1 6 8 1 1) | 34 | + target_compile_definitions(${test_name}_e2e_v2 PRIVATE IL_STATIC_SHAPE) |
| 35 | -add_indirect_load_e2e_case(indirect_load_rank2_axis0_simd 2 0 1 0 4 9 1 1 6 8 1 1) | 35 | +endfunction() |
| 36 | -add_indirect_load_e2e_case(indirect_load_rank2_axisneg2_simt 2 -2 0 1 4 9 1 1 4 8 1 1) | 36 | + |
| 37 | -add_indirect_load_e2e_case(indirect_load_rank2_axisneg2_simd 2 -2 1 0 4 9 1 1 4 8 1 1) | 37 | +function(mark_indirect_load_wide_types test_name) |
| 38 | -add_indirect_load_e2e_case(indirect_load_rank3_axis1_simt 3 1 0 1 3 5 8 1 2 7 6 1) | 38 | + target_compile_definitions(${test_name}_codegen_v2 PRIVATE IL_DATA_FLOAT IL_INDEX_INT64) |
| 39 | -add_indirect_load_e2e_case(indirect_load_rank3_axis1_simd 3 1 1 0 3 5 8 1 2 7 6 1) | 39 | + target_compile_definitions(${test_name}_e2e_v2 PRIVATE IL_DATA_FLOAT IL_INDEX_INT64) |
| 40 | -add_indirect_load_e2e_case(indirect_load_rank4_axis2_simt 4 2 0 1 3 3 5 8 2 2 5 6) | 40 | +endfunction() |
| 41 | -add_indirect_load_e2e_case(indirect_load_rank4_axis2_simd 4 2 1 0 3 3 5 8 2 2 5 6) | 41 | + |
| 42 | +function(mark_indirect_load_large_simt test_name) | ||
| 43 | + target_compile_definitions(${test_name}_e2e_v2 PRIVATE IL_EXPECT_SIMT_MULTI_ROUND) | ||
| 44 | +endfunction() | ||
| 45 | + | ||
| 46 | +function(mark_indirect_load_input_pre_vf test_name expected) | ||
| 47 | + target_compile_definitions(${test_name}_codegen_v2 PRIVATE IL_EXPECT_INPUT_PRE_VF=${expected}) | ||
| 48 | +endfunction() | ||
| 49 | + | ||
| 50 | +function(mark_indirect_load_mixed_index_pre test_name) | ||
| 51 | + target_compile_definitions(${test_name}_codegen_v2 PRIVATE IL_MIXED_INDEX_PRE) | ||
| 52 | + target_compile_definitions(${test_name}_e2e_v2 PRIVATE IL_MIXED_INDEX_PRE) | ||
| 53 | +endfunction() | ||
| 54 | + | ||
| 55 | +function(mark_indirect_load_output_post test_name output_post_type expect_simt) | ||
| 56 | + target_compile_definitions(${test_name}_codegen_v2 PRIVATE | ||
| 57 | + IL_OUTPUT_POST_TYPE=${output_post_type} | ||
| 58 | + IL_EXPECT_SIMT=${expect_simt}) | ||
| 59 | + target_compile_definitions(${test_name}_e2e_v2 PRIVATE | ||
| 60 | + IL_OUTPUT_POST_TYPE=${output_post_type} | ||
| 61 | + IL_EXPECT_SIMT=${expect_simt}) | ||
| 62 | +endfunction() | ||
| 63 | + | ||
| 64 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_simt 2 1 1 0 1 5 8 1 1 4 6 1 1) | ||
| 65 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_simd 2 1 1 1 0 5 8 1 1 4 6 1 1) | ||
| 66 | +mark_indirect_load_static_shape(indirect_load_rank2_axis1_simd) | ||
| 67 | +add_indirect_load_e2e_case(indirect_load_rank2_axisneg2_simt 2 -2 1 0 1 4 9 1 1 4 8 1 1) | ||
| 68 | +add_indirect_load_e2e_case(indirect_load_rank2_axisneg2_simd 2 -2 1 1 0 4 9 1 1 4 8 1 1) | ||
| 69 | +add_indirect_load_e2e_case(indirect_load_rank3_axis1_simt 3 1 1 0 1 3 5 8 1 2 7 6 1) | ||
| 70 | +add_indirect_load_e2e_case(indirect_load_rank3_axis1_simd 3 1 1 1 0 3 5 8 1 2 7 6 1) | ||
| 71 | +add_indirect_load_e2e_case(indirect_load_rank4_axis2_simt 4 2 1 0 1 3 3 5 8 2 2 5 6) | ||
| 72 | +add_indirect_load_e2e_case(indirect_load_rank4_axis2_simd 4 2 1 1 0 3 3 5 8 2 2 5 6) | ||
| 73 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_relu_exp2_pre_simd 2 1 3 0 0 5 8 1 1 4 6 1 1) | ||
| 74 | + | ||
| 75 | +# Static output expansion keeps both data and index preprocessing before IndirectLoad SIMD. | ||
| 76 | +add_indirect_load_e2e_case(indirect_load_rank2_axis0_relu_pre_expanded_simd 2 0 1 1 0 4 9 1 1 6 8 1 1) | ||
| 77 | +add_indirect_load_e2e_case(indirect_load_rank2_axis0_relu_relu_pre_expanded_simd 2 0 4 1 0 4 9 1 1 6 8 1 1) | ||
| 78 | +add_indirect_load_e2e_case(indirect_load_rank3_axis2_exp2_pre_expanded_simd 3 2 2 0 0 4 5 6 1 3 4 11 1) | ||
| 79 | +add_indirect_load_e2e_case(indirect_load_rank4_axis1_relu_exp2_pre_expanded_simd 4 1 3 0 0 2 3 4 5 2 7 4 3) | ||
| 80 | +add_indirect_load_e2e_case(indirect_load_rank3_axis2_mixed_vf_pre_expanded_simd 3 2 3 0 0 4 5 6 1 3 4 11 1) | ||
| 81 | +mark_indirect_load_static_shape(indirect_load_rank2_axis0_relu_pre_expanded_simd) | ||
| 82 | +mark_indirect_load_static_shape(indirect_load_rank2_axis0_relu_relu_pre_expanded_simd) | ||
| 83 | +mark_indirect_load_static_shape(indirect_load_rank3_axis2_exp2_pre_expanded_simd) | ||
| 84 | +mark_indirect_load_static_shape(indirect_load_rank4_axis1_relu_exp2_pre_expanded_simd) | ||
| 85 | +mark_indirect_load_static_shape(indirect_load_rank3_axis2_mixed_vf_pre_expanded_simd) | ||
| 86 | +mark_indirect_load_mixed_index_pre(indirect_load_rank3_axis2_mixed_vf_pre_expanded_simd) | ||
| 87 | +target_compile_definitions(indirect_load_rank2_axis0_relu_pre_expanded_simd_codegen_v2 PRIVATE IL_DATA_FLOAT) | ||
| 88 | +target_compile_definitions(indirect_load_rank2_axis0_relu_pre_expanded_simd_e2e_v2 PRIVATE IL_DATA_FLOAT) | ||
| 89 | +target_compile_definitions(indirect_load_rank2_axis0_relu_relu_pre_expanded_simd_codegen_v2 PRIVATE IL_DATA_FLOAT) | ||
| 90 | +target_compile_definitions(indirect_load_rank2_axis0_relu_relu_pre_expanded_simd_e2e_v2 PRIVATE IL_DATA_FLOAT) | ||
| 91 | +mark_indirect_load_input_pre_vf(indirect_load_rank2_axis0_relu_pre_expanded_simd 0) | ||
| 92 | +mark_indirect_load_input_pre_vf(indirect_load_rank2_axis0_relu_relu_pre_expanded_simd 1) | ||
| 93 | + | ||
| 94 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_large_simt 2 1 1 0 1 2 64 1 1 2 32771 1 1) | ||
| 95 | +mark_indirect_load_large_simt(indirect_load_rank2_axis1_large_simt) | ||
| 96 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_float_int64_simd 2 1 0 1 0 4 8 1 1 3 6 1 1) | ||
| 97 | +mark_indirect_load_wide_types(indirect_load_rank2_axis1_float_int64_simd) | ||
| 98 | + | ||
| 99 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_modified_bessel_k0_simd_only 2 1 0 0 0 5 8 1 1 4 6 1 1) | ||
| 100 | +mark_indirect_load_output_post(indirect_load_rank2_axis1_modified_bessel_k0_simd_only 1 0) | ||
| 101 | +target_compile_definitions(indirect_load_rank2_axis1_modified_bessel_k0_simd_only_codegen_v2 PRIVATE IL_DATA_FLOAT) | ||
| 102 | +target_compile_definitions(indirect_load_rank2_axis1_modified_bessel_k0_simd_only_e2e_v2 PRIVATE IL_DATA_FLOAT) | ||
| 103 | +target_include_directories(indirect_load_rank2_axis1_modified_bessel_k0_simd_only_e2e_v2 PRIVATE | ||
| 104 | + ${CODE_ROOT_DIR}/v35/ascendc/api_regbase) | ||
| 105 | + | ||
| 106 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_precision_cast_simt 2 1 5 0 1 5 8 1 1 4 6 1 1) | ||
| 107 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_precision_cast_simd 2 1 5 1 0 5 8 1 1 4 6 1 1) | ||
| 108 | + | ||
| 109 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_bf16_int64_simt 2 1 0 0 1 5 8 1 1 4 6 1 1) | ||
| 110 | +mark_indirect_load_output_post(indirect_load_rank2_axis1_bf16_int64_simt 2 1) | ||
| 111 | +target_compile_definitions(indirect_load_rank2_axis1_bf16_int64_simt_codegen_v2 PRIVATE IL_DATA_BF16 IL_INDEX_INT64) | ||
| 112 | +target_compile_definitions(indirect_load_rank2_axis1_bf16_int64_simt_e2e_v2 PRIVATE IL_DATA_BF16 IL_INDEX_INT64) | ||
| 113 | + | ||
| 114 | +add_indirect_load_e2e_case(indirect_load_rank2_axis1_uint32_int32_simd 2 1 0 1 0 5 8 1 1 4 6 1 1) | ||
| 115 | +mark_indirect_load_output_post(indirect_load_rank2_axis1_uint32_int32_simd 3 1) | ||
| 116 | +target_compile_definitions(indirect_load_rank2_axis1_uint32_int32_simd_codegen_v2 PRIVATE IL_DATA_UINT32) | ||
| 117 | +target_compile_definitions(indirect_load_rank2_axis1_uint32_int32_simd_e2e_v2 PRIVATE IL_DATA_UINT32) | ||
| @@ -29,8 +29,56 @@ | |||
| 29 | namespace { | 29 | namespace { |
| 30 | constexpr size_t kRank = IL_RANK; | 30 | constexpr size_t kRank = IL_RANK; |
| 31 | constexpr int64_t kAxis = IL_AXIS; | 31 | constexpr int64_t kAxis = IL_AXIS; |
| 32 | -constexpr bool kHasInputPre = IL_HAS_INPUT_PRE; | 32 | +constexpr auto kInputPreType = static_cast<ascir::IndirectLoadInputPreType>(IL_INPUT_PRE_TYPE); |
| 33 | +constexpr bool kHasInputPre = kInputPreType != ascir::IndirectLoadInputPreType::kNone; | ||
| 33 | constexpr bool kUseExp2 = IL_USE_EXP2; | 34 | constexpr bool kUseExp2 = IL_USE_EXP2; |
| 35 | +#ifdef IL_OUTPUT_POST_TYPE | ||
| 36 | +constexpr auto kOutputPostType = static_cast<ascir::IndirectLoadOutputPostType>(IL_OUTPUT_POST_TYPE); | ||
| 37 | +#else | ||
| 38 | +constexpr auto kOutputPostType = ascir::IndirectLoadOutputPostType::kDefault; | ||
| 39 | +#endif | ||
| 40 | +#ifdef IL_EXPECT_SIMT | ||
| 41 | +constexpr bool kExpectSimt = IL_EXPECT_SIMT; | ||
| 42 | +#else | ||
| 43 | +constexpr bool kExpectSimt = true; | ||
| 44 | +#endif | ||
| 45 | +#if defined(IL_DATA_BF16) | ||
| 46 | +constexpr af::DataType kDataType = af::DT_BF16; | ||
| 47 | +#elif defined(IL_DATA_UINT32) | ||
| 48 | +constexpr af::DataType kDataType = af::DT_UINT32; | ||
| 49 | +#elif defined(IL_DATA_FLOAT) | ||
| 50 | +constexpr af::DataType kDataType = af::DT_FLOAT; | ||
| 51 | +#else | ||
| 52 | +constexpr af::DataType kDataType = af::DT_FLOAT16; | ||
| 53 | +#endif | ||
| 54 | +#ifdef IL_INDEX_INT64 | ||
| 55 | +constexpr af::DataType kIndexType = af::DT_INT64; | ||
| 56 | +#else | ||
| 57 | +constexpr af::DataType kIndexType = af::DT_INT32; | ||
| 58 | +#endif | ||
| 59 | +#ifdef IL_STATIC_SHAPE | ||
| 60 | +constexpr bool kStaticShape = true; | ||
| 61 | +#else | ||
| 62 | +constexpr bool kStaticShape = false; | ||
| 63 | +#endif | ||
| 64 | +constexpr int64_t kInputNumel = IL_X_S0 * IL_X_S1 * IL_X_S2 * IL_X_S3; | ||
| 65 | +constexpr int64_t kOutputNumel = IL_INDEX_S0 * IL_INDEX_S1 * IL_INDEX_S2 * IL_INDEX_S3; | ||
| 66 | +constexpr bool kExpectInputPreMoved = kHasInputPre && (!kStaticShape || kOutputNumel <= kInputNumel); | ||
| 67 | +#ifdef IL_MIXED_INDEX_PRE | ||
| 68 | +constexpr bool kMixedIndexPre = true; | ||
| 69 | +#else | ||
| 70 | +constexpr bool kMixedIndexPre = false; | ||
| 71 | +#endif | ||
| 72 | + | ||
| 73 | +std::vector<int64_t> GetStaticShape(bool input) { | ||
| 74 | + if (!kStaticShape) { | ||
| 75 | + return {}; | ||
| 76 | + } | ||
| 77 | + std::vector<int64_t> shape = input ? std::vector<int64_t>{IL_X_S0, IL_X_S1, IL_X_S2, IL_X_S3} | ||
| 78 | + : std::vector<int64_t>{IL_INDEX_S0, IL_INDEX_S1, IL_INDEX_S2, IL_INDEX_S3}; | ||
| 79 | + shape.resize(kRank); | ||
| 80 | + return shape; | ||
| 81 | +} | ||
| 34 | 82 | ||
| 35 | const af::Axis *FindDerivedAxis(const af::AscGraph &graph, af::Axis::Type type, af::AxisId from) { | 83 | const af::Axis *FindDerivedAxis(const af::AscGraph &graph, af::Axis::Type type, af::AxisId from) { |
| 36 | for (const auto &axis : graph.GetAllAxis()) { | 84 | for (const auto &axis : graph.GetAllAxis()) { |
| @@ -59,6 +107,31 @@ void ExpectAxisOrigins(af::AscGraph &graph, af::AxisId axis_id, const std::vecto | |||
| 59 | EXPECT_EQ(origins, expected); | 107 | EXPECT_EQ(origins, expected); |
| 60 | } | 108 | } |
| 61 | 109 | ||
| 110 | +void ExpectMixedInputPre(const af::AscNodePtr &indirect_load) { | ||
| 111 | + if (!kMixedIndexPre) { | ||
| 112 | + return; | ||
| 113 | + } | ||
| 114 | + const af::AscNodePtr data_post = ascgen_utils::indirect_load::GetInputProducer(indirect_load, 0UL); | ||
| 115 | + ASSERT_NE(data_post, nullptr); | ||
| 116 | + EXPECT_EQ(data_post->GetName(), "input_exp2"); | ||
| 117 | + const af::AscNodePtr data_vf = ascgen_utils::indirect_load::GetInputProducer(data_post, 0UL); | ||
| 118 | + ASSERT_NE(data_vf, nullptr); | ||
| 119 | + EXPECT_TRUE(af::ops::IsOps<af::ascir_op::VectorFunc>(data_vf)); | ||
| 120 | + | ||
| 121 | + const af::AscNodePtr index_post = ascgen_utils::indirect_load::GetInputProducer(indirect_load, 1UL); | ||
| 122 | + ASSERT_NE(index_post, nullptr); | ||
| 123 | + EXPECT_EQ(index_post->GetName(), "index_floor_to_int"); | ||
| 124 | + const af::AscNodePtr index_log2 = ascgen_utils::indirect_load::GetInputProducer(index_post, 0UL); | ||
| 125 | + ASSERT_NE(index_log2, nullptr); | ||
| 126 | + EXPECT_EQ(index_log2->GetName(), "index_log2"); | ||
| 127 | + const af::AscNodePtr index_exp2 = ascgen_utils::indirect_load::GetInputProducer(index_log2, 0UL); | ||
| 128 | + ASSERT_NE(index_exp2, nullptr); | ||
| 129 | + EXPECT_EQ(index_exp2->GetName(), "index_exp2"); | ||
| 130 | + const af::AscNodePtr index_vf = ascgen_utils::indirect_load::GetInputProducer(index_exp2, 0UL); | ||
| 131 | + ASSERT_NE(index_vf, nullptr); | ||
| 132 | + EXPECT_TRUE(af::ops::IsOps<af::ascir_op::VectorFunc>(index_vf)); | ||
| 133 | +} | ||
| 134 | + | ||
| 62 | void ExpectLoopFramework(af::AscGraph &graph, const af::AscNodePtr &indirect_load) { | 135 | void ExpectLoopFramework(af::AscGraph &graph, const af::AscNodePtr &indirect_load) { |
| 63 | ascgen_utils::indirect_load::TemplateAxes axes; | 136 | ascgen_utils::indirect_load::TemplateAxes axes; |
| 64 | ascgen_utils::indirect_load::TemplateLogicalView logical_view; | 137 | ascgen_utils::indirect_load::TemplateLogicalView logical_view; |
| @@ -107,9 +180,33 @@ void ExpectLoopFramework(af::AscGraph &graph, const af::AscNodePtr &indirect_loa | |||
| 107 | graph, axes.input_inner_axis, | 180 | graph, axes.input_inner_axis, |
| 108 | std::vector<af::AxisId>(logical_view.data.axis_ids.begin() + split, logical_view.data.axis_ids.end())); | 181 | std::vector<af::AxisId>(logical_view.data.axis_ids.begin() + split, logical_view.data.axis_ids.end())); |
| 109 | } | 182 | } |
| 183 | + | ||
| 184 | + const auto input_producer = ascgen_utils::indirect_load::GetInputProducer(indirect_load, 0UL); | ||
| 185 | + ASSERT_NE(input_producer, nullptr); | ||
| 186 | + if (kExpectInputPreMoved) { | ||
| 187 | + EXPECT_EQ(input_producer->GetName(), "input_load"); | ||
| 188 | + } else if (kHasInputPre) { | ||
| 189 | +#ifdef IL_EXPECT_INPUT_PRE_VF | ||
| 190 | + EXPECT_EQ(af::ops::IsOps<af::ascir_op::VectorFunc>(input_producer), IL_EXPECT_INPUT_PRE_VF); | ||
| 191 | +#endif | ||
| 192 | + if (af::ops::IsOps<af::ascir_op::VectorFunc>(input_producer)) { | ||
| 193 | + EXPECT_EQ(ascgen_utils::indirect_load::GetTemplateRole(input_producer), | ||
| 194 | + ascgen_utils::indirect_load::TemplateRole::kSimdInputPre); | ||
| 195 | + } else { | ||
| 196 | + EXPECT_EQ(input_producer->GetName(), | ||
| 197 | + kInputPreType == ascir::IndirectLoadInputPreType::kRelu ? "input_relu" : "input_exp2"); | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + const auto index_producer = ascgen_utils::indirect_load::GetInputProducer(indirect_load, 1UL); | ||
| 201 | + ASSERT_NE(index_producer, nullptr); | ||
| 202 | + EXPECT_EQ(index_producer->GetName(), kMixedIndexPre ? "index_floor_to_int" : "index_abs"); | ||
| 203 | + ExpectMixedInputPre(indirect_load); | ||
| 204 | +#if IL_INPUT_PRE_TYPE == 5 | ||
| 205 | + EXPECT_EQ(indirect_load->outputs()[0]->attr.dtype, af::DT_FLOAT16); | ||
| 206 | +#endif | ||
| 110 | } | 207 | } |
| 111 | 208 | ||
| 112 | -void CheckScheduledLoopFramework(ascir::FusedScheduledResult &result) { | 209 | +bool CheckScheduledLoopFramework(ascir::FusedScheduledResult &result) { |
| 113 | size_t simd_count = 0UL; | 210 | size_t simd_count = 0UL; |
| 114 | size_t simt_count = 0UL; | 211 | size_t simt_count = 0UL; |
| 115 | for (auto &candidates : result.node_idx_to_scheduled_results) { | 212 | for (auto &candidates : result.node_idx_to_scheduled_results) { |
| @@ -131,12 +228,33 @@ void CheckScheduledLoopFramework(ascir::FusedScheduledResult &result) { | |||
| 131 | } | 228 | } |
| 132 | } | 229 | } |
| 133 | EXPECT_GT(simd_count, 0UL); | 230 | EXPECT_GT(simd_count, 0UL); |
| 134 | - EXPECT_GT(simt_count, 0UL); | 231 | + if (kExpectSimt) { |
| 232 | + EXPECT_GT(simt_count, 0UL); | ||
| 233 | + return simd_count > 0UL && simt_count > 0UL; | ||
| 234 | + } else { | ||
| 235 | + EXPECT_EQ(simt_count, 0UL); | ||
| 236 | + return simd_count > 0UL && simt_count == 0UL; | ||
| 237 | + } | ||
| 135 | } | 238 | } |
| 136 | 239 | ||
| 137 | void CheckGeneratedKernel(const std::string &kernel) { | 240 | void CheckGeneratedKernel(const std::string &kernel) { |
| 138 | EXPECT_NE(kernel.find("// IndirectLoad SIMD"), std::string::npos); | 241 | EXPECT_NE(kernel.find("// IndirectLoad SIMD"), std::string::npos); |
| 139 | - EXPECT_NE(kernel.find("// IndirectLoad SIMT"), std::string::npos); | 242 | + EXPECT_NE(kernel.find("IndirectLoadSimd<"), std::string::npos); |
| 243 | + EXPECT_EQ(kernel.find("auto indirect_load_offset"), std::string::npos); | ||
| 244 | + if (kExpectSimt) { | ||
| 245 | + EXPECT_NE(kernel.find("// IndirectLoad SIMT"), std::string::npos); | ||
| 246 | + EXPECT_NE(kernel.find("IndirectLoadSimt<"), std::string::npos); | ||
| 247 | + EXPECT_EQ(kernel.find("IndirectLoadSimtKernel_"), std::string::npos); | ||
| 248 | + } else { | ||
| 249 | + EXPECT_EQ(kernel.find("// IndirectLoad SIMT"), std::string::npos); | ||
| 250 | + EXPECT_EQ(kernel.find("IndirectLoadSimt<"), std::string::npos); | ||
| 251 | + } | ||
| 252 | +#ifdef IL_DATA_BF16 | ||
| 253 | + EXPECT_NE(kernel.find("IndirectLoadSimt<bfloat16_t, int64_t, bfloat16_t"), std::string::npos); | ||
| 254 | +#endif | ||
| 255 | +#ifdef IL_DATA_UINT32 | ||
| 256 | + EXPECT_NE(kernel.find("IndirectLoadSimd<uint32_t, int32_t"), std::string::npos); | ||
| 257 | +#endif | ||
| 140 | } | 258 | } |
| 141 | } // namespace | 259 | } // namespace |
| 142 | 260 | ||
| @@ -159,7 +277,9 @@ TEST_F(TestBackendIndirectLoadStoreE2e, IndirectLoadStoreCodegen) { | |||
| 159 | #define REGISTER_TILING_DEFAULT(tiling) | 277 | #define REGISTER_TILING_DEFAULT(tiling) |
| 160 | #define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling; | 278 | #define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling; |
| 161 | )"; | 279 | )"; |
| 162 | - auto graph = ascir::ShareGraph::IndirectLoadStoreFusedGraph(kRank, kAxis, af::DT_FLOAT16, kHasInputPre, kUseExp2); | 280 | + auto graph = ascir::ShareGraph::IndirectLoadStoreFusedGraph(kRank, kAxis, kDataType, kIndexType, kInputPreType, |
| 281 | + kUseExp2, kOutputPostType, GetStaticShape(true), | ||
| 282 | + GetStaticShape(false), kMixedIndexPre); | ||
| 163 | ASSERT_NE(graph, nullptr); | 283 | ASSERT_NE(graph, nullptr); |
| 164 | std::map<std::string, std::string> shape_info; | 284 | std::map<std::string, std::string> shape_info; |
| 165 | for (size_t i = 0UL; i < 2UL * kRank; ++i) { | 285 | for (size_t i = 0UL; i < 2UL * kRank; ++i) { |
| @@ -175,14 +295,16 @@ TEST_F(TestBackendIndirectLoadStoreE2e, IndirectLoadStoreCodegen) { | |||
| 175 | codegen::CodegenResult result; | 295 | codegen::CodegenResult result; |
| 176 | testing::internal::CaptureStdout(); | 296 | testing::internal::CaptureStdout(); |
| 177 | const auto optimize_status = optimizer.Optimize(graph, fused_schedule_result); | 297 | const auto optimize_status = optimizer.Optimize(graph, fused_schedule_result); |
| 178 | - if (optimize_status == 0) { | 298 | + const std::string optimize_logs = testing::internal::GetCapturedStdout(); |
| 179 | - CheckScheduledLoopFramework(fused_schedule_result); | 299 | + EXPECT_EQ(optimize_logs.find("[ERROR]"), std::string::npos) << optimize_logs; |
| 180 | - } | 300 | + ASSERT_EQ(optimize_status, 0) << optimize_logs; |
| 181 | - const auto codegen_status = optimize_status == 0 ? codegen.Generate(shape_info, fused_schedule_result, result) : -1; | 301 | + ASSERT_TRUE(CheckScheduledLoopFramework(fused_schedule_result)) << optimize_logs; |
| 182 | - const std::string logs = testing::internal::GetCapturedStdout(); | 302 | + |
| 183 | - EXPECT_EQ(logs.find("[ERROR]"), std::string::npos) << logs; | 303 | + testing::internal::CaptureStdout(); |
| 184 | - ASSERT_EQ(optimize_status, 0) << logs; | 304 | + const auto codegen_status = codegen.Generate(shape_info, fused_schedule_result, result); |
| 185 | - ASSERT_EQ(codegen_status, 0) << logs; | 305 | + const std::string codegen_logs = testing::internal::GetCapturedStdout(); |
| 306 | + EXPECT_EQ(codegen_logs.find("[ERROR]"), std::string::npos) << codegen_logs; | ||
| 307 | + ASSERT_EQ(codegen_status, 0) << codegen_logs; | ||
| 186 | CheckGeneratedKernel(result.kernel); | 308 | CheckGeneratedKernel(result.kernel); |
| 187 | 309 | ||
| 188 | std::fstream kernel_file(parts[0], std::ios::out); | 310 | std::fstream kernel_file(parts[0], std::ios::out); |
| @@ -22,29 +22,70 @@ | |||
| 22 | 22 | ||
| 23 | extern "C" __global__ __aicore__ void indirect_load_store_test(GM_ADDR x, GM_ADDR index, GM_ADDR y, GM_ADDR workspace, | 23 | extern "C" __global__ __aicore__ void indirect_load_store_test(GM_ADDR x, GM_ADDR index, GM_ADDR y, GM_ADDR workspace, |
| 24 | GM_ADDR tiling); | 24 | GM_ADDR tiling); |
| 25 | +#ifdef IL_STATIC_SHAPE | ||
| 26 | +extern "C" int64_t AutofuseTiling(AutofuseTilingData *, uint32_t *, uint32_t *, uint32_t, uint32_t); | ||
| 27 | +#endif | ||
| 25 | #if IL_RANK == 2 | 28 | #if IL_RANK == 2 |
| 29 | +#ifndef IL_STATIC_SHAPE | ||
| 26 | extern "C" int64_t AutofuseTiling(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, AutofuseTilingData *, uint32_t *, | 30 | extern "C" int64_t AutofuseTiling(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, AutofuseTilingData *, uint32_t *, |
| 27 | uint32_t *, uint32_t, uint32_t); | 31 | uint32_t *, uint32_t, uint32_t); |
| 32 | +#endif | ||
| 28 | constexpr std::array<int32_t, 2> kInputShape = {IL_X_S0, IL_X_S1}; | 33 | constexpr std::array<int32_t, 2> kInputShape = {IL_X_S0, IL_X_S1}; |
| 29 | constexpr std::array<int32_t, 2> kIndexShape = {IL_INDEX_S0, IL_INDEX_S1}; | 34 | constexpr std::array<int32_t, 2> kIndexShape = {IL_INDEX_S0, IL_INDEX_S1}; |
| 30 | #elif IL_RANK == 3 | 35 | #elif IL_RANK == 3 |
| 36 | +#ifndef IL_STATIC_SHAPE | ||
| 31 | extern "C" int64_t AutofuseTiling(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, uint32_t s4, uint32_t s5, | 37 | extern "C" int64_t AutofuseTiling(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, uint32_t s4, uint32_t s5, |
| 32 | AutofuseTilingData *, uint32_t *, uint32_t *, uint32_t, uint32_t); | 38 | AutofuseTilingData *, uint32_t *, uint32_t *, uint32_t, uint32_t); |
| 39 | +#endif | ||
| 33 | constexpr std::array<int32_t, 3> kInputShape = {IL_X_S0, IL_X_S1, IL_X_S2}; | 40 | constexpr std::array<int32_t, 3> kInputShape = {IL_X_S0, IL_X_S1, IL_X_S2}; |
| 34 | constexpr std::array<int32_t, 3> kIndexShape = {IL_INDEX_S0, IL_INDEX_S1, IL_INDEX_S2}; | 41 | constexpr std::array<int32_t, 3> kIndexShape = {IL_INDEX_S0, IL_INDEX_S1, IL_INDEX_S2}; |
| 35 | #elif IL_RANK == 4 | 42 | #elif IL_RANK == 4 |
| 43 | +#ifndef IL_STATIC_SHAPE | ||
| 36 | extern "C" int64_t AutofuseTiling(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, uint32_t s4, uint32_t s5, | 44 | extern "C" int64_t AutofuseTiling(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, uint32_t s4, uint32_t s5, |
| 37 | uint32_t s6, uint32_t s7, AutofuseTilingData *, uint32_t *, uint32_t *, uint32_t, | 45 | uint32_t s6, uint32_t s7, AutofuseTilingData *, uint32_t *, uint32_t *, uint32_t, |
| 38 | uint32_t); | 46 | uint32_t); |
| 47 | +#endif | ||
| 39 | constexpr std::array<int32_t, 4> kInputShape = {IL_X_S0, IL_X_S1, IL_X_S2, IL_X_S3}; | 48 | constexpr std::array<int32_t, 4> kInputShape = {IL_X_S0, IL_X_S1, IL_X_S2, IL_X_S3}; |
| 40 | constexpr std::array<int32_t, 4> kIndexShape = {IL_INDEX_S0, IL_INDEX_S1, IL_INDEX_S2, IL_INDEX_S3}; | 49 | constexpr std::array<int32_t, 4> kIndexShape = {IL_INDEX_S0, IL_INDEX_S1, IL_INDEX_S2, IL_INDEX_S3}; |
| 41 | #endif | 50 | #endif |
| 42 | 51 | ||
| 43 | namespace { | 52 | namespace { |
| 44 | constexpr int32_t kAxis = IL_AXIS < 0 ? IL_AXIS + IL_RANK : IL_AXIS; | 53 | constexpr int32_t kAxis = IL_AXIS < 0 ? IL_AXIS + IL_RANK : IL_AXIS; |
| 54 | +#if defined(IL_DATA_BF16) | ||
| 55 | +using DataType = bfloat16_t; | ||
| 56 | +#elif defined(IL_DATA_UINT32) | ||
| 57 | +using DataType = uint32_t; | ||
| 58 | +#elif defined(IL_DATA_FLOAT) | ||
| 59 | +using DataType = float; | ||
| 60 | +#else | ||
| 61 | +using DataType = half; | ||
| 62 | +#endif | ||
| 63 | +#ifdef IL_INDEX_INT64 | ||
| 64 | +using IndexType = int64_t; | ||
| 65 | +#else | ||
| 66 | +using IndexType = int32_t; | ||
| 67 | +#endif | ||
| 68 | + | ||
| 69 | +float BesselK0Reference(float x) { | ||
| 70 | + const float y = x * x / 4.0F; | ||
| 71 | + float series_term = 1.0F; | ||
| 72 | + float series_sum = 1.0F; | ||
| 73 | + for (int32_t order = 1; order <= 20; ++order) { | ||
| 74 | + const float scale = x * 0.5F / static_cast<float>(order); | ||
| 75 | + series_term *= scale * scale; | ||
| 76 | + series_sum += series_term; | ||
| 77 | + } | ||
| 78 | + const float poly = | ||
| 79 | + -0.57721566F + | ||
| 80 | + y * (0.42278420F + | ||
| 81 | + y * (0.23069756F + y * (0.03488590F + y * (0.00262698F + y * (0.00010750F + y * 0.00000740F))))); | ||
| 82 | + return -std::log(x * 0.5F) * series_sum + poly; | ||
| 83 | +} | ||
| 45 | 84 | ||
| 46 | void RunTiling(AutofuseTilingData &tiling, uint32_t &workspace_size, uint32_t &block_dim) { | 85 | void RunTiling(AutofuseTilingData &tiling, uint32_t &workspace_size, uint32_t &block_dim) { |
| 47 | -#if IL_RANK == 2 | 86 | +#ifdef IL_STATIC_SHAPE |
| 87 | + AutofuseTiling(&tiling, &workspace_size, &block_dim, 48, 192 * 1024); | ||
| 88 | +#elif IL_RANK == 2 | ||
| 48 | AutofuseTiling(kInputShape[0], kInputShape[1], kIndexShape[0], kIndexShape[1], &tiling, &workspace_size, &block_dim, | 89 | AutofuseTiling(kInputShape[0], kInputShape[1], kIndexShape[0], kIndexShape[1], &tiling, &workspace_size, &block_dim, |
| 49 | 48, 192 * 1024); | 90 | 48, 192 * 1024); |
| 50 | #elif IL_RANK == 3 | 91 | #elif IL_RANK == 3 |
| @@ -65,18 +106,24 @@ int32_t ElementCount(const std::array<int32_t, N> &shape) { | |||
| 65 | return count; | 106 | return count; |
| 66 | } | 107 | } |
| 67 | 108 | ||
| 68 | -void InitializeData(half *x, int32_t *index, half *expected, int32_t input_count, int32_t output_count) { | 109 | +void InitializeData(DataType *x, IndexType *index, DataType *expected, int32_t input_count, int32_t output_count) { |
| 69 | std::array<int32_t, IL_RANK> input_strides{}; | 110 | std::array<int32_t, IL_RANK> input_strides{}; |
| 70 | input_strides.back() = 1; | 111 | input_strides.back() = 1; |
| 71 | for (size_t i = input_strides.size() - 1UL; i > 0UL; --i) { | 112 | for (size_t i = input_strides.size() - 1UL; i > 0UL; --i) { |
| 72 | input_strides[i - 1UL] = kInputShape[i] * input_strides[i]; | 113 | input_strides[i - 1UL] = kInputShape[i] * input_strides[i]; |
| 73 | } | 114 | } |
| 74 | for (int32_t i = 0; i < input_count; ++i) { | 115 | for (int32_t i = 0; i < input_count; ++i) { |
| 75 | - x[i] = static_cast<half>(static_cast<float>((i % 29) - 14) * 0.25F); | 116 | +#if defined(IL_DATA_UINT32) |
| 117 | + x[i] = static_cast<DataType>(i % 5); | ||
| 118 | +#elif defined(IL_OUTPUT_POST_TYPE) && IL_OUTPUT_POST_TYPE == 1 | ||
| 119 | + x[i] = static_cast<DataType>(static_cast<float>((i % 8) + 1) * 0.25F); | ||
| 120 | +#else | ||
| 121 | + x[i] = static_cast<DataType>(static_cast<float>((i % 29) - 14) * 0.25F); | ||
| 122 | +#endif | ||
| 76 | } | 123 | } |
| 77 | for (int32_t i = 0; i < output_count; ++i) { | 124 | for (int32_t i = 0; i < output_count; ++i) { |
| 78 | const int32_t index_value = (i * 3 + 1) % kInputShape[kAxis]; | 125 | const int32_t index_value = (i * 3 + 1) % kInputShape[kAxis]; |
| 79 | - index[i] = i % 2 == 0 ? index_value : -index_value; | 126 | + index[i] = static_cast<IndexType>(i % 2 == 0 ? index_value : -index_value); |
| 80 | int32_t remaining = i; | 127 | int32_t remaining = i; |
| 81 | int32_t input_offset = 0; | 128 | int32_t input_offset = 0; |
| 82 | for (size_t dim = kIndexShape.size(); dim-- > 0UL;) { | 129 | for (size_t dim = kIndexShape.size(); dim-- > 0UL;) { |
| @@ -85,13 +132,29 @@ void InitializeData(half *x, int32_t *index, half *expected, int32_t input_count | |||
| 85 | input_offset += (static_cast<int32_t>(dim) == kAxis ? index_value : coord) * input_strides[dim]; | 132 | input_offset += (static_cast<int32_t>(dim) == kAxis ? index_value : coord) * input_strides[dim]; |
| 86 | } | 133 | } |
| 87 | float value = static_cast<float>(x[input_offset]); | 134 | float value = static_cast<float>(x[input_offset]); |
| 88 | -#if IL_HAS_INPUT_PRE | 135 | +#if defined(IL_OUTPUT_POST_TYPE) && IL_OUTPUT_POST_TYPE == 1 |
| 89 | - value = std::max(value, 0.0F); | 136 | + expected[i] = static_cast<DataType>(BesselK0Reference(value)); |
| 90 | -#endif | 137 | +#elif defined(IL_OUTPUT_POST_TYPE) && IL_OUTPUT_POST_TYPE == 2 |
| 91 | -#if IL_USE_EXP2 | 138 | + expected[i] = static_cast<DataType>(value); |
| 92 | - expected[i] = static_cast<half>(-std::exp2(value)); | 139 | +#elif defined(IL_OUTPUT_POST_TYPE) && IL_OUTPUT_POST_TYPE == 3 |
| 140 | + expected[i] = static_cast<DataType>(std::exp2(value)); | ||
| 141 | +#elif IL_INPUT_PRE_TYPE == 5 | ||
| 142 | + expected[i] = static_cast<DataType>(IL_USE_EXP2 ? std::exp2(value) : std::exp(value)); | ||
| 93 | #else | 143 | #else |
| 94 | - expected[i] = static_cast<half>(-std::exp(value)); | 144 | +#if IL_INPUT_PRE_TYPE == 1 || IL_INPUT_PRE_TYPE == 4 |
| 145 | + value = std::max(value, 0.0F); | ||
| 146 | +#elif IL_INPUT_PRE_TYPE == 3 | ||
| 147 | + value = std::exp2(std::max(value, 0.0F)); | ||
| 148 | +#endif | ||
| 149 | +#if IL_INPUT_PRE_TYPE == 2 | ||
| 150 | + expected[i] = static_cast<DataType>(-std::exp2(value)); | ||
| 151 | +#elif IL_INPUT_PRE_TYPE == 3 | ||
| 152 | + expected[i] = static_cast<DataType>(-value); | ||
| 153 | +#elif IL_USE_EXP2 | ||
| 154 | + expected[i] = static_cast<DataType>(-std::exp2(value)); | ||
| 155 | +#else | ||
| 156 | + expected[i] = static_cast<DataType>(-std::exp(value)); | ||
| 157 | +#endif | ||
| 95 | #endif | 158 | #endif |
| 96 | } | 159 | } |
| 97 | } | 160 | } |
| @@ -101,32 +164,42 @@ TEST(E2EIndirectLoadStore, GeneratedKernelMatchesReference) { | |||
| 101 | const int32_t input_count = ElementCount(kInputShape); | 164 | const int32_t input_count = ElementCount(kInputShape); |
| 102 | const int32_t output_count = ElementCount(kIndexShape); | 165 | const int32_t output_count = ElementCount(kIndexShape); |
| 103 | const auto gm_free = [](void *ptr) { AscendC::GmFree(ptr); }; | 166 | const auto gm_free = [](void *ptr) { AscendC::GmFree(ptr); }; |
| 104 | - std::unique_ptr<half, decltype(gm_free)> x(reinterpret_cast<half *>(AscendC::GmAlloc(input_count * sizeof(half))), | 167 | + std::unique_ptr<DataType, decltype(gm_free)> x( |
| 105 | - gm_free); | 168 | + reinterpret_cast<DataType *>(AscendC::GmAlloc(input_count * sizeof(DataType))), gm_free); |
| 106 | - std::unique_ptr<int32_t, decltype(gm_free)> index( | 169 | + std::unique_ptr<IndexType, decltype(gm_free)> index( |
| 107 | - reinterpret_cast<int32_t *>(AscendC::GmAlloc(output_count * sizeof(int32_t))), gm_free); | 170 | + reinterpret_cast<IndexType *>(AscendC::GmAlloc(output_count * sizeof(IndexType))), gm_free); |
| 108 | - std::unique_ptr<half, decltype(gm_free)> output( | 171 | + std::unique_ptr<DataType, decltype(gm_free)> output( |
| 109 | - reinterpret_cast<half *>(AscendC::GmAlloc(output_count * sizeof(half))), gm_free); | 172 | + reinterpret_cast<DataType *>(AscendC::GmAlloc(output_count * sizeof(DataType))), gm_free); |
| 110 | ASSERT_NE(x, nullptr); | 173 | ASSERT_NE(x, nullptr); |
| 111 | ASSERT_NE(index, nullptr); | 174 | ASSERT_NE(index, nullptr); |
| 112 | ASSERT_NE(output, nullptr); | 175 | ASSERT_NE(output, nullptr); |
| 113 | - std::vector<half> expected(static_cast<size_t>(output_count)); | 176 | + std::vector<DataType> expected(static_cast<size_t>(output_count)); |
| 114 | InitializeData(x.get(), index.get(), expected.data(), input_count, output_count); | 177 | InitializeData(x.get(), index.get(), expected.data(), input_count, output_count); |
| 115 | - std::fill_n(output.get(), output_count, static_cast<half>(0.0F)); | 178 | + std::fill_n(output.get(), output_count, static_cast<DataType>(0.0F)); |
| 116 | 179 | ||
| 117 | AutofuseTilingData tiling_data{}; | 180 | AutofuseTilingData tiling_data{}; |
| 118 | uint32_t workspace_size = 0U; | 181 | uint32_t workspace_size = 0U; |
| 119 | uint32_t block_dim = 48U; | 182 | uint32_t block_dim = 48U; |
| 120 | RunTiling(tiling_data, workspace_size, block_dim); | 183 | RunTiling(tiling_data, workspace_size, block_dim); |
| 184 | +#if !defined(IL_EXPECT_SIMT) || IL_EXPECT_SIMT | ||
| 121 | ASSERT_EQ(tiling_data.graph0_tiling_key, IL_TILING_KEY); | 185 | ASSERT_EQ(tiling_data.graph0_tiling_key, IL_TILING_KEY); |
| 186 | +#endif | ||
| 122 | ASSERT_GT(tiling_data.block_dim, 0U); | 187 | ASSERT_GT(tiling_data.block_dim, 0U); |
| 188 | +#ifdef IL_EXPECT_SIMT_MULTI_ROUND | ||
| 189 | + ASSERT_GT((static_cast<uint32_t>(output_count) + tiling_data.block_dim - 1U) / tiling_data.block_dim, 1024U); | ||
| 190 | +#endif | ||
| 123 | 191 | ||
| 124 | AscendC::SetKernelMode(KernelMode::AIV_MODE); | 192 | AscendC::SetKernelMode(KernelMode::AIV_MODE); |
| 125 | ICPU_RUN_KF(indirect_load_store_test, tiling_data.block_dim, reinterpret_cast<uint8_t *>(x.get()), | 193 | ICPU_RUN_KF(indirect_load_store_test, tiling_data.block_dim, reinterpret_cast<uint8_t *>(x.get()), |
| 126 | reinterpret_cast<uint8_t *>(index.get()), reinterpret_cast<uint8_t *>(output.get()), nullptr, | 194 | reinterpret_cast<uint8_t *>(index.get()), reinterpret_cast<uint8_t *>(output.get()), nullptr, |
| 127 | reinterpret_cast<uint8_t *>(&tiling_data)); | 195 | reinterpret_cast<uint8_t *>(&tiling_data)); |
| 128 | for (int32_t i = 0; i < output_count; ++i) { | 196 | for (int32_t i = 0; i < output_count; ++i) { |
| 197 | +#if defined(IL_DATA_BF16) || defined(IL_DATA_UINT32) | ||
| 198 | + EXPECT_EQ(static_cast<float>(output.get()[i]), static_cast<float>(expected[static_cast<size_t>(i)])) | ||
| 199 | + << "offset=" << i; | ||
| 200 | +#else | ||
| 129 | EXPECT_NEAR(static_cast<float>(output.get()[i]), static_cast<float>(expected[static_cast<size_t>(i)]), 0.0625F) | 201 | EXPECT_NEAR(static_cast<float>(output.get()[i]), static_cast<float>(expected[static_cast<size_t>(i)]), 0.0625F) |
| 130 | << "offset=" << i; | 202 | << "offset=" << i; |
| 203 | +#endif | ||
| 131 | } | 204 | } |
| 132 | } | 205 | } |
| @@ -78,6 +78,8 @@ set(ascendc_api_regbase_extend_src | |||
| 78 | igammac_helper/asymptotic_series.h | 78 | igammac_helper/asymptotic_series.h |
| 79 | igammac_helper/series_complement.h | 79 | igammac_helper/series_complement.h |
| 80 | hypot.h | 80 | hypot.h |
| 81 | + indirect_load_simd.h | ||
| 82 | + indirect_load_simt.h | ||
| 81 | ) | 83 | ) |
| 82 | 84 | ||
| 83 | set(generated_regbase_files) | 85 | set(generated_regbase_files) |
| @@ -0,0 +1,68 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#ifndef AUTOFUSE_V35_ASCENDC_API_REGBASE_INDIRECT_LOAD_SIMD_H_ | ||
| 12 | +#define AUTOFUSE_V35_ASCENDC_API_REGBASE_INDIRECT_LOAD_SIMD_H_ | ||
| 13 | + | ||
| 14 | +namespace AscendC { | ||
| 15 | +namespace Internal { | ||
| 16 | +template <int32_t Dim, int32_t Axis, int32_t Rank> | ||
| 17 | +struct IndirectLoadSimdInnerOffset { | ||
| 18 | + __aicore__ inline static int64_t Call(int64_t inner, const int64_t *shape) { | ||
| 19 | + int64_t offset = inner % shape[Dim] * shape[Rank + Dim]; | ||
| 20 | + if constexpr (Dim > Axis + 1) { | ||
| 21 | + offset += IndirectLoadSimdInnerOffset<Dim - 1, Axis, Rank>::Call(inner / shape[Dim], shape); | ||
| 22 | + } | ||
| 23 | + return offset; | ||
| 24 | + } | ||
| 25 | +}; | ||
| 26 | + | ||
| 27 | +template <int32_t Dim, int32_t Axis> | ||
| 28 | +struct IndirectLoadSimdInnerSize { | ||
| 29 | + __aicore__ inline static int64_t Call(const int64_t *shape) { | ||
| 30 | + if constexpr (Dim == Axis) { | ||
| 31 | + return 1; | ||
| 32 | + } else { | ||
| 33 | + return shape[Dim] * IndirectLoadSimdInnerSize<Dim - 1, Axis>::Call(shape); | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | +}; | ||
| 37 | +} // namespace Internal | ||
| 38 | + | ||
| 39 | +template <typename X, typename Index, int32_t Rank, int32_t Axis, typename... ShapeArgs> | ||
| 40 | +__aicore__ inline void IndirectLoadSimd(const LocalTensor<X> &x, const LocalTensor<Index> &index, | ||
| 41 | + const LocalTensor<X> &y, const LocalTensor<uint8_t> &tmp, uint32_t actual_size, | ||
| 42 | + int64_t output_offset, int64_t input_axis, ShapeArgs... shape_args) { | ||
| 43 | + static_assert(Rank > 0 && Axis >= 0 && Axis < Rank, "IndirectLoad SIMD rank or axis is invalid."); | ||
| 44 | + static_assert(sizeof...(ShapeArgs) == static_cast<size_t>(2 * Rank), "IndirectLoad SIMD shape is invalid."); | ||
| 45 | + const int64_t shape[] = {static_cast<int64_t>(shape_args)...}; | ||
| 46 | + const int64_t index_inner = Internal::IndirectLoadSimdInnerSize<Rank - 1, Axis>::Call(shape); | ||
| 47 | + const int64_t input_inner = shape[Rank + Axis]; | ||
| 48 | + const int64_t input_slice_count = input_axis * input_inner; | ||
| 49 | + const int64_t output_slice_count = shape[Axis] * index_inner; | ||
| 50 | + const int64_t outer_begin = output_offset / output_slice_count; | ||
| 51 | + LocalTensor<uint32_t> offsets = tmp.template ReinterpretCast<uint32_t>(); | ||
| 52 | + for (int64_t i = 0; i < actual_size; ++i) { | ||
| 53 | + const int64_t global_idx = output_offset + i; | ||
| 54 | + const int64_t outer_local = global_idx / output_slice_count - outer_begin; | ||
| 55 | + const int64_t index_value = static_cast<int64_t>(index.GetValue(i)); | ||
| 56 | + int64_t input_inner_offset = 0; | ||
| 57 | + if constexpr (Axis + 1 < Rank) { | ||
| 58 | + input_inner_offset = | ||
| 59 | + Internal::IndirectLoadSimdInnerOffset<Rank - 1, Axis, Rank>::Call(global_idx % index_inner, shape); | ||
| 60 | + } | ||
| 61 | + const int64_t src_idx = outer_local * input_slice_count + index_value * input_inner + input_inner_offset; | ||
| 62 | + offsets.SetValue(i, static_cast<uint32_t>(src_idx * sizeof(X))); | ||
| 63 | + } | ||
| 64 | + Gather(y, x, offsets, static_cast<uint32_t>(0), actual_size); | ||
| 65 | +} | ||
| 66 | +} // namespace AscendC | ||
| 67 | + | ||
| 68 | +#endif // AUTOFUSE_V35_ASCENDC_API_REGBASE_INDIRECT_LOAD_SIMD_H_ | ||
| @@ -0,0 +1,72 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#ifndef AUTOFUSE_V35_ASCENDC_API_REGBASE_INDIRECT_LOAD_SIMT_H_ | ||
| 12 | +#define AUTOFUSE_V35_ASCENDC_API_REGBASE_INDIRECT_LOAD_SIMT_H_ | ||
| 13 | + | ||
| 14 | +namespace AscendC { | ||
| 15 | +namespace Internal { | ||
| 16 | +constexpr uint32_t kIndirectLoadSimtThreadNum = 1024U; | ||
| 17 | + | ||
| 18 | +template <int32_t Dim, int32_t Axis, int32_t Rank> | ||
| 19 | +struct IndirectLoadSimtOffset { | ||
| 20 | + __simt_callee__ __aicore__ inline static int64_t Call(int64_t linear_index, int64_t indirect_index, | ||
| 21 | + const int64_t *shape) { | ||
| 22 | + int64_t input_offset = 0; | ||
| 23 | + if constexpr (Dim == Axis) { | ||
| 24 | + input_offset = indirect_index * shape[Rank + Dim]; | ||
| 25 | + } else { | ||
| 26 | + input_offset = linear_index % shape[Dim] * shape[Rank + Dim]; | ||
| 27 | + } | ||
| 28 | + if constexpr (Dim > 0) { | ||
| 29 | + input_offset += | ||
| 30 | + IndirectLoadSimtOffset<Dim - 1, Axis, Rank>::Call(linear_index / shape[Dim], indirect_index, shape); | ||
| 31 | + } | ||
| 32 | + return input_offset; | ||
| 33 | + } | ||
| 34 | +}; | ||
| 35 | + | ||
| 36 | +template <typename X, typename Index, typename Y, int32_t Rank, int32_t Axis, typename IndexTransform, | ||
| 37 | + typename OutputTransform, typename... ShapeArgs> | ||
| 38 | +__simt_vf__ __aicore__ LAUNCH_BOUND(kIndirectLoadSimtThreadNum) inline void IndirectLoadSimtKernel( | ||
| 39 | + __gm__ X *x, __gm__ Index *index, __gm__ Y *y, uint32_t actual_size, int64_t output_offset, int64_t x_axis_size, | ||
| 40 | + ShapeArgs... shape_args) { | ||
| 41 | + static_assert(Rank > 0 && Axis >= 0 && Axis < Rank, "IndirectLoad SIMT rank or axis is invalid."); | ||
| 42 | + static_assert(sizeof...(ShapeArgs) == static_cast<size_t>(2 * Rank), "IndirectLoad SIMT shape is invalid."); | ||
| 43 | + const int64_t shape[] = {static_cast<int64_t>(shape_args)...}; | ||
| 44 | + for (uint32_t i = threadIdx.x; i < actual_size; i += blockDim.x) { | ||
| 45 | + const int64_t output_index = output_offset + i; | ||
| 46 | + const int64_t indirect_index = static_cast<int64_t>(IndexTransform::Call(index[output_index])); | ||
| 47 | + if (unlikely(indirect_index < 0 || indirect_index >= x_axis_size)) { | ||
| 48 | + y[output_index] = static_cast<Y>(0); | ||
| 49 | + continue; | ||
| 50 | + } | ||
| 51 | + const int64_t input_offset = | ||
| 52 | + IndirectLoadSimtOffset<Rank - 1, Axis, Rank>::Call(output_index, indirect_index, shape); | ||
| 53 | + y[output_index] = OutputTransform::Call(x[input_offset]); | ||
| 54 | + } | ||
| 55 | +} | ||
| 56 | +} // namespace Internal | ||
| 57 | + | ||
| 58 | +template <typename X, typename Index, typename Y, int32_t Rank, int32_t Axis, typename IndexTransform, | ||
| 59 | + typename OutputTransform, typename... ShapeArgs> | ||
| 60 | +__aicore__ inline void IndirectLoadSimt(__gm__ X *x, __gm__ Index *index, __gm__ Y *y, uint32_t actual_size, | ||
| 61 | + int64_t output_offset, int64_t x_axis_size, ShapeArgs... shape_args) { | ||
| 62 | + Simt::VF_CALL< | ||
| 63 | + Internal::IndirectLoadSimtKernel<X, Index, Y, Rank, Axis, IndexTransform, OutputTransform, ShapeArgs...>>( | ||
| 64 | + Simt::Dim3(Internal::kIndirectLoadSimtThreadNum), x, index, y, actual_size, output_offset, x_axis_size, | ||
| 65 | + shape_args...); | ||
| 66 | + const int32_t event_id = static_cast<int32_t>(GetTPipePtr()->FetchEventID(HardEvent::V_MTE3)); | ||
| 67 | + SetFlag<HardEvent::V_MTE3>(event_id); | ||
| 68 | + WaitFlag<HardEvent::V_MTE3>(event_id); | ||
| 69 | +} | ||
| 70 | +} // namespace AscendC | ||
| 71 | + | ||
| 72 | +#endif // AUTOFUSE_V35_ASCENDC_API_REGBASE_INDIRECT_LOAD_SIMT_H_ | ||
| @@ -30,6 +30,19 @@ class AscIrCodegenV2 : public AscIrCodegen { | |||
| 30 | virtual uint32_t GetMicroInstNum() const { | 30 | virtual uint32_t GetMicroInstNum() const { |
| 31 | return 1U; | 31 | return 1U; |
| 32 | } | 32 | } |
| 33 | + | ||
| 34 | + virtual bool IsSimtScalarSupported(const AscNode &node) const { | ||
| 35 | + (void)node; | ||
| 36 | + return false; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + virtual ge::graphStatus GenerateSimtScalarExpr(const AscNode &node, const std::vector<std::string> &inputs, | ||
| 40 | + std::string &expr) const { | ||
| 41 | + (void)node; | ||
| 42 | + (void)inputs; | ||
| 43 | + (void)expr; | ||
| 44 | + return af::FAILED; | ||
| 45 | + } | ||
| 33 | }; | 46 | }; |
| 34 | } // namespace ascir | 47 | } // namespace ascir |
| 35 | } // namespace af | 48 | } // namespace af |
| @@ -242,6 +242,12 @@ Register::Register() { | |||
| 242 | }; | 242 | }; |
| 243 | const std::string kAscendcShiftedChebyshevPolynomialWRegBaseStr = { | 243 | const std::string kAscendcShiftedChebyshevPolynomialWRegBaseStr = { |
| 244 | #include "shifted_chebyshev_polynomial_w_reg_base.h" | 244 | #include "shifted_chebyshev_polynomial_w_reg_base.h" |
| 245 | + }; | ||
| 246 | + const std::string kAscendcIndirectLoadSimtRegBaseStr = { | ||
| 247 | +#include "indirect_load_simt_reg_base.h" | ||
| 248 | + }; | ||
| 249 | + const std::string kAscendcIndirectLoadSimdRegBaseStr = { | ||
| 250 | +#include "indirect_load_simd_reg_base.h" | ||
| 245 | }; | 251 | }; |
| 246 | std::unordered_map<std::string, std::string> api_to_file{ | 252 | std::unordered_map<std::string, std::string> api_to_file{ |
| 247 | {"cast_reg_base.h", kAscendcCastRegStr}, | 253 | {"cast_reg_base.h", kAscendcCastRegStr}, |
| @@ -313,6 +319,8 @@ Register::Register() { | |||
| 313 | {"shifted_chebyshev_polynomial_u_reg_base.h", kAscendcShiftedChebyshevPolynomialURegBaseStr}, | 319 | {"shifted_chebyshev_polynomial_u_reg_base.h", kAscendcShiftedChebyshevPolynomialURegBaseStr}, |
| 314 | {"shifted_chebyshev_polynomial_v_reg_base.h", kAscendcShiftedChebyshevPolynomialVRegBaseStr}, | 320 | {"shifted_chebyshev_polynomial_v_reg_base.h", kAscendcShiftedChebyshevPolynomialVRegBaseStr}, |
| 315 | {"shifted_chebyshev_polynomial_w_reg_base.h", kAscendcShiftedChebyshevPolynomialWRegBaseStr}, | 321 | {"shifted_chebyshev_polynomial_w_reg_base.h", kAscendcShiftedChebyshevPolynomialWRegBaseStr}, |
| 322 | + {"indirect_load_simt_reg_base.h", kAscendcIndirectLoadSimtRegBaseStr}, | ||
| 323 | + {"indirect_load_simd_reg_base.h", kAscendcIndirectLoadSimdRegBaseStr}, | ||
| 316 | }; | 324 | }; |
| 317 | 325 | ||
| 318 | AscendCApiRegistry::GetInstance().RegisterApi(api_to_file); | 326 | AscendCApiRegistry::GetInstance().RegisterApi(api_to_file); |
| @@ -10,15 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | #include "reg_indirect_load_api_call.h" | 11 | #include "reg_indirect_load_api_call.h" |
| 12 | 12 | ||
| 13 | -#include <map> | ||
| 14 | #include <sstream> | 13 | #include <sstream> |
| 15 | #include "api_call/utils/api_call_factory.h" | 14 | #include "api_call/utils/api_call_factory.h" |
| 16 | -#include "asc_graph_utils.h" | ||
| 17 | #include "ascir_ops.h" | 15 | #include "ascir_ops.h" |
| 18 | #include "common/checker.h" | 16 | #include "common/checker.h" |
| 19 | -#include "common_utils.h" | ||
| 20 | #include "indirect_load_utils.h" | 17 | #include "indirect_load_utils.h" |
| 21 | -#include "schedule_result.h" | ||
| 22 | #include "v35/codegen/simt_scalar_call/simt_scalar_emitter.h" | 18 | #include "v35/codegen/simt_scalar_call/simt_scalar_emitter.h" |
| 23 | 19 | ||
| 24 | namespace codegen { | 20 | namespace codegen { |
| @@ -28,8 +24,6 @@ struct LogicalTensorInfo { | |||
| 28 | std::vector<ascir::SizeExpr> strides; | 24 | std::vector<ascir::SizeExpr> strides; |
| 29 | }; | 25 | }; |
| 30 | 26 | ||
| 31 | -constexpr uint32_t kIndirectLoadSimtThreadNum = 1024; | ||
| 32 | - | ||
| 33 | bool IsAxisDerivedFrom(const TPipe &tpipe, ascir::AxisId axis_id, ascir::AxisId ancestor_axis_id) { | 27 | bool IsAxisDerivedFrom(const TPipe &tpipe, ascir::AxisId axis_id, ascir::AxisId ancestor_axis_id) { |
| 34 | if (axis_id == ancestor_axis_id) { | 28 | if (axis_id == ancestor_axis_id) { |
| 35 | return true; | 29 | return true; |
| @@ -100,37 +94,12 @@ af::Status CheckIndirectLoadShape(const LogicalTensorInfo &x_info, const Logical | |||
| 100 | return af::SUCCESS; | 94 | return af::SUCCESS; |
| 101 | } | 95 | } |
| 102 | 96 | ||
| 103 | -af::Status CollectVectorFuncNodes(const af::AscNodePtr &vf_node, std::vector<af::AscNodePtr> &nodes) { | ||
| 104 | - if (vf_node == nullptr || !af::ops::IsOps<af::ascir_op::VectorFunc>(vf_node)) { | ||
| 105 | - return af::SUCCESS; | ||
| 106 | - } | ||
| 107 | - const std::string *graph_name = af::AttrUtils::GetStr(vf_node->GetOpDescBarePtr(), "sub_graph_name"); | ||
| 108 | - GE_ASSERT_NOTNULL(graph_name, "Get sub graph name failed, vf node:%s", vf_node->GetNamePtr()); | ||
| 109 | - af::AscGraph owner_graph("owner_graph"); | ||
| 110 | - GE_ASSERT_SUCCESS(af::AscGraphUtils::FromComputeGraph(vf_node->GetOwnerComputeGraph(), owner_graph), | ||
| 111 | - "Get owner graph failed, vf node:%s", vf_node->GetNamePtr()); | ||
| 112 | - af::AscGraph sub_graph("vf_sub_graph"); | ||
| 113 | - GE_ASSERT_SUCCESS(owner_graph.FindSubGraph(*graph_name, sub_graph), "Get sub graph failed, vf node:%s", | ||
| 114 | - vf_node->GetNamePtr()); | ||
| 115 | - for (const af::AscNodePtr &sub_node : sub_graph.GetAllNodes()) { | ||
| 116 | - if (af::ops::IsOps<af::ascir_op::Data>(sub_node) || af::ops::IsOps<af::ascir_op::Load>(sub_node) || | ||
| 117 | - af::ops::IsOps<af::ascir_op::Store>(sub_node) || af::ops::IsOps<af::ascir_op::Output>(sub_node)) { | ||
| 118 | - continue; | ||
| 119 | - } | ||
| 120 | - nodes.emplace_back(sub_node); | ||
| 121 | - } | ||
| 122 | - return af::SUCCESS; | ||
| 123 | -} | ||
| 124 | - | ||
| 125 | af::Status CollectSimtInlineTransformNode(const af::AscNodePtr &node, std::vector<af::AscNodePtr> &nodes) { | 97 | af::Status CollectSimtInlineTransformNode(const af::AscNodePtr &node, std::vector<af::AscNodePtr> &nodes) { |
| 126 | GE_ASSERT_TRUE(ascgen_utils::indirect_load::GetTemplateRole(node) == | 98 | GE_ASSERT_TRUE(ascgen_utils::indirect_load::GetTemplateRole(node) == |
| 127 | ascgen_utils::indirect_load::TemplateRole::kSimtInlineTransform, | 99 | ascgen_utils::indirect_load::TemplateRole::kSimtInlineTransform, |
| 128 | "IndirectLoad SIMT transform node has no inline-transform role."); | 100 | "IndirectLoad SIMT transform node has no inline-transform role."); |
| 129 | - const size_t node_count = nodes.size(); | 101 | + GE_ASSERT_TRUE(!af::ops::IsOps<af::ascir_op::VectorFunc>(node), |
| 130 | - GE_ASSERT_SUCCESS(CollectVectorFuncNodes(node, nodes)); | 102 | + "IndirectLoad SIMT transform must use scalar emission, node:%s", node->GetNamePtr()); |
| 131 | - if (nodes.size() != node_count) { | ||
| 132 | - return af::SUCCESS; | ||
| 133 | - } | ||
| 134 | GE_ASSERT_TRUE(node->GetInDataNodesSize() == 1UL, "IndirectLoad SIMT transform node must have exactly one input."); | 103 | GE_ASSERT_TRUE(node->GetInDataNodesSize() == 1UL, "IndirectLoad SIMT transform node must have exactly one input."); |
| 135 | nodes.emplace_back(node); | 104 | nodes.emplace_back(node); |
| 136 | return af::SUCCESS; | 105 | return af::SUCCESS; |
| @@ -142,10 +111,6 @@ af::Status CollectSimtIndexPreNodes(const ascir::NodeView &node, std::vector<af: | |||
| 142 | auto peer_out_anchor = index_anchor->GetPeerOutAnchor(); | 111 | auto peer_out_anchor = index_anchor->GetPeerOutAnchor(); |
| 143 | GE_ASSERT_NOTNULL(peer_out_anchor, "IndirectLoad index input anchor has no peer output."); | 112 | GE_ASSERT_NOTNULL(peer_out_anchor, "IndirectLoad index input anchor has no peer output."); |
| 144 | auto current = std::dynamic_pointer_cast<af::AscNode>(peer_out_anchor->GetOwnerNode()); | 113 | auto current = std::dynamic_pointer_cast<af::AscNode>(peer_out_anchor->GetOwnerNode()); |
| 145 | - GE_ASSERT_SUCCESS(CollectVectorFuncNodes(current, nodes)); | ||
| 146 | - if (!nodes.empty()) { | ||
| 147 | - return af::SUCCESS; | ||
| 148 | - } | ||
| 149 | std::vector<af::AscNodePtr> reversed_nodes; | 114 | std::vector<af::AscNodePtr> reversed_nodes; |
| 150 | while (current != nullptr && !af::ops::IsOps<af::ascir_op::Data>(current)) { | 115 | while (current != nullptr && !af::ops::IsOps<af::ascir_op::Data>(current)) { |
| 151 | if (af::ops::IsOps<af::ascir_op::Load>(current)) { | 116 | if (af::ops::IsOps<af::ascir_op::Load>(current)) { |
| @@ -175,99 +140,6 @@ af::Status CollectSimtOutputMetadata(const ascir::NodeView &node, std::vector<af | |||
| 175 | return af::FAILED; | 140 | return af::FAILED; |
| 176 | } | 141 | } |
| 177 | 142 | ||
| 178 | -struct SimdCodegenParams { | ||
| 179 | - const Tensor &x; | ||
| 180 | - const Tensor &index; | ||
| 181 | - const Tensor &y; | ||
| 182 | - af::AscNodePtr input_pre_vf; | ||
| 183 | - size_t axis_pos; | ||
| 184 | - std::string x_dtype_name; | ||
| 185 | - std::string y_dtype_name; | ||
| 186 | - std::string tmp_buf_name; | ||
| 187 | - std::string output_offset_expr; | ||
| 188 | - std::string index_axis_expr; | ||
| 189 | - std::string input_axis_expr; | ||
| 190 | - std::string index_inner_expr; | ||
| 191 | - std::string input_inner_expr; | ||
| 192 | - std::string index_outer_sizes_expr; | ||
| 193 | - std::string input_outer_strides_expr; | ||
| 194 | -}; | ||
| 195 | - | ||
| 196 | -void EmitSimdWindowSetup(const SimdCodegenParams ¶ms, std::stringstream &ss) { | ||
| 197 | - ss << " LocalTensor<uint8_t> indirect_load_tmp = " << params.tmp_buf_name << ";" << std::endl; | ||
| 198 | - ss << " LocalTensor<" << params.x_dtype_name << "> input_used = indirect_load_tmp.template ReinterpretCast<" | ||
| 199 | - << params.x_dtype_name << ">();" << std::endl; | ||
| 200 | - ss << " int64_t output_offset = " << params.output_offset_expr << ";" << std::endl; | ||
| 201 | - ss << " int64_t index_axis = " << params.index_axis_expr << ";" << std::endl; | ||
| 202 | - ss << " int64_t input_axis = " << params.input_axis_expr << ";" << std::endl; | ||
| 203 | - ss << " int64_t index_inner = " << params.index_inner_expr << ";" << std::endl; | ||
| 204 | - ss << " int64_t input_inner = " << params.input_inner_expr << ";" << std::endl; | ||
| 205 | - ss << " int64_t input_slice_count = input_axis * input_inner;" << std::endl; | ||
| 206 | - ss << " int64_t output_slice_count = index_axis * index_inner;" << std::endl; | ||
| 207 | - ss << " int64_t outer_begin = output_offset / output_slice_count;" << std::endl; | ||
| 208 | - ss << " int64_t outer_end = (output_offset + " << params.y.actual_size | ||
| 209 | - << " + output_slice_count - 1) / output_slice_count;" << std::endl; | ||
| 210 | - ss << " int64_t outer_count = outer_end - outer_begin;" << std::endl; | ||
| 211 | - ss << " int64_t input_window_count = outer_count * input_slice_count;" << std::endl; | ||
| 212 | - ss << " constexpr int64_t indirect_load_block_bytes = 32;" << std::endl; | ||
| 213 | - ss << " int64_t input_bytes = (input_window_count * sizeof(" << params.x_dtype_name | ||
| 214 | - << ") + indirect_load_block_bytes - 1) / indirect_load_block_bytes * indirect_load_block_bytes;" << std::endl; | ||
| 215 | - if (params.input_pre_vf != nullptr) { | ||
| 216 | - ss << " int64_t input_pre_bytes = (input_window_count * sizeof(" << params.y_dtype_name | ||
| 217 | - << ") + indirect_load_block_bytes - 1) / indirect_load_block_bytes * indirect_load_block_bytes;" << std::endl; | ||
| 218 | - } | ||
| 219 | -} | ||
| 220 | - | ||
| 221 | -void EmitSimdInputWindow(const SimdCodegenParams ¶ms, std::stringstream &ss) { | ||
| 222 | - if (params.axis_pos == 0UL) { | ||
| 223 | - ss << " DataCopyPadExtend<" << params.x_dtype_name << ", AscendC::PaddingMode::Normal>(input_used[0], " << params.x | ||
| 224 | - << "[0], 1, input_window_count, 0, 0);" << std::endl; | ||
| 225 | - } else { | ||
| 226 | - ss << " int64_t index_sizes[] = {" << params.index_outer_sizes_expr << "};" << std::endl; | ||
| 227 | - ss << " int64_t input_outer_strides[] = {" << params.input_outer_strides_expr << "};" << std::endl; | ||
| 228 | - ss << " for (int64_t outer_local = 0; outer_local < outer_count; ++outer_local) {" << std::endl; | ||
| 229 | - ss << " int64_t outer_linear = outer_begin + outer_local;" << std::endl; | ||
| 230 | - ss << " int64_t input_window_offset = 0;" << std::endl; | ||
| 231 | - ss << " for (int64_t axis = " << params.axis_pos << " - 1; axis >= 0; --axis) {" << std::endl; | ||
| 232 | - ss << " int64_t coord = outer_linear % index_sizes[axis];" << std::endl; | ||
| 233 | - ss << " outer_linear = outer_linear / index_sizes[axis];" << std::endl; | ||
| 234 | - ss << " input_window_offset += coord * input_outer_strides[axis];" << std::endl; | ||
| 235 | - ss << " }" << std::endl; | ||
| 236 | - ss << " DataCopyPadExtend<" << params.x_dtype_name << ", AscendC::PaddingMode::Normal>(" | ||
| 237 | - << "input_used[outer_local * input_slice_count], " << params.x | ||
| 238 | - << "[input_window_offset], 1, input_slice_count, 0, 0);" << std::endl; | ||
| 239 | - ss << " }" << std::endl; | ||
| 240 | - } | ||
| 241 | - if (params.input_pre_vf == nullptr) { | ||
| 242 | - ss << " LocalTensor<" << params.x_dtype_name << "> input_pre_used = input_used;" << std::endl; | ||
| 243 | - return; | ||
| 244 | - } | ||
| 245 | - ss << " LocalTensor<uint8_t> input_pre_buf = indirect_load_tmp[input_bytes];" << std::endl; | ||
| 246 | - ss << " LocalTensor<" << params.y_dtype_name << "> input_pre_used = input_pre_buf.template ReinterpretCast<" | ||
| 247 | - << params.y_dtype_name << ">();" << std::endl; | ||
| 248 | - ss << " VFCall" << params.input_pre_vf->GetName() << "((__local_mem__ " << params.y_dtype_name | ||
| 249 | - << " *)input_pre_used[0].GetPhyAddr(), (__local_mem__ " << params.x_dtype_name | ||
| 250 | - << " *)input_used[0].GetPhyAddr(), static_cast<uint32_t>(input_window_count));" << std::endl; | ||
| 251 | -} | ||
| 252 | - | ||
| 253 | -void EmitSimdGather(const SimdCodegenParams ¶ms, std::stringstream &ss) { | ||
| 254 | - const bool has_input_pre = params.input_pre_vf != nullptr; | ||
| 255 | - ss << " LocalTensor<uint8_t> offset_buf = indirect_load_tmp[" | ||
| 256 | - << (has_input_pre ? "input_bytes + input_pre_bytes" : "input_bytes") << "];" << std::endl; | ||
| 257 | - ss << " auto indirect_load_offset = offset_buf.template ReinterpretCast<uint32_t>();" << std::endl; | ||
| 258 | - ss << " for (int64_t i = 0; i < " << params.y.actual_size << "; ++i) {" << std::endl; | ||
| 259 | - ss << " int64_t global_idx = output_offset + i;" << std::endl; | ||
| 260 | - ss << " int64_t outer_local = global_idx / output_slice_count - outer_begin;" << std::endl; | ||
| 261 | - ss << " int64_t index_val = static_cast<int64_t>(" << params.index << ".GetValue(i));" << std::endl; | ||
| 262 | - ss << " int64_t inner = global_idx % index_inner;" << std::endl; | ||
| 263 | - ss << " int64_t src_idx = outer_local * input_slice_count + index_val * input_inner + inner;" << std::endl; | ||
| 264 | - ss << " indirect_load_offset.SetValue(i, static_cast<uint32_t>(src_idx * sizeof(" | ||
| 265 | - << (has_input_pre ? params.y_dtype_name : params.x_dtype_name) << ")));" << std::endl; | ||
| 266 | - ss << " }" << std::endl; | ||
| 267 | - ss << " AscendC::Gather(" << params.y << ", input_pre_used, indirect_load_offset, static_cast<uint32_t>(0), " | ||
| 268 | - << params.y.actual_size << ");" << std::endl; | ||
| 269 | -} | ||
| 270 | - | ||
| 271 | af::Status GenerateTypedTransform(const std::string &name, const std::string &input_dtype, | 143 | af::Status GenerateTypedTransform(const std::string &name, const std::string &input_dtype, |
| 272 | const std::vector<af::AscNodePtr> &nodes, std::stringstream &ss) { | 144 | const std::vector<af::AscNodePtr> &nodes, std::stringstream &ss) { |
| 273 | std::string return_dtype = input_dtype; | 145 | std::string return_dtype = input_dtype; |
| @@ -300,87 +172,6 @@ af::Status GenerateTypedTransform(const std::string &name, const std::string &in | |||
| 300 | ss << "};" << std::endl; | 172 | ss << "};" << std::endl; |
| 301 | return af::SUCCESS; | 173 | return af::SUCCESS; |
| 302 | } | 174 | } |
| 303 | - | ||
| 304 | -struct SimtKernelDefinitionParams { | ||
| 305 | - const std::string &kernel_name; | ||
| 306 | - const std::string &x_dtype_name; | ||
| 307 | - const std::string &index_dtype_name; | ||
| 308 | - const std::string &output_dtype_name; | ||
| 309 | - const std::string &index_transform; | ||
| 310 | - const std::string &output_transform; | ||
| 311 | - size_t rank; | ||
| 312 | - int64_t axis; | ||
| 313 | -}; | ||
| 314 | - | ||
| 315 | -void EmitSimtKernelDefinition(const SimtKernelDefinitionParams ¶ms, std::stringstream &ss) { | ||
| 316 | - ss << "__simt_vf__ __aicore__ LAUNCH_BOUND(" << kIndirectLoadSimtThreadNum << ") inline void " << params.kernel_name | ||
| 317 | - << "(__gm__ " << params.x_dtype_name << " *x, __gm__ " << params.index_dtype_name << " *index, __gm__ " | ||
| 318 | - << params.output_dtype_name << " *y, uint32_t actual_size, int64_t output_offset, int64_t x_axis_size"; | ||
| 319 | - for (size_t i = 0; i < params.rank; ++i) { | ||
| 320 | - ss << ", int64_t index_size" << i; | ||
| 321 | - } | ||
| 322 | - for (size_t i = 0; i < params.rank; ++i) { | ||
| 323 | - ss << ", int64_t x_stride" << i; | ||
| 324 | - } | ||
| 325 | - ss << ") {" << std::endl; | ||
| 326 | - ss << " for (uint32_t i = threadIdx.x; i < actual_size; i += blockDim.x) {" << std::endl; | ||
| 327 | - ss << " int64_t output_index = output_offset + i;" << std::endl; | ||
| 328 | - ss << " int64_t indirect_index = static_cast<int64_t>(" << params.index_transform | ||
| 329 | - << "::Call(index[output_index]));" << std::endl; | ||
| 330 | - ss << " if (unlikely(indirect_index < 0 || indirect_index >= x_axis_size)) {" << std::endl; | ||
| 331 | - ss << " y[output_index] = static_cast<" << params.output_dtype_name << ">(0);" << std::endl; | ||
| 332 | - ss << " continue;" << std::endl; | ||
| 333 | - ss << " }" << std::endl; | ||
| 334 | - ss << " int64_t linear_index = output_index;" << std::endl; | ||
| 335 | - ss << " int64_t input_offset = 0;" << std::endl; | ||
| 336 | - for (int64_t axis = static_cast<int64_t>(params.rank) - 1; axis >= 0; --axis) { | ||
| 337 | - if (axis != params.axis) { | ||
| 338 | - ss << " int64_t coord" << axis << " = linear_index % index_size" << axis << ";" << std::endl; | ||
| 339 | - } | ||
| 340 | - if (axis > 0) { | ||
| 341 | - ss << " linear_index = linear_index / index_size" << axis << ";" << std::endl; | ||
| 342 | - } | ||
| 343 | - if (axis == params.axis) { | ||
| 344 | - ss << " input_offset += indirect_index * x_stride" << axis << ";" << std::endl; | ||
| 345 | - } else { | ||
| 346 | - ss << " input_offset += coord" << axis << " * x_stride" << axis << ";" << std::endl; | ||
| 347 | - } | ||
| 348 | - } | ||
| 349 | - ss << " y[output_index] = " << params.output_transform << "::Call(x[input_offset]);" << std::endl; | ||
| 350 | - ss << " }" << std::endl; | ||
| 351 | - ss << "}" << std::endl; | ||
| 352 | -} | ||
| 353 | - | ||
| 354 | -struct SimtCodegenParams { | ||
| 355 | - const Tensor &x; | ||
| 356 | - const Tensor &index; | ||
| 357 | - std::string output_gm_expr; | ||
| 358 | - std::string x_dtype_name; | ||
| 359 | - std::string index_dtype_name; | ||
| 360 | - std::string output_dtype_name; | ||
| 361 | - std::string kernel_name; | ||
| 362 | - std::string x_axis_size_expr; | ||
| 363 | - std::string rank_sizes_expr; | ||
| 364 | - std::string x_strides_expr; | ||
| 365 | - std::string outer_tb_var; | ||
| 366 | -}; | ||
| 367 | - | ||
| 368 | -void EmitSimtLaunch(const SimtCodegenParams ¶ms, std::stringstream &ss) { | ||
| 369 | - ss << " __gm__ " << params.x_dtype_name << " *x_ptr = (__gm__ " << params.x_dtype_name << " *)" << params.x | ||
| 370 | - << ".GetPhyAddr();" << std::endl; | ||
| 371 | - ss << " __gm__ " << params.index_dtype_name << " *index_ptr = (__gm__ " << params.index_dtype_name << " *)" | ||
| 372 | - << params.index << ".GetPhyAddr();" << std::endl; | ||
| 373 | - ss << " __gm__ " << params.output_dtype_name << " *y_ptr = (__gm__ " << params.output_dtype_name << " *)" | ||
| 374 | - << params.output_gm_expr << ".GetPhyAddr();" << std::endl; | ||
| 375 | - ss << " AscendC::Simt::VF_CALL<" << params.kernel_name << ">(AscendC::Simt::Dim3(" << kIndirectLoadSimtThreadNum | ||
| 376 | - << "), x_ptr, index_ptr, y_ptr, static_cast<uint32_t>(" << params.outer_tb_var << "_loop_size), block_dim_offset, " | ||
| 377 | - << params.x_axis_size_expr << params.rank_sizes_expr << params.x_strides_expr << ");" << std::endl; | ||
| 378 | - ss << " int32_t event_id_v_to_mte3 = static_cast<int32_t>(GetTPipePtr()->FetchEventID(AscendC::HardEvent::V_MTE3));" | ||
| 379 | - << std::endl; | ||
| 380 | - ss << " AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(event_id_v_to_mte3);" << std::endl; | ||
| 381 | - ss << " AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(event_id_v_to_mte3);" << std::endl; | ||
| 382 | -} | ||
| 383 | - | ||
| 384 | } // namespace | 175 | } // namespace |
| 385 | 176 | ||
| 386 | Status IndirectLoadRegApiCall::ParseAttr(const ascir::NodeView &node) { | 177 | Status IndirectLoadRegApiCall::ParseAttr(const ascir::NodeView &node) { |
| @@ -390,20 +181,15 @@ Status IndirectLoadRegApiCall::ParseAttr(const ascir::NodeView &node) { | |||
| 390 | ascgen_utils::indirect_load::TemplateAxes template_axes; | 181 | ascgen_utils::indirect_load::TemplateAxes template_axes; |
| 391 | GE_ASSERT_SUCCESS(ascgen_utils::indirect_load::GetTemplateAxes(node, template_axes)); | 182 | GE_ASSERT_SUCCESS(ascgen_utils::indirect_load::GetTemplateAxes(node, template_axes)); |
| 392 | outer_axis_ = template_axes.outer_axis; | 183 | outer_axis_ = template_axes.outer_axis; |
| 393 | - template_id_ = ::ascir::GetTemplateIdOrDefault(*node, ascir::TemplateId::kIndirectLoadSimt); | 184 | + template_id_ = ::ascir::GetTemplateIdOrDefault(*node); |
| 185 | + GE_ASSERT_TRUE( | ||
| 186 | + template_id_ == ascir::TemplateId::kIndirectLoadSimd || template_id_ == ascir::TemplateId::kIndirectLoadSimt, | ||
| 187 | + "IndirectLoad node[%s] has invalid template id[%d].", node->GetNamePtr(), static_cast<int32_t>(template_id_)); | ||
| 394 | GE_ASSERT_SUCCESS(ascgen_utils::indirect_load::GetTemplateLogicalView(node, logical_view_)); | 188 | GE_ASSERT_SUCCESS(ascgen_utils::indirect_load::GetTemplateLogicalView(node, logical_view_)); |
| 395 | const int64_t rank = static_cast<int64_t>(logical_view_.data.axis_ids.size()); | 189 | const int64_t rank = static_cast<int64_t>(logical_view_.data.axis_ids.size()); |
| 396 | GE_ASSERT_TRUE(axis >= -rank && axis < rank, "IndirectLoad axis is out of range."); | 190 | GE_ASSERT_TRUE(axis >= -rank && axis < rank, "IndirectLoad axis is out of range."); |
| 397 | axis_ = axis < 0L ? axis + rank : axis; | 191 | axis_ = axis < 0L ? axis + rank : axis; |
| 398 | - if (template_id_ == ascir::TemplateId::kIndirectLoadSimd) { | 192 | + if (template_id_ == ascir::TemplateId::kIndirectLoadSimt) { |
| 399 | - const auto input_producer = ascgen_utils::indirect_load::GetInputProducer(node, 0UL); | ||
| 400 | - if (af::ops::IsOps<af::ascir_op::VectorFunc>(input_producer)) { | ||
| 401 | - GE_ASSERT_TRUE(ascgen_utils::indirect_load::GetTemplateRole(input_producer) == | ||
| 402 | - ascgen_utils::indirect_load::TemplateRole::kSimdInputPre, | ||
| 403 | - "IndirectLoad SIMD input VectorFunc has no input-pre role."); | ||
| 404 | - input_pre_vf_ = input_producer; | ||
| 405 | - } | ||
| 406 | - } else { | ||
| 407 | GE_ASSERT_SUCCESS(CollectSimtIndexPreNodes(node, index_pre_nodes_)); | 193 | GE_ASSERT_SUCCESS(CollectSimtIndexPreNodes(node, index_pre_nodes_)); |
| 408 | GE_ASSERT_SUCCESS(CollectSimtOutputMetadata(node, output_post_nodes_, output_gm_tensor_, output_dtype_)); | 194 | GE_ASSERT_SUCCESS(CollectSimtOutputMetadata(node, output_post_nodes_, output_gm_tensor_, output_dtype_)); |
| 409 | GE_ASSERT_TRUE(!node->outputs().empty(), "IndirectLoad SIMT node has no output tensor."); | 195 | GE_ASSERT_TRUE(!node->outputs().empty(), "IndirectLoad SIMT node has no output tensor."); |
| @@ -444,27 +230,18 @@ Status IndirectLoadRegApiCall::GenerateFuncDefinition(const TPipe &tpipe, const | |||
| 444 | "IndirectLoad SIMT input and index rank must be equal."); | 230 | "IndirectLoad SIMT input and index rank must be equal."); |
| 445 | std::string x_dtype; | 231 | std::string x_dtype; |
| 446 | std::string index_dtype; | 232 | std::string index_dtype; |
| 447 | - std::string output_dtype; | ||
| 448 | GE_ASSERT_SUCCESS(Tensor::DtypeName(x.dtype, x_dtype)); | 233 | GE_ASSERT_SUCCESS(Tensor::DtypeName(x.dtype, x_dtype)); |
| 449 | GE_ASSERT_SUCCESS(Tensor::DtypeName(index.dtype, index_dtype)); | 234 | GE_ASSERT_SUCCESS(Tensor::DtypeName(index.dtype, index_dtype)); |
| 450 | - GE_ASSERT_SUCCESS(Tensor::DtypeName(output_dtype_, output_dtype)); | ||
| 451 | const std::string valid_node_name = ascgen_utils::GenValidName(node_name); | 235 | const std::string valid_node_name = ascgen_utils::GenValidName(node_name); |
| 452 | const std::string index_transform = "IndirectLoadIndexTransform_" + valid_node_name; | 236 | const std::string index_transform = "IndirectLoadIndexTransform_" + valid_node_name; |
| 453 | const std::string output_transform = "IndirectLoadOutputTransform_" + valid_node_name; | 237 | const std::string output_transform = "IndirectLoadOutputTransform_" + valid_node_name; |
| 454 | - const std::string kernel_name = | ||
| 455 | - "IndirectLoadSimtKernel_" + ascgen_utils::GenValidName(graph_name) + "_" + valid_node_name; | ||
| 456 | - | ||
| 457 | GELOGI( | 238 | GELOGI( |
| 458 | - "[IndirectLoad] Generate SIMT wrapper for node[%s], rank[%zu], axis[%ld], index_pre_nodes[%zu], " | 239 | + "[IndirectLoad] Generate SIMT transforms for node[%s], rank[%zu], axis[%ld], index_pre_nodes[%zu], " |
| 459 | - "output_post_nodes[%zu], kernel[%s].", | 240 | + "output_post_nodes[%zu].", |
| 460 | - node_name.c_str(), x_info.sizes.size(), axis_, index_pre_nodes_.size(), output_post_nodes_.size(), | 241 | + node_name.c_str(), x_info.sizes.size(), axis_, index_pre_nodes_.size(), output_post_nodes_.size()); |
| 461 | - kernel_name.c_str()); | ||
| 462 | 242 | ||
| 463 | GE_ASSERT_SUCCESS(GenerateTypedTransform(index_transform, index_dtype, index_pre_nodes_, ss)); | 243 | GE_ASSERT_SUCCESS(GenerateTypedTransform(index_transform, index_dtype, index_pre_nodes_, ss)); |
| 464 | GE_ASSERT_SUCCESS(GenerateTypedTransform(output_transform, x_dtype, output_post_nodes_, ss)); | 244 | GE_ASSERT_SUCCESS(GenerateTypedTransform(output_transform, x_dtype, output_post_nodes_, ss)); |
| 465 | - const SimtKernelDefinitionParams params{kernel_name, x_dtype, index_dtype, output_dtype, | ||
| 466 | - index_transform, output_transform, x_info.sizes.size(), axis_}; | ||
| 467 | - EmitSimtKernelDefinition(params, ss); | ||
| 468 | return af::SUCCESS; | 245 | return af::SUCCESS; |
| 469 | } | 246 | } |
| 470 | 247 | ||
| @@ -473,18 +250,15 @@ Status IndirectLoadRegApiCall::Generate(const TPipe &tpipe, const std::vector<as | |||
| 473 | const std::vector<std::reference_wrapper<const Tensor>> &outputs, | 250 | const std::vector<std::reference_wrapper<const Tensor>> &outputs, |
| 474 | std::string &result) const { | 251 | std::string &result) const { |
| 475 | GE_ASSERT_TRUE(inputs.size() == 2U && outputs.size() == 1U, "IndirectLoad expects 2 inputs and 1 output."); | 252 | GE_ASSERT_TRUE(inputs.size() == 2U && outputs.size() == 1U, "IndirectLoad expects 2 inputs and 1 output."); |
| 253 | + GE_ASSERT_TRUE(template_id_ == ascir::TemplateId::kIndirectLoadSimd, | ||
| 254 | + "IndirectLoad tensor-based Generate only supports SIMD."); | ||
| 476 | const LogicalTensorInfo x_info = BuildLogicalTensorInfo(logical_view_.data, tpipe); | 255 | const LogicalTensorInfo x_info = BuildLogicalTensorInfo(logical_view_.data, tpipe); |
| 477 | const LogicalTensorInfo index_info = BuildLogicalTensorInfo(logical_view_.index, tpipe); | 256 | const LogicalTensorInfo index_info = BuildLogicalTensorInfo(logical_view_.index, tpipe); |
| 478 | const LogicalTensorInfo output_info = BuildLogicalTensorInfo(logical_view_.output, tpipe); | 257 | const LogicalTensorInfo output_info = BuildLogicalTensorInfo(logical_view_.output, tpipe); |
| 479 | GE_ASSERT_SUCCESS(CheckIndirectLoadShape(x_info, index_info, output_info)); | 258 | GE_ASSERT_SUCCESS(CheckIndirectLoadShape(x_info, index_info, output_info)); |
| 480 | (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs); | 259 | (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs); |
| 481 | - | 260 | + GELOGI("[IndirectLoad] Generate SIMD API body for node[%s].", node_name.c_str()); |
| 482 | - if (template_id_ == ascir::TemplateId::kIndirectLoadSimd) { | 261 | + return GenerateSimd(tpipe, current_axis, inputs, outputs, result); |
| 483 | - GELOGI("[IndirectLoad] Generate SIMD API body for node[%s].", node_name.c_str()); | ||
| 484 | - return GenerateSimd(tpipe, current_axis, inputs, outputs, result); | ||
| 485 | - } | ||
| 486 | - GELOGI("[IndirectLoad] Generate SIMT API body for node[%s].", node_name.c_str()); | ||
| 487 | - return GenerateSimt(tpipe, current_axis, inputs, result); | ||
| 488 | } | 262 | } |
| 489 | 263 | ||
| 490 | Status IndirectLoadRegApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> ¤t_axis, | 264 | Status IndirectLoadRegApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> ¤t_axis, |
| @@ -515,37 +289,22 @@ Status IndirectLoadRegApiCall::GenerateSimd(const TPipe &tpipe, const std::vecto | |||
| 515 | const LogicalTensorInfo index_info = BuildLogicalTensorInfo(logical_view_.index, tpipe); | 289 | const LogicalTensorInfo index_info = BuildLogicalTensorInfo(logical_view_.index, tpipe); |
| 516 | const size_t axis_pos = static_cast<size_t>(axis_); | 290 | const size_t axis_pos = static_cast<size_t>(axis_); |
| 517 | std::string x_dtype_name; | 291 | std::string x_dtype_name; |
| 518 | - std::string y_dtype_name; | 292 | + std::string index_dtype_name; |
| 519 | - Tensor::DtypeName(x.dtype, x_dtype_name); | 293 | + GE_ASSERT_SUCCESS(Tensor::DtypeName(x.dtype, x_dtype_name)); |
| 520 | - Tensor::DtypeName(y.dtype, y_dtype_name); | 294 | + GE_ASSERT_SUCCESS(Tensor::DtypeName(index.dtype, index_dtype_name)); |
| 521 | - const bool has_input_pre = input_pre_vf_ != nullptr; | 295 | + GE_ASSERT_TRUE(x.dtype == y.dtype, "IndirectLoad SIMD input/output dtype must match after input preprocess."); |
| 522 | - GE_ASSERT_TRUE(has_input_pre || x.dtype == y.dtype, | 296 | + GELOGD("[IndirectLoad] Generate SIMD body for node[%s], rank[%zu], axis[%zu].", node_name.c_str(), |
| 523 | - "IndirectLoad SIMD without input preprocess requires matching input/output dtype."); | 297 | + x_info.sizes.size(), axis_pos); |
| 524 | - GELOGD("[IndirectLoad] Generate SIMD body for node[%s], rank[%zu], axis[%zu], has_input_pre[%d].", node_name.c_str(), | ||
| 525 | - x_info.sizes.size(), axis_pos, static_cast<int32_t>(has_input_pre)); | ||
| 526 | 298 | ||
| 527 | - const SimdCodegenParams params{ | ||
| 528 | - x, | ||
| 529 | - index, | ||
| 530 | - y, | ||
| 531 | - input_pre_vf_, | ||
| 532 | - axis_pos, | ||
| 533 | - x_dtype_name, | ||
| 534 | - y_dtype_name, | ||
| 535 | - tpipe.tmp_buf.name + "_" + std::to_string(tmp_iter->second), | ||
| 536 | - tpipe.tiler.Offset(current_axis, y.axis, y.axis_strides), | ||
| 537 | - tpipe.tiler.Size(index_info.sizes[axis_pos]), | ||
| 538 | - tpipe.tiler.Size(x_info.sizes[axis_pos]), | ||
| 539 | - tpipe.tiler.Size(index_info.strides[axis_pos]), | ||
| 540 | - tpipe.tiler.Size(x_info.strides[axis_pos]), | ||
| 541 | - JoinSizeExprs(std::vector<ascir::SizeExpr>(index_info.sizes.begin(), index_info.sizes.begin() + axis_pos), tpipe), | ||
| 542 | - JoinSizeExprs(std::vector<ascir::SizeExpr>(x_info.strides.begin(), x_info.strides.begin() + axis_pos), tpipe)}; | ||
| 543 | std::stringstream ss; | 299 | std::stringstream ss; |
| 544 | ss << "// IndirectLoad SIMD" << std::endl; | 300 | ss << "// IndirectLoad SIMD" << std::endl; |
| 545 | ss << "{" << std::endl; | 301 | ss << "{" << std::endl; |
| 546 | - EmitSimdWindowSetup(params, ss); | 302 | + ss << " AscendC::IndirectLoadSimd<" << x_dtype_name << ", " << index_dtype_name << ", " << x_info.sizes.size() |
| 547 | - EmitSimdInputWindow(params, ss); | 303 | + << ", " << axis_ << ">(" << std::endl; |
| 548 | - EmitSimdGather(params, ss); | 304 | + ss << " " << x << ", " << index << ", " << y << ", " << tpipe.tmp_buf.name << "_" << tmp_iter->second << ", " |
| 305 | + << y.actual_size << ", " << tpipe.tiler.Offset(current_axis, y.axis, y.axis_strides) << ", " | ||
| 306 | + << tpipe.tiler.Size(x_info.sizes[axis_pos]) << ", " << JoinSizeExprs(index_info.sizes, tpipe) << ", " | ||
| 307 | + << JoinSizeExprs(x_info.strides, tpipe) << ");" << std::endl; | ||
| 549 | ss << "}" << std::endl; | 308 | ss << "}" << std::endl; |
| 550 | result = ss.str(); | 309 | result = ss.str(); |
| 551 | return af::SUCCESS; | 310 | return af::SUCCESS; |
| @@ -561,8 +320,6 @@ Status IndirectLoadRegApiCall::GenerateSimt(const TPipe &tpipe, const std::vecto | |||
| 561 | GELOGD("[IndirectLoad] Generate SIMT body for node[%s], output_gm[%s].", node_name.c_str(), | 320 | GELOGD("[IndirectLoad] Generate SIMT body for node[%s], output_gm[%s].", node_name.c_str(), |
| 562 | output_gm_tensor_.c_str()); | 321 | output_gm_tensor_.c_str()); |
| 563 | 322 | ||
| 564 | - const std::string x_axis_size = tpipe.tiler.Size(x_info.sizes[axis_]); | ||
| 565 | - | ||
| 566 | std::string outer_tb_var; | 323 | std::string outer_tb_var; |
| 567 | const bool has_outer_tb = | 324 | const bool has_outer_tb = |
| 568 | FindCurrentAxisVar(tpipe, current_axis, Axis::Type::kAxisTypeBlockInner, outer_axis_, outer_tb_var); | 325 | FindCurrentAxisVar(tpipe, current_axis, Axis::Type::kAxisTypeBlockInner, outer_axis_, outer_tb_var); |
| @@ -571,16 +328,23 @@ Status IndirectLoadRegApiCall::GenerateSimt(const TPipe &tpipe, const std::vecto | |||
| 571 | GE_ASSERT_SUCCESS(Tensor::DtypeName(x.dtype, x_dtype)); | 328 | GE_ASSERT_SUCCESS(Tensor::DtypeName(x.dtype, x_dtype)); |
| 572 | GE_ASSERT_SUCCESS(Tensor::DtypeName(index.dtype, index_dtype)); | 329 | GE_ASSERT_SUCCESS(Tensor::DtypeName(index.dtype, index_dtype)); |
| 573 | GE_ASSERT_SUCCESS(Tensor::DtypeName(output_dtype_, output_dtype)); | 330 | GE_ASSERT_SUCCESS(Tensor::DtypeName(output_dtype_, output_dtype)); |
| 574 | - const std::string kernel_name = | 331 | + const std::string valid_node_name = ascgen_utils::GenValidName(node_name); |
| 575 | - "IndirectLoadSimtKernel_" + ascgen_utils::GenValidName(graph_name) + "_" + ascgen_utils::GenValidName(node_name); | 332 | + const std::string index_transform = "IndirectLoadIndexTransform_" + valid_node_name; |
| 576 | - const std::string rank_sizes = std::string(", ") + JoinSizeExprs(index_info.sizes, tpipe); | 333 | + const std::string output_transform = "IndirectLoadOutputTransform_" + valid_node_name; |
| 577 | - const std::string x_strides = std::string(", ") + JoinSizeExprs(x_info.strides, tpipe); | ||
| 578 | - const SimtCodegenParams params{x, index, output_gm_tensor_, x_dtype, index_dtype, output_dtype, | ||
| 579 | - kernel_name, x_axis_size, rank_sizes, x_strides, outer_tb_var}; | ||
| 580 | std::stringstream ss; | 334 | std::stringstream ss; |
| 581 | ss << "// IndirectLoad SIMT" << std::endl; | 335 | ss << "// IndirectLoad SIMT" << std::endl; |
| 582 | ss << "{" << std::endl; | 336 | ss << "{" << std::endl; |
| 583 | - EmitSimtLaunch(params, ss); | 337 | + ss << " __gm__ " << x_dtype << " *x_ptr = (__gm__ " << x_dtype << " *)" << x << ".GetPhyAddr();" << std::endl; |
| 338 | + ss << " __gm__ " << index_dtype << " *index_ptr = (__gm__ " << index_dtype << " *)" << index << ".GetPhyAddr();" | ||
| 339 | + << std::endl; | ||
| 340 | + ss << " __gm__ " << output_dtype << " *y_ptr = (__gm__ " << output_dtype << " *)" << output_gm_tensor_ | ||
| 341 | + << ".GetPhyAddr();" << std::endl; | ||
| 342 | + ss << " AscendC::IndirectLoadSimt<" << x_dtype << ", " << index_dtype << ", " << output_dtype << ", " | ||
| 343 | + << x_info.sizes.size() << ", " << axis_ << ", " << index_transform << ", " << output_transform << ">(" | ||
| 344 | + << std::endl; | ||
| 345 | + ss << " x_ptr, index_ptr, y_ptr, static_cast<uint32_t>(" << outer_tb_var << "_loop_size), block_dim_offset, " | ||
| 346 | + << tpipe.tiler.Size(x_info.sizes[axis_]) << ", " << JoinSizeExprs(index_info.sizes, tpipe) << ", " | ||
| 347 | + << JoinSizeExprs(x_info.strides, tpipe) << ");" << std::endl; | ||
| 584 | ss << "}" << std::endl; | 348 | ss << "}" << std::endl; |
| 585 | result = ss.str(); | 349 | result = ss.str(); |
| 586 | return af::SUCCESS; | 350 | return af::SUCCESS; |
| @@ -15,12 +15,10 @@ | |||
| 15 | 15 | ||
| 16 | #include "codegen_kernel.h" | 16 | #include "codegen_kernel.h" |
| 17 | #include "indirect_load_utils.h" | 17 | #include "indirect_load_utils.h" |
| 18 | -#include "schedule_result.h" | ||
| 19 | 18 | ||
| 20 | namespace codegen { | 19 | namespace codegen { |
| 21 | class IndirectLoadRegApiCall final : public ApiCall { | 20 | class IndirectLoadRegApiCall final : public ApiCall { |
| 22 | public: | 21 | public: |
| 23 | - using ApiCall::Generate; | ||
| 24 | explicit IndirectLoadRegApiCall(const std::string &api_name) : ApiCall(api_name) {} | 22 | explicit IndirectLoadRegApiCall(const std::string &api_name) : ApiCall(api_name) {} |
| 25 | ~IndirectLoadRegApiCall() final = default; | 23 | ~IndirectLoadRegApiCall() final = default; |
| 26 | Status GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, std::stringstream &ss) const override; | 24 | Status GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, std::stringstream &ss) const override; |
| @@ -42,9 +40,8 @@ class IndirectLoadRegApiCall final : public ApiCall { | |||
| 42 | 40 | ||
| 43 | int64_t axis_ = 0; | 41 | int64_t axis_ = 0; |
| 44 | ascir::AxisId outer_axis_ = af::kIdNone; | 42 | ascir::AxisId outer_axis_ = af::kIdNone; |
| 45 | - ascir::TemplateId template_id_{ascir::TemplateId::kIndirectLoadSimt}; | 43 | + ascir::TemplateId template_id_{ascir::TemplateId::kDefault}; |
| 46 | ascgen_utils::indirect_load::TemplateLogicalView logical_view_; | 44 | ascgen_utils::indirect_load::TemplateLogicalView logical_view_; |
| 47 | - af::AscNodePtr input_pre_vf_; | ||
| 48 | std::vector<af::AscNodePtr> index_pre_nodes_; | 45 | std::vector<af::AscNodePtr> index_pre_nodes_; |
| 49 | std::vector<af::AscNodePtr> output_post_nodes_; | 46 | std::vector<af::AscNodePtr> output_post_nodes_; |
| 50 | std::string output_gm_tensor_; | 47 | std::string output_gm_tensor_; |
| @@ -12,20 +12,11 @@ | |||
| 12 | 12 | ||
| 13 | #include "ascir_ops.h" | 13 | #include "ascir_ops.h" |
| 14 | #include "ascir_ops_utils.h" | 14 | #include "ascir_ops_utils.h" |
| 15 | +#include "v35/ascir/ascir_codegen_v2.h" | ||
| 15 | #include "common/checker.h" | 16 | #include "common/checker.h" |
| 16 | #include "common_utils.h" | 17 | #include "common_utils.h" |
| 17 | -#include "indirect_load_utils.h" | ||
| 18 | -#include "schedule_result.h" | ||
| 19 | 18 | ||
| 20 | namespace codegen { | 19 | namespace codegen { |
| 21 | -bool CanEmitSimtScalar(const ascir::NodeView &node) { | ||
| 22 | - if (node == nullptr) { | ||
| 23 | - return false; | ||
| 24 | - } | ||
| 25 | - const auto impl = ascgen_utils::GetAscIrCodegenImpl(node->GetType()); | ||
| 26 | - return impl != nullptr && impl->IsSimtScalarSupported(*node); | ||
| 27 | -} | ||
| 28 | - | ||
| 29 | af::Status EmitSimtScalarExpr(const ascir::NodeView &node, const std::vector<std::string> &inputs, std::string &expr) { | 20 | af::Status EmitSimtScalarExpr(const ascir::NodeView &node, const std::vector<std::string> &inputs, std::string &expr) { |
| 30 | GE_ASSERT_NOTNULL(node, "SIMT scalar node is null."); | 21 | GE_ASSERT_NOTNULL(node, "SIMT scalar node is null."); |
| 31 | GE_ASSERT_TRUE(!inputs.empty() && inputs.size() == node->inputs.Size(), | 22 | GE_ASSERT_TRUE(!inputs.empty() && inputs.size() == node->inputs.Size(), |
| @@ -34,12 +25,11 @@ af::Status EmitSimtScalarExpr(const ascir::NodeView &node, const std::vector<std | |||
| 34 | const auto impl = ascgen_utils::GetAscIrCodegenImpl(node->GetType()); | 25 | const auto impl = ascgen_utils::GetAscIrCodegenImpl(node->GetType()); |
| 35 | GE_ASSERT_NOTNULL(impl, "SIMT scalar codegen is not registered for node %s[%s].", node->GetTypePtr(), | 26 | GE_ASSERT_NOTNULL(impl, "SIMT scalar codegen is not registered for node %s[%s].", node->GetTypePtr(), |
| 36 | node->GetNamePtr()); | 27 | node->GetNamePtr()); |
| 37 | - GE_ASSERT_TRUE(impl->IsSimtScalarSupported(*node), "SIMT scalar codegen is not supported for node %s[%s].", | 28 | + const auto *v2_impl = dynamic_cast<af::ascir::AscIrCodegenV2 *>(impl.get()); |
| 29 | + GE_ASSERT_NOTNULL(v2_impl, "SIMT scalar codegen for node %s[%s] is not a V2 implementation.", node->GetTypePtr(), | ||
| 30 | + node->GetNamePtr()); | ||
| 31 | + GE_ASSERT_TRUE(v2_impl->IsSimtScalarSupported(*node), "SIMT scalar codegen is not supported for node %s[%s].", | ||
| 38 | node->GetTypePtr(), node->GetNamePtr()); | 32 | node->GetTypePtr(), node->GetNamePtr()); |
| 39 | - return impl->GenerateSimtScalarExpr(*node, inputs, expr); | 33 | + return v2_impl->GenerateSimtScalarExpr(*node, inputs, expr); |
| 40 | -} | ||
| 41 | - | ||
| 42 | -bool IsSkippedApiEmitProcessNode(const ascir::NodeView &node) { | ||
| 43 | - return ascgen_utils::indirect_load::GetTemplateBehavior(std::dynamic_pointer_cast<af::AscNode>(node)).skips_api_emit; | ||
| 44 | } | 34 | } |
| 45 | } // namespace codegen | 35 | } // namespace codegen |
| @@ -16,9 +16,7 @@ | |||
| 16 | #include "ascir.h" | 16 | #include "ascir.h" |
| 17 | 17 | ||
| 18 | namespace codegen { | 18 | namespace codegen { |
| 19 | -bool CanEmitSimtScalar(const ascir::NodeView &node); | ||
| 20 | af::Status EmitSimtScalarExpr(const ascir::NodeView &node, const std::vector<std::string> &inputs, std::string &expr); | 19 | af::Status EmitSimtScalarExpr(const ascir::NodeView &node, const std::vector<std::string> &inputs, std::string &expr); |
| 21 | -bool IsSkippedApiEmitProcessNode(const ascir::NodeView &node); | ||
| 22 | } // namespace codegen | 20 | } // namespace codegen |
| 23 | 21 | ||
| 24 | #endif // __AUTOFUSE_SIMT_SCALAR_EMITTER_H__ | 22 | #endif // __AUTOFUSE_SIMT_SCALAR_EMITTER_H__ |
| @@ -320,22 +320,6 @@ Status VfCall::ParseSubGraph(const ascir::NodeView &vf_node, const ascir::ImplGr | |||
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | Status VfCall::ParseInputOutputInfo(const TPipe &tpipe) const { | 322 | Status VfCall::ParseInputOutputInfo(const TPipe &tpipe) const { |
| 323 | - if (inputs.empty() && skip_api_emit) { | ||
| 324 | - for (const auto *input : node->inputs()) { | ||
| 325 | - GE_ASSERT_NOTNULL(input, "Skipped VfCall node %s has null input.", node->GetNamePtr()); | ||
| 326 | - auto tensor_ptr = tpipe.GetTensor(input->attr.mem.tensor_id); | ||
| 327 | - GE_CHK_BOOL_RET_STATUS(tensor_ptr != nullptr, af::FAILED, "Check[Param] tensor_ptr is nullptr"); | ||
| 328 | - ub_inputs_.emplace_back(*tensor_ptr); | ||
| 329 | - } | ||
| 330 | - } | ||
| 331 | - if (outputs.empty() && skip_api_emit) { | ||
| 332 | - for (const auto *output : node->outputs()) { | ||
| 333 | - GE_ASSERT_NOTNULL(output, "Skipped VfCall node %s has null output.", node->GetNamePtr()); | ||
| 334 | - auto tensor_ptr = tpipe.GetTensor(output->attr.mem.tensor_id); | ||
| 335 | - GE_CHK_BOOL_RET_STATUS(tensor_ptr != nullptr, af::FAILED, "Check[Param] tensor_ptr is nullptr"); | ||
| 336 | - ub_outputs_.emplace_back(*tensor_ptr); | ||
| 337 | - } | ||
| 338 | - } | ||
| 339 | for (const auto &in : inputs) { | 323 | for (const auto &in : inputs) { |
| 340 | auto tensor_ptr = tpipe.GetTensor(in->id); | 324 | auto tensor_ptr = tpipe.GetTensor(in->id); |
| 341 | GE_CHK_BOOL_RET_STATUS(tensor_ptr != nullptr, af::FAILED, "Check[Param] tensor_ptr is nullptr"); | 325 | GE_CHK_BOOL_RET_STATUS(tensor_ptr != nullptr, af::FAILED, "Check[Param] tensor_ptr is nullptr"); |
| @@ -1169,9 +1169,8 @@ af::Status VectorFuncPartitioner::ModifySubgraphAttrs(af::AscGraph &vf_graph) { | |||
| 1169 | af::Status VectorFuncPartitioner::BuildSubgraphs() { | 1169 | af::Status VectorFuncPartitioner::BuildSubgraphs() { |
| 1170 | for (const auto &cluster : cluster_dict_.GetAllClusters()) { | 1170 | for (const auto &cluster : cluster_dict_.GetAllClusters()) { |
| 1171 | // 不包含隐式广播的单节点不融合 | 1171 | // 不包含隐式广播的单节点不融合 |
| 1172 | - const bool force_vf = ascgen_utils::indirect_load::ShouldApplyInputInnerVectorization(cluster->Nodes().front()); | 1172 | + if (!cluster->meta_data_.enable_vf || |
| 1173 | - if (!cluster->meta_data_.enable_vf || (cluster->Nodes().size() < kMinVfNodesNum && !force_vf && | 1173 | + (cluster->Nodes().size() < kMinVfNodesNum && !ascgen_utils::IsNodeContainsBrcInline(cluster->Nodes().back()))) { |
| 1174 | - !ascgen_utils::IsNodeContainsBrcInline(cluster->Nodes().back()))) { | ||
| 1175 | continue; | 1174 | continue; |
| 1176 | } | 1175 | } |
| 1177 | // 1. create vf op && subgraph | 1176 | // 1. create vf op && subgraph |
| @@ -207,7 +207,7 @@ af::Status NddmaTemplate::ProcessSliceToNddma(const af::AscNodePtr &node_load, b | |||
| 207 | GE_CHECK_NOTNULL(node_load->GetOpDesc()); | 207 | GE_CHECK_NOTNULL(node_load->GetOpDesc()); |
| 208 | 208 | ||
| 209 | const auto indirect_load_behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node_load); | 209 | const auto indirect_load_behavior = ascgen_utils::indirect_load::GetTemplateBehavior(node_load); |
| 210 | - if (indirect_load_behavior.uses_direct_gm_pipeline || indirect_load_behavior.skips_api_emit) { | 210 | + if (indirect_load_behavior.uses_direct_gm_pipeline) { |
| 211 | return af::SUCCESS; | 211 | return af::SUCCESS; |
| 212 | } | 212 | } |
| 213 | 213 | ||
| @@ -771,13 +771,28 @@ build_backend() { | |||
| 771 | load_gather_split_b_t_abs_store_test_e2e_v2 \ | 771 | load_gather_split_b_t_abs_store_test_e2e_v2 \ |
| 772 | load_gather_tail_split_b_t_abs_store_test_e2e_v2 \ | 772 | load_gather_tail_split_b_t_abs_store_test_e2e_v2 \ |
| 773 | load_gather_one_axis_split_b_t_abs_store_test_e2e_v2 \ | 773 | load_gather_one_axis_split_b_t_abs_store_test_e2e_v2 \ |
| 774 | - indirect_load_rank2_axis1_simt_e2e_v2 \ | 774 | + indirect_load_rank2_axis1_simt_e2e_v2 \ |
| 775 | - indirect_load_rank2_axis1_simd_e2e_v2 \ | 775 | + indirect_load_rank2_axis1_simd_e2e_v2 \ |
| 776 | - indirect_load_rank3_axis1_simt_e2e_v2 \ | 776 | + indirect_load_rank2_axisneg2_simt_e2e_v2 \ |
| 777 | - indirect_load_rank3_axis1_simd_e2e_v2 \ | 777 | + indirect_load_rank2_axisneg2_simd_e2e_v2 \ |
| 778 | - indirect_load_rank4_axis2_simt_e2e_v2 \ | 778 | + indirect_load_rank3_axis1_simt_e2e_v2 \ |
| 779 | - indirect_load_rank4_axis2_simd_e2e_v2 \ | 779 | + indirect_load_rank3_axis1_simd_e2e_v2 \ |
| 780 | - load_where_x2_x3_is_ubscalar_store_test_e2e_v2 \ | 780 | + indirect_load_rank4_axis2_simt_e2e_v2 \ |
| 781 | + indirect_load_rank4_axis2_simd_e2e_v2 \ | ||
| 782 | + indirect_load_rank2_axis1_relu_exp2_pre_simd_e2e_v2 \ | ||
| 783 | + indirect_load_rank2_axis0_relu_pre_expanded_simd_e2e_v2 \ | ||
| 784 | + indirect_load_rank2_axis0_relu_relu_pre_expanded_simd_e2e_v2 \ | ||
| 785 | + indirect_load_rank3_axis2_exp2_pre_expanded_simd_e2e_v2 \ | ||
| 786 | + indirect_load_rank4_axis1_relu_exp2_pre_expanded_simd_e2e_v2 \ | ||
| 787 | + indirect_load_rank3_axis2_mixed_vf_pre_expanded_simd_e2e_v2 \ | ||
| 788 | + indirect_load_rank2_axis1_large_simt_e2e_v2 \ | ||
| 789 | + indirect_load_rank2_axis1_float_int64_simd_e2e_v2 \ | ||
| 790 | + indirect_load_rank2_axis1_modified_bessel_k0_simd_only_e2e_v2 \ | ||
| 791 | + indirect_load_rank2_axis1_precision_cast_simt_e2e_v2 \ | ||
| 792 | + indirect_load_rank2_axis1_precision_cast_simd_e2e_v2 \ | ||
| 793 | + indirect_load_rank2_axis1_bf16_int64_simt_e2e_v2 \ | ||
| 794 | + indirect_load_rank2_axis1_uint32_int32_simd_e2e_v2 \ | ||
| 795 | + load_where_x2_x3_is_ubscalar_store_test_e2e_v2 \ | ||
| 781 | gather_reduce_store_test_e2e_v2 \ | 796 | gather_reduce_store_test_e2e_v2 \ |
| 782 | load_where_store_test_e2e_v2 \ | 797 | load_where_store_test_e2e_v2 \ |
| 783 | load_where_x2_is_ubscalar_store_test_e2e_v2 \ | 798 | load_where_x2_is_ubscalar_store_test_e2e_v2 \ |