已合并
feat: reuse cv tiling wrapper compilation & support dtype-aware cv fusion #1700
feat: reuse cv tiling wrapper compilation & support dtype-aware cv fusion #1700
已合并
xuyafei创建于 15 天前
62 个文件变更+4289-2082
Mautofuse/codegen/api_call/elewise/compare_api_call.cpp+18-20
@@ -10,21 +10,12 @@
10#include "compare_api_call.h"10#include "compare_api_call.h"
11 11 
12#include <sstream>12#include <sstream>
13-#include "attr_utils.h"
14-#include "ascir_ops.h"
15-#include "common_utils.h"
16-#include "common/ge_common/debug/log.h"
17-#include "graph/ascendc_ir/utils/asc_tensor_utils.h"
18#include "common/checker.h"13#include "common/checker.h"
19#include "api_call/utils/api_call_factory.h"14#include "api_call/utils/api_call_factory.h"
20#include "api_call/utils/api_call_utils.h"15#include "api_call/utils/api_call_utils.h"
21-#include "codegen/expression_convert_struct.h"
22 16 
23namespace codegen {17namespace codegen {
24using namespace std;18using namespace std;
25-using namespace af::ops;
26-using namespace af::ascir_op;
27-using namespace ascgen_utils;
28 19 
29static void CreateComputeNodeOuterForIfRequired(size_t outer_repeats_size, ApiLoopParams param,20static void CreateComputeNodeOuterForIfRequired(size_t outer_repeats_size, ApiLoopParams param,
30 const std::stringstream &ss1, std::stringstream &ss) {21 const std::stringstream &ss1, std::stringstream &ss) {
@@ -69,19 +60,20 @@ Status CompareApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axi
69 }60 }
70 61 
71 if (x2.IsAnyScalar()) {62 if (x2.IsAnyScalar()) {
63+ const std::string actual_size =
64+ IsCVFusionStage(this->api_call_context) ? GenBlockAlignNExpr(x1, x1.actual_size.Str()) : x1.actual_size.Str();
72 ub_inputs.push_back(x1);65 ub_inputs.push_back(x1);
73 ub_outputs.push_back(y);66 ub_outputs.push_back(y);
74 bool status = GenerateVectorizedAxisMergeStatus(ub_inputs, ub_outputs, merge_info, tpipe);67 bool status = GenerateVectorizedAxisMergeStatus(ub_inputs, ub_outputs, merge_info, tpipe);
75 GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed");68 GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed");
76 SaveApiLoopAxisParams(merge_info, param);69 SaveApiLoopAxisParams(merge_info, param);
77 std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name;70 std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name;
78- scalar_local_blk_tensor_name_x2 = scalar_local_blk_tensor_name_x2;
79 size_t outer_repeats_size = param.outer_repeats.size();71 size_t outer_repeats_size = param.outer_repeats.size();
80 if (outer_repeats_size == 0U) {72 if (outer_repeats_size == 0U) {
81 ss << "CompareScalarExtend" << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], "73 ss << "CompareScalarExtend" << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], "
82 << x1 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", "74 << x1 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", "
83- << "CMPMODE::" << this->api_name_ << ", " << x1.actual_size << ", " << tpipe.tmp_buf << "_"75+ << "CMPMODE::" << this->api_name_ << ", " << actual_size << ", " << tpipe.tmp_buf << "_" << std::to_string(id)
84- << std::to_string(id) << ");" << std::endl;76+ << ");" << std::endl;
85 } else {77 } else {
86 std::stringstream ss1;78 std::stringstream ss1;
87 size_t input0_strides_size = param.inputs_strides[0].size();79 size_t input0_strides_size = param.inputs_strides[0].size();
@@ -98,12 +90,16 @@ Status CompareApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axi
98 ss1 << "CompareExtend<" << dtype_name << ", CMPMODE::" << this->api_name_ << ">(" << y << "["90 ss1 << "CompareExtend<" << dtype_name << ", CMPMODE::" << this->api_name_ << ">(" << y << "["
99 << output_inner_offset << "], " << x1 << "[" << input0_inner_offset << "], "91 << output_inner_offset << "], " << x1 << "[" << input0_inner_offset << "], "
100 << scalar_local_blk_tensor_name_x2 << "[0], " << param.outer_repeats[outer_repeats_size - 1] << ", "92 << scalar_local_blk_tensor_name_x2 << "[0], " << param.outer_repeats[outer_repeats_size - 1] << ", "
101- << tpipe.tiler.ActualSize(param.cal_count) << ", " << tpipe.tiler.Size(param.input_second_to_last_stride)93+ << (IsCVFusionStage(this->api_call_context) ? GenBlockAlignNExpr(x1, tpipe.tiler.ActualSize(param.cal_count))
102- << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_"94+ : tpipe.tiler.ActualSize(param.cal_count))
103- << std::to_string(id) << ");" << std::endl;95+ << ", " << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "
96+ << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" << std::to_string(id)
97+ << ");" << std::endl;
104 CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss);98 CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss);
105 }99 }
106 } else {100 } else {
101+ const std::string actual_size =
102+ IsCVFusionStage(this->api_call_context) ? GenBlockAlignNExpr(x1, x1.actual_size.Str()) : x1.actual_size.Str();
107 ub_inputs.push_back(x1);103 ub_inputs.push_back(x1);
108 ub_inputs.push_back(x2);104 ub_inputs.push_back(x2);
109 ub_outputs.push_back(y);105 ub_outputs.push_back(y);
@@ -115,8 +111,8 @@ Status CompareApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axi
115 ss << "CompareExtend" << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1111 ss << "CompareExtend" << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1
116 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["112 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["
117 << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], "113 << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], "
118- << "CMPMODE::" << this->api_name_ << ", " << x1.actual_size << ", " << tpipe.tmp_buf << "_"114+ << "CMPMODE::" << this->api_name_ << ", " << actual_size << ", " << tpipe.tmp_buf << "_" << std::to_string(id)
119- << std::to_string(id) << ");" << std::endl;115+ << ");" << std::endl;
120 } else {116 } else {
121 size_t input0_strides_size = param.inputs_strides[0].size();117 size_t input0_strides_size = param.inputs_strides[0].size();
122 std::vector<ascir::SizeExpr> inner0_input_strides(param.inputs_strides[0].begin(),118 std::vector<ascir::SizeExpr> inner0_input_strides(param.inputs_strides[0].begin(),
@@ -138,9 +134,11 @@ Status CompareApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axi
138 ss1 << "CompareExtend<" << dtype_name << ", CMPMODE::" << this->api_name_ << ">(" << y << "["134 ss1 << "CompareExtend<" << dtype_name << ", CMPMODE::" << this->api_name_ << ">(" << y << "["
139 << output_inner_offset << "], " << x1 << "[" << input0_inner_offset << "], " << x2 << "["135 << output_inner_offset << "], " << x1 << "[" << input0_inner_offset << "], " << x2 << "["
140 << input1_inner_offset << "], " << param.outer_repeats[outer_repeats_size - 1] << ", "136 << input1_inner_offset << "], " << param.outer_repeats[outer_repeats_size - 1] << ", "
141- << tpipe.tiler.ActualSize(param.cal_count) << ", " << tpipe.tiler.Size(param.input_second_to_last_stride)137+ << (IsCVFusionStage(this->api_call_context) ? GenBlockAlignNExpr(x1, tpipe.tiler.ActualSize(param.cal_count))
142- << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_"138+ : tpipe.tiler.ActualSize(param.cal_count))
143- << std::to_string(id) << ");" << std::endl;139+ << ", " << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "
140+ << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" << std::to_string(id)
141+ << ");" << std::endl;
144 CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss);142 CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss);
145 }143 }
146 }144 }
Mautofuse/codegen/api_call/elewise/logical_not_api_call.cpp+3-1
@@ -17,6 +17,7 @@
17#include "graph/ascendc_ir/utils//asc_tensor_utils.h"17#include "graph/ascendc_ir/utils//asc_tensor_utils.h"
18#include "common/checker.h"18#include "common/checker.h"
19#include "api_call/utils/api_call_factory.h"19#include "api_call/utils/api_call_factory.h"
20+#include "api_call/utils/api_call_utils.h"
20#include "codegen/expression_convert_struct.h"21#include "codegen/expression_convert_struct.h"
21 22 
22namespace codegen {23namespace codegen {
@@ -44,7 +45,8 @@ Status LogicalNotApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::
44 stringstream ss;45 stringstream ss;
45 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["46 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["
46 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], local_blk_tensor_of_half_1, " << tpipe.tmp_buf << "_"47 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], local_blk_tensor_of_half_1, " << tpipe.tmp_buf << "_"
47- << std::to_string(id) << ", " << x.actual_size << ");" << std::endl;48+ << std::to_string(id) << ", " << GetCVAlignedSize(this->api_call_context, y, x.actual_size.Str()) << ");"
49+ << std::endl;
48 result = ss.str();50 result = ss.str();
49 return af::SUCCESS;51 return af::SUCCESS;
50}52}
Mautofuse/codegen/api_call/elewise/unary_api_tmp_call.cpp+2-9
@@ -10,20 +10,13 @@
10#include "unary_api_tmp_call.h"10#include "unary_api_tmp_call.h"
11 11 
12#include <sstream>12#include <sstream>
13-#include "attr_utils.h"
14-#include "ascir_ops.h"
15-#include "common_utils.h"
16-#include "common/ge_common/debug/log.h"
17-#include "graph/ascendc_ir/utils/asc_tensor_utils.h"
18#include "common/checker.h"13#include "common/checker.h"
19#include "api_call/utils/api_call_factory.h"14#include "api_call/utils/api_call_factory.h"
15+#include "api_call/utils/api_call_utils.h"
20#include "codegen/expression_convert_struct.h"16#include "codegen/expression_convert_struct.h"
21 17 
22namespace codegen {18namespace codegen {
23using namespace std;19using namespace std;
24-using namespace af::ops;
25-using namespace af::ascir_op;
26-using namespace ascgen_utils;
27 20 
28Status UnaryApiTmpCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> &current_axis,21Status UnaryApiTmpCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> &current_axis,
29 const std::vector<std::reference_wrapper<const Tensor>> &inputs,22 const std::vector<std::reference_wrapper<const Tensor>> &inputs,
@@ -45,7 +38,7 @@ Status UnaryApiTmpCall::Generate(const TPipe &tpipe, const std::vector<ascir::Ax
45 stringstream ss;38 stringstream ss;
46 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["39 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["
47 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << tpipe.tmp_buf << "_" << std::to_string(id)40 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << tpipe.tmp_buf << "_" << std::to_string(id)
48- << ", " << x.actual_size << ");" << std::endl;41+ << ", " << GetCVAlignedSize(this->api_call_context, y, x.actual_size.Str()) << ");" << std::endl;
49 result = ss.str();42 result = ss.str();
50 return af::SUCCESS;43 return af::SUCCESS;
51}44}
Mautofuse/codegen/api_call/elewise/unary_bitwidth_change_api_call.cpp+3-11
@@ -10,11 +10,6 @@
10#include "unary_bitwidth_change_api_call.h"10#include "unary_bitwidth_change_api_call.h"
11 11 
12#include <sstream>12#include <sstream>
13-#include "attr_utils.h"
14-#include "ascir_ops.h"
15-#include "common_utils.h"
16-#include "common/ge_common/debug/log.h"
17-#include "graph/ascendc_ir/utils/asc_tensor_utils.h"
18#include "common/checker.h"13#include "common/checker.h"
19#include "api_call/utils/api_call_factory.h"14#include "api_call/utils/api_call_factory.h"
20#include "api_call/utils/api_call_utils.h"15#include "api_call/utils/api_call_utils.h"
@@ -22,9 +17,6 @@
22 17 
23namespace codegen {18namespace codegen {
24using namespace std;19using namespace std;
25-using namespace af::ops;
26-using namespace af::ascir_op;
27-using namespace ascgen_utils;
28 20 
29Status UnaryBitWidthChangeApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> &current_axis,21Status UnaryBitWidthChangeApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> &current_axis,
30 const std::vector<std::reference_wrapper<const Tensor>> &inputs,22 const std::vector<std::reference_wrapper<const Tensor>> &inputs,
@@ -57,7 +49,7 @@ Status UnaryBitWidthChangeApiCall::Generate(const TPipe &tpipe, const std::vecto
57 tpipe.tmp_buf.name + "_" + std::to_string(id));49 tpipe.tmp_buf.name + "_" + std::to_string(id));
58 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["50 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["
59 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << tpipe.tmp_buf << "_" << std::to_string(id)51 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << tpipe.tmp_buf << "_" << std::to_string(id)
60- << ", " << x.actual_size << ");" << std::endl;52+ << ", " << GetCVAlignedSize(this->api_call_context, x, x.actual_size.Str()) << ");" << std::endl;
61 } else {53 } else {
62 (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs,54 (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs,
63 CombinedExprFactory::SymbolVar(tpipe.tiler.ActualSize(param.cal_count)),55 CombinedExprFactory::SymbolVar(tpipe.tiler.ActualSize(param.cal_count)),
@@ -66,8 +58,8 @@ Status UnaryBitWidthChangeApiCall::Generate(const TPipe &tpipe, const std::vecto
66 std::string output_inner_offset = CalcInnerOffset(tpipe, param.outputs_strides[0]);58 std::string output_inner_offset = CalcInnerOffset(tpipe, param.outputs_strides[0]);
67 std::stringstream ss1;59 std::stringstream ss1;
68 ss1 << this->api_name_ << "(" << y << "[" << output_inner_offset << "], " << x << "[" << input_inner_offset << "], "60 ss1 << this->api_name_ << "(" << y << "[" << output_inner_offset << "], " << x << "[" << input_inner_offset << "], "
69- << tpipe.tmp_buf << "_" << std::to_string(id) << ", " << tpipe.tiler.ActualSize(param.cal_count) << ");"61+ << tpipe.tmp_buf << "_" << std::to_string(id) << ", "
70- << std::endl;62+ << GetCVAlignedSize(this->api_call_context, x, tpipe.tiler.ActualSize(param.cal_count)) << ");" << std::endl;
71 CreateComputeNodeOuterFor(param.outer_repeats, ss1, ss, 0);63 CreateComputeNodeOuterFor(param.outer_repeats, ss1, ss, 0);
72 }64 }
73 65 
Mautofuse/codegen/api_call/elewise/where_api_call.cpp+30-19
@@ -10,20 +10,14 @@
10#include "where_api_call.h"10#include "where_api_call.h"
11 11 
12#include <sstream>12#include <sstream>
13-#include "attr_utils.h"
14-#include "ascir_ops.h"
15#include "common_utils.h"13#include "common_utils.h"
16#include "common/ge_common/debug/log.h"14#include "common/ge_common/debug/log.h"
17-#include "graph/ascendc_ir/utils//asc_tensor_utils.h"
18#include "common/checker.h"15#include "common/checker.h"
19#include "api_call/utils/api_call_factory.h"16#include "api_call/utils/api_call_factory.h"
20#include "api_call/utils/api_call_utils.h"17#include "api_call/utils/api_call_utils.h"
21-#include "codegen/expression_convert_struct.h"
22 18 
23namespace codegen {19namespace codegen {
24using namespace std;20using namespace std;
25-using namespace af::ops;
26-using namespace af::ascir_op;
27using namespace ascgen_utils;21using namespace ascgen_utils;
28 22 
29Status WhereApiCall::PrepareInputsAndOutputs(const std::vector<std::reference_wrapper<const Tensor>> &inputs,23Status WhereApiCall::PrepareInputsAndOutputs(const std::vector<std::reference_wrapper<const Tensor>> &inputs,
@@ -97,7 +91,8 @@ Status WhereApiCall::GenerateNoLoopCase(const TPipe &tpipe, const std::vector<as
97 ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], ";91 ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], ";
98 }92 }
99 93 
100- ss << x1.actual_size << ", " << tpipe.tmp_buf << "_" << std::to_string(id) << ");" << std::endl;94+ ss << GetCVAlignedSize(this->api_call_context, y, x1.actual_size.Str()) << ", " << tpipe.tmp_buf << "_"
95+ << std::to_string(id) << ");" << std::endl;
101 96 
102 return af::SUCCESS;97 return af::SUCCESS;
103}98}
@@ -107,6 +102,9 @@ Status WhereApiCall::GenerateBothScalarCase(const TPipe &tpipe, const ApiLoopPar
107 const std::string &scalar_local_blk_tensor_name_x3, const int64_t id,102 const std::string &scalar_local_blk_tensor_name_x3, const int64_t id,
108 std::stringstream &ss) const {103 std::stringstream &ss) const {
109 stringstream ss1;104 stringstream ss1;
105+ std::string dtype_name;
106+ GE_CHK_STATUS_RET(Tensor::DtypeName(y.dtype, dtype_name), "Codegen get data type:%d failed",
107+ static_cast<int32_t>(y.dtype));
110 108 
111 size_t output_strides_size = param.outputs_strides[0].size();109 size_t output_strides_size = param.outputs_strides[0].size();
112 std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(),110 std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(),
@@ -122,11 +120,12 @@ Status WhereApiCall::GenerateBothScalarCase(const TPipe &tpipe, const ApiLoopPar
122 ss1 << this->api_name_ << "<true, true>(" << y << "[" << output_inner_offset << "], " << x1 << "["120 ss1 << this->api_name_ << "<true, true>(" << y << "[" << output_inner_offset << "], " << x1 << "["
123 << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << scalar_local_blk_tensor_name_x3121 << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << scalar_local_blk_tensor_name_x3
124 << "[0], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", "122 << "[0], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", "
125- << tpipe.tiler.ActualSize(param.cal_count) << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "123+ << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ", "
124+ << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "
126 << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "125 << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "
127- << "ONE_BLK_SIZE / sizeof(float), "126+ << "ONE_BLK_SIZE / sizeof(" << dtype_name << "), "
128- << "ONE_BLK_SIZE / sizeof(float), " << tpipe.tmp_buf << "_" << std::to_string(id) << ", ONE_BLK_SIZE * 2);"127+ << "ONE_BLK_SIZE / sizeof(" << dtype_name << "), " << tpipe.tmp_buf << "_" << std::to_string(id)
129- << std::endl;128+ << ", ONE_BLK_SIZE * 2);" << std::endl;
130 129 
131 if (param.outer_repeats.size() == 1) {130 if (param.outer_repeats.size() == 1) {
132 ss << ss1.str();131 ss << ss1.str();
@@ -142,6 +141,9 @@ Status WhereApiCall::GenerateX2ScalarCase(const TPipe &tpipe, const ApiLoopParam
142 const std::string &scalar_local_blk_tensor_name_x2, const int64_t id,141 const std::string &scalar_local_blk_tensor_name_x2, const int64_t id,
143 std::stringstream &ss) const {142 std::stringstream &ss) const {
144 stringstream ss1;143 stringstream ss1;
144+ std::string dtype_name;
145+ GE_CHK_STATUS_RET(Tensor::DtypeName(y.dtype, dtype_name), "Codegen get data type:%d failed",
146+ static_cast<int32_t>(y.dtype));
145 147 
146 size_t output_strides_size = param.outputs_strides[0].size();148 size_t output_strides_size = param.outputs_strides[0].size();
147 std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(),149 std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(),
@@ -162,10 +164,11 @@ Status WhereApiCall::GenerateX2ScalarCase(const TPipe &tpipe, const ApiLoopParam
162 164 
163 ss1 << this->api_name_ << "<true, false>(" << y << "[" << output_inner_offset << "], " << x1 << "["165 ss1 << this->api_name_ << "<true, false>(" << y << "[" << output_inner_offset << "], " << x1 << "["
164 << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << x3 << "[" << input2_inner_offset166 << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << x3 << "[" << input2_inner_offset
165- << "], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " << tpipe.tiler.ActualSize(param.cal_count)167+ << "], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", "
166- << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "168+ << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ", "
169+ << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "
167 << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "170 << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "
168- << "ONE_BLK_SIZE / sizeof(float), " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "171+ << "ONE_BLK_SIZE / sizeof(" << dtype_name << "), " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "
169 << tpipe.tmp_buf << "_" << std::to_string(id) << ", ONE_BLK_SIZE);" << std::endl;172 << tpipe.tmp_buf << "_" << std::to_string(id) << ", ONE_BLK_SIZE);" << std::endl;
170 173 
171 if (param.outer_repeats.size() == 1) {174 if (param.outer_repeats.size() == 1) {
@@ -182,6 +185,9 @@ Status WhereApiCall::GenerateX3ScalarCase(const TPipe &tpipe, const ApiLoopParam
182 const std::string &scalar_local_blk_tensor_name_x3, const int64_t id,185 const std::string &scalar_local_blk_tensor_name_x3, const int64_t id,
183 std::stringstream &ss) const {186 std::stringstream &ss) const {
184 stringstream ss1;187 stringstream ss1;
188+ std::string dtype_name;
189+ GE_CHK_STATUS_RET(Tensor::DtypeName(y.dtype, dtype_name), "Codegen get data type:%d failed",
190+ static_cast<int32_t>(y.dtype));
185 191 
186 size_t output_strides_size = param.outputs_strides[0].size();192 size_t output_strides_size = param.outputs_strides[0].size();
187 std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(),193 std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(),
@@ -203,11 +209,12 @@ Status WhereApiCall::GenerateX3ScalarCase(const TPipe &tpipe, const ApiLoopParam
203 ss1 << this->api_name_ << "<false, true>(" << y << "[" << output_inner_offset << "], " << x1 << "["209 ss1 << this->api_name_ << "<false, true>(" << y << "[" << output_inner_offset << "], " << x1 << "["
204 << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << scalar_local_blk_tensor_name_x3210 << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << scalar_local_blk_tensor_name_x3
205 << "[0], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", "211 << "[0], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", "
206- << tpipe.tiler.ActualSize(param.cal_count) << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "212+ << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ", "
213+ << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "
207 << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "214 << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "
208 << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "215 << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "
209- << "ONE_BLK_SIZE / sizeof(float), " << tpipe.tmp_buf << "_" << std::to_string(id) << ", ONE_BLK_SIZE);"216+ << "ONE_BLK_SIZE / sizeof(" << dtype_name << "), " << tpipe.tmp_buf << "_" << std::to_string(id)
210- << std::endl;217+ << ", ONE_BLK_SIZE);" << std::endl;
211 218 
212 if (param.outer_repeats.size() == 1) {219 if (param.outer_repeats.size() == 1) {
213 ss << ss1.str();220 ss << ss1.str();
@@ -222,6 +229,9 @@ Status WhereApiCall::GenerateNormalCase(const TPipe &tpipe, const ApiLoopParams
222 const Tensor &x2, const Tensor &x3, const Tensor &y, const int64_t id,229 const Tensor &x2, const Tensor &x3, const Tensor &y, const int64_t id,
223 std::stringstream &ss) const {230 std::stringstream &ss) const {
224 stringstream ss1;231 stringstream ss1;
232+ std::string dtype_name;
233+ GE_CHK_STATUS_RET(Tensor::DtypeName(y.dtype, dtype_name), "Codegen get data type:%d failed",
234+ static_cast<int32_t>(y.dtype));
225 235 
226 size_t output_strides_size = param.outputs_strides[0].size();236 size_t output_strides_size = param.outputs_strides[0].size();
227 std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(),237 std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(),
@@ -248,8 +258,9 @@ Status WhereApiCall::GenerateNormalCase(const TPipe &tpipe, const ApiLoopParams
248 258 
249 ss1 << this->api_name_ << "<false, false>(" << y << "[" << output_inner_offset << "], " << x1 << "["259 ss1 << this->api_name_ << "<false, false>(" << y << "[" << output_inner_offset << "], " << x1 << "["
250 << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << x3 << "[" << input2_inner_offset260 << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << x3 << "[" << input2_inner_offset
251- << "], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " << tpipe.tiler.ActualSize(param.cal_count)261+ << "], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", "
252- << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "262+ << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ", "
263+ << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "
253 << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "264 << tpipe.tiler.Size(param.input_second_to_last_stride) << ", "
254 << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "265 << tpipe.tiler.Size(param.output_second_to_last_stride) << ", "
255 << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" << std::to_string(id)266 << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" << std::to_string(id)
Mautofuse/codegen/api_call/utils/api_call_utils.cpp+27-0
@@ -574,6 +574,33 @@ bool GetMaxDtypeSize(const ge::DataType input_data_type, const ge::DataType out_
574 return true;574 return true;
575}575}
576 576 
577+bool IsCVFusionStage(const ApiCallContext &context) {
578+ return context.stage != ComputeStage::kDefault;
579+}
580+ 
581+Status GetTensorDtypeSize(const Tensor &tensor, int64_t &dtype_size) {
582+ const int32_t tensor_dtype_size = GetSizeByDataType(tensor.dtype);
583+ GE_CHK_BOOL_RET_STATUS(tensor_dtype_size > 0 && tensor_dtype_size < ge::kDataTypeSizeBitOffset, af::FAILED,
584+ "get dtype size failed, tensor:%s, dtype:%d", tensor.name.c_str(),
585+ static_cast<int32_t>(tensor.dtype));
586+ dtype_size = tensor_dtype_size;
587+ return af::SUCCESS;
588+}
589+ 
590+std::string GenBlockAlignNExpr(const Tensor &tensor, const std::string &n_expr) {
591+ int64_t dtype_size = 0;
592+ if (GetTensorDtypeSize(tensor, dtype_size) != af::SUCCESS || dtype_size <= 0) {
593+ return n_expr;
594+ }
595+ const int64_t align_value = 32 / dtype_size;
596+ return "((" + n_expr + " + " + std::to_string(align_value) + " - 1) / " + std::to_string(align_value) + " * " +
597+ std::to_string(align_value) + ")";
598+}
599+ 
600+std::string GetCVAlignedSize(const ApiCallContext &context, const Tensor &tensor, const std::string &size_expr) {
601+ return IsCVFusionStage(context) ? GenBlockAlignNExpr(tensor, size_expr) : size_expr;
602+}
603+ 
577void GenerateLinkStoreEventCode(const Tensor &ub, const std::string &offset_str, std::stringstream &ss) {604void GenerateLinkStoreEventCode(const Tensor &ub, const std::string &offset_str, std::stringstream &ss) {
578 std::hash<std::string> hasher;605 std::hash<std::string> hasher;
579 [[maybe_unused]] size_t hasher_value = hasher(offset_str);606 [[maybe_unused]] size_t hasher_value = hasher(offset_str);
Mautofuse/codegen/api_call/utils/api_call_utils.h+4-0
@@ -122,6 +122,10 @@ bool CheckAxisContinuous(const std::vector<Tensor> &inputs, const std::vector<Te
122 VectorizedAixsLoopStatus &axis_info, int64_t index);122 VectorizedAixsLoopStatus &axis_info, int64_t index);
123void SaveApiLoopAxisParams(VectorizedAxisLoopMergeStatus &merge_info, ApiLoopParams &param);123void SaveApiLoopAxisParams(VectorizedAxisLoopMergeStatus &merge_info, ApiLoopParams &param);
124bool GetMaxDtypeSize(const ge::DataType input_data_type, const ge::DataType out_put_data_type, std::string &dtype_size);124bool GetMaxDtypeSize(const ge::DataType input_data_type, const ge::DataType out_put_data_type, std::string &dtype_size);
125+bool IsCVFusionStage(const ApiCallContext &context);
126+Status GetTensorDtypeSize(const Tensor &tensor, int64_t &dtype_size);
127+std::string GenBlockAlignNExpr(const Tensor &tensor, const std::string &n_expr);
128+std::string GetCVAlignedSize(const ApiCallContext &context, const Tensor &tensor, const std::string &size_expr);
125bool ShouldIgnoreZeroAxis(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, int64_t cur_index);129bool ShouldIgnoreZeroAxis(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, int64_t cur_index);
126bool IsInputOutputStrideAllZero(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs,130bool IsInputOutputStrideAllZero(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs,
127 int64_t cur_index);131 int64_t cur_index);
Mautofuse/codegen/codegen_kernel.cpp+5-1
@@ -1656,7 +1656,11 @@ Status TPipe::LocalTQueAlloc(std::string &result) const {
1656 std::string dtype_name;1656 std::string dtype_name;
1657 GE_CHK_STATUS_RET(Tensor::DtypeName(tensor->second.dtype, dtype_name), "Codegen get data type:%d failed",1657 GE_CHK_STATUS_RET(Tensor::DtypeName(tensor->second.dtype, dtype_name), "Codegen get data type:%d failed",
1658 static_cast<int32_t>(tensor->second.dtype));1658 static_cast<int32_t>(tensor->second.dtype));
1659- tensor_size_max << tensor->second.size << " * sizeof(" << dtype_name << ")";1659+ std::string tensor_byte_size = tensor->second.size.Str() + " * sizeof(" + dtype_name + ")";
1660+ if (this->cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
1661+ tensor_byte_size = "KernelUtils::BlkAlign<uint8_t>(" + tensor_byte_size + ")";
1662+ }
1663+ tensor_size_max << tensor_byte_size;
1660 }1664 }
1661 }1665 }
1662 1666 
Mautofuse/codegen/codegen_kernel_loop.cpp+14-6
@@ -115,6 +115,14 @@ Status AddSkippedApiEmitProcessCall(const ascir::NodeView &node, Loop *current_l
115 }115 }
116 return af::SUCCESS;116 return af::SUCCESS;
117}117}
118+std::string GetQueueSliceByteSize(const TPipe &tpipe, const Tensor &tensor) {
119+ auto size = af::GetSizeByDataType(tensor.dtype);
120+ std::string byte_size = tensor.size.name + " * " + std::to_string(size);
121+ if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
122+ byte_size = "KernelUtils::BlkAlign<uint8_t>(" + byte_size + ")";
123+ }
124+ return byte_size;
125+}
118 126 
119Status MoveToNodeLoop(const ascir::NodeView &node, std::vector<ascir::AxisId> &current_axis, Loop *&current_loop) {127Status MoveToNodeLoop(const ascir::NodeView &node, std::vector<ascir::AxisId> &current_axis, Loop *&current_loop) {
120 if (node->attr.api.unit == af::ComputeUnit::kUnitNone) {128 if (node->attr.api.unit == af::ComputeUnit::kUnitNone) {
@@ -613,7 +621,7 @@ Status Loop::GenerateBody(const Tiler &tiler, const TPipe &tpipe, std::vector<as
613 std::string call;621 std::string call;
614 std::string cache_guard;622 std::string cache_guard;
615 623 
616- if (this->axis_id != af::kIdNone) {624+ if (this->axis_id != af::kIdNone && this->compute_stage == ComputeStage::kDefault) {
617 auto axis = tiler.GetAxis(this->axis_id);625 auto axis = tiler.GetAxis(this->axis_id);
618 const bool is_enable_cache = axis.is_split_b && body.call->enable_cache;626 const bool is_enable_cache = axis.is_split_b && body.call->enable_cache;
619 const bool is_double_tile = IsReduceDoubleTile(tiler, tpipe, this->is_graph_has_reduce_node) &&627 const bool is_double_tile = IsReduceDoubleTile(tiler, tpipe, this->is_graph_has_reduce_node) &&
@@ -779,7 +787,9 @@ Status Loop::GenerateLoop(const Tiler &tiler, const TPipe &tpipe, std::vector<as
779 if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) {787 if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) {
780 ss << tiler.CalcFromAxis(axis.id);788 ss << tiler.CalcFromAxis(axis.id);
781 }789 }
782- GenerateEnCacheCondition(tiler, tpipe, axis, ss);790+ if (this->compute_stage == ComputeStage::kDefault) {
791+ GenerateEnCacheCondition(tiler, tpipe, axis, ss);
792+ }
783 if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) {793 if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) {
784 std::set<ascir::AxisId> vectorized_axis;794 std::set<ascir::AxisId> vectorized_axis;
785 for (const auto &tensor : tpipe.tensors) {795 for (const auto &tensor : tpipe.tensors) {
@@ -1242,8 +1252,7 @@ af::Status DefineShareOffsets(const TPipe &tpipe, const ApiTensor &out, const Te
1242 }1252 }
1243 auto prev_tensor = tpipe.GetTensor(order_to_tensor[i - 1]->id);1253 auto prev_tensor = tpipe.GetTensor(order_to_tensor[i - 1]->id);
1244 GE_ASSERT_NOTNULL(prev_tensor, "Check[Param] tensor_ptr is nullptr");1254 GE_ASSERT_NOTNULL(prev_tensor, "Check[Param] tensor_ptr is nullptr");
1245- auto size = af::GetSizeByDataType(prev_tensor->dtype);1255+ auto var_size = prev_var_name + " + " + GetQueueSliceByteSize(tpipe, *prev_tensor);
1246- auto var_size = prev_var_name + " + " + prev_tensor->size.name + " * " + std::to_string(size);
1247 const auto &cur_var_name = t.que_share_offset.name + "_part_" + std::to_string(i);1256 const auto &cur_var_name = t.que_share_offset.name + "_part_" + std::to_string(i);
1248 decltype(t.que_share_offset) offset_var(cur_var_name);1257 decltype(t.que_share_offset) offset_var(cur_var_name);
1249 ss << offset_var.DefineConst(std::move(var_size)) << std::endl;1258 ss << offset_var.DefineConst(std::move(var_size)) << std::endl;
@@ -1276,8 +1285,7 @@ BoolType ApiCall::AllocShareOutputs(const TPipe &tpipe, const ApiTensor &out, co
1276 auto tensor_ptr = tpipe.GetTensor(out.share_prev->id);1285 auto tensor_ptr = tpipe.GetTensor(out.share_prev->id);
1277 GE_CHK_BOOL_RET_SPECIAL_STATUS(tensor_ptr == nullptr, BoolType::FAILED, "Check[Param] tensor_ptr is nullptr");1286 GE_CHK_BOOL_RET_SPECIAL_STATUS(tensor_ptr == nullptr, BoolType::FAILED, "Check[Param] tensor_ptr is nullptr");
1278 auto prev_tensor = *tensor_ptr;1287 auto prev_tensor = *tensor_ptr;
1279- auto size = af::GetSizeByDataType(prev_tensor.dtype);1288+ relative_offset = t.que_share_offset.name + " + " + GetQueueSliceByteSize(tpipe, prev_tensor);
1280- relative_offset = t.que_share_offset.name + " + " + prev_tensor.size.name + " * " + std::to_string(size);
1281 ss << t.que_share_offset.Assign(relative_offset);1289 ss << t.que_share_offset.Assign(relative_offset);
1282 ss << std::endl;1290 ss << std::endl;
1283 }1291 }
Mautofuse/codegen/codegen_tiling.cpp+113-83
@@ -100,7 +100,7 @@ void RequireEntrySystemHeaders(autofuse::SourceDependencies &dependencies, bool
100 bool is_multi_group) {100 bool is_multi_group) {
101 if (is_inductor && is_cv) {101 if (is_inductor && is_cv) {
102 RequireSystemHeaders(dependencies, {"algorithm", "cfloat", "cstddef", "cstdint", "cstring", "ostream", "sstream",102 RequireSystemHeaders(dependencies, {"algorithm", "cfloat", "cstddef", "cstdint", "cstring", "ostream", "sstream",
103- "string", "vector"});103+ "iomanip", "string", "vector"});
104 } else if (is_inductor) {104 } else if (is_inductor) {
105 RequireSystemHeaders(dependencies, {"algorithm", "cfloat", "cmath", "cstddef", "cstdint", "map", "ostream",105 RequireSystemHeaders(dependencies, {"algorithm", "cfloat", "cmath", "cstddef", "cstdint", "map", "ostream",
106 "sstream", "string", "unordered_map", "vector"});106 "sstream", "string", "unordered_map", "vector"});
@@ -1127,6 +1127,114 @@ std::string TilingLib::GenCubeFusionTilingBodyInductor(const ascir::FusedSchedul
1127 return ss.str();1127 return ss.str();
1128}1128}
1129 1129 
1130+void TilingLib::GenInductorShapeDim(const ascir::FusedScheduledResult &elemwise_schedule_result,
1131+ codegen::PgoShapeStringStream &pgo_shape_dim,
1132+ std::vector<std::string> &dynamic_shape_vars, const std::string &tiling_var) const {
1133+ for (auto vars : elemwise_schedule_result.origin_vars) {
1134+ if (!(vars.IsConstExpr())) {
1135+ std::string var_define = std::string(vars.Str().get());
1136+ dynamic_shape_vars.push_back(var_define);
1137+ pgo_shape_dim.shape_dim_def << "uint32_t " << var_define << ", ";
1138+ pgo_shape_dim.shape_dim_use << var_define << ", ";
1139+ TilingSetShapeDim(pgo_shape_dim.tiling_set_shape_dim, var_define, elemwise_schedule_result, tiling_var);
1140+ }
1141+ }
1142+}
1143+ 
1144+std::string TilingLib::GenCallCubeTilingForInductor(const ascir::FusedScheduledResult &fused_schedule_result,
1145+ const std::vector<std::string> &dynamic_shape_vars,
1146+ const codegen::PgoShapeStringStream &pgo_shape_dim) const {
1147+ std::stringstream ss;
1148+ MatMulCubeInfo cube_info;
1149+ GE_ASSERT_SUCCESS(ExtractMatMulCubeInfoFromFusedResult(fused_schedule_result, cube_info),
1150+ "[Extract][MatMulCubeInfo]Failed to extract MatMul cube info from FusedScheduledResult");
1151+ ss << "using namespace ge::autofuse;" << std::endl;
1152+ AppendCvBaseAlignHelperDefs(ss);
1153+ AppendCvSafetyMixModeHelperDefs(ss, cube_info.is_batch);
1154+ 
1155+ // 在CallCubeTiling函数之前定义全局变量(用于静态shape常量生成)
1156+ ss << "// Global variable to store tiling bytes for const generation in static shape\n";
1157+ ss << "std::vector<uint8_t> g_matmul_tiling_bytes;\n\n";
1158+ ss << "extern \"C\" void CallCubeTiling(" << pgo_shape_dim.shape_dim_def.str()
1159+ << "int64_t &ws_size, uint32_t &cube_block_dim, int64_t &tiling_key, uint32_t &basem, uint32_t "
1160+ "&basen, CVAutofuseTilingData *tiling_data) {"
1161+ << std::endl;
1162+ GenCallCubeTilingCacheRead(ss, dynamic_shape_vars);
1163+ ss << ProcessCubeKernelTilingFromFusedResult(fused_schedule_result) << std::endl;
1164+ GenCallCubeTilingCacheWrite(ss, dynamic_shape_vars);
1165+ ss << "}" << std::endl;
1166+ return ss.str();
1167+}
1168+ 
1169+void TilingLib::GenCallCubeTilingCacheRead(std::stringstream &ss,
1170+ const std::vector<std::string> &dynamic_shape_vars) const {
1171+ ss << "static bool g_cube_tiling_cache_valid = false;\n";
1172+ for (const auto &var_name : dynamic_shape_vars) {
1173+ ss << "static uint32_t g_cube_tiling_cache_" << var_name << " = 0;\n";
1174+ }
1175+ ss << "static int64_t g_cube_tiling_cache_ws_size = 0;\n";
1176+ ss << "static uint32_t g_cube_tiling_cache_block_dim = 0;\n";
1177+ ss << "static int64_t g_cube_tiling_cache_tiling_key = 0;\n";
1178+ ss << "static uint32_t g_cube_tiling_cache_basem = 0;\n";
1179+ ss << "static uint32_t g_cube_tiling_cache_basen = 0;\n";
1180+ ss << "static uint8_t g_cube_tiling_cache_bytes[sizeof(tiling_data->matmul_tiling_data)] = {};\n";
1181+ ss << "static size_t g_cube_tiling_cache_bytes_size = 0;\n";
1182+ ss << "if (g_cube_tiling_cache_valid";
1183+ for (const auto &var_name : dynamic_shape_vars) {
1184+ ss << " && g_cube_tiling_cache_" << var_name << " == " << var_name;
1185+ }
1186+ ss << ") {\n";
1187+ ss << " ws_size = g_cube_tiling_cache_ws_size;\n";
1188+ ss << " cube_block_dim = g_cube_tiling_cache_block_dim;\n";
1189+ ss << " tiling_key = g_cube_tiling_cache_tiling_key;\n";
1190+ ss << " basem = g_cube_tiling_cache_basem;\n";
1191+ ss << " basen = g_cube_tiling_cache_basen;\n";
1192+ ss << " std::memcpy(tiling_data->matmul_tiling_data, g_cube_tiling_cache_bytes, "
1193+ "g_cube_tiling_cache_bytes_size);\n";
1194+ ss << " return;\n";
1195+ ss << "}\n";
1196+}
1197+ 
1198+void TilingLib::GenCallCubeTilingCacheWrite(std::stringstream &ss,
1199+ const std::vector<std::string> &dynamic_shape_vars) const {
1200+ ss << "g_cube_tiling_cache_valid = true;\n";
1201+ for (const auto &var_name : dynamic_shape_vars) {
1202+ ss << "g_cube_tiling_cache_" << var_name << " = " << var_name << ";\n";
1203+ }
1204+ ss << "g_cube_tiling_cache_ws_size = ws_size;\n";
1205+ ss << "g_cube_tiling_cache_block_dim = cube_block_dim;\n";
1206+ ss << "g_cube_tiling_cache_tiling_key = tiling_key;\n";
1207+ ss << "g_cube_tiling_cache_basem = basem;\n";
1208+ ss << "g_cube_tiling_cache_basen = basen;\n";
1209+ ss << "std::memcpy(g_cube_tiling_cache_bytes, tiling_data->matmul_tiling_data, copy_size);\n";
1210+ ss << "g_cube_tiling_cache_bytes_size = copy_size;\n";
1211+}
1212+ 
1213+std::string TilingLib::GenPlainInductorTilingTail(const ascir::FusedScheduledResult &elemwise_schedule_result,
1214+ codegen::PgoShapeStringStream &pgo_shape_dim,
1215+ const std::string &tiling) const {
1216+ std::stringstream ss;
1217+ ss << " tiling->set_block_dim(limit->aiv_num);" << std::endl;
1218+ ss << " tiling->set_ub_size(limit->ub_size - 256);" << std::endl;
1219+ ss << " if (!optiling::GetTiling(*tiling, -1, nullptr)) {return -1;}" << std::endl;
1220+ ss << " *blockDim = tiling->get_block_dim();" << std::endl; // Only consider 48 for now
1221+ ss << " using namespace optiling;" << std::endl;
1222+ ss << " *workspaceSize = GetWorkspaceSize(*tiling);" << std::endl;
1223+ ss << std::endl;
1224+ ss << " return 0;" << std::endl;
1225+ ss << "}" << std::endl;
1226+ if (enable_autofuse_pgo_) {
1227+ // PGOGetTilingKey
1228+ ss << GenPGOGetTilingKey(tiling);
1229+ // AutofuseTilingWithConfig
1230+ ss << GenPgoTilingFunc(elemwise_schedule_result, tiling, pgo_shape_dim, true);
1231+ } else {
1232+ // 生成 AutofuseTilingWithConfig 函数
1233+ ss << GenPgoAutofuseTiling(elemwise_schedule_result, pgo_shape_dim, tiling, true);
1234+ }
1235+ return ss.str();
1236+}
1237+ 
1130std::string TilingLib::GenTilingFuncForInductor(const ascir::FusedScheduledResult &fused_schedule_result,1238std::string TilingLib::GenTilingFuncForInductor(const ascir::FusedScheduledResult &fused_schedule_result,
1131 const ::ascir::FusedScheduledResult &elemwise_schedule_result,1239 const ::ascir::FusedScheduledResult &elemwise_schedule_result,
1132 const std::string func, const std::string tiling) const {1240 const std::string func, const std::string tiling) const {
@@ -1137,72 +1245,11 @@ std::string TilingLib::GenTilingFuncForInductor(const ascir::FusedScheduledResul
1137 if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result)) {1245 if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result)) {
1138 tiling_var = "tiling->tiling_data.";1246 tiling_var = "tiling->tiling_data.";
1139 }1247 }
1140- for (auto vars : elemwise_schedule_result.origin_vars) {1248+ GenInductorShapeDim(elemwise_schedule_result, pgo_shape_dim, dynamic_shape_vars, tiling_var);
1141- if (!(vars.IsConstExpr())) {
1142- std::string var_define = std::string(vars.Str().get());
1143- dynamic_shape_vars.push_back(var_define);
1144- pgo_shape_dim.shape_dim_def << "uint32_t " << var_define << ", ";
1145- pgo_shape_dim.shape_dim_use << var_define << ", ";
1146- TilingSetShapeDim(pgo_shape_dim.tiling_set_shape_dim, var_define, elemwise_schedule_result, tiling_var);
1147- }
1148- }
1149 1249 
1150 ss << GenGetResLimitStru();1250 ss << GenGetResLimitStru();
1151 if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result)) {1251 if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result)) {
1152- MatMulCubeInfo cube_info;1252+ ss << GenCallCubeTilingForInductor(fused_schedule_result, dynamic_shape_vars, pgo_shape_dim);
1153- GE_ASSERT_SUCCESS(ExtractMatMulCubeInfoFromFusedResult(fused_schedule_result, cube_info),
1154- "[Extract][MatMulCubeInfo]Failed to extract MatMul cube info from FusedScheduledResult");
1155- std::stringstream call_cube_tiling;
1156- call_cube_tiling << "using namespace ge::autofuse;" << std::endl;
1157- AppendCvBaseAlignHelperDefs(call_cube_tiling);
1158- AppendCvSafetyMixModeHelperDefs(call_cube_tiling, cube_info.is_batch);
1159- 
1160- // 在CallCubeTiling函数之前定义全局变量(用于静态shape常量生成)
1161- call_cube_tiling << "// Global variable to store tiling bytes for const generation in static shape\n";
1162- call_cube_tiling << "std::vector<uint8_t> g_matmul_tiling_bytes;\n\n";
1163- 
1164- call_cube_tiling << "extern \"C\" void CallCubeTiling(" << pgo_shape_dim.shape_dim_def.str()
1165- << "int64_t &ws_size, uint32_t &cube_block_dim, int64_t &tiling_key, uint32_t &basem, uint32_t "
1166- "&basen, CVAutofuseTilingData *tiling_data) {"
1167- << std::endl;
1168- call_cube_tiling << "static bool g_cube_tiling_cache_valid = false;\n";
1169- for (const auto &var_name : dynamic_shape_vars) {
1170- call_cube_tiling << "static uint32_t g_cube_tiling_cache_" << var_name << " = 0;\n";
1171- }
1172- call_cube_tiling << "static int64_t g_cube_tiling_cache_ws_size = 0;\n";
1173- call_cube_tiling << "static uint32_t g_cube_tiling_cache_block_dim = 0;\n";
1174- call_cube_tiling << "static int64_t g_cube_tiling_cache_tiling_key = 0;\n";
1175- call_cube_tiling << "static uint32_t g_cube_tiling_cache_basem = 0;\n";
1176- call_cube_tiling << "static uint32_t g_cube_tiling_cache_basen = 0;\n";
1177- call_cube_tiling << "static uint8_t g_cube_tiling_cache_bytes[sizeof(tiling_data->matmul_tiling_data)] = {};\n";
1178- call_cube_tiling << "if (g_cube_tiling_cache_valid";
1179- for (const auto &var_name : dynamic_shape_vars) {
1180- call_cube_tiling << " && g_cube_tiling_cache_" << var_name << " == " << var_name;
1181- }
1182- call_cube_tiling << ") {\n";
1183- call_cube_tiling << " ws_size = g_cube_tiling_cache_ws_size;\n";
1184- call_cube_tiling << " cube_block_dim = g_cube_tiling_cache_block_dim;\n";
1185- call_cube_tiling << " tiling_key = g_cube_tiling_cache_tiling_key;\n";
1186- call_cube_tiling << " basem = g_cube_tiling_cache_basem;\n";
1187- call_cube_tiling << " basen = g_cube_tiling_cache_basen;\n";
1188- call_cube_tiling << " std::memcpy(tiling_data->matmul_tiling_data, g_cube_tiling_cache_bytes, "
1189- "sizeof(tiling_data->matmul_tiling_data));\n";
1190- call_cube_tiling << " return;\n";
1191- call_cube_tiling << "}\n";
1192- call_cube_tiling << ProcessCubeKernelTilingFromFusedResult(fused_schedule_result) << std::endl;
1193- call_cube_tiling << "g_cube_tiling_cache_valid = true;\n";
1194- for (const auto &var_name : dynamic_shape_vars) {
1195- call_cube_tiling << "g_cube_tiling_cache_" << var_name << " = " << var_name << ";\n";
1196- }
1197- call_cube_tiling << "g_cube_tiling_cache_ws_size = ws_size;\n";
1198- call_cube_tiling << "g_cube_tiling_cache_block_dim = cube_block_dim;\n";
1199- call_cube_tiling << "g_cube_tiling_cache_tiling_key = tiling_key;\n";
1200- call_cube_tiling << "g_cube_tiling_cache_basem = basem;\n";
1201- call_cube_tiling << "g_cube_tiling_cache_basen = basen;\n";
1202- call_cube_tiling << "std::memcpy(g_cube_tiling_cache_bytes, tiling_data->matmul_tiling_data, "
1203- "sizeof(tiling_data->matmul_tiling_data));\n";
1204- call_cube_tiling << "}" << std::endl;
1205- ss << call_cube_tiling.str();
1206 }1253 }
1207 1254 
1208 // AutofuseTiling1255 // AutofuseTiling
@@ -1226,25 +1273,7 @@ std::string TilingLib::GenTilingFuncForInductor(const ascir::FusedScheduledResul
1226 return ss.str() + GenCubeFusionTilingBodyInductor(fused_schedule_result, elemwise_schedule_result,1273 return ss.str() + GenCubeFusionTilingBodyInductor(fused_schedule_result, elemwise_schedule_result,
1227 pgo_shape_dim.shape_dim_use.str());1274 pgo_shape_dim.shape_dim_use.str());
1228 }1275 }
1229- ss << " tiling->set_block_dim(limit->aiv_num);" << std::endl;1276+ ss << GenPlainInductorTilingTail(elemwise_schedule_result, pgo_shape_dim, tiling);
1230- ss << " tiling->set_ub_size(limit->ub_size - 256);" << std::endl;
1231- ss << " if (!optiling::GetTiling(*tiling, -1, nullptr)) {return -1;}" << std::endl;
1232- ss << " *blockDim = tiling->get_block_dim();" << std::endl; // Only consider 48 for now
1233- ss << " using namespace optiling;" << std::endl;
1234- ss << " *workspaceSize = GetWorkspaceSize(*tiling);" << std::endl;
1235- ss << std::endl;
1236- 
1237- ss << " return 0;" << std::endl;
1238- ss << "}" << std::endl;
1239- if (enable_autofuse_pgo_) {
1240- // PGOGetTilingKey
1241- ss << GenPGOGetTilingKey(tiling);
1242- // AutofuseTilingWithConfig
1243- ss << GenPgoTilingFunc(elemwise_schedule_result, tiling, pgo_shape_dim, true);
1244- } else {
1245- // 生成 AutofuseTilingWithConfig 函数
1246- ss << GenPgoAutofuseTiling(elemwise_schedule_result, pgo_shape_dim, tiling, true);
1247- }
1248 return ss.str();1277 return ss.str();
1249}1278}
1250 1279 
@@ -1645,6 +1674,7 @@ namespace gert {
1645 int vector_core_num = std::atoi(core_num.c_str());1674 int vector_core_num = std::atoi(core_num.c_str());
1646 GetTilingParse(tiling_parse_def, vector_core_num);1675 GetTilingParse(tiling_parse_def, vector_core_num);
1647 ss << tiling_parse_def << std::endl;1676 ss << tiling_parse_def << std::endl;
1677+ const std::string graph_name = CamelToLowerSneak(fused_schedule_result.fused_graph_name.GetString());
1648 if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result) && IsStaticSchedResult(fused_schedule_result)) {1678 if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result) && IsStaticSchedResult(fused_schedule_result)) {
1649 ss << extern_c << " ge::graphStatus TilingFunc(gert::TilingSymbolEvalContext *context)" << std::endl;1679 ss << extern_c << " ge::graphStatus TilingFunc(gert::TilingSymbolEvalContext *context)" << std::endl;
1650 ss << "{" << std::endl;1680 ss << "{" << std::endl;
Mautofuse/codegen/codegen_tiling.h+12-0
@@ -51,6 +51,8 @@ struct MatMulCubeInfo {
51 int32_t offset_x = 0;51 int32_t offset_x = 0;
52 int64_t enable_hf32 = false;52 int64_t enable_hf32 = false;
53 bool is_batch = false;53 bool is_batch = false;
54+ bool has_bias = false;
55+ bool has_offset_w = false;
54 bool has_relu = false;56 bool has_relu = false;
55 uint32_t input_num = 0U;57 uint32_t input_num = 0U;
56 uint32_t type_size = 4U;58 uint32_t type_size = 4U;
@@ -196,6 +198,16 @@ class TilingLib {
196 std::string GenTilingFuncForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result,198 std::string GenTilingFuncForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result,
197 const ::ascir::FusedScheduledResult &elemwise_schedule_result,199 const ::ascir::FusedScheduledResult &elemwise_schedule_result,
198 const std::string func, const std::string tiling) const;200 const std::string func, const std::string tiling) const;
201+ void GenInductorShapeDim(const ::ascir::FusedScheduledResult &elemwise_schedule_result,
202+ codegen::PgoShapeStringStream &pgo_shape_dim, std::vector<std::string> &dynamic_shape_vars,
203+ const std::string &tiling_var) const;
204+ std::string GenCallCubeTilingForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result,
205+ const std::vector<std::string> &dynamic_shape_vars,
206+ const codegen::PgoShapeStringStream &pgo_shape_dim) const;
207+ void GenCallCubeTilingCacheRead(std::stringstream &ss, const std::vector<std::string> &dynamic_shape_vars) const;
208+ void GenCallCubeTilingCacheWrite(std::stringstream &ss, const std::vector<std::string> &dynamic_shape_vars) const;
209+ std::string GenPlainInductorTilingTail(const ::ascir::FusedScheduledResult &elemwise_schedule_result,
210+ codegen::PgoShapeStringStream &pgo_shape_dim, const std::string &tiling) const;
199 // codegen_tiling_inductor_topn.cpp: candidate protocol, selection and multi-group performance aggregation.211 // codegen_tiling_inductor_topn.cpp: candidate protocol, selection and multi-group performance aggregation.
200 std::string GenGetTopnSolutionsFuncForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result,212 std::string GenGetTopnSolutionsFuncForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result,
201 const std::string &tiling, bool use_measured_perf = false,213 const std::string &tiling, bool use_measured_perf = false,
Mautofuse/codegen/codegen_tiling_cube.cpp+14-0
@@ -158,6 +158,8 @@ Status TilingLib::ExtractMatMulCubeInfoFromImplGraph(const af::AscGraph &impl_gr
158 cube_info.transpose_x2 = (mm_attr_data.transpose_x2 != 0) || (mm_attr_data.adj_x2 != 0);158 cube_info.transpose_x2 = (mm_attr_data.transpose_x2 != 0) || (mm_attr_data.adj_x2 != 0);
159 cube_info.offset_x = mm_attr_data.offset_x;159 cube_info.offset_x = mm_attr_data.offset_x;
160 cube_info.is_batch = mm_attr_data.is_batch;160 cube_info.is_batch = mm_attr_data.is_batch;
161+ cube_info.has_bias = mm_attr_data.is_bias;
162+ cube_info.has_offset_w = mm_attr_data.is_offset_w;
161 cube_info.has_relu = (mm_attr_data.has_relu != 0);163 cube_info.has_relu = (mm_attr_data.has_relu != 0);
162 cube_info.enable_hf32 = mm_attr_data.enable_hf32;164 cube_info.enable_hf32 = mm_attr_data.enable_hf32;
163 cube_info.matmul_node = node;165 cube_info.matmul_node = node;
@@ -346,6 +348,18 @@ void TilingLib::PrepareMatMulAttrs(const MatMulCubeInfo &cube_info, std::vector<
346 attr5.dtype = "int";348 attr5.dtype = "int";
347 attr5.value_int = kAscendcOpParaSize;349 attr5.value_int = kAscendcOpParaSize;
348 attrs.push_back(attr5);350 attrs.push_back(attr5);
351+ 
352+ AttrInfo attr6;
353+ attr6.name = "autofuse_has_bias";
354+ attr6.dtype = "bool";
355+ attr6.value_bool = cube_info.has_bias;
356+ attrs.push_back(attr6);
357+ 
358+ AttrInfo attr7;
359+ attr7.name = "autofuse_has_offset_w";
360+ attr7.dtype = "bool";
361+ attr7.value_bool = cube_info.has_offset_w;
362+ attrs.push_back(attr7);
349}363}
350 364 
351void TilingLib::GenerateTensorListCode(std::stringstream &code_ss, const std::vector<TensorInfo> &inputs,365void TilingLib::GenerateTensorListCode(std::stringstream &code_ss, const std::vector<TensorInfo> &inputs,
Mautofuse/codegen/codegen_tiling_cube_wrapper.h+1045-1208
@@ -14,803 +14,20 @@ inline const std::string kCubeKernelTilingWrapperHppValue = R"(
14#ifndef CUBE_KERNEL_TILING_WRAPPER_H14#ifndef CUBE_KERNEL_TILING_WRAPPER_H
15#define CUBE_KERNEL_TILING_WRAPPER_H15#define CUBE_KERNEL_TILING_WRAPPER_H
16 16 
17-#include <string>
18-#include <vector>
19-#include <map>
20-#include <utility>
21-#include <cstdint>
22-#include <memory>
23-#include <sstream>
24-#include <stdexcept>
25#include <cstddef>17#include <cstddef>
26-#include <cstring>18+#include <cstdint>
27-#include <cmath>19+#include <map>
28-#include <iomanip>20+#include <memory>
29-#include <algorithm>21+#include <string>
30-#include <limits>22+#include <utility>
31-#include "acl/acl.h"23+#include <vector>
24+ 
25+#include "graph/types.h"
32#include "arch35/mat_mul_tiling_data.h"26#include "arch35/mat_mul_tiling_data.h"
33-#include "platform/platform_info.h"
34 27 
35namespace ge {28namespace ge {
36namespace autofuse {29namespace autofuse {
37 30 
38-namespace json_internal {
39- 
40-enum class Type {
41- null,
42- boolean,
43- number_integer,
44- number_float,
45- string,
46- array,
47- object
48-};
49- 
50-class Json {
51-public:
52- Json() : type_(Type::null) {}
53- Json(bool value) : type_(Type::boolean), bool_value_(value) {}
54- Json(int value) : type_(Type::number_integer), int_value_(value) {}
55- Json(int64_t value) : type_(Type::number_integer), int_value_(value) {}
56- Json(double value) : type_(Type::number_float), float_value_(value) {}
57- Json(const char* value) : type_(Type::string), string_value_(new std::string(value)) {}
58- Json(const std::string& value) : type_(Type::string), string_value_(new std::string(value)) {}
59- Json(const std::vector<int64_t>& value) : type_(Type::array), array_value_(new std::vector<Json>()) {
60- for (const auto& v : value) {
61- array_value_->push_back(Json(v));
62- }
63- }
64- Json(const std::vector<double>& value) : type_(Type::array), array_value_(new std::vector<Json>()) {
65- for (const auto& v : value) {
66- array_value_->push_back(Json(v));
67- }
68- }
69- Json(const std::vector<std::string>& value) : type_(Type::array), array_value_(new std::vector<Json>()) {
70- for (const auto& v : value) {
71- array_value_->push_back(Json(v));
72- }
73- }
74- 
75- Json(const Json& other) : type_(other.type_) {
76- CopyValue(other);
77- }
78- 
79- Json(Json&& other) noexcept : type_(other.type_) {
80- MoveValue(std::move(other));
81- other.type_ = Type::null;
82- }
83- 
84- Json& operator=(const Json& other) {
85- if (this != &other) {
86- Clear();
87- type_ = other.type_;
88- CopyValue(other);
89- }
90- return *this;
91- }
92- 
93- Json& operator=(Json&& other) noexcept {
94- if (this != &other) {
95- Clear();
96- type_ = other.type_;
97- MoveValue(std::move(other));
98- other.type_ = Type::null;
99- }
100- return *this;
101- }
102- 
103- ~Json() {
104- Clear();
105- }
106- 
107- Type type() const { return type_; }
108- bool is_null() const { return type_ == Type::null; }
109- bool is_boolean() const { return type_ == Type::boolean; }
110- bool is_number() const { return type_ == Type::number_integer || type_ == Type::number_float; }
111- bool is_string() const { return type_ == Type::string; }
112- bool is_array() const { return type_ == Type::array; }
113- bool is_object() const { return type_ == Type::object; }
114- 
115- bool get_bool() const {
116- if (type_ != Type::boolean) throw std::runtime_error("Json is not a boolean");
117- return bool_value_;
118- }
119- 
120- int64_t get_int64() const {
121- if (type_ == Type::number_integer) return int_value_;
122- if (type_ == Type::number_float) return static_cast<int64_t>(float_value_);
123- throw std::runtime_error("Json is not a number");
124- }
125- 
126- int get_int() const {
127- return static_cast<int>(get_int64());
128- }
129- 
130- double get_double() const {
131- if (type_ == Type::number_float) return float_value_;
132- if (type_ == Type::number_integer) return static_cast<double>(int_value_);
133- throw std::runtime_error("Json is not a number");
134- }
135- 
136- std::string get_string() const {
137- if (type_ != Type::string) throw std::runtime_error("Json is not a string");
138- return *string_value_;
139- }
140- 
141- std::vector<int64_t> get_int64_array() const {
142- if (type_ != Type::array) throw std::runtime_error("Json is not an array");
143- std::vector<int64_t> result;
144- for (const auto& item : *array_value_) {
145- result.push_back(item.get_int64());
146- }
147- return result;
148- }
149- 
150- std::vector<double> get_double_array() const {
151- if (type_ != Type::array) throw std::runtime_error("Json is not an array");
152- std::vector<double> result;
153- for (const auto& item : *array_value_) {
154- result.push_back(item.get_double());
155- }
156- return result;
157- }
158- 
159- std::vector<std::string> get_string_array() const {
160- if (type_ != Type::array) throw std::runtime_error("Json is not an array");
161- std::vector<std::string> result;
162- for (const auto& item : *array_value_) {
163- result.push_back(item.get_string());
164- }
165- return result;
166- }
167- 
168- Json& operator[](const std::string& key) {
169- if (type_ == Type::null) {
170- type_ = Type::object;
171- object_value_ = new std::map<std::string, Json>();
172- }
173- if (type_ != Type::object) throw std::runtime_error("Json is not an object");
174- return (*object_value_)[key];
175- }
176- 
177- const Json& operator[](const std::string& key) const {
178- if (type_ != Type::object) throw std::runtime_error("Json is not an object");
179- static const Json null_json;
180- auto it = object_value_->find(key);
181- if (it == object_value_->end()) return null_json;
182- return it->second;
183- }
184- 
185- Json& operator[](size_t index) {
186- if (type_ != Type::array) throw std::runtime_error("Json is not an array");
187- if (index >= array_value_->size()) throw std::runtime_error("Array index out of bounds");
188- return (*array_value_)[index];
189- }
190- 
191- const Json& operator[](size_t index) const {
192- if (type_ != Type::array) throw std::runtime_error("Json is not an array");
193- if (index >= array_value_->size()) throw std::runtime_error("Array index out of bounds");
194- return (*array_value_)[index];
195- }
196- 
197- bool contains(const std::string& key) const {
198- if (type_ != Type::object) return false;
199- return object_value_->find(key) != object_value_->end();
200- }
201- 
202- void push_back(const Json& value) {
203- if (type_ == Type::null) {
204- type_ = Type::array;
205- array_value_ = new std::vector<Json>();
206- }
207- if (type_ != Type::array) throw std::runtime_error("Json is not an array");
208- array_value_->push_back(value);
209- }
210- 
211- void push_back(Json&& value) {
212- if (type_ == Type::null) {
213- type_ = Type::array;
214- array_value_ = new std::vector<Json>();
215- }
216- if (type_ != Type::array) throw std::runtime_error("Json is not an array");
217- array_value_->push_back(std::move(value));
218- }
219- 
220- size_t size() const {
221- if (type_ == Type::array) return array_value_->size();
222- if (type_ == Type::object) return object_value_->size();
223- return 0;
224- }
225- 
226- std::string dump(int indent = -1) const {
227- std::ostringstream oss;
228- Dump(oss, indent, 0);
229- return oss.str();
230- }
231- 
232- static Json parse(const std::string& str) {
233- Parser parser(str);
234- return parser.Parse();
235- }
236- 
237- static Json array() {
238- Json j;
239- j.type_ = Type::array;
240- j.array_value_ = new std::vector<Json>();
241- return j;
242- }
243- 
244- static Json object() {
245- Json j;
246- j.type_ = Type::object;
247- j.object_value_ = new std::map<std::string, Json>();
248- return j;
249- }
250- 
251-private:
252- Type type_;
253- 
254- union {
255- bool bool_value_;
256- int64_t int_value_;
257- double float_value_;
258- std::string* string_value_;
259- std::vector<Json>* array_value_;
260- std::map<std::string, Json>* object_value_;
261- };
262- 
263- void Clear() {
264- switch (type_) {
265- case Type::string:
266- delete string_value_;
267- break;
268- case Type::array:
269- delete array_value_;
270- break;
271- case Type::object:
272- delete object_value_;
273- break;
274- default:
275- break;
276- }
277- }
278- 
279- void CopyValue(const Json& other) {
280- switch (other.type_) {
281- case Type::null:
282- break;
283- case Type::boolean:
284- bool_value_ = other.bool_value_;
285- break;
286- case Type::number_integer:
287- int_value_ = other.int_value_;
288- break;
289- case Type::number_float:
290- float_value_ = other.float_value_;
291- break;
292- case Type::string:
293- string_value_ = new std::string(*other.string_value_);
294- break;
295- case Type::array:
296- array_value_ = new std::vector<Json>(*other.array_value_);
297- break;
298- case Type::object:
299- object_value_ = new std::map<std::string, Json>(*other.object_value_);
300- break;
301- }
302- }
303- 
304- void MoveValue(Json&& other) {
305- switch (other.type_) {
306- case Type::null:
307- break;
308- case Type::boolean:
309- bool_value_ = other.bool_value_;
310- break;
311- case Type::number_integer:
312- int_value_ = other.int_value_;
313- break;
314- case Type::number_float:
315- float_value_ = other.float_value_;
316- break;
317- case Type::string:
318- string_value_ = other.string_value_;
319- other.string_value_ = nullptr;
320- break;
321- case Type::array:
322- array_value_ = other.array_value_;
323- other.array_value_ = nullptr;
324- break;
325- case Type::object:
326- object_value_ = other.object_value_;
327- other.object_value_ = nullptr;
328- break;
329- }
330- }
331- 
332- void Dump(std::ostringstream& oss, int indent, int level) const {
333- std::string indent_str;
334- if (indent > 0) {
335- indent_str = std::string(level * indent, ' ');
336- }
337- 
338- switch (type_) {
339- case Type::null:
340- oss << "null";
341- break;
342- case Type::boolean:
343- oss << (bool_value_ ? "true" : "false");
344- break;
345- case Type::number_integer:
346- oss << int_value_;
347- break;
348- case Type::number_float:
349- oss << float_value_;
350- break;
351- case Type::string:
352- oss << "\"" << EscapeString(*string_value_) << "\"";
353- break;
354- case Type::array:
355- oss << "[";
356- if (indent > 0 && !array_value_->empty()) {
357- oss << "\n";
358- }
359- for (size_t i = 0; i < array_value_->size(); ++i) {
360- if (indent > 0) {
361- oss << indent_str << std::string(indent, ' ');
362- }
363- (*array_value_)[i].Dump(oss, indent, level + 1);
364- if (i < array_value_->size() - 1) {
365- oss << ",";
366- }
367- if (indent > 0) {
368- oss << "\n";
369- }
370- }
371- if (indent > 0 && !array_value_->empty()) {
372- oss << indent_str;
373- }
374- oss << "]";
375- break;
376- case Type::object:
377- oss << "{";
378- if (indent > 0 && !object_value_->empty()) {
379- oss << "\n";
380- }
381- auto it = object_value_->begin();
382- for (size_t i = 0; i < object_value_->size(); ++i, ++it) {
383- if (indent > 0) {
384- oss << indent_str << std::string(indent, ' ');
385- }
386- oss << "\"" << it->first << "\":";
387- if (indent > 0) {
388- oss << " ";
389- }
390- it->second.Dump(oss, indent, level + 1);
391- if (i < object_value_->size() - 1) {
392- oss << ",";
393- }
394- if (indent > 0) {
395- oss << "\n";
396- }
397- }
398- if (indent > 0 && !object_value_->empty()) {
399- oss << indent_str;
400- }
401- oss << "}";
402- break;
403- }
404- }
405- 
406- static std::string EscapeString(const std::string& str) {
407- std::string result;
408- for (char c : str) {
409- switch (c) {
410- case '"': result += "\\\""; break;
411- case '\\': result += "\\\\"; break;
412- case '\b': result += "\\b"; break;
413- case '\f': result += "\\f"; break;
414- case '\n': result += "\\n"; break;
415- case '\r': result += "\\r"; break;
416- case '\t': result += "\\t"; break;
417- default:
418- if (static_cast<unsigned char>(c) < 0x20) {
419- char buf[7];
420- snprintf(buf, sizeof(buf), "\\u%04x", static_cast<unsigned char>(c));
421- result += buf;
422- } else {
423- result += c;
424- }
425- break;
426- }
427- }
428- return result;
429- }
430- 
431- class Parser {
432- public:
433- Parser(const std::string& str) : str_(str), pos_(0) {
434- SkipWhitespace();
435- }
436- 
437- Json Parse() {
438- if (pos_ >= str_.size()) {
439- throw std::runtime_error("Empty JSON string");
440- }
441- return ParseValue();
442- }
443- 
444- private:
445- const std::string& str_;
446- size_t pos_;
447- 
448- void SkipWhitespace() {
449- while (pos_ < str_.size() && (str_[pos_] == ' ' || str_[pos_] == '\t' ||
450- str_[pos_] == '\n' || str_[pos_] == '\r')) {
451- ++pos_;
452- }
453- }
454- 
455- char Peek() const {
456- if (pos_ >= str_.size()) return '\0';
457- return str_[pos_];
458- }
459- 
460- char Consume() {
461- if (pos_ >= str_.size()) return '\0';
462- return str_[pos_++];
463- }
464- 
465- Json ParseValue() {
466- SkipWhitespace();
467- char c = Peek();
468- 
469- if (c == 'n') return ParseNull();
470- if (c == 't' || c == 'f') return ParseBoolean();
471- if (c == '"') return ParseString();
472- if (c == '[') return ParseArray();
473- if (c == '{') return ParseObject();
474- if (c == '-' || (c >= '0' && c <= '9')) return ParseNumber();
475- 
476- throw std::runtime_error(std::string("Unexpected character: ") + c);
477- }
478- 
479- Json ParseNull() {
480- if (str_.substr(pos_, 4) == "null") {
481- pos_ += 4;
482- return Json();
483- }
484- throw std::runtime_error("Expected 'null'");
485- }
486- 
487- Json ParseBoolean() {
488- if (str_.substr(pos_, 4) == "true") {
489- pos_ += 4;
490- return Json(true);
491- }
492- if (str_.substr(pos_, 5) == "false") {
493- pos_ += 5;
494- return Json(false);
495- }
496- throw std::runtime_error("Expected 'true' or 'false'");
497- }
498- 
499- Json ParseNumber() {
500- size_t start = pos_;
501- if (Peek() == '-') Consume();
502- 
503- while (pos_ < str_.size() && (str_[pos_] >= '0' && str_[pos_] <= '9')) {
504- ++pos_;
505- }
506- 
507- bool is_float = false;
508- if (pos_ < str_.size() && str_[pos_] == '.') {
509- is_float = true;
510- ++pos_;
511- while (pos_ < str_.size() && (str_[pos_] >= '0' && str_[pos_] <= '9')) {
512- ++pos_;
513- }
514- }
515- 
516- if (pos_ < str_.size() && (str_[pos_] == 'e' || str_[pos_] == 'E')) {
517- is_float = true;
518- ++pos_;
519- if (pos_ < str_.size() && (str_[pos_] == '+' || str_[pos_] == '-')) {
520- ++pos_;
521- }
522- while (pos_ < str_.size() && (str_[pos_] >= '0' && str_[pos_] <= '9')) {
523- ++pos_;
524- }
525- }
526- 
527- std::string num_str = str_.substr(start, pos_ - start);
528- if (is_float) {
529- return Json(std::stod(num_str));
530- } else {
531- return Json(static_cast<int64_t>(std::stoll(num_str)));
532- }
533- }
534- 
535- Json ParseString() {
536- if (Consume() != '"') {
537- throw std::runtime_error("Expected '\"'");
538- }
539- 
540- std::string result;
541- while (pos_ < str_.size() && str_[pos_] != '"') {
542- if (str_[pos_] == '\\') {
543- ++pos_;
544- if (pos_ >= str_.size()) {
545- throw std::runtime_error("Unexpected end of string");
546- }
547- switch (str_[pos_]) {
548- case '"': result += '"'; break;
549- case '\\': result += '\\'; break;
550- case '/': result += '/'; break;
551- case 'b': result += '\b'; break;
552- case 'f': result += '\f'; break;
553- case 'n': result += '\n'; break;
554- case 'r': result += '\r'; break;
555- case 't': result += '\t'; break;
556- case 'u': {
557- if (pos_ + 4 >= str_.size()) {
558- throw std::runtime_error("Invalid unicode escape");
559- }
560- std::string hex_str = str_.substr(pos_ + 1, 4);
561- unsigned int codepoint = std::stoul(hex_str, nullptr, 16);
562- if (codepoint < 0x80) {
563- result += static_cast<char>(codepoint);
564- } else if (codepoint < 0x800) {
565- result += static_cast<char>(0xC0 | (codepoint >> 6));
566- result += static_cast<char>(0x80 | (codepoint & 0x3F));
567- } else {
568- result += static_cast<char>(0xE0 | (codepoint >> 12));
569- result += static_cast<char>(0x80 | ((codepoint >> 6) & 0x3F));
570- result += static_cast<char>(0x80 | (codepoint & 0x3F));
571- }
572- pos_ += 4;
573- break;
574- }
575- default:
576- throw std::runtime_error("Invalid escape sequence");
577- }
578- } else {
579- result += str_[pos_];
580- }
581- ++pos_;
582- }
583- 
584- if (pos_ >= str_.size() || Consume() != '"') {
585- throw std::runtime_error("Unterminated string");
586- }
587- 
588- return Json(result);
589- }
590- 
591- Json ParseArray() {
592- if (Consume() != '[') {
593- throw std::runtime_error("Expected '['");
594- }
595- 
596- Json result = Json::array();
597- SkipWhitespace();
598- 
599- if (Peek() == ']') {
600- Consume();
601- return result;
602- }
603- 
604- while (true) {
605- result.push_back(ParseValue());
606- SkipWhitespace();
607- 
608- if (Peek() == ']') {
609- Consume();
610- return result;
611- }
612- 
613- if (Peek() == ',') {
614- Consume();
615- } else {
616- throw std::runtime_error("Expected ',' or ']' in array");
617- }
618- }
619- }
620- 
621- Json ParseObject() {
622- if (Consume() != '{') {
623- throw std::runtime_error("Expected '{'");
624- }
625- 
626- Json result = Json::object();
627- SkipWhitespace();
628- 
629- if (Peek() == '}') {
630- Consume();
631- return result;
632- }
633- 
634- while (true) {
635- SkipWhitespace();
636- Json key = ParseString();
637- SkipWhitespace();
638- 
639- if (Consume() != ':') {
640- throw std::runtime_error("Expected ':' after key");
641- }
642- 
643- Json value = ParseValue();
644- result[key.get_string()] = std::move(value);
645- SkipWhitespace();
646- 
647- if (Peek() == '}') {
648- Consume();
649- return result;
650- }
651- 
652- if (Peek() == ',') {
653- Consume();
654- } else {
655- throw std::runtime_error("Expected ',' or '}' in object");
656- }
657- }
658- }
659- };
660-};
661- 
662-} // namespace json_internal
663- 
664-namespace crypto {
665- 
666-class SHA1 {
667-public:
668- static constexpr size_t DIGEST_LENGTH = 20;
669- 
670- static std::string Hash(const std::string& input) {
671- SHA1 sha1;
672- sha1.Update(reinterpret_cast<const uint8_t*>(input.c_str()), input.length());
673- uint8_t digest[DIGEST_LENGTH];
674- sha1.Final(digest);
675- return DigestToHex(digest);
676- }
677- 
678-private:
679- SHA1() {
680- Reset();
681- }
682- 
683- void Reset() {
684- m_digest[0] = 0x67452301;
685- m_digest[1] = 0xEFCDAB89;
686- m_digest[2] = 0x98BADCFE;
687- m_digest[3] = 0x10325476;
688- m_digest[4] = 0xC3D2E1F0;
689- m_block_len = 0;
690- m_total_len = 0;
691- }
692- 
693- void Update(const uint8_t* data, size_t len) {
694- while (len) {
695- size_t copy_len = std::min(len, 64 - m_block_len);
696- std::memcpy(m_block + m_block_len, data, copy_len);
697- 
698- m_block_len += copy_len;
699- m_total_len += copy_len;
700- data += copy_len;
701- len -= copy_len;
702- 
703- if (m_block_len == 64) {
704- ProcessBlock(m_block);
705- m_block_len = 0;
706- }
707- }
708- }
709- 
710- void Final(uint8_t* digest) {
711- uint64_t total_bits = m_total_len * 8;
712- 
713- m_block[m_block_len++] = 0x80;
714- if (m_block_len > 56) {
715- while (m_block_len < 64) {
716- m_block[m_block_len++] = 0;
717- }
718- ProcessBlock(m_block);
719- m_block_len = 0;
720- }
721- 
722- while (m_block_len < 56) {
723- m_block[m_block_len++] = 0;
724- }
725- 
726- for (int i = 7; i >= 0; --i) {
727- m_block[m_block_len++] = static_cast<uint8_t>((total_bits >> (i * 8)) & 0xFF);
728- }
729- 
730- ProcessBlock(m_block);
731- 
732- for (int i = 0; i < 5; ++i) {
733- digest[i * 4 + 0] = static_cast<uint8_t>((m_digest[i] >> 24) & 0xFF);
734- digest[i * 4 + 1] = static_cast<uint8_t>((m_digest[i] >> 16) & 0xFF);
735- digest[i * 4 + 2] = static_cast<uint8_t>((m_digest[i] >> 8) & 0xFF);
736- digest[i * 4 + 3] = static_cast<uint8_t>(m_digest[i] & 0xFF);
737- }
738- }
739- 
740- void ProcessBlock(const uint8_t* block) {
741- uint32_t w[80];
742- 
743- for (int i = 0; i < 16; ++i) {
744- w[i] = (block[i * 4 + 0] << 24) | (block[i * 4 + 1] << 16) |
745- (block[i * 4 + 2] << 8) | block[i * 4 + 3];
746- }
747- 
748- for (int i = 16; i < 80; ++i) {
749- uint32_t temp = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
750- w[i] = ROTL(temp, 1);
751- }
752- 
753- uint32_t a = m_digest[0];
754- uint32_t b = m_digest[1];
755- uint32_t c = m_digest[2];
756- uint32_t d = m_digest[3];
757- uint32_t e = m_digest[4];
758- 
759- for (int i = 0; i < 80; ++i) {
760- uint32_t f, k;
761- 
762- if (i < 20) {
763- f = (b & c) | ((~b) & d);
764- k = 0x5A827999;
765- } else if (i < 40) {
766- f = b ^ c ^ d;
767- k = 0x6ED9EBA1;
768- } else if (i < 60) {
769- f = (b & c) | (b & d) | (c & d);
770- k = 0x8F1BBCDC;
771- } else {
772- f = b ^ c ^ d;
773- k = 0xCA62C1D6;
774- }
775- 
776- uint32_t temp = ROTL(a, 5) + f + e + k + w[i];
777- e = d;
778- d = c;
779- c = ROTL(b, 30);
780- b = a;
781- a = temp;
782- }
783- 
784- m_digest[0] += a;
785- m_digest[1] += b;
786- m_digest[2] += c;
787- m_digest[3] += d;
788- m_digest[4] += e;
789- }
790- 
791- static uint32_t ROTL(uint32_t x, uint32_t n) {
792- return (x << n) | (x >> (32 - n));
793- }
794- 
795- static std::string DigestToHex(const uint8_t* digest) {
796- std::ostringstream oss;
797- oss << std::hex << std::setfill('0');
798- for (size_t i = 0; i < DIGEST_LENGTH; ++i) {
799- oss << std::setw(2) << static_cast<int>(digest[i]);
800- }
801- return oss.str();
802- }
803- 
804- uint32_t m_digest[5];
805- uint8_t m_block[64];
806- size_t m_block_len;
807- uint64_t m_total_len;
808-};
809- 
810-} // namespace crypto
811- 
812-using Json = json_internal::Json;
813- 
814struct TensorInfo {31struct TensorInfo {
815 std::string param_name;32 std::string param_name;
816 std::vector<int64_t> shape;33 std::vector<int64_t> shape;
@@ -862,6 +79,13 @@ struct TilingResult {
862 MatMulV3BasicTilingData matmul_basic_tiling_data;79 MatMulV3BasicTilingData matmul_basic_tiling_data;
863};80};
864 81 
82+extern "C" bool AutofuseDoCubeMatMulTiling(const CompileInfo* compile_info,
83+ const std::vector<TensorInfo>* inputs,
84+ const std::vector<TensorInfo>* outputs,
85+ const std::vector<AttrInfo>* attrs,
86+ bool is_batch,
87+ TilingResult* result);
88+ 
865class CubeKernelTilingWrapper {89class CubeKernelTilingWrapper {
866public:90public:
867 CubeKernelTilingWrapper();91 CubeKernelTilingWrapper();
@@ -874,38 +98,12 @@ public:
874 bool is_batch = false);98 bool is_batch = false);
875 99 
876 static void BuildMatMulArgs(const std::vector<TensorInfo>& args_list,100 static void BuildMatMulArgs(const std::vector<TensorInfo>& args_list,
877- int input_num,101+ int input_num,
878- bool transpose_a,102+ bool transpose_a,
879- bool transpose_b,103+ bool transpose_b,
880- std::vector<TensorInfo>& origin_inputs,104+ std::vector<TensorInfo>& origin_inputs,
881- std::vector<TensorInfo>& origin_outputs,105+ std::vector<TensorInfo>& origin_outputs,
882- std::vector<TensorInfo>& inputs);106+ std::vector<TensorInfo>& inputs);
883- 
884- static std::string GenerateCompileInfoHash(const std::string& compile_info_info);
885- 
886- static void ChangeParamNameToName(std::vector<TensorInfo>& inputs);
887- static void InputsPreProcess(std::vector<TensorInfo>& inputs);
888- static void AttrsPreProcess(std::vector<AttrInfo>& attrs);
889- static std::vector<uint8_t> AlignTilingDataTo8Bytes(const std::vector<uint8_t>& tiling_data, const std::string& soc_version);
890- 
891-private:
892- static std::string SerializeToJson(const CompileInfo& compile_info);
893- static std::string SerializeToJson(const std::vector<TensorInfo>& tensors);
894- static std::string SerializeToJson(const std::vector<AttrInfo>& attrs);
895- static std::string SerializeToJson(const std::map<std::string, std::string>& extra_params);
896- 
897- static bool ParseTilingResult(const std::string& json_str, TilingResult& result);
898- 
899- char* CallDoOpTilingForCompile(const char* op_type,
900- const char* compile_info,
901- const char* compile_info_hash,
902- const char* inputs,
903- const char* outputs,
904- const char* attrs,
905- char* buf,
906- size_t buf_size,
907- uint64_t* timer,
908- const char* extra_params);
909};107};
910 108 
911} // namespace autofuse109} // namespace autofuse
@@ -916,413 +114,1052 @@ private:
916 114 
917inline const std::string kCubeKernelTilingWrapperCppValue = R"(115inline const std::string kCubeKernelTilingWrapperCppValue = R"(
918#include "autofuse_tiling_func_log.h"116#include "autofuse_tiling_func_log.h"
919-#include <sstream>117+#include "registry/op_impl_space_registry_v2.h"
920-#include <iomanip>118+ 
921-#include <dlfcn.h>119+#include "context_builder/op_tiling_context_builder.h"
922-#include <iostream>120+#include "context_builder/op_tiling_parse_context_builder.h"
121+#include "exe_graph/runtime/continuous_vector.h"
122+#include "exe_graph/runtime/storage_format.h"
123+#include "exe_graph/runtime/storage_shape.h"
124+#include "exe_graph/runtime/tensor.h"
125+#include "platform/platform_info.h"
126+#include "platform/platform_infos_def.h"
127+#include "register/op_impl_kernel_registry.h"
128+ 
129+#include <algorithm>
130+#include <array>
923#include <cstdlib>131#include <cstdlib>
924-#include <unistd.h>
925#include <cstring>132#include <cstring>
926-#include <cmath>
927#include <limits>133#include <limits>
928- 134+#include <map>
929-using json = ge::autofuse::Json;135+#include <memory>
930-using SHA1 = ge::autofuse::crypto::SHA1;136+#include <mutex>
931- 137+#include <sstream>
932-#ifndef DEFAULT_ASCEND_OPP_PATH138+#include <tuple>
933-#define DEFAULT_ASCEND_OPP_PATH "/usr/local/Ascend/cann/opp"139+#include <type_traits>
934-#endif140+#include <utility>
935- 
936-extern "C" const char *DoOpTilingForCompile(const char *optype,
937- const char *compile_info,
938- const char *compile_info_hash,
939- const char *inputs,
940- const char *outputs,
941- const char *attrs,
942- char *run_info_json,
943- size_t run_info_len,
944- uint64_t *elapse,
945- const char *extra_info);
946 141 
947namespace ge {142namespace ge {
948namespace autofuse {143namespace autofuse {
949 144 
145+namespace {
146+constexpr size_t kMaxTilingDataSize = 64 * 1024;
147+constexpr size_t kWorkspaceCapacity = 4096;
148+const std::vector<uint32_t> kSingleOutputInstanceNum = {1U};
149+ 
150+struct OpHostFuncs {
151+ gert::OpImplRegisterV2::TilingKernelFunc tiling = nullptr;
152+ gert::OpImplRegisterV2::KernelFunc tiling_parse = nullptr;
153+ gert::OpImplRegisterV2::CompileInfoCreatorFunc compile_info_creator = nullptr;
154+ size_t max_tiling_data_size = 0UL;
155+};
156+ 
157+struct CachedOpHostFuncs {
158+ OpHostFuncs funcs;
159+ bool loaded = false;
160+ std::once_flag once;
161+};
162+ 
163+struct OpHostSchema {
164+ const char *op_type;
165+};
166+ 
167+struct MatMulAttrs {
168+ bool transpose_x1 = false;
169+ bool transpose_x2 = false;
170+ int64_t offset_x = 0;
171+ int64_t op_impl_mode = 0;
172+ bool enable_hf32 = false;
173+ bool has_bias = false;
174+ bool has_offset_w = false;
175+ bool has_optional_input_markers = false;
176+};
177+ 
178+struct RuntimeTilingKey {
179+ std::string soc_version;
180+ std::string device_id;
181+ std::string op_type;
182+ std::string dtype;
183+ std::string format;
184+ std::vector<int64_t> input0_shape;
185+ std::vector<int64_t> input1_shape;
186+ std::vector<int64_t> input2_shape;
187+ std::vector<int64_t> input3_shape;
188+ std::string input2_dtype;
189+ std::string input3_dtype;
190+ std::string input2_format;
191+ std::string input3_format;
192+ std::vector<int64_t> output_shape;
193+ bool is_batch = false;
194+ size_t input_num = 0U;
195+ bool has_bias = false;
196+ bool has_offset_w = false;
197+ bool transpose_x1 = false;
198+ bool transpose_x2 = false;
199+ int64_t offset_x = 0;
200+ int64_t op_impl_mode = 0;
201+ bool enable_hf32 = false;
202+ int64_t aicore_num = 0;
203+ int64_t aiv_num = 0;
204+ 
205+ bool operator<(const RuntimeTilingKey &other) const {
206+ return std::tie(soc_version, device_id, op_type, dtype, format, input0_shape, input1_shape, input2_shape,
207+ input3_shape, input2_dtype, input3_dtype, input2_format, input3_format, output_shape, is_batch,
208+ input_num, has_bias, has_offset_w, transpose_x1, transpose_x2, offset_x, op_impl_mode, enable_hf32,
209+ aicore_num, aiv_num) <
210+ std::tie(other.soc_version, other.device_id, other.op_type, other.dtype, other.format, other.input0_shape,
211+ other.input1_shape, other.input2_shape, other.input3_shape, other.input2_dtype, other.input3_dtype,
212+ other.input2_format, other.input3_format, other.output_shape, other.is_batch, other.input_num,
213+ other.has_bias, other.has_offset_w, other.transpose_x1, other.transpose_x2, other.offset_x,
214+ other.op_impl_mode, other.enable_hf32, other.aicore_num, other.aiv_num);
215+ }
216+};
217+ 
218+struct CompileState;
219+ 
220+struct CompileStateKey {
221+ std::string soc_version;
222+ std::string device_id;
223+ std::string dtype;
224+ std::string format;
225+ std::string input2_dtype;
226+ std::string input3_dtype;
227+ std::string input2_format;
228+ std::string input3_format;
229+ bool is_batch = false;
230+ size_t input_num = 0U;
231+ bool has_bias = false;
232+ bool has_offset_w = false;
233+ bool transpose_x1 = false;
234+ bool transpose_x2 = false;
235+ int64_t offset_x = 0;
236+ int64_t op_impl_mode = 0;
237+ bool enable_hf32 = false;
238+ int64_t aicore_num = 0;
239+ int64_t aiv_num = 0;
240+ 
241+ bool operator<(const CompileStateKey &other) const {
242+ return std::tie(soc_version, device_id, dtype, format, input2_dtype, input3_dtype, input2_format, input3_format,
243+ is_batch, input_num, transpose_x1, transpose_x2, offset_x, op_impl_mode, enable_hf32, aicore_num,
244+ aiv_num, has_bias, has_offset_w) <
245+ std::tie(other.soc_version, other.device_id, other.dtype, other.format, other.input2_dtype,
246+ other.input3_dtype, other.input2_format, other.input3_format, other.is_batch, other.input_num,
247+ other.transpose_x1, other.transpose_x2, other.offset_x, other.op_impl_mode, other.enable_hf32,
248+ other.aicore_num, other.aiv_num, other.has_bias, other.has_offset_w);
249+ }
250+};
251+ 
252+struct CompileState {
253+ std::string compile_json;
254+ fe::PlatFormInfos platform_info;
255+ void *compile_info_ptr = nullptr;
256+};
257+ 
258+struct TilingRequest {
259+ const CompileInfo &compile_info;
260+ const std::vector<TensorInfo> &inputs;
261+ const std::vector<TensorInfo> &outputs;
262+ bool is_batch = false;
263+ const OpHostSchema &schema;
264+ MatMulAttrs matmul_attrs;
265+ ge::DataType data_type = ge::DT_UNDEFINED;
266+ ge::Format format = ge::FORMAT_RESERVED;
267+};
268+ 
269+struct TilingScratch {
270+ std::unique_ptr<uint8_t[]> tiling_data_holder;
271+ std::unique_ptr<uint8_t[]> workspace_holder;
272+ size_t tiling_data_capacity = 0UL;
273+ std::vector<gert::Tensor *> input_tensors;
274+ std::vector<gert::Tensor *> output_tensors;
275+ 
276+ bool EnsureCapacity(size_t required_tiling_data_capacity, std::string &error_msg, const char *op_type) {
277+ if (tiling_data_holder == nullptr || required_tiling_data_capacity > tiling_data_capacity) {
278+ auto new_tiling_data_holder = gert::TilingData::CreateCap(required_tiling_data_capacity);
279+ if (new_tiling_data_holder == nullptr) {
280+ error_msg = std::string(op_type) + " tiling data allocation failed";
281+ return false;
282+ }
283+ tiling_data_holder = std::move(new_tiling_data_holder);
284+ tiling_data_capacity = required_tiling_data_capacity;
285+ }
286+ if (workspace_holder == nullptr) {
287+ workspace_holder = gert::ContinuousVector::Create<size_t>(kWorkspaceCapacity);
288+ if (workspace_holder == nullptr) {
289+ error_msg = std::string(op_type) + " workspace allocation failed";
290+ return false;
291+ }
292+ }
293+ input_tensors.reserve(4U);
294+ output_tensors.reserve(1U);
295+ return true;
296+ }
297+ 
298+ gert::TilingData *MutableTilingData() const {
299+ return reinterpret_cast<gert::TilingData *>(tiling_data_holder.get());
300+ }
301+ 
302+ gert::ContinuousVector *MutableWorkspace() const {
303+ return reinterpret_cast<gert::ContinuousVector *>(workspace_holder.get());
304+ }
305+};
306+ 
307+TilingScratch &GetTilingScratch() {
308+ thread_local TilingScratch scratch;
309+ return scratch;
310+}
311+ 
312+CachedOpHostFuncs &GetMatMulFuncsCache() {
313+ static auto *cache = new CachedOpHostFuncs();
314+ return *cache;
315+}
316+ 
317+CachedOpHostFuncs &GetBatchMatMulFuncsCache() {
318+ static auto *cache = new CachedOpHostFuncs();
319+ return *cache;
320+}
321+ 
322+std::mutex &GetCompileStateMutex() {
323+ static auto *mutex = new std::mutex();
324+ return *mutex;
325+}
326+ 
327+std::map<CompileStateKey, std::shared_ptr<const CompileState>> &GetCompileStateCache() {
328+ static auto cache = std::make_shared<std::map<CompileStateKey, std::shared_ptr<const CompileState>>>();
329+ return *cache;
330+}
331+ 
332+std::mutex &GetTilingResultCacheMutex() {
333+ static auto *mutex = new std::mutex();
334+ return *mutex;
335+}
336+ 
337+std::map<RuntimeTilingKey, TilingResult> &GetTilingResultCache() {
338+ static auto *cache = new std::map<RuntimeTilingKey, TilingResult>();
339+ return *cache;
340+}
341+ 
342+const OpHostSchema &GetOpHostSchema(bool is_batch) {
343+ static const OpHostSchema kMatMulV3Schema{"MatMulV3"};
344+ static const OpHostSchema kBatchMatMulV3Schema{"BatchMatMulV3"};
345+ return is_batch ? kBatchMatMulV3Schema : kMatMulV3Schema;
346+}
347+ 
348+ge::DataType DtypeToGeDataType(const std::string &dtype) {
349+ if (dtype == "float" || dtype == "float32" || dtype == "DT_FLOAT" || dtype == "torch.float32") {
350+ return ge::DT_FLOAT;
351+ }
352+ if (dtype == "float16" || dtype == "half" || dtype == "DT_FLOAT16" || dtype == "torch.float16") {
353+ return ge::DT_FLOAT16;
354+ }
355+ if (dtype == "bfloat16" || dtype == "bf16" || dtype == "DT_BF16" || dtype == "torch.bfloat16") {
356+ return ge::DT_BF16;
357+ }
358+ return ge::DT_UNDEFINED;
359+}
360+ 
361+ge::Format FormatToGeFormat(const std::string &format) {
362+ if (format.empty() || format == "ND" || format == "FORMAT_ND" || format == "ACL_FORMAT_ND") {
363+ return ge::FORMAT_ND;
364+ }
365+ return ge::FORMAT_RESERVED;
366+}
367+ 
368+bool AttrAsBool(const AttrInfo &attr) {
369+ if (attr.dtype == "bool") {
370+ return attr.value_bool;
371+ }
372+ if (attr.dtype == "int" || attr.dtype == "int32" || attr.dtype == "int64") {
373+ return attr.value_int != 0;
374+ }
375+ return false;
376+}
377+ 
378+int64_t AttrAsInt(const AttrInfo &attr) {
379+ if (attr.dtype == "bool") {
380+ return attr.value_bool ? 1 : 0;
381+ }
382+ if (attr.dtype == "int" || attr.dtype == "int32" || attr.dtype == "int64") {
383+ return attr.value_int;
384+ }
385+ return 0;
386+}
387+ 
388+MatMulAttrs ReadMatMulAttrs(const std::vector<AttrInfo> &attrs, bool is_batch) {
389+ MatMulAttrs result;
390+ const char *transpose_x1_name = is_batch ? "adj_x1" : "transpose_x1";
391+ const char *transpose_x2_name = is_batch ? "adj_x2" : "transpose_x2";
392+ for (const auto &attr : attrs) {
393+ if (attr.name == transpose_x1_name) {
394+ result.transpose_x1 = AttrAsBool(attr);
395+ } else if (attr.name == transpose_x2_name) {
396+ result.transpose_x2 = AttrAsBool(attr);
397+ } else if (attr.name == "offset_x") {
398+ result.offset_x = AttrAsInt(attr);
399+ } else if (attr.name == "opImplMode") {
400+ result.op_impl_mode = AttrAsInt(attr);
401+ } else if (attr.name == "enable_hf32") {
402+ result.enable_hf32 = AttrAsBool(attr);
403+ } else if (attr.name == "autofuse_has_bias") {
404+ result.has_bias = AttrAsBool(attr);
405+ result.has_optional_input_markers = true;
406+ } else if (attr.name == "autofuse_has_offset_w") {
407+ result.has_offset_w = AttrAsBool(attr);
408+ result.has_optional_input_markers = true;
409+ }
410+ }
411+ result.enable_hf32 = result.enable_hf32 || result.op_impl_mode != 0;
412+ return result;
413+}
414+ 
415+bool LoadOpHostFuncs(const char *op_type, OpHostFuncs &funcs) {
416+ auto registry = gert::DefaultOpImplSpaceRegistryV2::GetInstance().GetSpaceRegistry();
417+ if (registry == nullptr) {
418+ return false;
419+ }
420+ const auto *op_impl = registry->GetOpImpl(op_type);
421+ if (op_impl == nullptr) {
422+ return false;
423+ }
424+ funcs.tiling = op_impl->tiling;
425+ funcs.tiling_parse = op_impl->tiling_parse;
426+ funcs.compile_info_creator = op_impl->compile_info_creator;
427+ funcs.max_tiling_data_size = op_impl->max_tiling_data_size;
428+ return funcs.tiling != nullptr && funcs.tiling_parse != nullptr && funcs.compile_info_creator != nullptr;
429+}
430+ 
431+const CachedOpHostFuncs &GetOpHostFuncs(bool is_batch, const char *op_type) {
432+ CachedOpHostFuncs &cache = is_batch ? GetBatchMatMulFuncsCache() : GetMatMulFuncsCache();
433+ std::call_once(cache.once, [&cache, op_type]() { cache.loaded = LoadOpHostFuncs(op_type, cache.funcs); });
434+ return cache;
435+}
436+ 
437+bool ParseUint32(const std::string &value, uint32_t &result) {
438+ if (value.empty()) {
439+ return false;
440+ }
441+ char *end = nullptr;
442+ const unsigned long parsed = std::strtoul(value.c_str(), &end, 10);
443+ if (end == value.c_str() || *end != '\0' || parsed > std::numeric_limits<uint32_t>::max()) {
444+ return false;
445+ }
446+ result = static_cast<uint32_t>(parsed);
447+ return true;
448+}
449+ 
450+bool ParseUint64(const std::string &value, uint64_t &result) {
451+ if (value.empty()) {
452+ return false;
453+ }
454+ char *end = nullptr;
455+ const unsigned long long parsed = std::strtoull(value.c_str(), &end, 10);
456+ if (end == value.c_str() || *end != '\0') {
457+ return false;
458+ }
459+ result = static_cast<uint64_t>(parsed);
460+ return true;
461+}
462+ 
463+uint32_t GetCompileDeviceId(const CompileInfo &compile_info) {
464+ uint32_t device_id = 0;
465+ (void)ParseUint32(compile_info.device_id, device_id);
466+ return device_id;
467+}
468+ 
469+std::string GetPlatformString(fe::PlatFormInfos &platform_info, const std::string &label, const std::string &key,
470+ const std::string &fallback = "") {
471+ std::string value;
472+ if (platform_info.GetPlatformResWithLock(label, key, value) && !value.empty()) {
473+ return value;
474+ }
475+ return fallback;
476+}
477+ 
478+uint64_t GetPlatformUint64(fe::PlatFormInfos &platform_info, const std::string &label, const std::string &key,
479+ uint64_t fallback = 0U) {
480+ uint64_t value = 0U;
481+ if (ParseUint64(GetPlatformString(platform_info, label, key), value)) {
482+ return value;
483+ }
484+ return fallback;
485+}
486+ 
487+uint64_t GetLocalMemSize(fe::PlatFormInfos &platform_info, fe::LocalMemType mem_type, const std::string &label,
488+ const std::string &key) {
489+ uint64_t size = 0U;
490+ platform_info.GetLocalMemSize(mem_type, size);
491+ if (size != 0U) {
492+ return size;
493+ }
494+ return GetPlatformUint64(platform_info, label, key);
495+}
496+ 
497+uint32_t GetPlatformCoreNum(fe::PlatFormInfos &platform_info, const std::string &core_type,
498+ const std::string &soc_info_key) {
499+ uint32_t core_num = platform_info.GetCoreNumByType(core_type);
500+ if (core_num != 0U) {
501+ return core_num;
502+ }
503+ return static_cast<uint32_t>(GetPlatformUint64(platform_info, "SoCInfo", soc_info_key));
504+}
505+ 
506+void UpdatePlatformCoreNum(const CompileInfo &compile_info, fe::PlatFormInfos &platform_info) {
507+ uint32_t aic_num = compile_info.aicore_num > 0 ? static_cast<uint32_t>(compile_info.aicore_num)
508+ : GetPlatformCoreNum(platform_info, "AiCore", "cube_core_cnt");
509+ uint32_t aiv_num = compile_info.aiv_num > 0 ? static_cast<uint32_t>(compile_info.aiv_num)
510+ : GetPlatformCoreNum(platform_info, "VectorCore", "vector_core_cnt");
511+ std::map<std::string, std::string> soc_info;
512+ if (platform_info.GetPlatformResWithLock("SoCInfo", soc_info)) {
513+ if (aic_num != 0U) {
514+ soc_info["cube_core_cnt"] = std::to_string(aic_num);
515+ soc_info["ai_core_cnt"] = std::to_string(aic_num);
516+ }
517+ if (aiv_num != 0U) {
518+ soc_info["vector_core_cnt"] = std::to_string(aiv_num);
519+ }
520+ platform_info.SetPlatformResWithLock("SoCInfo", soc_info);
521+ }
522+ platform_info.SetCoreNumByCoreType("AiCore");
523+}
524+ 
525+bool FillRuntimePlatformInfo(const CompileInfo &compile_info, fe::PlatFormInfos &platform_info) {
526+ if (fe::PlatformInfoManager::GeInstance().GetRuntimePlatformInfosByDevice(GetCompileDeviceId(compile_info),
527+ platform_info, true) != 0U) {
528+ return false;
529+ }
530+ UpdatePlatformCoreNum(compile_info, platform_info);
531+ return true;
532+}
533+ 
534+std::string JsonEscape(const std::string &value) {
535+ std::string escaped;
536+ escaped.reserve(value.size());
537+ for (const char ch : value) {
538+ if (ch == '\\' || ch == '"') {
539+ escaped.push_back('\\');
540+ }
541+ escaped.push_back(ch);
542+ }
543+ return escaped;
544+}
545+ 
546+const char *BoolLiteral(bool value) {
547+ return value ? "true" : "false";
548+}
549+ 
550+bool HasIntrinsic(fe::PlatFormInfos &platform_info, const std::string &intrinsic_name) {
551+ std::map<std::string, std::string> intrinsic_res;
552+ if (platform_info.GetPlatformResWithLock("AICoreintrinsicDtypeMap", intrinsic_res) &&
553+ intrinsic_res.find(intrinsic_name) != intrinsic_res.end()) {
554+ return true;
555+ }
556+ auto intrinsic_map = platform_info.GetAICoreIntrinsicDtype();
557+ return intrinsic_map.find(intrinsic_name) != intrinsic_map.end();
558+}
559+ 
560+std::string MakeCubeCompileJson(const CompileInfo &compile_info, fe::PlatFormInfos &platform_info, bool is_batch,
561+ bool transpose_x1, bool transpose_x2, int64_t offset_x, int64_t op_impl_mode,
562+ bool enable_hf32) {
563+ const std::string soc_version =
564+ GetPlatformString(platform_info, "version", "Short_SoC_version", compile_info.soc_version);
565+ const uint32_t core_num = GetPlatformCoreNum(platform_info, "AiCore", "cube_core_cnt");
566+ const uint32_t vector_core_num = GetPlatformCoreNum(platform_info, "VectorCore", "vector_core_cnt");
567+ const uint64_t bt_size = GetPlatformUint64(platform_info, "AICoreSpec", "bt_size");
568+ const uint64_t ub_size = GetLocalMemSize(platform_info, fe::LocalMemType::UB, "AICoreSpec", "ub_size");
569+ const uint64_t l2_size = GetLocalMemSize(platform_info, fe::LocalMemType::L2, "SoCInfo", "l2_size");
570+ const uint64_t l1_size = GetLocalMemSize(platform_info, fe::LocalMemType::L1, "AICoreSpec", "l1_size");
571+ const uint64_t l0a_size = GetLocalMemSize(platform_info, fe::LocalMemType::L0_A, "AICoreSpec", "l0_a_size");
572+ const uint64_t l0b_size = GetLocalMemSize(platform_info, fe::LocalMemType::L0_B, "AICoreSpec", "l0_b_size");
573+ const uint64_t l0c_size = GetLocalMemSize(platform_info, fe::LocalMemType::L0_C, "AICoreSpec", "l0_c_size");
574+ const std::string load3d_constraints =
575+ GetPlatformString(platform_info, "AICoreSpec", "load3d_constraints", "unknown");
576+ std::ostringstream ss;
577+ ss << "{\"_pattern\":\"MatMul\",\"attrs\":{";
578+ ss << "\"transpose_a\":" << BoolLiteral(transpose_x1) << ",";
579+ ss << "\"transpose_b\":" << BoolLiteral(transpose_x2) << ",";
580+ ss << "\"offset_x\":" << offset_x << ",";
581+ ss << (is_batch ? "\"enable_hf32\":" : "\"opImplMode\":") << (is_batch ? (enable_hf32 ? 1 : 0) : op_impl_mode);
582+ ss << "},\"binary_attrs\":{\"bias_flag\":false,\"nd_flag\":true,\"split_k_flag\":false,";
583+ ss << "\"zero_flag\":false,\"weight_nz\":false,\"l2_size\":" << l2_size << "},\"binary_mode_flag\":true,";
584+ ss << "\"block_dim\":{\"CORE_NUM\":" << core_num << ",\"vector_core_cnt\":" << vector_core_num << "},";
585+ ss << "\"corerect_range_flag\":null,\"dynamic_mode\":\"dynamic_mkn\",\"fused_double_operand_num\":0,";
586+ ss << "\"hardware_info\":{\"BT_SIZE\":" << bt_size << ",\"load3d_constraints\":\"" << JsonEscape(load3d_constraints)
587+ << "\",";
588+ ss << "\"Intrinsic_fix_pipe_l0c2out\":" << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_fix_pipe_l0c2out"))
589+ << ",";
590+ ss << "\"Intrinsic_data_move_l12ub\":" << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_data_move_l12ub"))
591+ << ",";
592+ ss << "\"Intrinsic_data_move_l0c2ub\":" << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_data_move_l0c2ub"))
593+ << ",";
594+ ss << "\"Intrinsic_data_move_out2l1_nd2nz\":"
595+ << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_data_move_out2l1_nd2nz")) << ",";
596+ ss << "\"Intrinsic_data_move_l12bt\":" << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_data_move_l12bt"))
597+ << ",";
598+ ss << "\"UB_SIZE\":" << ub_size << ",\"L2_SIZE\":" << l2_size << ",\"L1_SIZE\":" << l1_size << ",";
599+ ss << "\"L0A_SIZE\":" << l0a_size << ",\"L0B_SIZE\":" << l0b_size << ",\"L0C_SIZE\":" << l0c_size << ",";
600+ ss << "\"CORE_NUM\":" << core_num << ",\"vector_core_cnt\":" << vector_core_num << ",";
601+ ss << "\"socVersion\":\"" << JsonEscape(soc_version) << "\"},\"format_a\":\"ND\",\"format_b\":\"ND\",";
602+ ss << "\"repo_range\":{},\"repo_seeds\":{}}";
603+ return ss.str();
604+}
605+ 
606+std::vector<uint32_t> MakeMatMulInputInstanceNum(bool has_bias, bool has_offset_w) {
607+ return {1U, 1U, has_bias ? 1U : 0U, has_offset_w ? 1U : 0U};
608+}
609+ 
610+std::vector<const TensorInfo *> BuildMatMulInputSlots(const std::vector<TensorInfo> &inputs, const MatMulAttrs &attrs) {
611+ std::vector<const TensorInfo *> slots = {&inputs[0], &inputs[1], nullptr, nullptr};
612+ size_t input_index = 2U;
613+ if (attrs.has_bias && input_index < inputs.size()) {
614+ slots[2U] = &inputs[input_index++];
615+ }
616+ if (attrs.has_offset_w && input_index < inputs.size()) {
617+ slots[3U] = &inputs[input_index++];
618+ }
619+ return slots;
620+}
621+ 
622+std::unique_ptr<CompileState> BuildCompileState(const CompileInfo &compile_info, const OpHostSchema &schema,
623+ const OpHostFuncs &funcs, bool is_batch, ge::DataType data_type,
624+ ge::Format format, const MatMulAttrs &attrs,
625+ const std::vector<TensorInfo> &inputs, std::string &error_msg) {
626+ auto state = std::make_unique<CompileState>();
627+ if (!FillRuntimePlatformInfo(compile_info, state->platform_info)) {
628+ error_msg = std::string(schema.op_type) + " platform info setup failed";
629+ return nullptr;
630+ }
631+ state->compile_info_ptr = funcs.compile_info_creator();
632+ if (state->compile_info_ptr == nullptr) {
633+ error_msg = std::string(schema.op_type) + " compile info creation failed";
634+ return nullptr;
635+ }
636+ state->compile_json = MakeCubeCompileJson(compile_info, state->platform_info, is_batch, attrs.transpose_x1,
637+ attrs.transpose_x2, attrs.offset_x, attrs.op_impl_mode, attrs.enable_hf32);
638+ gert::OpTilingParseContextBuilder parse_builder;
639+ const auto input_slots = BuildMatMulInputSlots(inputs, attrs);
640+ auto parse_holder = parse_builder.OpType(schema.op_type)
641+ .OpName(schema.op_type)
642+ .IOInstanceNum(MakeMatMulInputInstanceNum(attrs.has_bias, attrs.has_offset_w),
643+ kSingleOutputInstanceNum)
644+ .InputTensorDesc(0, data_type, format, format)
645+ .InputTensorDesc(1, data_type, format, format)
646+ .InputTensorDesc(2, input_slots[2U] == nullptr ? data_type : DtypeToGeDataType(input_slots[2U]->dtype),
647+ input_slots[2U] == nullptr ? format : FormatToGeFormat(input_slots[2U]->format),
648+ input_slots[2U] == nullptr ? format : FormatToGeFormat(input_slots[2U]->format))
649+ .InputTensorDesc(3,
650+ input_slots[3U] == nullptr ? ge::DT_INT8 : DtypeToGeDataType(input_slots[3U]->dtype),
651+ input_slots[3U] == nullptr ? format : FormatToGeFormat(input_slots[3U]->format),
652+ input_slots[3U] == nullptr ? format : FormatToGeFormat(input_slots[3U]->format))
653+ .OutputTensorDesc(0, data_type, format, format)
654+ .CompiledJson(state->compile_json.c_str())
655+ .CompiledInfo(state->compile_info_ptr)
656+ .PlatformInfo(const_cast<fe::PlatFormInfos *>(&state->platform_info))
657+ .Build();
658+ auto *parse_ctx = reinterpret_cast<gert::KernelContext *>(parse_holder.GetContext());
659+ const auto parse_ret = parse_ctx == nullptr ? ge::GRAPH_FAILED : funcs.tiling_parse(parse_ctx);
660+ if (parse_ctx == nullptr || parse_ret != ge::GRAPH_SUCCESS) {
661+ error_msg = std::string(schema.op_type) + " tiling parse failed";
662+ return nullptr;
663+ }
664+ return state;
665+}
666+ 
667+CompileStateKey MakeCompileStateKey(const CompileInfo &compile_info, bool is_batch, size_t input_num,
668+ const std::vector<TensorInfo> &inputs, const std::string &dtype,
669+ const std::string &format, const MatMulAttrs &attrs) {
670+ std::string input2_dtype;
671+ std::string input3_dtype;
672+ std::string input2_format;
673+ std::string input3_format;
674+ if (inputs.size() > 2U) {
675+ input2_dtype = inputs[2U].dtype;
676+ input2_format = inputs[2U].format;
677+ }
678+ if (inputs.size() > 3U) {
679+ input3_dtype = inputs[3U].dtype;
680+ input3_format = inputs[3U].format;
681+ }
682+ return CompileStateKey{compile_info.soc_version,
683+ compile_info.device_id,
684+ dtype,
685+ format,
686+ input2_dtype,
687+ input3_dtype,
688+ input2_format,
689+ input3_format,
690+ is_batch,
691+ input_num,
692+ attrs.has_bias,
693+ attrs.has_offset_w,
694+ attrs.transpose_x1,
695+ attrs.transpose_x2,
696+ attrs.offset_x,
697+ attrs.op_impl_mode,
698+ attrs.enable_hf32,
699+ compile_info.aicore_num,
700+ compile_info.aiv_num};
701+}
702+ 
703+std::shared_ptr<const CompileState> GetCompileState(const CompileInfo &compile_info, const OpHostSchema &schema,
704+ const OpHostFuncs &funcs, bool is_batch, ge::DataType data_type,
705+ ge::Format format, const MatMulAttrs &attrs,
706+ const std::string &dtype, const std::string &format_name,
707+ const std::vector<TensorInfo> &inputs,
708+ std::string &error_msg) {
709+ const CompileStateKey key = MakeCompileStateKey(compile_info, is_batch, inputs.size(), inputs, dtype, format_name,
710+ attrs);
711+ {
712+ std::lock_guard<std::mutex> lock(GetCompileStateMutex());
713+ auto &cache = GetCompileStateCache();
714+ const auto it = cache.find(key);
715+ if (it != cache.end() && it->second != nullptr) {
716+ return it->second;
717+ }
718+ }
719+ 
720+ auto state = BuildCompileState(compile_info, schema, funcs, is_batch, data_type, format, attrs, inputs, error_msg);
721+ if (state == nullptr) {
722+ return nullptr;
723+ }
724+ 
725+ auto cached_state = std::shared_ptr<const CompileState>(std::move(state));
726+ std::lock_guard<std::mutex> lock(GetCompileStateMutex());
727+ auto &cache_state = GetCompileStateCache()[key];
728+ if (cache_state == nullptr) {
729+ cache_state = std::move(cached_state);
730+ }
731+ return cache_state;
732+}
733+ 
734+void FillShape(gert::Shape &shape, const std::vector<int64_t> &dims) {
735+ shape.SetScalar();
736+ for (const auto dim : dims) {
737+ shape.AppendDim(dim);
738+ }
739+}
740+ 
741+std::vector<int64_t> GetRuntimeShape(const TensorInfo &tensor) {
742+ return tensor.shape.empty() ? tensor.ori_shape : tensor.shape;
743+}
744+ 
745+TilingRequest MakeTilingRequest(const CompileInfo &compile_info, const std::vector<TensorInfo> &inputs,
746+ const std::vector<TensorInfo> &outputs, const std::vector<AttrInfo> &attrs,
747+ bool is_batch) {
748+ const auto &schema = GetOpHostSchema(is_batch);
749+ MatMulAttrs matmul_attrs = ReadMatMulAttrs(attrs, is_batch);
750+ return TilingRequest{compile_info, inputs, outputs, is_batch, schema, matmul_attrs,
751+ DtypeToGeDataType(inputs[0].dtype), FormatToGeFormat(inputs[0].format)};
752+}
753+ 
754+RuntimeTilingKey MakeRuntimeTilingKey(const TilingRequest &request) {
755+ RuntimeTilingKey key;
756+ key.soc_version = request.compile_info.soc_version;
757+ key.device_id = request.compile_info.device_id;
758+ key.op_type = request.schema.op_type == nullptr ? std::string() : request.schema.op_type;
759+ key.input_num = request.inputs.size();
760+ key.has_bias = request.matmul_attrs.has_bias;
761+ key.has_offset_w = request.matmul_attrs.has_offset_w;
762+ if (!request.inputs.empty()) {
763+ key.dtype = request.inputs[0].dtype;
764+ key.format = request.inputs[0].format;
765+ key.input0_shape = GetRuntimeShape(request.inputs[0]);
766+ }
767+ if (request.inputs.size() > 1) {
768+ key.input1_shape = GetRuntimeShape(request.inputs[1]);
769+ }
770+ if (request.inputs.size() > 2) {
771+ key.input2_shape = GetRuntimeShape(request.inputs[2]);
772+ key.input2_dtype = request.inputs[2].dtype;
773+ key.input2_format = request.inputs[2].format;
774+ }
775+ if (request.inputs.size() > 3) {
776+ key.input3_shape = GetRuntimeShape(request.inputs[3]);
777+ key.input3_dtype = request.inputs[3].dtype;
778+ key.input3_format = request.inputs[3].format;
779+ }
780+ if (!request.outputs.empty()) {
781+ key.output_shape = GetRuntimeShape(request.outputs[0]);
782+ }
783+ key.is_batch = request.is_batch;
784+ key.transpose_x1 = request.matmul_attrs.transpose_x1;
785+ key.transpose_x2 = request.matmul_attrs.transpose_x2;
786+ key.offset_x = request.matmul_attrs.offset_x;
787+ key.op_impl_mode = request.matmul_attrs.op_impl_mode;
788+ key.enable_hf32 = request.matmul_attrs.enable_hf32;
789+ key.aicore_num = request.compile_info.aicore_num;
790+ key.aiv_num = request.compile_info.aiv_num;
791+ return key;
792+}
793+ 
794+bool TryGetCachedTilingResult(const RuntimeTilingKey &key, TilingResult *result) {
795+ if (result == nullptr) {
796+ return false;
797+ }
798+ std::lock_guard<std::mutex> lock(GetTilingResultCacheMutex());
799+ const auto &cache = GetTilingResultCache();
800+ const auto it = cache.find(key);
801+ if (it == cache.end() || !it->second.success) {
802+ return false;
803+ }
804+ *result = it->second;
805+ return true;
806+}
807+ 
808+void CacheTilingResult(const RuntimeTilingKey &key, const TilingResult &result) {
809+ if (!result.success) {
810+ return;
811+ }
812+ std::lock_guard<std::mutex> lock(GetTilingResultCacheMutex());
813+ GetTilingResultCache()[key] = result;
814+}
815+ 
816+gert::StorageShape MakeStorageShape(const TensorInfo &tensor) {
817+ gert::StorageShape storage_shape;
818+ const auto runtime_shape = GetRuntimeShape(tensor);
819+ FillShape(storage_shape.MutableOriginShape(), tensor.ori_shape.empty() ? runtime_shape : tensor.ori_shape);
820+ FillShape(storage_shape.MutableStorageShape(), runtime_shape);
821+ return storage_shape;
822+}
823+ 
824+bool ValidateTilingRequest(const CompileInfo *compile_info, const std::vector<TensorInfo> *inputs,
825+ const std::vector<TensorInfo> *outputs, const std::vector<AttrInfo> *attrs,
826+ TilingResult *result) {
827+ return compile_info != nullptr && inputs != nullptr && outputs != nullptr && attrs != nullptr && result != nullptr &&
828+ inputs->size() >= 2 && inputs->size() <= 4 && !outputs->empty();
829+}
830+ 
831+bool IsSupportedTilingTensorDesc(const std::vector<TensorInfo> &inputs, const std::vector<TensorInfo> &outputs,
832+ ge::DataType data_type, ge::Format format) {
833+ if (data_type == ge::DT_UNDEFINED || format == ge::FORMAT_RESERVED || DtypeToGeDataType(outputs[0].dtype) != data_type ||
834+ FormatToGeFormat(outputs[0].format) != format) {
835+ return false;
836+ }
837+ for (const auto &input : inputs) {
838+ if (DtypeToGeDataType(input.dtype) == ge::DT_UNDEFINED || FormatToGeFormat(input.format) == ge::FORMAT_RESERVED) {
839+ return false;
840+ }
841+ }
842+ return DtypeToGeDataType(inputs[1].dtype) == data_type && FormatToGeFormat(inputs[1].format) == format;
843+}
844+ 
845+bool IsOptionalInputSlotsValid(const TilingRequest &request) {
846+ const size_t expected_input_num = 2U + (request.matmul_attrs.has_bias ? 1U : 0U) +
847+ (request.matmul_attrs.has_offset_w ? 1U : 0U);
848+ return request.inputs.size() == expected_input_num;
849+}
850+ 
851+template <typename TilingContext>
852+void FillTilingResultFromContext(TilingContext *tiling_ctx, TilingResult &result) {
853+ auto *raw_tiling_data = tiling_ctx->GetRawTilingData();
854+ const size_t tiling_data_len = raw_tiling_data->GetDataSize();
855+ result.tiling_data.assign(reinterpret_cast<const uint8_t *>(raw_tiling_data->GetData()),
856+ reinterpret_cast<const uint8_t *>(raw_tiling_data->GetData()) + tiling_data_len);
857+ result.tiling_key = static_cast<int64_t>(tiling_ctx->GetTilingKey());
858+ result.block_dim = static_cast<int64_t>(tiling_ctx->GetBlockDim());
859+ const size_t workspace_num = tiling_ctx->GetWorkspaceNum();
860+ auto *workspace_sizes = workspace_num > 0 ? tiling_ctx->GetWorkspaceSizes(workspace_num) : nullptr;
861+ result.workspace_size = workspace_sizes == nullptr ? 0 : static_cast<int64_t>(workspace_sizes[0]);
862+ result.success = true;
863+}
864+ 
865+uint32_t PositiveOrDefault(int64_t value, uint32_t default_value) {
866+ return value > 0 ? static_cast<uint32_t>(value) : default_value;
867+}
868+ 
869+template <typename T>
870+bool CopyExactTilingData(const TilingResult &result, const size_t tiling_data_len, T &tiling_data) {
871+ if (tiling_data_len != sizeof(T)) {
872+ return false;
873+ }
874+ std::memcpy(&tiling_data, result.tiling_data.data(), sizeof(T));
875+ return true;
876+}
877+ 
878+void FillMetaFromBasicTiling(TilingResult &result, const MatMulV3BasicTilingData &tiling_data) {
879+ result.matmul_basic_tiling_data = tiling_data;
880+ result.cube_used_core_num = std::max(tiling_data.usedCoreNum, 1U);
881+ result.cube_base_m = std::max(tiling_data.baseM, 1U);
882+ result.cube_base_n = std::max(tiling_data.baseN, 1U);
883+}
884+ 
885+void FillMetaFromBatchBasicTiling(TilingResult &result, const BatchMatMulV3BasicTilingData &tiling_data) {
886+ result.batch_matmul_tiling_data = tiling_data;
887+ FillMetaFromBasicTiling(result, tiling_data.matMulTilingData);
888+}
889+ 
890+void FillMetaFromTCubeTiling(TilingResult &result, const TCubeTiling &tiling_data) {
891+ result.cube_used_core_num = PositiveOrDefault(tiling_data.usedCoreNum, 1U);
892+ result.cube_base_m = PositiveOrDefault(tiling_data.baseM, 1U);
893+ result.cube_base_n = PositiveOrDefault(tiling_data.baseN, 1U);
894+}
895+ 
896+void FillBatchTilingMeta(TilingResult &result, const size_t tiling_data_len) {
897+ BatchMatMulV3BasicTilingData batch_basic_tiling_data = {};
898+ if (CopyExactTilingData(result, tiling_data_len, batch_basic_tiling_data)) {
899+ FillMetaFromBatchBasicTiling(result, batch_basic_tiling_data);
900+ return;
901+ }
902+ BatchMatMulV3TilingData batch_tiling_data = {};
903+ if (CopyExactTilingData(result, tiling_data_len, batch_tiling_data)) {
904+ FillMetaFromTCubeTiling(result, batch_tiling_data.matMulTilingData.tCubeTiling);
905+ return;
906+ }
907+ BatchMatMulV3IterBatchBasicTilingData iter_batch_tiling_data = {};
908+ if (CopyExactTilingData(result, tiling_data_len, iter_batch_tiling_data)) {
909+ result.cube_base_m = std::max(iter_batch_tiling_data.baseM, 1U);
910+ result.cube_base_n = std::max(iter_batch_tiling_data.baseN, 1U);
911+ return;
912+ }
913+ BatchMatMulToMulBasicTilingData batch_to_mul_tiling_data = {};
914+ if (CopyExactTilingData(result, tiling_data_len, batch_to_mul_tiling_data)) {
915+ result.cube_used_core_num = std::max(batch_to_mul_tiling_data.usedCoreNum, 1U);
916+ return;
917+ }
918+ BatchMatMulV3MergeBatchBasicTilingData merge_batch_tiling_data = {};
919+ (void)CopyExactTilingData(result, tiling_data_len, merge_batch_tiling_data);
920+}
921+ 
922+void FillMatMulTilingMeta(TilingResult &result, const size_t tiling_data_len) {
923+ MatMulV3BasicTilingData basic_tiling_data = {};
924+ if (CopyExactTilingData(result, tiling_data_len, basic_tiling_data)) {
925+ FillMetaFromBasicTiling(result, basic_tiling_data);
926+ return;
927+ }
928+ MatMulV3TilingDataCopy tiling_data_copy = {};
929+ if (CopyExactTilingData(result, tiling_data_len, tiling_data_copy)) {
930+ FillMetaFromTCubeTiling(result, tiling_data_copy.matMulTilingData.tCubeTiling);
931+ return;
932+ }
933+ MatMulV3TilingData tiling_data = {};
934+ if (CopyExactTilingData(result, tiling_data_len, tiling_data)) {
935+ FillMetaFromTCubeTiling(result, tiling_data.tCubeTiling);
936+ return;
937+ }
938+ MatMulToMulBasicTilingData to_mul_tiling_data = {};
939+ if (CopyExactTilingData(result, tiling_data_len, to_mul_tiling_data)) {
940+ result.cube_used_core_num = std::max(to_mul_tiling_data.usedCoreNum, 1U);
941+ if (to_mul_tiling_data.baseMN > 0) {
942+ result.cube_base_m = 1U;
943+ result.cube_base_n = to_mul_tiling_data.baseMN;
944+ }
945+ return;
946+ }
947+ MatMulV3KEqZeroBasicTilingData k_eq_zero_tiling_data = {};
948+ (void)CopyExactTilingData(result, tiling_data_len, k_eq_zero_tiling_data);
949+}
950+ 
951+void FillTilingMeta(TilingResult &result, bool is_batch) {
952+ const size_t tiling_data_len = result.tiling_data.size();
953+ if (is_batch) {
954+ FillBatchTilingMeta(result, tiling_data_len);
955+ return;
956+ }
957+ FillMatMulTilingMeta(result, tiling_data_len);
958+}
959+ 
960+template <typename RunTiling>
961+bool BuildTilingContext(const TilingRequest &request, const CompileState &compile_state, gert::TilingData *tiling_data,
962+ gert::ContinuousVector *workspace, const std::vector<gert::Tensor *> &input_tensors,
963+ const std::vector<gert::Tensor *> &output_tensors, RunTiling run_tiling) {
964+ gert::OpTilingContextBuilder tiling_builder;
965+ auto tiling_holder =
966+ request.is_batch ? tiling_builder.OpType(request.schema.op_type)
967+ .OpName(request.schema.op_type)
968+ .IOInstanceNum(MakeMatMulInputInstanceNum(request.matmul_attrs.has_bias,
969+ request.matmul_attrs.has_offset_w),
970+ kSingleOutputInstanceNum)
971+ .AppendAttr(request.matmul_attrs.transpose_x1)
972+ .AppendAttr(request.matmul_attrs.transpose_x2)
973+ .AppendAttr(request.matmul_attrs.offset_x)
974+ .AppendAttr(request.matmul_attrs.enable_hf32)
975+ .CompileInfo(compile_state.compile_info_ptr)
976+ .PlatformInfo(const_cast<fe::PlatFormInfos *>(&compile_state.platform_info))
977+ .TilingData(tiling_data)
978+ .Workspace(workspace)
979+ .InputTensors(input_tensors)
980+ .OutputTensors(output_tensors)
981+ .Build()
982+ : tiling_builder.OpType(request.schema.op_type)
983+ .OpName(request.schema.op_type)
984+ .IOInstanceNum(MakeMatMulInputInstanceNum(request.matmul_attrs.has_bias,
985+ request.matmul_attrs.has_offset_w),
986+ kSingleOutputInstanceNum)
987+ .AppendAttr(request.matmul_attrs.transpose_x1)
988+ .AppendAttr(request.matmul_attrs.transpose_x2)
989+ .AppendAttr(request.matmul_attrs.offset_x)
990+ .AppendAttr(request.matmul_attrs.op_impl_mode)
991+ .CompileInfo(compile_state.compile_info_ptr)
992+ .PlatformInfo(const_cast<fe::PlatFormInfos *>(&compile_state.platform_info))
993+ .TilingData(tiling_data)
994+ .Workspace(workspace)
995+ .InputTensors(input_tensors)
996+ .OutputTensors(output_tensors)
997+ .Build();
998+ return run_tiling(tiling_holder.GetContext());
999+}
1000+ 
1001+bool RunSharedCubeTiling(const TilingRequest &request, TilingResult &result) {
1002+ const RuntimeTilingKey runtime_key = MakeRuntimeTilingKey(request);
1003+ if (TryGetCachedTilingResult(runtime_key, &result)) {
1004+ return true;
1005+ }
1006+ 
1007+ const char *op_type = request.schema.op_type;
1008+ const auto &cached_funcs = GetOpHostFuncs(request.is_batch, op_type);
1009+ if (!cached_funcs.loaded) {
1010+ result.error_msg = std::string(op_type) + " shared op_host registry lookup failed";
1011+ return false;
1012+ }
1013+ 
1014+ const auto &funcs = cached_funcs.funcs;
1015+ auto compile_state = GetCompileState(request.compile_info, request.schema, funcs, request.is_batch, request.data_type,
1016+ request.format, request.matmul_attrs, request.inputs[0].dtype,
1017+ request.inputs[0].format, request.inputs, result.error_msg);
1018+ if (compile_state == nullptr) {
1019+ return false;
1020+ }
1021+ 
1022+ const size_t tiling_data_capacity = std::max(funcs.max_tiling_data_size, kMaxTilingDataSize);
1023+ auto &scratch = GetTilingScratch();
1024+ if (!scratch.EnsureCapacity(tiling_data_capacity, result.error_msg, op_type)) {
1025+ return false;
1026+ }
1027+ auto *tiling_data = scratch.MutableTilingData();
1028+ auto *workspace = scratch.MutableWorkspace();
1029+ tiling_data->SetDataSize(0UL);
1030+ (void)workspace->SetSize(0UL);
1031+ 
1032+ gert::StorageFormat storage_format(request.format, request.format, {});
1033+ std::vector<gert::Tensor> input_tensors_storage;
1034+ const auto input_slots = BuildMatMulInputSlots(request.inputs, request.matmul_attrs);
1035+ input_tensors_storage.reserve(input_slots.size());
1036+ scratch.input_tensors.clear();
1037+ for (const auto *input : input_slots) {
1038+ if (input == nullptr) {
1039+ continue;
1040+ }
1041+ ge::Format input_format = FormatToGeFormat(input->format);
1042+ gert::StorageFormat input_storage_format(input_format, input_format, {});
1043+ input_tensors_storage.emplace_back(MakeStorageShape(*input), input_storage_format, DtypeToGeDataType(input->dtype));
1044+ scratch.input_tensors.push_back(&input_tensors_storage.back());
1045+ }
1046+ std::array<gert::Tensor, 1> output_tensors_storage = {
1047+ gert::Tensor(MakeStorageShape(request.outputs[0]), storage_format, request.data_type)};
1048+ scratch.output_tensors.clear();
1049+ scratch.output_tensors.push_back(&output_tensors_storage[0]);
1050+ 
1051+ const bool tiling_ok = BuildTilingContext(
1052+ request, *compile_state, tiling_data, workspace, scratch.input_tensors, scratch.output_tensors,
1053+ [&](auto *tiling_ctx) {
1054+ if (tiling_ctx == nullptr) {
1055+ result.error_msg = std::string(op_type) + " shared tiling context build failed";
1056+ return false;
1057+ }
1058+ if (funcs.tiling(tiling_ctx) != ge::GRAPH_SUCCESS) {
1059+ result.error_msg = std::string(op_type) + " shared tiling call failed";
1060+ return false;
1061+ }
1062+ if (tiling_ctx->GetRawTilingData() == nullptr || tiling_ctx->GetRawTilingData()->GetDataSize() == 0) {
1063+ result.error_msg = std::string(op_type) + " shared tiling returned empty data";
1064+ return false;
1065+ }
1066+ FillTilingResultFromContext(tiling_ctx, result);
1067+ return true;
1068+ });
1069+ if (!tiling_ok) {
1070+ return false;
1071+ }
1072+ CacheTilingResult(runtime_key, result);
1073+ return true;
1074+}
1075+ 
1076+} // namespace
1077+ 
1078+extern "C" bool AutofuseDoCubeMatMulTiling(const ge::autofuse::CompileInfo *compile_info,
1079+ const std::vector<ge::autofuse::TensorInfo> *inputs,
1080+ const std::vector<ge::autofuse::TensorInfo> *outputs,
1081+ const std::vector<ge::autofuse::AttrInfo> *attrs, bool is_batch,
1082+ ge::autofuse::TilingResult *result) {
1083+ using namespace ge::autofuse;
1084+ if (!ValidateTilingRequest(compile_info, inputs, outputs, attrs, result)) {
1085+ return false;
1086+ }
1087+ const TilingRequest request = MakeTilingRequest(*compile_info, *inputs, *outputs, *attrs, is_batch);
1088+ if (!IsOptionalInputSlotsValid(request)) {
1089+ return false;
1090+ }
1091+ if (!IsSupportedTilingTensorDesc(*inputs, *outputs, request.data_type, request.format)) {
1092+ return false;
1093+ }
1094+ return RunSharedCubeTiling(request, *result);
1095+}
1096+ 
950CubeKernelTilingWrapper::CubeKernelTilingWrapper() {}1097CubeKernelTilingWrapper::CubeKernelTilingWrapper() {}
951 1098 
952CubeKernelTilingWrapper::~CubeKernelTilingWrapper() {}1099CubeKernelTilingWrapper::~CubeKernelTilingWrapper() {}
953 1100 
954-void CubeKernelTilingWrapper::BuildMatMulArgs(const std::vector<TensorInfo>& args_list,1101+void CubeKernelTilingWrapper::BuildMatMulArgs(const std::vector<TensorInfo> &args_list, int input_num,
955- int input_num,1102+ bool transpose_a, bool transpose_b,
956- bool transpose_a,1103+ std::vector<TensorInfo> &origin_inputs,
957- bool transpose_b,1104+ std::vector<TensorInfo> &origin_outputs,
958- std::vector<TensorInfo>& origin_inputs,1105+ std::vector<TensorInfo> &inputs) {
959- std::vector<TensorInfo>& origin_outputs,1106+ origin_inputs.clear();
960- std::vector<TensorInfo>& inputs) {1107+ origin_outputs.clear();
961- origin_inputs.clear();1108+ inputs.clear();
962- origin_outputs.clear();
963- inputs.clear();
964 1109 
965- int64_t m = 0;1110+ int64_t m = 0;
966- int64_t n = 0;1111+ int64_t n = 0;
967- std::vector<int64_t> write_shape;1112+ std::vector<int64_t> write_shape;
968 1113 
969- for (int i = 0; i < input_num && i < static_cast<int>(args_list.size()); ++i) {1114+ for (int i = 0; i < input_num && i < static_cast<int>(args_list.size()); ++i) {
970- TensorInfo input = args_list[i];1115+ TensorInfo input = args_list[i];
971- input.param_name = "input" + std::to_string(i);1116+ input.param_name = "input" + std::to_string(i);
972- input.ori_shape = input.shape;1117+ input.ori_shape = input.shape;
973 1118 
974- origin_inputs.push_back(input);1119+ origin_inputs.push_back(input);
975- inputs.push_back(input);1120+ inputs.push_back(input);
976 1121 
977- if (i == 0) {1122+ if (i == 0) {
978- write_shape = input.shape;1123+ write_shape = input.shape;
979- if (transpose_a) {1124+ m = transpose_a ? input.shape[input.shape.size() - 1] : input.shape[input.shape.size() - 2];
980- m = input.shape[input.shape.size() - 1];1125+ } else if (i == 1) {
981- } else {1126+ n = transpose_b ? input.shape[input.shape.size() - 2] : input.shape[input.shape.size() - 1];
982- m = input.shape[input.shape.size() - 2];
983- }
984- } else if (i == 1) {
985- if (transpose_b) {
986- n = input.shape[input.shape.size() - 2];
987- } else {
988- n = input.shape[input.shape.size() - 1];
989- }
990- }
991 }1127 }
1128+ }
992 1129 
993- if (args_list.size() >= 2) {1130+ if (args_list.size() >= 2) {
994- TensorInfo output = args_list[args_list.size() - 2];1131+ TensorInfo output = args_list[args_list.size() - 2];
995- output.param_name = "output0";1132+ output.param_name = "output0";
996- if (!write_shape.empty()) {1133+ if (!write_shape.empty()) {
997- write_shape[write_shape.size() - 1] = n;1134+ write_shape[write_shape.size() - 1] = n;
998- write_shape[write_shape.size() - 2] = m;1135+ write_shape[write_shape.size() - 2] = m;
999- output.shape = write_shape;1136+ output.shape = write_shape;
1000- output.ori_shape = write_shape;1137+ output.ori_shape = write_shape;
1001- }
1002- if (!inputs.empty()) {
1003- output.dtype = inputs.back().dtype;
1004- }
1005- origin_outputs.push_back(output);
1006 }1138 }
1139+ if (!inputs.empty()) {
1140+ output.dtype = inputs.back().dtype;
1141+ }
1142+ origin_outputs.push_back(output);
1143+ }
1007}1144}
1008 1145 
1009-std::string CubeKernelTilingWrapper::SerializeToJson(const CompileInfo& compile_info) {1146+TilingResult CubeKernelTilingWrapper::DoMatMulTiling(const CompileInfo &compile_info,
1010- json j;1147+ const std::vector<TensorInfo> &inputs,
1011- j["soc_version"] = compile_info.soc_version;1148+ const std::vector<TensorInfo> &outputs,
1012- j["core_type"] = compile_info.core_type;1149+ const std::vector<AttrInfo> &attrs, bool is_batch) {
1013- j["device_id"] = compile_info.device_id;1150+ TilingResult result;
1014- j["op_kernel_lib"] = compile_info.op_kernel_lib;1151+ if (AutofuseDoCubeMatMulTiling(&compile_info, &inputs, &outputs, &attrs, is_batch, &result)) {
1015- j["op_impl_mode"] = compile_info.op_impl_mode;1152+ FillTilingMeta(result, is_batch);
1016- j["aicore_num"] = compile_info.aicore_num;1153+ } else {
1017- j["aiv_num"] = compile_info.aiv_num;1154+ result.success = false;
1018- 1155+ if (result.error_msg.empty()) {
1019- if (!compile_info.extra_info.empty()) {1156+ result.error_msg = "codegen shared MatMulV3 tiling failed";
1020- json extra;
1021- for (const auto& pair : compile_info.extra_info) {
1022- extra[pair.first] = pair.second;
1023- }
1024- j["extra_info"] = extra;
1025 }1157 }
1026- 1158+ }
1027- return j.dump();1159+ return result;
1028}1160}
1029 1161 
1030-std::string CubeKernelTilingWrapper::SerializeToJson(const std::vector<TensorInfo>& tensors) {1162+} // namespace autofuse
1031- json j = json::array();1163+} // namespace ge
1032- for (const auto& tensor : tensors) {
1033- json t;
1034- t["param_name"] = tensor.param_name;
1035- t["shape"] = tensor.shape;
1036- t["ori_shape"] = tensor.ori_shape;
1037- t["dtype"] = tensor.dtype;
1038- t["format"] = tensor.format;
1039- t["name"] = tensor.name;
1040- t["range_start"] = tensor.range_start;
1041- t["range_end"] = tensor.range_end;
1042- j.push_back(t);
1043- }
1044- return j.dump();
1045-}
1046- 
1047-std::string CubeKernelTilingWrapper::SerializeToJson(const std::vector<AttrInfo>& attrs) {
1048- json j = json::array();
1049- for (const auto& attr : attrs) {
1050- json a;
1051- a["name"] = attr.name;
1052- a["dtype"] = attr.dtype;
1053- 
1054- if (attr.is_list) {
1055- if (attr.dtype == "list_int" || attr.dtype == "list_int32") {
1056- a["value"] = attr.value_list_int;
1057- } else if (attr.dtype == "list_float" || attr.dtype == "list_float32") {
1058- a["value"] = attr.value_list_float;
1059- } else if (attr.dtype == "list_str") {
1060- a["value"] = attr.value_list_str;
1061- }
1062- } else {
1063- if (attr.dtype == "bool") {
1064- a["value"] = attr.value_bool;
1065- } else if (attr.dtype == "int" || attr.dtype == "int32" || attr.dtype == "int64") {
1066- a["value"] = attr.value_int;
1067- } else if (attr.dtype == "float" || attr.dtype == "float32" || attr.dtype == "float64") {
1068- a["value"] = attr.value_float;
1069- } else {
1070- a["value"] = attr.value_str;
1071- }
1072- }
1073- j.push_back(a);
1074- }
1075- return j.dump();
1076-}
1077- 
1078-std::string CubeKernelTilingWrapper::SerializeToJson(const std::map<std::string, std::string>& extra_params) {
1079- json j;
1080- for (const auto& pair : extra_params) {
1081- j[pair.first] = pair.second;
1082- }
1083- return j.dump();
1084-}
1085- 
1086-std::string CubeKernelTilingWrapper::GenerateCompileInfoHash(const std::string& compile_info_json) {
1087- return SHA1::Hash(compile_info_json);
1088-}
1089- 
1090-void CubeKernelTilingWrapper::ChangeParamNameToName(std::vector<TensorInfo>& inputs) {
1091- for (auto& input : inputs) {
1092- if (input.name.empty() && !input.param_name.empty()) {
1093- input.name = input.param_name;
1094- }
1095- }
1096-}
1097- 
1098-void CubeKernelTilingWrapper::InputsPreProcess(std::vector<TensorInfo>& inputs) {
1099- for (auto& input : inputs) {
1100- if (input.range_start != 0 || input.range_end != 0) {
1101- if (input.range_start == std::numeric_limits<int64_t>::min() ||
1102- input.range_start == std::numeric_limits<int64_t>::max()) {
1103- input.range_start = 0;
1104- }
1105- if (input.range_end == std::numeric_limits<int64_t>::min() ||
1106- input.range_end == std::numeric_limits<int64_t>::max()) {
1107- input.range_end = 0;
1108- }
1109- }
1110- }
1111-}
1112- 
1113-void CubeKernelTilingWrapper::AttrsPreProcess(std::vector<AttrInfo>& attrs) {
1114- for (auto& attr : attrs) {
1115- if (attr.dtype == "float" || attr.dtype == "float32" || attr.dtype == "float64") {
1116- if (!attr.is_list) {
1117- if (std::isinf(attr.value_float)) {
1118- if (attr.value_float > 0) {
1119- attr.value_str = "float(1.0 / 0.0) ";
1120- } else {
1121- attr.value_str = "float(-1.0 / 0.0) ";
1122- }
1123- } else if (std::isnan(attr.value_float)) {
1124- attr.value_str = "float(0.0 / 0.0) ";
1125- }
1126- } else {
1127- for (auto& val : attr.value_list_float) {
1128- if (std::isinf(val)) {
1129- if (val > 0) {
1130- val = std::numeric_limits<double>::max();
1131- } else {
1132- val = std::numeric_limits<double>::min();
1133- }
1134- } else if (std::isnan(val)) {
1135- val = 0.0;
1136- }
1137- }
1138- }
1139- } else if (attr.dtype == "list_float" || attr.dtype == "list_float32") {
1140- for (auto& val : attr.value_list_float) {
1141- if (std::isinf(val)) {
1142- if (val > 0) {
1143- val = std::numeric_limits<double>::max();
1144- } else {
1145- val = std::numeric_limits<double>::min();
1146- }
1147- } else if (std::isnan(val)) {
1148- val = 0.0;
1149- }
1150- }
1151- }
1152- }
1153-}
1154- 
1155-std::vector<uint8_t> CubeKernelTilingWrapper::AlignTilingDataTo8Bytes(const std::vector<uint8_t>& tiling_data, const std::string& soc_version) {
1156- size_t original_size = tiling_data.size();
1157- std::vector<uint8_t> aligned_data = tiling_data;
1158- 
1159- if (soc_version == "Ascend310P") {
1160- return aligned_data;
1161- }
1162- 
1163- size_t aligned_size = ((original_size + 7) / 8) * 8;
1164- size_t padding_size = aligned_size - original_size;
1165- 
1166- aligned_data.resize(aligned_size, 0);
1167- 
1168- return aligned_data;
1169-}
1170- 
1171-bool CubeKernelTilingWrapper::ParseTilingResult(const std::string& json_str, TilingResult& result) {
1172- try {
1173- json j = json::parse(json_str);
1174- 
1175- if (j.contains("ret_code") && j["ret_code"].get_int64() != 0) {
1176- result.success = false;
1177- if (j.contains("error_messages") && j["error_messages"].is_array()) {
1178- for (size_t i = 0; i < j["error_messages"].size(); ++i) {
1179- const auto& err = j["error_messages"][i];
1180- if (err.contains("errormsg")) {
1181- result.error_msg += err["errormsg"].get_string() + "; ";
1182- }
1183- }
1184- }
1185- return false;
1186- }
1187- result.success = true;
1188- return true;
1189- } catch (const std::exception& e) {
1190- result.success = false;
1191- result.error_msg = std::string("Parse JSON failed: ") + e.what();
1192- return false;
1193- }
1194-}
1195- 
1196-char* CubeKernelTilingWrapper::CallDoOpTilingForCompile(const char* op_type,
1197- const char* compile_info,
1198- const char* compile_info_hash,
1199- const char* inputs,
1200- const char* outputs,
1201- const char* attrs,
1202- char* buf,
1203- size_t buf_size,
1204- uint64_t* timer,
1205- const char* extra_params) {
1206- fe::PlatFormInfos platform_infos;
1207- fe::OptionalInfos q;
1208- const char* soc_name = aclrtGetSocName();
1209- std::string soc_ver = soc_name ? soc_name : "";
1210- q.Init();
1211- q.SetSocVersion(soc_ver);
1212- fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(q); // 这两个SetOptionalCompilationInfo都得有
1213- fe::PlatformInfoManager::GeInstance().SetOptionalCompilationInfo(q); // 否则获取soc version失败tiling计算出错
1214- fe::PlatformInfoManager::GeInstance().InitRuntimePlatformInfos(soc_ver);
1215- int32_t device_id = 0;
1216- aclrtGetDevice(&device_id);
1217- if (fe::PlatformInfoManager::GeInstance().GetRuntimePlatformInfosByDevice(device_id, platform_infos) != 0) {
1218- OP_LOGE(OP_NAME, "GetRuntimePlatformInfosByDevice failed");
1219- return nullptr;
1220- }
1221- OP_LOGI(OP_NAME, "Calling DoOpTilingForCompile...");
1222- const char* result = DoOpTilingForCompile(op_type, compile_info, compile_info_hash,
1223- inputs, outputs, attrs, buf, buf_size, timer, extra_params);
1224- OP_LOGI(OP_NAME, "DoOpTilingForCompile returned");
1225- 
1226- return const_cast<char*>(result);
1227-}
1228- 
1229-TilingResult CubeKernelTilingWrapper::DoMatMulTiling(const CompileInfo& compile_info,
1230- const std::vector<TensorInfo>& inputs,
1231- const std::vector<TensorInfo>& outputs,
1232- const std::vector<AttrInfo>& attrs,
1233- bool is_batch) {
1234- TilingResult result;
1235- 
1236- std::vector<TensorInfo> processed_inputs = inputs;
1237- std::vector<AttrInfo> processed_attrs = attrs;
1238- 
1239- ChangeParamNameToName(processed_inputs);
1240- InputsPreProcess(processed_inputs);
1241- AttrsPreProcess(processed_attrs);
1242- 
1243- std::string compile_info_json = SerializeToJson(compile_info);
1244- std::string inputs_json = SerializeToJson(processed_inputs);
1245- std::string outputs_json = SerializeToJson(outputs);
1246- std::string attrs_json = SerializeToJson(processed_attrs);
1247- 
1248- std::string compile_info_hash = GenerateCompileInfoHash(compile_info_json);
1249- 
1250- json extra_params;
1251- extra_params["op_name"] = is_batch ? "BatchMatMulV3" : "MatMulV3";
1252- extra_params["deterministic"] = false;
1253- std::string extra_params_json = extra_params.dump();
1254- 
1255- std::string op_type = is_batch ? "BatchMatMulV3" : "MatMulV3";
1256- 
1257- const size_t buf_size = 1024 * 64;
1258- std::vector<char> buf(buf_size, 0);
1259- 
1260- char* ret = CallDoOpTilingForCompile(op_type.c_str(),
1261- compile_info_json.c_str(),
1262- compile_info_hash.c_str(),
1263- inputs_json.c_str(),
1264- outputs_json.c_str(),
1265- attrs_json.c_str(),
1266- buf.data(),
1267- buf_size,
1268- nullptr,
1269- extra_params_json.c_str());
1270- 
1271- if (ret == nullptr) {
1272- result.success = false;
1273- result.error_msg = "DoOpTilingForCompile returned nullptr";
1274- return (result);
1275- }
1276- 
1277- std::string ret_json(ret);
1278- ParseTilingResult(ret_json, result);
1279- 
1280- if (result.success) {
1281- std::string buf_json(buf.data());
1282- json j = json::parse(buf_json);
1283- if (j.contains("tiling_data")) {
1284- std::string hex_str = j["tiling_data"].get_string();
1285- result.tiling_data.clear();
1286- for (size_t i = 0; i < hex_str.length(); i += 2) {
1287- std::string byte_str = hex_str.substr(i, 2);
1288- result.tiling_data.push_back(static_cast<uint8_t>(std::stoul(byte_str, nullptr, 16)));
1289- }
1290- 
1291- result.tiling_data = AlignTilingDataTo8Bytes(result.tiling_data, compile_info.soc_version);
1292- 
1293- if (result.tiling_data.size() >= sizeof(MatMulV3BasicTilingData)) {
1294- memcpy(&result.matmul_basic_tiling_data, result.tiling_data.data(), sizeof(MatMulV3BasicTilingData));
1295- result.cube_used_core_num = std::max(result.matmul_basic_tiling_data.usedCoreNum, 1U);
1296- result.cube_base_m = std::max(result.matmul_basic_tiling_data.baseM, 1U);
1297- result.cube_base_n = std::max(result.matmul_basic_tiling_data.baseN, 1U);
1298- }
1299- if (result.tiling_data.size() >= sizeof(BatchMatMulV3BasicTilingData)) {
1300- memcpy(&result.batch_matmul_tiling_data, result.tiling_data.data(), sizeof(BatchMatMulV3BasicTilingData));
1301- if (is_batch) {
1302- result.cube_used_core_num = std::max(result.batch_matmul_tiling_data.matMulTilingData.usedCoreNum, 1U);
1303- result.cube_base_m = std::max(result.batch_matmul_tiling_data.matMulTilingData.baseM, 1U);
1304- result.cube_base_n = std::max(result.batch_matmul_tiling_data.matMulTilingData.baseN, 1U);
1305- }
1306- }
1307- }
1308- if (j.contains("tiling_key")) {
1309- result.tiling_key = j["tiling_key"].get_int64();
1310- }
1311- if (j.contains("block_dim")) {
1312- result.block_dim = j["block_dim"].get_int64();
1313- }
1314- if (j.contains("workspaces")) {
1315- result.workspace_size = j["workspaces"][0].get_int64();
1316- }
1317- if (j.contains("clear_atomic")) {
1318- result.atomic_flag = j["clear_atomic"].get_bool();
1319- }
1320- }
1321- 
1322- return result;
1323-}
1324- 
1325-} // namespace autofuse
1326-} // namespace ge
1327 1164 
1328)";1165)";
Mautofuse/codegen/codegen_tiling_data.cpp+1-0
@@ -10,6 +10,7 @@
10 10 
11#include "codegen_tiling_data.h"11#include "codegen_tiling_data.h"
12#include <sstream>12#include <sstream>
13+#include <iomanip>
13 14 
14#include "common_utils.h"15#include "common_utils.h"
15#include "common/ge_common/debug/log.h"16#include "common/ge_common/debug/log.h"
Mautofuse/compiler/python/ascendc_compile.py+157-9
@@ -39,6 +39,11 @@ CV_HOST_LINK_LIBRARIES = HOST_LINK_LIBRARIES + ["nnopbase"]
39INDUCTOR_COMPILE_TRACE_LABEL = "InductorCompile"39INDUCTOR_COMPILE_TRACE_LABEL = "InductorCompile"
40HOST_COMPILE_MAX_WORKERS = 3240HOST_COMPILE_MAX_WORKERS = 32
41HOST_CPP_STANDARD = "-std=c++17"41HOST_CPP_STANDARD = "-std=c++17"
42+CV_WRAPPER_SOURCE_NAME = "cube_kernel_tiling_wrapper.cpp"
43+CV_WRAPPER_SPLIT_KEY = "BCubeKernelTilingWrapperCpp"
44+CV_WRAPPER_CACHE_DIR_NAME = "cv_tiling_wrapper_cache"
45+CV_WRAPPER_SO_BASENAME = "libautofuse_cv_tiling_wrapper"
46+CV_WRAPPER_RPATH_OPTION = f"-Wl,-rpath,$ORIGIN/{CV_WRAPPER_CACHE_DIR_NAME}"
42PGO_BUNDLE_SCHEMA_VERSION = 147PGO_BUNDLE_SCHEMA_VERSION = 1
43PGO_RESULT_PROTOCOL_VERSION = 148PGO_RESULT_PROTOCOL_VERSION = 1
44PGO_KERNEL_FORMAT = "aicore_binary_elf_v1"49PGO_KERNEL_FORMAT = "aicore_binary_elf_v1"
@@ -185,10 +190,12 @@ def run_compile_command(cmd: List[str], stage_name):
185 print(f"[{stage_name}] {result.stdout}")190 print(f"[{stage_name}] {result.stdout}")
186 191 
187 192 
188-def link_shared(target_file, obj_files, link_libraries=None):193+def link_shared(target_file, obj_files, link_libraries=None, extra_link_options=None):
189 link_command = [f"{ASCEND_PATH}/tools/bisheng_compiler/bin/bisheng"]194 link_command = [f"{ASCEND_PATH}/tools/bisheng_compiler/bin/bisheng"]
190 link_command.extend(obj_files)195 link_command.extend(obj_files)
191 link_command.extend(["-fPIC", "--shared", "-o", target_file])196 link_command.extend(["-fPIC", "--shared", "-o", target_file])
197+ if extra_link_options:
198+ link_command.extend(extra_link_options)
192 if link_libraries:199 if link_libraries:
193 link_command.extend(["-L", f"{ASCEND_PATH}/lib64"])200 link_command.extend(["-L", f"{ASCEND_PATH}/lib64"])
194 link_command.extend(["-L", f"{ASCEND_PATH}/{machine}-linux/lib64"])201 link_command.extend(["-L", f"{ASCEND_PATH}/{machine}-linux/lib64"])
@@ -197,6 +204,115 @@ def link_shared(target_file, obj_files, link_libraries=None):
197 return target_file204 return target_file
198 205 
199 206 
207+def is_cv_wrapper_source(source_file):
208+ base_name = os.path.basename(source_file)
209+ return base_name == CV_WRAPPER_SOURCE_NAME or base_name.endswith(
210+ f"_tiling_func_{CV_WRAPPER_SPLIT_KEY}.cpp"
211+ )
212+ 
213+ 
214+def get_shared_cv_wrapper_cache_dir(args: argparse.Namespace, temp_dir):
215+ output_file = getattr(args, "output_file", None)
216+ output_file_dir = (
217+ os.path.dirname(os.path.realpath(output_file)) if output_file else None
218+ )
219+ cache_root = (
220+ temp_dir
221+ or output_file_dir
222+ or os.getenv("RUN_DIR")
223+ or os.getenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR")
224+ )
225+ return os.path.join(os.path.realpath(cache_root), CV_WRAPPER_CACHE_DIR_NAME)
226+ 
227+ 
228+def read_file_bytes(file_path):
229+ with open(file_path, "rb") as f:
230+ return f.read()
231+ 
232+ 
233+def get_shared_cv_wrapper_so_path(args: argparse.Namespace, temp_dir, source_file):
234+ digest = hashlib.sha256()
235+ digest.update(read_file_bytes(source_file))
236+ digest.update(str(ASCEND_PATH).encode("utf-8"))
237+ digest.update(str(machine).encode("utf-8"))
238+ digest.update(str(getattr(args, "soc_version", "")).encode("utf-8"))
239+ digest.update(str(getattr(args, "compile_options", "")).encode("utf-8"))
240+ digest.update(str(getattr(args, "stage", "")).encode("utf-8"))
241+ so_name = f"{CV_WRAPPER_SO_BASENAME}_{digest.hexdigest()[:16]}.so"
242+ return os.path.join(get_shared_cv_wrapper_cache_dir(args, temp_dir), so_name)
243+ 
244+ 
245+def get_shared_cv_wrapper_soname_options(so_path):
246+ return [f"-Wl,-soname,{os.path.basename(so_path)}"]
247+ 
248+ 
249+def get_shared_cv_wrapper_rpath_options(args: argparse.Namespace):
250+ return (
251+ [CV_WRAPPER_RPATH_OPTION]
252+ if getattr(args, "shared_cv_wrapper_so", None)
253+ else None
254+ )
255+ 
256+ 
257+def build_shared_cv_wrapper_so(
258+ args: argparse.Namespace, temp_dir, source_file, so_path
259+):
260+ tmp_so_path = f"{so_path}.{os.getpid()}.{time.time_ns()}.tmp"
261+ try:
262+ wrapper_obj = compile_host_obj_file(args, temp_dir, source_file)
263+ link_shared(
264+ tmp_so_path,
265+ [wrapper_obj],
266+ link_libraries=CV_HOST_LINK_LIBRARIES,
267+ extra_link_options=get_shared_cv_wrapper_soname_options(so_path),
268+ )
269+ os.replace(tmp_so_path, so_path)
270+ finally:
271+ if os.path.exists(tmp_so_path):
272+ os.remove(tmp_so_path)
273+ 
274+ 
275+def ensure_shared_cv_wrapper_so(args: argparse.Namespace, temp_dir, source_file):
276+ so_path = get_shared_cv_wrapper_so_path(args, temp_dir, source_file)
277+ if os.path.exists(so_path):
278+ return so_path
279+ os.makedirs(os.path.dirname(so_path), exist_ok=True)
280+ lock_path = f"{so_path}.lock"
281+ with open(lock_path, "w") as lock_file:
282+ fcntl.flock(lock_file, fcntl.LOCK_EX)
283+ try:
284+ if os.path.exists(so_path):
285+ return so_path
286+ build_shared_cv_wrapper_so(args, temp_dir, source_file, so_path)
287+ finally:
288+ fcntl.flock(lock_file, fcntl.LOCK_UN)
289+ return so_path
290+ 
291+ 
292+def append_shared_cv_wrapper_so(args: argparse.Namespace, obj_files):
293+ shared_cv_wrapper_so = getattr(args, "shared_cv_wrapper_so", None)
294+ if shared_cv_wrapper_so and is_cv_fusion_compile(args):
295+ return obj_files + [shared_cv_wrapper_so]
296+ return obj_files
297+ 
298+ 
299+def prepare_shared_cv_wrapper(args: argparse.Namespace, temp_dir, host_files):
300+ if not is_cv_fusion_compile(args):
301+ return host_files
302+ regular_host_files = []
303+ wrapper_sources = []
304+ for source_file in host_files:
305+ if is_cv_wrapper_source(source_file):
306+ wrapper_sources.append(source_file)
307+ else:
308+ regular_host_files.append(source_file)
309+ if wrapper_sources:
310+ args.shared_cv_wrapper_so = ensure_shared_cv_wrapper_so(
311+ args, temp_dir, wrapper_sources[0]
312+ )
313+ return regular_host_files
314+ 
315+ 
200def link_pgo_executable(target_file, obj_files, mspti_link_flags):316def link_pgo_executable(target_file, obj_files, mspti_link_flags):
201 link_command = [f"{ASCEND_PATH}/tools/bisheng_compiler/bin/bisheng", *obj_files]317 link_command = [f"{ASCEND_PATH}/tools/bisheng_compiler/bin/bisheng", *obj_files]
202 link_command.extend(["-fPIC", "-o", target_file])318 link_command.extend(["-fPIC", "-o", target_file])
@@ -413,14 +529,18 @@ def build_host_include_options(temp_dir):
413 "-I",529 "-I",
414 f"{ASCEND_PATH}/include",530 f"{ASCEND_PATH}/include",
415 "-I",531 "-I",
532+ f"{ASCEND_PATH}/{machine}-linux/pkg_inc",
533+ "-I",
534+ f"{ASCEND_PATH}/{machine}-linux/pkg_inc/base",
535+ "-I",
536+ f"{ASCEND_PATH}/pkg_inc",
537+ "-I",
416 f"{ASCEND_PATH}/pkg_inc/base",538 f"{ASCEND_PATH}/pkg_inc/base",
417 "-I",539 "-I",
418 f"{ASCEND_PATH}/include/base",540 f"{ASCEND_PATH}/include/base",
419 "-I",541 "-I",
420 f"{ASCEND_PATH}/include/experiment",542 f"{ASCEND_PATH}/include/experiment",
421 "-I",543 "-I",
422- f"{ASCEND_PATH}/{machine}-linux/pkg_inc/base",
423- "-I",
424 f"{ASCEND_PATH}/{machine}-linux/include",544 f"{ASCEND_PATH}/{machine}-linux/include",
425 "-I",545 "-I",
426 f"{ASCEND_PATH}/{machine}-linux/include/aclnn",546 f"{ASCEND_PATH}/{machine}-linux/include/aclnn",
@@ -705,7 +825,11 @@ def normalize_to_list(value):
705 825 
706@inductor_compile_duration("CompileHostObj")826@inductor_compile_duration("CompileHostObj")
707def compile_host_objs(args: argparse.Namespace, temp_dir, pch_path=None):827def compile_host_objs(args: argparse.Namespace, temp_dir, pch_path=None):
708- host_files = normalize_to_list(args.host_files)828+ host_files = prepare_shared_cv_wrapper(
829+ args, temp_dir, normalize_to_list(args.host_files)
830+ )
831+ if not host_files:
832+ return []
709 pch_state = {"path": pch_path, "lock": Lock()}833 pch_state = {"path": pch_path, "lock": Lock()}
710 if len(host_files) == 1:834 if len(host_files) == 1:
711 return [compile_host_obj_file(args, temp_dir, host_files[0], pch_state)]835 return [compile_host_obj_file(args, temp_dir, host_files[0], pch_state)]
@@ -793,18 +917,24 @@ def build_device_so(args: argparse.Namespace, host_obj_path, temp_dir):
793 host_obj_paths = normalize_to_list(host_obj_path)917 host_obj_paths = normalize_to_list(host_obj_path)
794 if host_obj_paths:918 if host_obj_paths:
795 obj_files = host_obj_paths + obj_files919 obj_files = host_obj_paths + obj_files
920+ obj_files = append_shared_cv_wrapper_so(args, obj_files)
796 link_libraries = (921 link_libraries = (
797 CV_HOST_LINK_LIBRARIES922 CV_HOST_LINK_LIBRARIES
798 if host_obj_paths and is_cv_fusion_compile(args)923 if host_obj_paths and is_cv_fusion_compile(args)
799 else (HOST_LINK_LIBRARIES if host_obj_paths else None)924 else (HOST_LINK_LIBRARIES if host_obj_paths else None)
800 )925 )
801 with InductorCompileDuration(args, "LinkDeviceSo"):926 with InductorCompileDuration(args, "LinkDeviceSo"):
802- return link_shared(target_file, obj_files, link_libraries=link_libraries)927+ return link_shared(
928+ target_file,
929+ obj_files,
930+ link_libraries=link_libraries,
931+ extra_link_options=get_shared_cv_wrapper_rpath_options(args),
932+ )
803 933 
804 934 
805def clean_before_modify(temp_dir):935def clean_before_modify(temp_dir):
806 src_directory = os.getcwd()936 src_directory = os.getcwd()
807- keep_dirs = {"host", "device"}937+ keep_dirs = {"host", "device", CV_WRAPPER_CACHE_DIR_NAME}
808 for entry in os.listdir(temp_dir):938 for entry in os.listdir(temp_dir):
809 entry_path = os.path.join(temp_dir, entry)939 entry_path = os.path.join(temp_dir, entry)
810 if os.path.isfile(entry_path):940 if os.path.isfile(entry_path):
@@ -1056,9 +1186,13 @@ def try_static_shape_compile(args: argparse.Namespace, temp_dir, so_path):
1056def link_host_target(args, temp_dir, pch_path=None):1186def link_host_target(args, temp_dir, pch_path=None):
1057 # 处理 host 编译阶段1187 # 处理 host 编译阶段
1058 if pch_path is None:1188 if pch_path is None:
1059- host_obj_paths = compile_host_objs(args, temp_dir)1189+ host_obj_paths = append_shared_cv_wrapper_so(
1190+ args, compile_host_objs(args, temp_dir)
1191+ )
1060 else:1192 else:
1061- host_obj_paths = compile_host_objs(args, temp_dir, pch_path)1193+ host_obj_paths = append_shared_cv_wrapper_so(
1194+ args, compile_host_objs(args, temp_dir, pch_path)
1195+ )
1062 so_file = os.path.join(temp_dir, os.path.basename(args.output_file))1196 so_file = os.path.join(temp_dir, os.path.basename(args.output_file))
1063 link_libraries = (1197 link_libraries = (
1064 CV_HOST_LINK_LIBRARIES if is_cv_fusion_compile(args) else HOST_LINK_LIBRARIES1198 CV_HOST_LINK_LIBRARIES if is_cv_fusion_compile(args) else HOST_LINK_LIBRARIES
@@ -1066,7 +1200,12 @@ def link_host_target(args, temp_dir, pch_path=None):
1066 if getattr(args, "pgo_runner_file", None) is not None:1200 if getattr(args, "pgo_runner_file", None) is not None:
1067 link_libraries = link_libraries + ["ascendcl", "runtime"]1201 link_libraries = link_libraries + ["ascendcl", "runtime"]
1068 with InductorCompileDuration(args, "LinkHostSo"):1202 with InductorCompileDuration(args, "LinkHostSo"):
1069- link_shared(so_file, host_obj_paths, link_libraries=link_libraries)1203+ link_shared(
1204+ so_file,
1205+ host_obj_paths,
1206+ link_libraries=link_libraries,
1207+ extra_link_options=get_shared_cv_wrapper_rpath_options(args),
1208+ )
1070 return so_file1209 return so_file
1071 1210 
1072 1211 
@@ -1104,6 +1243,15 @@ def copy_so_to_output(so_file, args, src_directory):
1104 os.makedirs(dst_dir_path)1243 os.makedirs(dst_dir_path)
1105 1244 
1106 shutil.copy(so_file, dst_file)1245 shutil.copy(so_file, dst_file)
1246+ shared_cv_wrapper_so = getattr(args, "shared_cv_wrapper_so", None)
1247+ if shared_cv_wrapper_so:
1248+ wrapper_dst_dir = os.path.join(dst_dir_path, CV_WRAPPER_CACHE_DIR_NAME)
1249+ os.makedirs(wrapper_dst_dir, exist_ok=True)
1250+ wrapper_dst_file = os.path.join(
1251+ wrapper_dst_dir, os.path.basename(shared_cv_wrapper_so)
1252+ )
1253+ if os.path.realpath(shared_cv_wrapper_so) != os.path.realpath(wrapper_dst_file):
1254+ shutil.copy(shared_cv_wrapper_so, wrapper_dst_file)
1107 print(f"copy file {so_file} to {dst_file}")1255 print(f"copy file {so_file} to {dst_file}")
1108 os.chdir(src_directory)1256 os.chdir(src_directory)
1109 1257 
Mautofuse/tests/framework/share_graph/include/share_graph.h+1-0
@@ -152,6 +152,7 @@ struct ShareGraph {
152 static af::ComputeGraphPtr LoadCompareCastSumStoreFusedGraph(size_t dims_size);152 static af::ComputeGraphPtr LoadCompareCastSumStoreFusedGraph(size_t dims_size);
153 static af::ComputeGraphPtr LoadMatmulElewiseBrcFusedGraph(bool is_dynamic = false);153 static af::ComputeGraphPtr LoadMatmulElewiseBrcFusedGraph(bool is_dynamic = false);
154 static af::ComputeGraphPtr LoadMatmulCompareScalarFusedGraph();154 static af::ComputeGraphPtr LoadMatmulCompareScalarFusedGraph();
155+ static af::ComputeGraphPtr LoadMatmulToIntCastFusedGraph();
155 static af::ComputeGraphPtr DivAbsFusedGraph(size_t dims_size);156 static af::ComputeGraphPtr DivAbsFusedGraph(size_t dims_size);
156 static af::ComputeGraphPtr TrueDivBf16FusedGraph(size_t dims_size);157 static af::ComputeGraphPtr TrueDivBf16FusedGraph(size_t dims_size);
157 static af::ComputeGraphPtr TruedivAbsFusedGraph(size_t dims_size);158 static af::ComputeGraphPtr TruedivAbsFusedGraph(size_t dims_size);
Mautofuse/tests/framework/share_graph/src/share_graph.cc+65-0
@@ -9713,6 +9713,17 @@ static void CreateMatmulGraphOutput(const MatmulGraphContext &context, const af:
9713 output_op.ir_attr.SetIndex(0);9713 output_op.ir_attr.SetIndex(0);
9714}9714}
9715 9715 
9716+static void CreateMatmulGraphOutput(const MatmulGraphContext &context, const af::AscOpOutput &input,
9717+ af::DataType dtype) {
9718+ af::ascir_op::Store store_op("store");
9719+ store_op.x = input;
9720+ SetFullMatmulGraphLayout(store_op, context, dtype);
9721+ af::ascir_op::Output output_op("output");
9722+ output_op.x = store_op.y;
9723+ output_op.y.dtype = dtype;
9724+ output_op.ir_attr.SetIndex(0);
9725+}
9726+ 
9716static void ConnectCompareInputs(const MatmulGraphContext &context, af::ascir_op::Eq &eq0) {9727static void ConnectCompareInputs(const MatmulGraphContext &context, af::ascir_op::Eq &eq0) {
9717 af::ascir_op::Data data2("data2", context.graph);9728 af::ascir_op::Data data2("data2", context.graph);
9718 SetFullMatmulGraphLayout(data2, context, af::DT_FLOAT);9729 SetFullMatmulGraphLayout(data2, context, af::DT_FLOAT);
@@ -9864,6 +9875,60 @@ af::ComputeGraphPtr ShareGraph::LoadMatmulCompareScalarFusedGraph() {
9864 return compute_graph;9875 return compute_graph;
9865}9876}
9866 9877 
9878+static void CreateMatmulToIntCastGraph(af::AscGraph &graph) {
9879+ const auto context = CreateMatmulGraphContext(graph);
9880+ af::ascir_op::MatMul matmul("matmul");
9881+ CreateMatmulPrefix(context, matmul);
9882+ 
9883+ af::ascir_op::RoundToInt round_to_int("round_to_int");
9884+ round_to_int.x = matmul.y;
9885+ SetFullMatmulGraphLayout(round_to_int, context, af::DT_INT32);
9886+ 
9887+ af::ascir_op::Cast cast0("cast0");
9888+ cast0.x = round_to_int.y;
9889+ SetFullMatmulGraphLayout(cast0, context, af::DT_FLOAT);
9890+ 
9891+ af::ascir_op::TruncToInt trunc_to_int("trunc_to_int");
9892+ trunc_to_int.x = cast0.y;
9893+ SetFullMatmulGraphLayout(trunc_to_int, context, af::DT_INT32);
9894+ 
9895+ af::ascir_op::Cast cast1("cast1");
9896+ cast1.x = trunc_to_int.y;
9897+ SetFullMatmulGraphLayout(cast1, context, af::DT_FLOAT);
9898+ 
9899+ af::ascir_op::FloorToInt floor_to_int("floor_to_int");
9900+ floor_to_int.x = cast1.y;
9901+ SetFullMatmulGraphLayout(floor_to_int, context, af::DT_INT32);
9902+ CreateMatmulGraphOutput(context, floor_to_int.y, af::DT_INT32);
9903+}
9904+ 
9905+af::ComputeGraphPtr ShareGraph::LoadMatmulToIntCastFusedGraph() {
9906+ auto builder = GraphBuilder("load_matmul_to_int_cast_store_test");
9907+ auto data0 = builder.AddNode("data0", "Data", 0, 1);
9908+ af::AttrUtils::SetInt(data0->GetOpDescBarePtr(), "_parent_node_index", 0);
9909+ auto data1 = builder.AddNode("data1", "Data", 0, 1);
9910+ af::AttrUtils::SetInt(data1->GetOpDescBarePtr(), "_parent_node_index", 1);
9911+ 
9912+ auto ascbc = builder.AddNode("ascbc", "AscGraph", 2, 1);
9913+ auto netoutput = builder.AddNode("netoutput1", af::NETOUTPUT, 1, 0);
9914+ 
9915+ builder.AddDataEdge(data0, 0, ascbc, 0);
9916+ builder.AddDataEdge(data1, 0, ascbc, 1);
9917+ builder.AddDataEdge(ascbc, 0, netoutput, 0);
9918+ ComputeGraphPtr compute_graph = builder.GetGraph();
9919+ if (compute_graph == nullptr) {
9920+ return nullptr;
9921+ }
9922+ auto ascbc_node = compute_graph->FindNode("ascbc");
9923+ af::AscGraph sub_graph("load_matmul_to_int_cast_store");
9924+ CreateMatmulToIntCastGraph(sub_graph);
9925+ 
9926+ std::string sub_graph_str;
9927+ af::AscGraphUtils::SerializeToReadable(sub_graph, sub_graph_str);
9928+ af::AttrUtils::SetStr(ascbc_node->GetOpDescBarePtr(), "ascgraph", sub_graph_str);
9929+ return compute_graph;
9930+}
9931+ 
9867/**9932/**
9868 * output9933 * output
9869 * |9934 * |
Mautofuse/tests/st/codegen/e2e/load_isfinite_store/load_isfinite_store_codegen.cpp+97-0
@@ -14,6 +14,8 @@
14#include "codegen.h"14#include "codegen.h"
15#include "e2e_load_isfinite_store.h"15#include "e2e_load_isfinite_store.h"
16#include "e2e_common.h"16#include "e2e_common.h"
17+#include "ascir_ops.h"
18+#include "elewise/unary_bitwidth_change_api_call.h"
17 19 
18std::vector<std::string> splitString(const std::string &input, char delimiter) {20std::vector<std::string> splitString(const std::string &input, char delimiter) {
19 std::vector<std::string> result;21 std::vector<std::string> result;
@@ -29,6 +31,101 @@ std::vector<std::string> splitString(const std::string &input, char delimiter) {
29 31 
30class LoadIsFiniteStoreTest : public testing::Test {};32class LoadIsFiniteStoreTest : public testing::Test {};
31 33 
34+namespace {
35+void ConnectUnaryBitWidthChangeGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
36+ const af::Axis &z0, const af::Axis &z1) {
37+ af::ascir_op::Data x_op("x", graph);
38+ af::ascir_op::Load load_op("load");
39+ af::ascir_op::Isnan isnan_op("isnan");
40+ graph.AddNode(load_op);
41+ graph.AddNode(isnan_op);
42+ 
43+ load_op.x = x_op.y;
44+ load_op.attr.sched.axis = {z0.id, z1.id};
45+ *load_op.y.axis = {z0.id, z1.id};
46+ *load_op.y.repeats = {s0, s1};
47+ *load_op.y.strides = {s1, af::ops::One};
48+ 
49+ isnan_op.x = load_op.y;
50+ *isnan_op.y.axis = {z0.id, z1.id};
51+ *isnan_op.y.repeats = {s0, s1};
52+ *isnan_op.y.strides = {s1, af::ops::One};
53+}
54+ 
55+void InitUnaryLoadAttrs(const af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1) {
56+ auto load = graph.FindNode("load");
57+ load->attr.api.compute_type = af::ComputeType::kComputeLoad;
58+ load->attr.api.type = af::ApiType::kAPITypeCompute;
59+ load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
60+ load->attr.sched.loop_axis = z0.id;
61+ load->outputs[0].attr.vectorized_axis = {z1.id};
62+ load->outputs[0].attr.vectorized_strides = {af::ops::One};
63+ load->outputs[0].attr.dtype = ge::DT_FLOAT;
64+ load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
65+ load->outputs[0].attr.mem.tensor_id = 0;
66+ load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
67+ load->outputs[0].attr.que.id = 1;
68+ load->outputs[0].attr.opt.merge_scope = af::kIdNone;
69+}
70+ 
71+void InitUnaryIsnanAttrs(const af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1) {
72+ auto isnan = graph.FindNode("isnan");
73+ isnan->attr.api.compute_type = af::ComputeType::kComputeElewise;
74+ isnan->attr.api.type = af::ApiType::kAPITypeCompute;
75+ isnan->attr.api.unit = af::ComputeUnit::kUnitVector;
76+ isnan->attr.sched.loop_axis = z0.id;
77+ isnan->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}};
78+ isnan->outputs[0].attr.vectorized_axis = {z1.id};
79+ isnan->outputs[0].attr.vectorized_strides = {af::ops::One};
80+ isnan->outputs[0].attr.dtype = ge::DT_INT16;
81+ isnan->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
82+ isnan->outputs[0].attr.mem.tensor_id = 3;
83+ isnan->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
84+ isnan->outputs[0].attr.que.id = 2;
85+ isnan->outputs[0].attr.opt.merge_scope = af::kIdNone;
86+}
87+ 
88+std::string GenerateUnaryBitWidthChangeNoLoopCall() {
89+ af::AscGraph graph("test_graph");
90+ auto s0 = graph.CreateSizeVar("s0");
91+ auto s1 = graph.CreateSizeVar("s1");
92+ auto z0 = graph.CreateAxis("z0", s0);
93+ auto z1 = graph.CreateAxis("z1", s1);
94+ ConnectUnaryBitWidthChangeGraph(graph, s0, s1, z0, z1);
95+ InitUnaryLoadAttrs(graph, z0, z1);
96+ InitUnaryIsnanAttrs(graph, z0, z1);
97+ 
98+ auto load = graph.FindNode("load");
99+ auto isnan = graph.FindNode("isnan");
100+ 
101+ codegen::Tiler tiler;
102+ codegen::TPipe tpipe("tpipe", tiler);
103+ EXPECT_EQ(tpipe.CollectQues(graph), 0);
104+ EXPECT_EQ(tpipe.AddTensor(load->outputs[0]), 0);
105+ EXPECT_EQ(tpipe.AddTensor(isnan->outputs[0]), 0);
106+ 
107+ tiler.AddAxis(z0);
108+ tiler.AddAxis(z1);
109+ tiler.AddSizeVar(af::SizeVar(s0));
110+ tiler.AddSizeVar(af::SizeVar(s1));
111+ 
112+ codegen::ApiTensor x1;
113+ x1.id = load->outputs[0].attr.mem.tensor_id;
114+ codegen::UnaryBitWidthChangeApiCall call("IsnanExtend");
115+ EXPECT_EQ(call.Init(isnan), 0);
116+ call.inputs.push_back(&x1);
117+ 
118+ std::string result;
119+ EXPECT_EQ(call.Generate(tpipe, {z0.id}, result), 0);
120+ return result;
121+}
122+} // namespace
123+ 
124+TEST_F(LoadIsFiniteStoreTest, UnaryBitWidthChangeNoLoopUsesAlignedSize) {
125+ const std::string result = GenerateUnaryBitWidthChangeNoLoopCall();
126+ EXPECT_EQ(result, "IsnanExtend(local_3[0], local_0[0], tmp_buf_0, local_0_actual_size);\n");
127+}
128+ 
32TEST_F(LoadIsFiniteStoreTest, LoadIsFiniteStoreCodegen) {129TEST_F(LoadIsFiniteStoreTest, LoadIsFiniteStoreCodegen) {
33 bool gen_success = true;130 bool gen_success = true;
34 af::AscGraph test_graph("load_isfinite_store");131 af::AscGraph test_graph("load_isfinite_store");
Mautofuse/tests/st/codegen/e2e/load_logicalnot_store/load_logicalnot_store_codegen.cpp+5-1
@@ -68,7 +68,11 @@ TEST_F(LoadLogicalNotStoreTest, LoadLogicalNotStoreCodegen) {
68 InitScheduleResultsByImplGraphs(test_impl_graphs, fused_schedule_result);68 InitScheduleResultsByImplGraphs(test_impl_graphs, fused_schedule_result);
69 codegen::CodegenResult result;69 codegen::CodegenResult result;
70 EXPECT_EQ(codegen.Generate(fused_schedule_result, result), 0);70 EXPECT_EQ(codegen.Generate(fused_schedule_result, result), 0);
71- kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel);71+ const std::string kernel = RemoveSubDirInclude(result.kernel);
72+ EXPECT_NE(kernel.find("LogicalNot(local_4[0], local_2[0], local_blk_tensor_of_half_1, tmp_buf_0, "
73+ "local_2_actual_size);"),
74+ std::string::npos);
75+ kernel_file << tilig_stub << kernel;
72 tiling_file << result.tiling;76 tiling_file << result.tiling;
73 tiling_data_file << result.tiling_data;77 tiling_data_file << result.tiling_data;
74 } catch (...) {78 } catch (...) {
Mautofuse/tests/st/codegen/e2e/load_where_store_expect_code/load_where_store_codegen.cpp+6-1
@@ -68,7 +68,12 @@ TEST_F(LoadWhereStoreTest, LoadWhereStoreCodegen) {
68 InitScheduleResultsByImplGraphs(test_impl_graphs, fused_schedule_result);68 InitScheduleResultsByImplGraphs(test_impl_graphs, fused_schedule_result);
69 codegen::CodegenResult result;69 codegen::CodegenResult result;
70 EXPECT_EQ(codegen.Generate(fused_schedule_result, result), 0);70 EXPECT_EQ(codegen.Generate(fused_schedule_result, result), 0);
71- kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel);71+ const std::string kernel = RemoveSubDirInclude(result.kernel);
72+ EXPECT_NE(kernel.find("Where<false, false>(local_6[0], local_3[0], local_4[0], local_5[0], z1t_actual_size, "
73+ "t->s2"),
74+ std::string::npos);
75+ EXPECT_NE(kernel.find("((8 * Ceiling((Rational(1 , 8) * t->s2))))/(1)"), std::string::npos);
76+ kernel_file << tilig_stub << kernel;
72 tiling_file << result.tiling;77 tiling_file << result.tiling;
73 tiling_data_file << result.tiling_data;78 tiling_data_file << result.tiling_data;
74 } catch (...) {79 } catch (...) {
Mautofuse/tests/st/python/test_inductor_pgo_compile_flow.py+3-1
@@ -176,7 +176,9 @@ def test_inductor_host_link_includes_acl_runtime(ascendc_compile_module, tmp_pat
176 ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs176 ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs
177 ascendc_compile_module.module.is_cv_fusion_compile = fake_is_cv_fusion_compile177 ascendc_compile_module.module.is_cv_fusion_compile = fake_is_cv_fusion_compile
178 178 
179- def fake_link_shared(target_file, obj_files, link_libraries=None):179+ def fake_link_shared(
180+ target_file, obj_files, link_libraries=None, extra_link_options=None
181+ ):
180 captured["link_libraries"] = link_libraries182 captured["link_libraries"] = link_libraries
181 return target_file183 return target_file
182 184 
Mautofuse/tests/ut/codegen/api_call/test_codegen_where_api_call.cpp+3-3
@@ -921,7 +921,7 @@ TEST(WhereApiCallTest, WhereApiCall_Scaler_x2x3_throwfor) {
921 std::cout << result << std::endl;921 std::cout << result << std::endl;
922 EXPECT_EQ(result, std::string{"Where<true, true>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], "922 EXPECT_EQ(result, std::string{"Where<true, true>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], "
923 "local_blk_tensor_of_local_2[0], t->s1, t->s2, t->s2, (2 * t->s2), ONE_BLK_SIZE / "923 "local_blk_tensor_of_local_2[0], t->s1, t->s2, t->s2, (2 * t->s2), ONE_BLK_SIZE / "
924- "sizeof(float), ONE_BLK_SIZE / sizeof(float), tmp_buf_0, ONE_BLK_SIZE * 2);\n"});924+ "sizeof(int16_t), ONE_BLK_SIZE / sizeof(int16_t), tmp_buf_0, ONE_BLK_SIZE * 2);\n"});
925}925}
926 926 
927TEST(WhereApiCallTest, WhereApiCall_Scaler_x2_throwfor) {927TEST(WhereApiCallTest, WhereApiCall_Scaler_x2_throwfor) {
@@ -1064,7 +1064,7 @@ TEST(WhereApiCallTest, WhereApiCall_Scaler_x2_throwfor) {
1064 std::cout << result << std::endl;1064 std::cout << result << std::endl;
1065 EXPECT_EQ(result,1065 EXPECT_EQ(result,
1066 std::string{"Where<true, false>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], local_2[0], t->s1, "1066 std::string{"Where<true, false>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], local_2[0], t->s1, "
1067- "t->s2, t->s2, t->s2, ONE_BLK_SIZE / sizeof(float), t->s2, tmp_buf_0, ONE_BLK_SIZE);\n"});1067+ "t->s2, t->s2, t->s2, ONE_BLK_SIZE / sizeof(int16_t), t->s2, tmp_buf_0, ONE_BLK_SIZE);\n"});
1068}1068}
1069 1069 
1070TEST(WhereApiCallTest, WhereApiCall_Scaler_x3_throwfor) {1070TEST(WhereApiCallTest, WhereApiCall_Scaler_x3_throwfor) {
@@ -1207,7 +1207,7 @@ TEST(WhereApiCallTest, WhereApiCall_Scaler_x3_throwfor) {
1207 std::cout << result << std::endl;1207 std::cout << result << std::endl;
1208 EXPECT_EQ(result,1208 EXPECT_EQ(result,
1209 std::string{"Where<false, true>(local_3[0], local_0[0], local_1[0], local_blk_tensor_of_local_2[0], t->s1, "1209 std::string{"Where<false, true>(local_3[0], local_0[0], local_1[0], local_blk_tensor_of_local_2[0], t->s1, "
1210- "t->s2, t->s2, t->s2, t->s2, ONE_BLK_SIZE / sizeof(float), tmp_buf_0, ONE_BLK_SIZE);\n"});1210+ "t->s2, t->s2, t->s2, t->s2, ONE_BLK_SIZE / sizeof(int16_t), tmp_buf_0, ONE_BLK_SIZE);\n"});
1211}1211}
1212 1212 
1213TEST(WhereApiCallTest, WhereApiCall_throwfor) {1213TEST(WhereApiCallTest, WhereApiCall_throwfor) {
Mautofuse/tests/ut/codegen/test_codegen_kernel.cpp+280-71
@@ -1151,6 +1151,42 @@ TEST(CodegenKernel, TPipe_TensorSizeCalc_AllocFromQue) {
1151 "const uint32_t local_1_que_buf_num = 4;\n"});1151 "const uint32_t local_1_que_buf_num = 4;\n"});
1152}1152}
1153 1153 
1154+TEST(CodegenKernel, TPipe_TensorSizeAssignForCvUbFuseShouldUseCubeOutputElementCount) {
1155+ af::AscGraph graph("test");
1156+ af::ascir_op::Data x("x", graph);
1157+ af::ascir_op::Data y("y", graph);
1158+ 
1159+ auto int8_node = graph.FindNode("x");
1160+ af::AscTensor int8_tensor = int8_node->outputs[0];
1161+ int8_tensor.attr.dtype = ge::DT_INT8;
1162+ int8_tensor.attr.mem.tensor_id = 1;
1163+ int8_tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeBuffer;
1164+ int8_tensor.attr.mem.position = af::Position::kPositionVecCalc;
1165+ int8_tensor.attr.opt.merge_scope = af::kIdNone;
1166+ int8_tensor.attr.buf.id = 1;
1167+ 
1168+ auto int64_node = graph.FindNode("y");
1169+ af::AscTensor int64_tensor = int64_node->outputs[0];
1170+ int64_tensor.attr.dtype = ge::DT_INT64;
1171+ int64_tensor.attr.mem.tensor_id = 2;
1172+ int64_tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeBuffer;
1173+ int64_tensor.attr.mem.position = af::Position::kPositionVecCalc;
1174+ int64_tensor.attr.opt.merge_scope = af::kIdNone;
1175+ int64_tensor.attr.buf.id = 2;
1176+ 
1177+ codegen::Tiler tiler;
1178+ codegen::TPipe tpipe("tpipe", tiler);
1179+ tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse;
1180+ ASSERT_EQ(tpipe.AddTensor(int8_tensor), af::SUCCESS);
1181+ ASSERT_EQ(tpipe.AddTensor(int64_tensor), af::SUCCESS);
1182+ 
1183+ std::string result;
1184+ ASSERT_EQ(tpipe.TensorSizeAssign("float", result), af::SUCCESS);
1185+ EXPECT_EQ(result, std::string{"local_1_size = stage_size / sizeof(float);\n"
1186+ "local_2_size = stage_size / sizeof(float);\n"
1187+ "\n"});
1188+}
1189+ 
1154TEST(CodegenKernel, TPipe_MergeScopeSizeCalc) {1190TEST(CodegenKernel, TPipe_MergeScopeSizeCalc) {
1155 af::SizeVar s0(af::Symbol("s0"));1191 af::SizeVar s0(af::Symbol("s0"));
1156 af::SizeVar s1(af::Symbol("s1"));1192 af::SizeVar s1(af::Symbol("s1"));
@@ -1490,6 +1526,50 @@ TEST(CodegenKernel, TPipe_LocalTQueAlloc) {
1490 "tpipe.InitBuffer(q1, q1_buf_num, t->q1_size);\n"});1526 "tpipe.InitBuffer(q1, q1_buf_num, t->q1_size);\n"});
1491}1527}
1492 1528 
1529+TEST(CodegenKernel, TPipe_LocalTQueAllocForCvUbFuseShouldAlignSharedTensorSlices) {
1530+ af::AscGraph graph("test");
1531+ af::ascir_op::Data x("x", graph);
1532+ af::ascir_op::Data y("y", graph);
1533+ 
1534+ auto int8_node = graph.FindNode("x");
1535+ af::AscTensor int8_tensor = int8_node->outputs[0];
1536+ int8_tensor.attr.dtype = ge::DT_INT8;
1537+ int8_tensor.attr.mem.tensor_id = 1;
1538+ int8_tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
1539+ int8_tensor.attr.mem.position = af::Position::kPositionVecIn;
1540+ int8_tensor.attr.mem.reuse_id = 1;
1541+ int8_tensor.attr.opt.merge_scope = af::kIdNone;
1542+ int8_tensor.attr.que.id = 1;
1543+ int8_tensor.attr.que.buf_num = 1;
1544+ 
1545+ auto int64_node = graph.FindNode("y");
1546+ af::AscTensor int64_tensor = int64_node->outputs[0];
1547+ int64_tensor.attr.dtype = ge::DT_INT64;
1548+ int64_tensor.attr.mem.tensor_id = 2;
1549+ int64_tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
1550+ int64_tensor.attr.mem.position = af::Position::kPositionVecIn;
1551+ int64_tensor.attr.mem.reuse_id = 1;
1552+ int64_tensor.attr.opt.merge_scope = af::kIdNone;
1553+ int64_tensor.attr.que.id = 1;
1554+ int64_tensor.attr.que.buf_num = 1;
1555+ 
1556+ codegen::Tiler tiler;
1557+ codegen::TPipe tpipe("tpipe", tiler);
1558+ tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse;
1559+ tpipe.CollectQues(graph);
1560+ ASSERT_EQ(tpipe.AddTensor(int8_tensor), af::SUCCESS);
1561+ ASSERT_EQ(tpipe.AddTensor(int64_tensor), af::SUCCESS);
1562+ 
1563+ std::string result;
1564+ ASSERT_EQ(tpipe.LocalTQueAlloc(result), af::SUCCESS);
1565+ EXPECT_EQ(result, std::string{"const uint32_t q1_size = KernelUtils::Max(local_1_size * sizeof(int8_t), "
1566+ "local_2_size * sizeof(int64_t), "
1567+ "KernelUtils::BlkAlign<uint8_t>(local_1_size * sizeof(int8_t)) + "
1568+ "KernelUtils::BlkAlign<uint8_t>(local_2_size * sizeof(int64_t)));\n"
1569+ "const uint32_t q1_buf_num = KernelUtils::Max(1);\n"
1570+ "tpipe.InitBuffer(q1, q1_buf_num, KernelUtils::BlkAlign<uint8_t>(q1_size));\n"});
1571+}
1572+ 
1493TEST(CodegenKernel, ApiCall_Generate) {1573TEST(CodegenKernel, ApiCall_Generate) {
1494 af::AscGraph graph("test");1574 af::AscGraph graph("test");
1495 af::ascir_op::Data x("x", graph);1575 af::ascir_op::Data x("x", graph);
@@ -1534,6 +1614,7 @@ class CodegenKernel_CallSync : public ::testing::Test {
1534 af::AscGraph graph;1614 af::AscGraph graph;
1535 af::AscNodePtr x;1615 af::AscNodePtr x;
1536 int tensor_id = 0;1616 int tensor_id = 0;
1617+ bool cv_ub_fuse_mode = false;
1537 1618 
1538 CodegenKernel_CallSync() : graph("test_graph"), x(nullptr) {1619 CodegenKernel_CallSync() : graph("test_graph"), x(nullptr) {
1539 Data x_op("x", graph);1620 Data x_op("x", graph);
@@ -1707,6 +1788,9 @@ class CodegenKernel_CallSync : public ::testing::Test {
1707 std::string Generate() {1788 std::string Generate() {
1708 codegen::Tiler tiler;1789 codegen::Tiler tiler;
1709 codegen::TPipe tpipe("tpipe", tiler);1790 codegen::TPipe tpipe("tpipe", tiler);
1791+ if (cv_ub_fuse_mode) {
1792+ tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse;
1793+ }
1710 tpipe.CollectQues(graph);1794 tpipe.CollectQues(graph);
1711 1795 
1712 codegen::Loop loop(af::kIdNone);1796 codegen::Loop loop(af::kIdNone);
@@ -2285,6 +2369,30 @@ TEST_F(CodegenKernel_CallSync, AllocLoad1_ShareLoad2Enq_DeqVec) {
2285 "q1.FreeTensor(q1_buf);\n\n"});2369 "q1.FreeTensor(q1_buf);\n\n"});
2286}2370}
2287 2371 
2372+TEST_F(CodegenKernel_CallSync, CvUbFuseSharedQueueOffsetShouldUseBlockAlignedSliceSize) {
2373+ cv_ub_fuse_mode = true;
2374+ auto load1 = Load("load1", x);
2375+ load1->outputs[0].attr.dtype = ge::DT_INT8;
2376+ auto load2 = LoadForShare("load2", x, load1);
2377+ load2->outputs[0].attr.dtype = ge::DT_INT64;
2378+ auto vec = Vec("vec", {load1, load2}, false);
2379+ 
2380+ EXPECT_EQ(Generate(), std::string{"uint32_t q1_reuse1_offset = 0;\n"
2381+ "q1_buf = q1.AllocTensor<uint8_t>();\n"
2382+ "local_1_actual_size = 1;\n"
2383+ "local_1 = q1_buf[q1_reuse1_offset].template ReinterpretCast<int8_t>();\n"
2384+ "load1();\n\n"
2385+ "q1_reuse1_offset = q1_reuse1_offset + "
2386+ "KernelUtils::BlkAlign<uint8_t>(local_1_size * 1);\n"
2387+ "local_2_actual_size = 1;\n"
2388+ "local_2 = q1_buf[q1_reuse1_offset].template ReinterpretCast<int64_t>();\n"
2389+ "load2();\n"
2390+ "q1.EnQue(q1_buf);\n\n"
2391+ "q1_buf = q1.DeQue<uint8_t>();\n"
2392+ "vec();\n"
2393+ "q1.FreeTensor(q1_buf);\n\n"});
2394+}
2395+ 
2288/*2396/*
2289 * load1 load22397 * load1 load2
2290 * \ /2398 * \ /
@@ -2452,6 +2560,12 @@ TEST(CodegenKernel, StageGenerate_WillNotDuplicatAllocTensorInSameStage) {
2452 GTEST_SKIP();2560 GTEST_SKIP();
2453}2561}
2454 2562 
2563+namespace {
2564+void BuildCompareApiCallCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
2565+ const af::Axis &z0, const af::Axis &z1);
2566+void InitCompareApiCallCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1);
2567+} // namespace
2568+ 
2455// 测试compare api不外抛for循环的场景2569// 测试compare api不外抛for循环的场景
2456TEST(CodegenKernel, CompareApiCallNotThrowingFor) {2570TEST(CodegenKernel, CompareApiCallNotThrowingFor) {
2457 af::AscGraph graph("test_graph");2571 af::AscGraph graph("test_graph");
@@ -2460,81 +2574,12 @@ TEST(CodegenKernel, CompareApiCallNotThrowingFor) {
2460 auto s1 = graph.CreateSizeVar("s1");2574 auto s1 = graph.CreateSizeVar("s1");
2461 auto z0 = graph.CreateAxis("z0", s0);2575 auto z0 = graph.CreateAxis("z0", s0);
2462 auto z1 = graph.CreateAxis("z1", s1);2576 auto z1 = graph.CreateAxis("z1", s1);
2463- 2577+ BuildCompareApiCallCvStageGraph(graph, s0, s1, z0, z1);
2464- Data x_op("x", graph);2578+ InitCompareApiCallCvStageAttrs(graph, z0, z1);
2465- Data x_op2("x2", graph);
2466- Load load_op("load");
2467- Load load_op2("load2");
2468- af::ascir_op::Gt gt_op("gt");
2469- graph.AddNode(load_op);
2470- graph.AddNode(load_op2);
2471- graph.AddNode(gt_op);
2472- 
2473- load_op.x = x_op.y;
2474- load_op.attr.sched.axis = {z0.id, z1.id};
2475- *load_op.y.axis = {z0.id, z1.id};
2476- *load_op.y.repeats = {s0, s1};
2477- *load_op.y.strides = {s1, One};
2478- 
2479- load_op2.x = x_op2.y;
2480- load_op2.attr.sched.axis = {z0.id, z1.id};
2481- *load_op2.y.axis = {z0.id, z1.id};
2482- *load_op2.y.repeats = {s0, s1};
2483- *load_op2.y.strides = {s1, One};
2484- 
2485- gt_op.x1 = load_op.y;
2486- gt_op.x2 = load_op2.y;
2487- *gt_op.y.axis = {z0.id, z1.id};
2488- *gt_op.y.repeats = {s0, s1};
2489- *gt_op.y.strides = {s1, One};
2490 2579 
2491 auto load = graph.FindNode("load");2580 auto load = graph.FindNode("load");
2492- load->attr.api.compute_type = af::ComputeType::kComputeLoad;
2493- load->attr.api.type = af::ApiType::kAPITypeCompute;
2494- load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
2495- load->attr.sched.loop_axis = z0.id;
2496- 
2497 auto load2 = graph.FindNode("load2");2581 auto load2 = graph.FindNode("load2");
2498- load2->attr.api.compute_type = af::ComputeType::kComputeLoad;
2499- load2->attr.api.type = af::ApiType::kAPITypeCompute;
2500- load2->attr.api.unit = af::ComputeUnit::kUnitMTE2;
2501- load2->attr.sched.loop_axis = z0.id;
2502- 
2503- auto size = ge::GetSizeByDataType(ge::DT_FLOAT16);
2504- load->outputs[0].attr.vectorized_axis = {z1.id};
2505- load->outputs[0].attr.vectorized_strides = {One};
2506- load->outputs[0].attr.dtype = ge::DT_FLOAT;
2507- load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
2508- load->outputs[0].attr.mem.tensor_id = 0;
2509- load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
2510- load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
2511- load->outputs[0].attr.que.id = 1;
2512- load->outputs[0].attr.opt.merge_scope = af::kIdNone;
2513- 
2514- load2->outputs[0].attr.vectorized_axis = {z1.id};
2515- load2->outputs[0].attr.vectorized_strides = {One};
2516- load2->outputs[0].attr.dtype = ge::DT_FLOAT;
2517- load2->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
2518- load2->outputs[0].attr.mem.tensor_id = 1;
2519- load2->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
2520- load2->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
2521- load2->outputs[0].attr.que.id = 1;
2522- load2->outputs[0].attr.opt.merge_scope = af::kIdNone;
2523- 
2524 auto gt = graph.FindNode("gt");2582 auto gt = graph.FindNode("gt");
2525- gt->attr.api.compute_type = af::ComputeType::kComputeElewise;
2526- gt->attr.api.type = af::ApiType::kAPITypeCompute;
2527- gt->attr.api.unit = af::ComputeUnit::kUnitVector;
2528- gt->attr.sched.loop_axis = z0.id;
2529- gt->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}};
2530- gt->outputs[0].attr.vectorized_axis = {z1.id};
2531- gt->outputs[0].attr.vectorized_strides = {One};
2532- gt->outputs[0].attr.dtype = ge::DT_INT16;
2533- gt->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
2534- gt->outputs[0].attr.mem.tensor_id = 3;
2535- gt->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
2536- gt->outputs[0].attr.que.id = 2;
2537- gt->outputs[0].attr.opt.merge_scope = af::kIdNone;
2538 2583 
2539 codegen::Tiler tiler;2584 codegen::Tiler tiler;
2540 codegen::TPipe tpipe("tpipe", tiler);2585 codegen::TPipe tpipe("tpipe", tiler);
@@ -2567,6 +2612,129 @@ TEST(CodegenKernel, CompareApiCallNotThrowingFor) {
2567 std::string{"CompareExtend(local_3[0], local_0[0], local_1[0], CMPMODE::GT, local_0_actual_size, tmp_buf_0);\n"});2612 std::string{"CompareExtend(local_3[0], local_0[0], local_1[0], CMPMODE::GT, local_0_actual_size, tmp_buf_0);\n"});
2568}2613}
2569 2614 
2615+namespace {
2616+void BuildCompareApiCallCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
2617+ const af::Axis &z0, const af::Axis &z1) {
2618+ Data x_op("x", graph);
2619+ Data x_op2("x2", graph);
2620+ Load load_op("load");
2621+ Load load_op2("load2");
2622+ af::ascir_op::Gt gt_op("gt");
2623+ graph.AddNode(load_op);
2624+ graph.AddNode(load_op2);
2625+ graph.AddNode(gt_op);
2626+ 
2627+ load_op.x = x_op.y;
2628+ load_op.attr.sched.axis = {z0.id, z1.id};
2629+ *load_op.y.axis = {z0.id, z1.id};
2630+ *load_op.y.repeats = {s0, s1};
2631+ *load_op.y.strides = {s1, One};
2632+ 
2633+ load_op2.x = x_op2.y;
2634+ load_op2.attr.sched.axis = {z0.id, z1.id};
2635+ *load_op2.y.axis = {z0.id, z1.id};
2636+ *load_op2.y.repeats = {s0, s1};
2637+ *load_op2.y.strides = {s1, One};
2638+ 
2639+ gt_op.x1 = load_op.y;
2640+ gt_op.x2 = load_op2.y;
2641+ *gt_op.y.axis = {z0.id, z1.id};
2642+ *gt_op.y.repeats = {s0, s1};
2643+ *gt_op.y.strides = {s1, One};
2644+}
2645+ 
2646+void InitCompareApiCallCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1) {
2647+ auto load = graph.FindNode("load");
2648+ load->attr.api.compute_type = af::ComputeType::kComputeLoad;
2649+ load->attr.api.type = af::ApiType::kAPITypeCompute;
2650+ load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
2651+ load->attr.sched.loop_axis = z0.id;
2652+ 
2653+ auto load2 = graph.FindNode("load2");
2654+ load2->attr.api.compute_type = af::ComputeType::kComputeLoad;
2655+ load2->attr.api.type = af::ApiType::kAPITypeCompute;
2656+ load2->attr.api.unit = af::ComputeUnit::kUnitMTE2;
2657+ load2->attr.sched.loop_axis = z0.id;
2658+ 
2659+ load->outputs[0].attr.vectorized_axis = {z1.id};
2660+ load->outputs[0].attr.vectorized_strides = {One};
2661+ load->outputs[0].attr.dtype = ge::DT_FLOAT;
2662+ load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
2663+ load->outputs[0].attr.mem.tensor_id = 0;
2664+ load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
2665+ load->outputs[0].attr.que.id = 1;
2666+ load->outputs[0].attr.opt.merge_scope = af::kIdNone;
2667+ 
2668+ load2->outputs[0].attr.vectorized_axis = {z1.id};
2669+ load2->outputs[0].attr.vectorized_strides = {One};
2670+ load2->outputs[0].attr.dtype = ge::DT_FLOAT;
2671+ load2->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
2672+ load2->outputs[0].attr.mem.tensor_id = 1;
2673+ load2->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
2674+ load2->outputs[0].attr.que.id = 1;
2675+ load2->outputs[0].attr.opt.merge_scope = af::kIdNone;
2676+ 
2677+ auto gt = graph.FindNode("gt");
2678+ gt->attr.api.compute_type = af::ComputeType::kComputeElewise;
2679+ gt->attr.api.type = af::ApiType::kAPITypeCompute;
2680+ gt->attr.api.unit = af::ComputeUnit::kUnitVector;
2681+ gt->attr.sched.loop_axis = z0.id;
2682+ gt->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}};
2683+ gt->outputs[0].attr.vectorized_axis = {z1.id};
2684+ gt->outputs[0].attr.vectorized_strides = {One};
2685+ gt->outputs[0].attr.dtype = ge::DT_INT16;
2686+ gt->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
2687+ gt->outputs[0].attr.mem.tensor_id = 3;
2688+ gt->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
2689+ gt->outputs[0].attr.que.id = 2;
2690+ gt->outputs[0].attr.opt.merge_scope = af::kIdNone;
2691+}
2692+} // namespace
2693+ 
2694+TEST(CodegenKernel, CompareApiCallCvStageAlignsActualSize) {
2695+ af::AscGraph graph("test_graph");
2696+ 
2697+ auto s0 = graph.CreateSizeVar("s0");
2698+ auto s1 = graph.CreateSizeVar("s1");
2699+ auto z0 = graph.CreateAxis("z0", s0);
2700+ auto z1 = graph.CreateAxis("z1", s1);
2701+ BuildCompareApiCallCvStageGraph(graph, s0, s1, z0, z1);
2702+ InitCompareApiCallCvStageAttrs(graph, z0, z1);
2703+ 
2704+ auto load = graph.FindNode("load");
2705+ auto load2 = graph.FindNode("load2");
2706+ auto gt = graph.FindNode("gt");
2707+ 
2708+ codegen::Tiler tiler;
2709+ codegen::TPipe tpipe("tpipe", tiler);
2710+ tpipe.CollectQues(graph);
2711+ tpipe.AddTensor(load->outputs[0]);
2712+ tpipe.AddTensor(load2->outputs[0]);
2713+ tpipe.AddTensor(gt->outputs[0]);
2714+ 
2715+ tiler.AddAxis(z0);
2716+ tiler.AddAxis(z1);
2717+ tiler.AddSizeVar(af::SizeVar(s0));
2718+ tiler.AddSizeVar(af::SizeVar(s1));
2719+ std::vector<af::AxisId> current_axis;
2720+ current_axis.push_back(z0.id);
2721+ 
2722+ codegen::ApiTensor x1;
2723+ codegen::ApiTensor x2;
2724+ x1.id = load->outputs[0].attr.mem.tensor_id;
2725+ x2.id = load2->outputs[0].attr.mem.tensor_id;
2726+ codegen::CompareApiCall call("GT");
2727+ EXPECT_EQ(call.Init(gt), 0);
2728+ call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
2729+ call.inputs.push_back(&x1);
2730+ call.inputs.push_back(&x2);
2731+ 
2732+ std::string result;
2733+ call.Generate(tpipe, current_axis, result);
2734+ EXPECT_EQ(result, std::string{"CompareExtend(local_3[0], local_0[0], local_1[0], CMPMODE::GT, ((local_0_actual_size "
2735+ "+ 8 - 1) / 8 * 8), tmp_buf_0);\n"});
2736+}
2737+ 
2570// 测试compare api需要外抛for循环的场景2738// 测试compare api需要外抛for循环的场景
2571TEST(CodegenKernel, CompareApiCallThrowingFor) {2739TEST(CodegenKernel, CompareApiCallThrowingFor) {
2572 af::AscGraph graph("test_graph");2740 af::AscGraph graph("test_graph");
@@ -6023,6 +6191,47 @@ TEST(CodegenKernel, ReduceDoubleTileUsesReduceSpecificCacheCondition) {
6023 delete cached_call;6191 delete cached_call;
6024}6192}
6025 6193 
6194+TEST(CodegenKernel, BroadcastInlineInCvStage_NoBlockDimCacheCondition) {
6195+ af::SizeVar s0(af::Symbol("s0"));
6196+ af::SizeVar s1(af::Symbol("s1"));
6197+ 
6198+ af::Axis z0{.id = 0, .name = "z0", .size = s0.expr};
6199+ af::Axis z1{.id = 1, .name = "z1", .size = s1.expr};
6200+ 
6201+ codegen::Tiler tiler;
6202+ tiler.AddSizeVar(af::SizeVar(s0));
6203+ tiler.AddSizeVar(af::SizeVar(s1));
6204+ tiler.AddAxis(z0);
6205+ tiler.AddAxis(z1);
6206+ 
6207+ for (auto &[id, cur_axis] : tiler.axis_map) {
6208+ (void)id;
6209+ cur_axis.is_split_b = true;
6210+ }
6211+ 
6212+ codegen::Loop loop1(z0.id);
6213+ codegen::Loop loop2(z1.id);
6214+ loop1.AddLoop(&loop2);
6215+ 
6216+ auto call1 = new MockApiCall("call1");
6217+ auto call2 = new MockApiCall("call2");
6218+ call1->enable_cache = true;
6219+ call1->exec_condition = af::ExecuteCondition::kCacheBlockSplitFusedBroadcastAxis;
6220+ call1->unit = af::ComputeUnit::kUnitVector;
6221+ call1->api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
6222+ call2->enable_cache = true;
6223+ call2->exec_condition = af::ExecuteCondition::kCacheBlockSplitOriginBroadcastAxis;
6224+ call2->unit = af::ComputeUnit::kUnitVector;
6225+ call2->api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
6226+ 
6227+ loop2.AddCall(call1);
6228+ loop2.AddCall(call2);
6229+ codegen::TPipe tpipe("t", tiler);
6230+ std::string result;
6231+ EXPECT_EQ(loop1.Generate(tiler, tpipe, result, codegen::ComputeStage::kCVFuseStage1), af::SUCCESS);
6232+ EXPECT_EQ(result.find("block_dim"), std::string::npos);
6233+}
6234+ 
6026TEST(CodegenKernel, CalculateVectorizedAixsMergeStatus) {6235TEST(CodegenKernel, CalculateVectorizedAixsMergeStatus) {
6027 af::SizeVar s0(af::Symbol("s0"));6236 af::SizeVar s0(af::Symbol("s0"));
6028 af::SizeVar s1(af::Symbol("s1"));6237 af::SizeVar s1(af::Symbol("s1"));
Mautofuse/tests/ut/codegen/test_codegen_tiling.cpp+41-9
@@ -1174,6 +1174,20 @@ TEST_F(TestCodegenTiling, NoWorkspaceTest) {
1174 "}\n"});1174 "}\n"});
1175}1175}
1176 1176 
1177+TEST_F(TestCodegenTiling, PrepareMatMulAttrsShouldUseDefaultOpImplModeForMatMulV3) {
1178+ codegen::MatMulCubeInfo cube_info;
1179+ cube_info.is_batch = false;
1180+ cube_info.enable_hf32 = 0;
1181+ 
1182+ std::vector<codegen::AttrInfo> attrs;
1183+ PrepareMatMulAttrs(cube_info, attrs);
1184+ 
1185+ ASSERT_GT(attrs.size(), 3U);
1186+ EXPECT_EQ(attrs[3].name, "opImplMode");
1187+ EXPECT_EQ(attrs[3].dtype, "int");
1188+ EXPECT_EQ(attrs[3].value_int, 0);
1189+}
1190+ 
1177TEST_F(TestCodegenTiling, SingleGroupWorkspaceSymbolTest) {1191TEST_F(TestCodegenTiling, SingleGroupWorkspaceSymbolTest) {
1178 ascir::ImplGraph graph0("test_graph0");1192 ascir::ImplGraph graph0("test_graph0");
1179 auto s0 = graph0.CreateSizeVar("s0");1193 auto s0 = graph0.CreateSizeVar("s0");
@@ -3160,11 +3174,10 @@ TEST_F(TestCodegenTiling, GenerateForInductorCvFusionShouldEmitCvTilingAndCubeWr
3160 auto tiling_files = this->GenerateForInductor(fused_schedule_result);3174 auto tiling_files = this->GenerateForInductor(fused_schedule_result);
3161 ASSERT_TRUE(tiling_files.find(codegen::kTilingDefAndConstIdentify) != tiling_files.end());3175 ASSERT_TRUE(tiling_files.find(codegen::kTilingDefAndConstIdentify) != tiling_files.end());
3162 ASSERT_TRUE(tiling_files.find(codegen::kTilingApiHeaderIdentify) != tiling_files.end());3176 ASSERT_TRUE(tiling_files.find(codegen::kTilingApiHeaderIdentify) != tiling_files.end());
3177+ ASSERT_TRUE(tiling_files.find(codegen::kTilingHeadIdentify) != tiling_files.end());
3163 ASSERT_TRUE(tiling_files.find(codegen::kCubeKernelTilingWrapperHpp) != tiling_files.end());3178 ASSERT_TRUE(tiling_files.find(codegen::kCubeKernelTilingWrapperHpp) != tiling_files.end());
3164 ASSERT_TRUE(tiling_files.find(codegen::kCubeKernelTilingWrapperCpp) != tiling_files.end());3179 ASSERT_TRUE(tiling_files.find(codegen::kCubeKernelTilingWrapperCpp) != tiling_files.end());
3165 EXPECT_TRUE(tiling_files.find("TilingDataLog") == tiling_files.end());3180 EXPECT_TRUE(tiling_files.find("TilingDataLog") == tiling_files.end());
3166- EXPECT_NE(tiling_files.at(codegen::kCubeKernelTilingWrapperCpp).find("#include \"autofuse_tiling_func_log.h\""),
3167- std::string::npos);
3168 3181 
3169 const auto &tiling_impl = tiling_files.at(codegen::kTilingDefAndConstIdentify);3182 const auto &tiling_impl = tiling_files.at(codegen::kTilingDefAndConstIdentify);
3170 const auto &api_header = tiling_files.at(codegen::kTilingApiHeaderIdentify);3183 const auto &api_header = tiling_files.at(codegen::kTilingApiHeaderIdentify);
@@ -3189,6 +3202,8 @@ void set_g_basen_basem_align(int32_t value) {
3189 EXPECT_NE(tiling_impl.find("CallCubeTiling"), std::string::npos);3202 EXPECT_NE(tiling_impl.find("CallCubeTiling"), std::string::npos);
3190 EXPECT_NE(tiling_impl.find("AutofuseTiling("), std::string::npos);3203 EXPECT_NE(tiling_impl.find("AutofuseTiling("), std::string::npos);
3191 EXPECT_NE(tiling_impl.find("GenConstTilingData"), std::string::npos);3204 EXPECT_NE(tiling_impl.find("GenConstTilingData"), std::string::npos);
3205+ EXPECT_NE(tiling_impl.find("autofuse_has_bias"), std::string::npos);
3206+ EXPECT_NE(tiling_impl.find("autofuse_has_offset_w"), std::string::npos);
3192 EXPECT_EQ(tiling_impl.find("GenerateTopnSolutions"), std::string::npos);3207 EXPECT_EQ(tiling_impl.find("GenerateTopnSolutions"), std::string::npos);
3193 EXPECT_EQ(tiling_impl.find("GetModeledPerfForTesting"), std::string::npos);3208 EXPECT_EQ(tiling_impl.find("GetModeledPerfForTesting"), std::string::npos);
3194 EXPECT_EQ(tiling_impl.find("AscirCompileAndLaunch"), std::string::npos);3209 EXPECT_EQ(tiling_impl.find("AscirCompileAndLaunch"), std::string::npos);
@@ -3197,7 +3212,8 @@ void set_g_basen_basem_align(int32_t value) {
3197 EXPECT_EQ(tiling_impl.find("#include \"autofuse_cube_tiling_data.h\""), std::string::npos);3212 EXPECT_EQ(tiling_impl.find("#include \"autofuse_cube_tiling_data.h\""), std::string::npos);
3198 EXPECT_NE(tiling_impl.find("#include \"cube_kernel_tiling_wrapper.h\""), std::string::npos);3213 EXPECT_NE(tiling_impl.find("#include \"cube_kernel_tiling_wrapper.h\""), std::string::npos);
3199 ExpectSystemHeaders(3214 ExpectSystemHeaders(
3200- tiling_impl, {"algorithm", "cfloat", "cstddef", "cstdint", "cstring", "ostream", "sstream", "string", "vector"},3215+ tiling_impl,
3216+ {"algorithm", "cfloat", "cstddef", "cstdint", "cstring", "iomanip", "ostream", "sstream", "string", "vector"},
3201 {"array", "cmath", "cstdlib", "functional", "map", "memory", "unordered_map", "utility"});3217 {"array", "cmath", "cstdlib", "functional", "map", "memory", "unordered_map", "utility"});
3202}3218}
3203 3219 
@@ -3207,15 +3223,31 @@ TEST_F(TestCodegenTiling, CubeWrapperShouldPreserveTilingDataBytes) {
3207 const auto matmul_tiling_header_pos = wrapper_hpp.find("#include \"arch35/mat_mul_tiling_data.h\"");3223 const auto matmul_tiling_header_pos = wrapper_hpp.find("#include \"arch35/mat_mul_tiling_data.h\"");
3208 const auto autofuse_namespace_pos = wrapper_hpp.find("namespace autofuse {");3224 const auto autofuse_namespace_pos = wrapper_hpp.find("namespace autofuse {");
3209 EXPECT_NE(wrapper_hpp.find("std::vector<uint8_t> tiling_data;"), std::string::npos);3225 EXPECT_NE(wrapper_hpp.find("std::vector<uint8_t> tiling_data;"), std::string::npos);
3210- EXPECT_NE(wrapper_hpp.find("#include <cmath>"), std::string::npos);
3211- EXPECT_NE(wrapper_hpp.find("#include <limits>"), std::string::npos);
3212 ASSERT_NE(matmul_tiling_header_pos, std::string::npos);3226 ASSERT_NE(matmul_tiling_header_pos, std::string::npos);
3213 ASSERT_NE(autofuse_namespace_pos, std::string::npos);3227 ASSERT_NE(autofuse_namespace_pos, std::string::npos);
3214 EXPECT_LT(matmul_tiling_header_pos, autofuse_namespace_pos);3228 EXPECT_LT(matmul_tiling_header_pos, autofuse_namespace_pos);
3215- EXPECT_NE(wrapper_cpp.find("result.tiling_data.push_back"), std::string::npos);3229+ EXPECT_NE(wrapper_cpp.find("result.tiling_data.assign"), std::string::npos);
3216- EXPECT_NE(wrapper_cpp.find("result.tiling_data = AlignTilingDataTo8Bytes"), std::string::npos);3230+ EXPECT_NE(wrapper_cpp.find("raw_tiling_data->GetDataSize()"), std::string::npos);
3217- EXPECT_NE(wrapper_cpp.find("#include \"autofuse_tiling_func_log.h\""), std::string::npos);3231+}
3218- EXPECT_EQ(wrapper_cpp.find("autofuse_tiling_data_log.h"), std::string::npos);3232+ 
3233+TEST_F(TestCodegenTiling, CubeWrapperShouldSupportBiasAndOffsetInputs) {
3234+ const auto &wrapper_cpp = kCubeKernelTilingWrapperCppValue;
3235+ EXPECT_NE(wrapper_cpp.find("MakeMatMulInputInstanceNum(request.matmul_attrs.has_bias"), std::string::npos);
3236+ EXPECT_NE(wrapper_cpp.find("key.input2_shape = GetRuntimeShape(request.inputs[2]);"), std::string::npos);
3237+ EXPECT_NE(wrapper_cpp.find("key.input3_shape = GetRuntimeShape(request.inputs[3]);"), std::string::npos);
3238+ EXPECT_NE(wrapper_cpp.find("key.input_num = request.inputs.size();"), std::string::npos);
3239+ EXPECT_NE(wrapper_cpp.find("inputs->size() >= 2 && inputs->size() <= 4"), std::string::npos);
3240+ EXPECT_NE(wrapper_cpp.find("has_bias = AttrAsBool(attr);"), std::string::npos);
3241+ EXPECT_NE(wrapper_cpp.find("has_offset_w = AttrAsBool(attr);"), std::string::npos);
3242+ EXPECT_NE(wrapper_cpp.find("if (attrs.has_offset_w && input_index < inputs.size())"), std::string::npos);
3243+ EXPECT_NE(wrapper_cpp.find("BuildMatMulInputSlots(request.inputs, request.matmul_attrs)"), std::string::npos);
3244+ EXPECT_NE(wrapper_cpp.find("if (input == nullptr)"), std::string::npos);
3245+ EXPECT_NE(wrapper_cpp.find("input2_dtype = inputs[2U].dtype;"), std::string::npos);
3246+ EXPECT_NE(wrapper_cpp.find("input3_format = inputs[3U].format;"), std::string::npos);
3247+ EXPECT_NE(wrapper_cpp.find("input_tensors_storage.reserve(input_slots.size());"), std::string::npos);
3248+ EXPECT_NE(wrapper_cpp.find("for (const auto *input : input_slots)"), std::string::npos);
3249+ EXPECT_NE(wrapper_cpp.find("DtypeToGeDataType(input.dtype) == ge::DT_UNDEFINED"), std::string::npos);
3250+ EXPECT_NE(wrapper_cpp.find("ge::Format input_format = FormatToGeFormat(input->format);"), std::string::npos);
3219}3251}
3220 3252 
3221TEST_F(TestCodegenTiling, MultiGroupInductorShouldContainTopnMainOutputAbi) {3253TEST_F(TestCodegenTiling, MultiGroupInductorShouldContainTopnMainOutputAbi) {
Mautofuse/tests/ut/python/test_ascendc_compile.py+496-9
@@ -12,7 +12,10 @@
12import hashlib12import hashlib
13import json13import json
14import os14import os
15+import time
15import types16import types
17+from dataclasses import dataclass
18+from concurrent.futures import ThreadPoolExecutor
16 19 
17import pytest20import pytest
18 21 
@@ -82,6 +85,43 @@ def _make_pgo_bundle(module, artifacts, output_file, generation, ld_preload=""):
82 return module.PgoBundle(*artifacts, output_file, generation, ld_preload=ld_preload)85 return module.PgoBundle(*artifacts, output_file, generation, ld_preload=ld_preload)
83 86 
84 87 
88+@dataclass
89+class CopySoToOutputCase:
90+ src_file: object
91+ dst_file: object
92+ output_dir: object
93+ wrapper_file: object
94+ src_directory: str
95+ args: object
96+ 
97+ 
98+def _make_copy_so_to_output_case(tmpdir, wrapper_in_output_dir=False):
99+ src_file = tmpdir.join("source.so")
100+ src_file.write("kernel")
101+ output_dir = tmpdir.mkdir("kernel_meta")
102+ if wrapper_in_output_dir:
103+ wrapper_dir = output_dir.mkdir("cv_tiling_wrapper_cache")
104+ else:
105+ wrapper_dir = tmpdir.mkdir("cache")
106+ wrapper_file = wrapper_dir.join("libautofuse_cv_tiling_wrapper_abc.so")
107+ wrapper_file.write("wrapper")
108+ dst_file = output_dir.join("target.so")
109+ src_directory = os.getcwd()
110+ args = type(
111+ "Args",
112+ (),
113+ {
114+ "output_file": str(dst_file),
115+ "shared_cv_wrapper_so": str(wrapper_file),
116+ "stage": "host",
117+ "graph_name": "graph",
118+ },
119+ )()
120+ return CopySoToOutputCase(
121+ src_file, dst_file, output_dir, wrapper_file, src_directory, args
122+ )
123+ 
124+ 
85def test_link_shared_adds_requested_libraries(ascendc_compile_module):125def test_link_shared_adds_requested_libraries(ascendc_compile_module):
86 captured = {}126 captured = {}
87 127 
@@ -119,6 +159,23 @@ def test_link_shared_skips_libraries_by_default(ascendc_compile_module):
119 assert "-lgraph_base" not in captured["cmd"]159 assert "-lgraph_base" not in captured["cmd"]
120 160 
121 161 
162+def test_link_shared_appends_extra_link_options(ascendc_compile_module):
163+ captured = {}
164+ 
165+ def fake_run_compile_command(cmd, stage_name):
166+ captured["cmd"] = cmd
167+ 
168+ ascendc_compile_module.module.run_compile_command = fake_run_compile_command
169+ 
170+ ascendc_compile_module.link_shared(
171+ "kernel.so",
172+ ["host.o"],
173+ extra_link_options=["-Wl,-rpath,$ORIGIN/cv_tiling_wrapper_cache"],
174+ )
175+ 
176+ assert "-Wl,-rpath,$ORIGIN/cv_tiling_wrapper_cache" in captured["cmd"]
177+ 
178+ 
122def test_link_pgo_executable_uses_host_runtime_and_mspti_libraries(179def test_link_pgo_executable_uses_host_runtime_and_mspti_libraries(
123 ascendc_compile_module,180 ascendc_compile_module,
124):181):
@@ -709,6 +766,33 @@ def test_copy_so_to_output_records_stage(ascendc_compile_module, tmpdir):
709 assert dst_file.read() == "binary"766 assert dst_file.read() == "binary"
710 767 
711 768 
769+def test_copy_so_to_output_copies_shared_cv_wrapper_next_to_output(
770+ ascendc_compile_module, tmpdir
771+):
772+ case = _make_copy_so_to_output_case(tmpdir)
773+ ascendc_compile_module.copy_so_to_output(
774+ str(case.src_file), case.args, case.src_directory
775+ )
776+ 
777+ copied_wrapper = case.output_dir.join(
778+ "cv_tiling_wrapper_cache", "libautofuse_cv_tiling_wrapper_abc.so"
779+ )
780+ assert case.dst_file.read() == "kernel"
781+ assert copied_wrapper.read() == "wrapper"
782+ 
783+ 
784+def test_copy_so_to_output_keeps_existing_shared_cv_wrapper_in_output_dir(
785+ ascendc_compile_module, tmpdir
786+):
787+ case = _make_copy_so_to_output_case(tmpdir, wrapper_in_output_dir=True)
788+ ascendc_compile_module.copy_so_to_output(
789+ str(case.src_file), case.args, case.src_directory
790+ )
791+ 
792+ assert case.dst_file.read() == "kernel"
793+ assert case.wrapper_file.read() == "wrapper"
794+ 
795+ 
712def test_static_shape_kernel_proc_removes_tiling_data_from_launch(796def test_static_shape_kernel_proc_removes_tiling_data_from_launch(
713 ascendc_compile_module, tmpdir797 ascendc_compile_module, tmpdir
714):798):
@@ -1182,6 +1266,67 @@ def test_compile_host_obj_removes_rejected_cached_pch(ascendc_compile_module, tm
1182 assert not os.path.exists(pch_path)1266 assert not os.path.exists(pch_path)
1183 1267 
1184 1268 
1269+def test_build_host_compile_cmd_includes_pkg_inc_roots(ascendc_compile_module):
1270+ ascendc_compile_module.module.ASCEND_PATH = "/usr/local/Ascend/cann"
1271+ ascendc_compile_module.module.machine = "x86_64"
1272+ 
1273+ include_options = ascendc_compile_module.build_host_include_options("/tmp/build")
1274+ 
1275+ assert "/usr/local/Ascend/cann/pkg_inc" in include_options
1276+ assert "/usr/local/Ascend/cann/x86_64-linux/pkg_inc" in include_options
1277+ 
1278+ 
1279+def test_build_host_include_options_prefers_machine_pkg_inc_base(
1280+ ascendc_compile_module,
1281+):
1282+ ascendc_compile_module.module.ASCEND_PATH = "/usr/local/Ascend/cann"
1283+ ascendc_compile_module.module.machine = "x86_64"
1284+ 
1285+ include_options = ascendc_compile_module.build_host_include_options("/tmp/build")
1286+ 
1287+ machine_base = include_options.index(
1288+ "/usr/local/Ascend/cann/x86_64-linux/pkg_inc/base"
1289+ )
1290+ generic_base = include_options.index("/usr/local/Ascend/cann/pkg_inc/base")
1291+ assert machine_base < generic_base
1292+ 
1293+ 
1294+def _assert_compile_host_objs_skips_shared_cv_wrapper_source(
1295+ ascendc_compile_module, tmpdir, monkeypatch, source_case
1296+):
1297+ graph_file_name, wrapper_file_name, wrapper_content = source_case
1298+ host_dir = tmpdir.mkdir("host")
1299+ graph_file = host_dir.join(graph_file_name)
1300+ wrapper_file = host_dir.join(wrapper_file_name)
1301+ graph_file.write("CVAutofuseTilingData graph tiling")
1302+ wrapper_file.write(wrapper_content)
1303+ args = _make_compile_args([str(graph_file), str(wrapper_file)])
1304+ compiled_sources = []
1305+ 
1306+ def fake_compile_host_obj_file(compile_args, temp_dir, source_file, pch_state=None):
1307+ compiled_sources.append(source_file)
1308+ return source_file + ".o"
1309+ 
1310+ def fake_ensure_shared_cv_wrapper_so(compile_args, temp_dir, source_file):
1311+ assert source_file == str(wrapper_file)
1312+ return "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so"
1313+ 
1314+ ascendc_compile_module.module.compile_host_obj_file = fake_compile_host_obj_file
1315+ ascendc_compile_module.module.ensure_shared_cv_wrapper_so = (
1316+ fake_ensure_shared_cv_wrapper_so
1317+ )
1318+ monkeypatch.setattr(ascendc_compile_module.os, "cpu_count", lambda: 2)
1319+ 
1320+ result = ascendc_compile_module.compile_host_objs(args, str(tmpdir))
1321+ 
1322+ assert result == [str(graph_file) + ".o"]
1323+ assert compiled_sources == [str(graph_file)]
1324+ assert (
1325+ args.shared_cv_wrapper_so
1326+ == "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so"
1327+ )
1328+ 
1329+ 
1185def test_build_host_compile_cmd_adds_pgo_mspti_include(ascendc_compile_module):1330def test_build_host_compile_cmd_adds_pgo_mspti_include(ascendc_compile_module):
1186 args = _make_compile_args("/tmp/build/host/graph_tiling_func_PgoRunner.cpp")1331 args = _make_compile_args("/tmp/build/host/graph_tiling_func_PgoRunner.cpp")
1187 args.pgo_mspti_dir = "/usr/local/Ascend/cann/tools/mspti"1332 args.pgo_mspti_dir = "/usr/local/Ascend/cann/tools/mspti"
@@ -1244,6 +1389,224 @@ def test_compile_host_objs_compiles_multiple_files(ascendc_compile_module, monke
1244 assert all("cmake" not in cmd and "make" not in cmd for cmd in compile_cmds)1389 assert all("cmake" not in cmd and "make" not in cmd for cmd in compile_cmds)
1245 1390 
1246 1391 
1392+def test_get_shared_cv_wrapper_cache_dir_prefers_run_dir_env(
1393+ ascendc_compile_module, tmpdir, monkeypatch
1394+):
1395+ run_dir = tmpdir.mkdir("run")
1396+ monkeypatch.setenv("RUN_DIR", str(run_dir))
1397+ args = _make_compile_args()
1398+ args.output_file = None
1399+ 
1400+ result = ascendc_compile_module.get_shared_cv_wrapper_cache_dir(args, "")
1401+ 
1402+ assert result == os.path.join(str(run_dir), "cv_tiling_wrapper_cache")
1403+ 
1404+ 
1405+def test_get_shared_cv_wrapper_cache_dir_uses_inductor_cache_without_run_dir(
1406+ ascendc_compile_module, tmpdir, monkeypatch
1407+):
1408+ cache_dir = tmpdir.mkdir("inductor_cache")
1409+ monkeypatch.delenv("RUN_DIR", raising=False)
1410+ monkeypatch.setenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR", str(cache_dir))
1411+ args = _make_compile_args()
1412+ args.output_file = None
1413+ 
1414+ result = ascendc_compile_module.get_shared_cv_wrapper_cache_dir(args, "")
1415+ 
1416+ assert result == os.path.join(str(cache_dir), "cv_tiling_wrapper_cache")
1417+ 
1418+ 
1419+def test_get_shared_cv_wrapper_cache_dir_prefers_output_file_dir(
1420+ ascendc_compile_module, tmpdir, monkeypatch
1421+):
1422+ output_dir = tmpdir.mkdir("kernel_meta")
1423+ output_file = output_dir.join("kernel.so")
1424+ run_dir = tmpdir.mkdir("run")
1425+ cache_dir = tmpdir.mkdir("inductor_cache")
1426+ monkeypatch.setenv("RUN_DIR", str(run_dir))
1427+ monkeypatch.setenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR", str(cache_dir))
1428+ args = _make_compile_args()
1429+ args.output_file = str(output_file)
1430+ 
1431+ result = ascendc_compile_module.get_shared_cv_wrapper_cache_dir(args, "")
1432+ 
1433+ assert result == os.path.join(str(output_dir), "cv_tiling_wrapper_cache")
1434+ 
1435+ 
1436+def test_get_shared_cv_wrapper_cache_dir_prefers_temp_dir(
1437+ ascendc_compile_module, tmpdir, monkeypatch
1438+):
1439+ temp_dir = tmpdir.mkdir("temp")
1440+ output_dir = tmpdir.mkdir("kernel_meta")
1441+ output_file = output_dir.join("kernel.so")
1442+ run_dir = tmpdir.mkdir("run")
1443+ cache_dir = tmpdir.mkdir("inductor_cache")
1444+ monkeypatch.setenv("RUN_DIR", str(run_dir))
1445+ monkeypatch.setenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR", str(cache_dir))
1446+ args = _make_compile_args()
1447+ args.output_file = str(output_file)
1448+ 
1449+ result = ascendc_compile_module.get_shared_cv_wrapper_cache_dir(args, str(temp_dir))
1450+ 
1451+ assert result == os.path.join(str(temp_dir), "cv_tiling_wrapper_cache")
1452+ 
1453+ 
1454+def test_compile_host_objs_skips_shared_cv_wrapper_source(
1455+ ascendc_compile_module, tmpdir, monkeypatch
1456+):
1457+ _assert_compile_host_objs_skips_shared_cv_wrapper_source(
1458+ ascendc_compile_module,
1459+ tmpdir,
1460+ monkeypatch,
1461+ (
1462+ "graph_tiling_func.cpp",
1463+ "cube_kernel_tiling_wrapper.cpp",
1464+ "CVAutofuseTilingData wrapper tiling",
1465+ ),
1466+ )
1467+ 
1468+ 
1469+def test_compile_host_objs_skips_split_shared_cv_wrapper_source(
1470+ ascendc_compile_module, tmpdir, monkeypatch
1471+):
1472+ _assert_compile_host_objs_skips_shared_cv_wrapper_source(
1473+ ascendc_compile_module,
1474+ tmpdir,
1475+ monkeypatch,
1476+ (
1477+ "autofused_tiling_func_tiling_def_and_tiling_const.cpp",
1478+ "autofused_tiling_func_BCubeKernelTilingWrapperCpp.cpp",
1479+ "AutofuseDoCubeMatMulTiling wrapper tiling",
1480+ ),
1481+ )
1482+ 
1483+ 
1484+def test_ensure_shared_cv_wrapper_so_reuses_existing_so(
1485+ ascendc_compile_module, tmpdir, monkeypatch
1486+):
1487+ run_dir = tmpdir.mkdir("run")
1488+ host_dir = tmpdir.mkdir("host")
1489+ wrapper_file = host_dir.join("cube_kernel_tiling_wrapper.cpp")
1490+ wrapper_file.write("CVAutofuseTilingData wrapper tiling")
1491+ args = _make_compile_args([str(wrapper_file)])
1492+ monkeypatch.setenv("RUN_DIR", str(run_dir))
1493+ so_path = ascendc_compile_module.get_shared_cv_wrapper_so_path(
1494+ args, str(tmpdir), str(wrapper_file)
1495+ )
1496+ os.makedirs(os.path.dirname(so_path), exist_ok=True)
1497+ with open(so_path, "w") as f:
1498+ f.write("cached")
1499+ 
1500+ def fail_compile(*_args, **_kwargs):
1501+ pytest.fail("cached wrapper so should not be recompiled")
1502+ 
1503+ ascendc_compile_module.module.compile_host_obj_file = fail_compile
1504+ ascendc_compile_module.module.link_shared = fail_compile
1505+ 
1506+ result = ascendc_compile_module.ensure_shared_cv_wrapper_so(
1507+ args, str(tmpdir), str(wrapper_file)
1508+ )
1509+ 
1510+ assert result == so_path
1511+ 
1512+ 
1513+def test_ensure_shared_cv_wrapper_so_serializes_concurrent_first_compile(
1514+ ascendc_compile_module, tmpdir, monkeypatch
1515+):
1516+ run_dir = tmpdir.mkdir("run")
1517+ host_dir = tmpdir.mkdir("host")
1518+ wrapper_file = host_dir.join("cube_kernel_tiling_wrapper.cpp")
1519+ wrapper_file.write("CVAutofuseTilingData wrapper tiling")
1520+ args = _make_compile_args([str(wrapper_file)])
1521+ args.output_file = str(tmpdir.mkdir("kernel_meta").join("kernel.so"))
1522+ monkeypatch.setenv("RUN_DIR", str(run_dir))
1523+ compile_calls = []
1524+ 
1525+ def fake_compile_host_obj_file(compile_args, temp_dir, source_file):
1526+ compile_calls.append(source_file)
1527+ time.sleep(0.05)
1528+ return source_file + ".o"
1529+ 
1530+ def fake_link_shared(
1531+ target_file, obj_files, link_libraries=None, extra_link_options=None
1532+ ):
1533+ with open(target_file, "w") as f:
1534+ f.write("linked")
1535+ return target_file
1536+ 
1537+ ascendc_compile_module.module.compile_host_obj_file = fake_compile_host_obj_file
1538+ ascendc_compile_module.module.link_shared = fake_link_shared
1539+ 
1540+ with ThreadPoolExecutor(max_workers=2) as executor:
1541+ futures = [
1542+ executor.submit(
1543+ ascendc_compile_module.ensure_shared_cv_wrapper_so,
1544+ args,
1545+ str(tmpdir),
1546+ str(wrapper_file),
1547+ )
1548+ for _ in range(2)
1549+ ]
1550+ results = [future.result() for future in futures]
1551+ 
1552+ assert results[0] == results[1]
1553+ assert os.path.exists(results[0])
1554+ assert compile_calls == [str(wrapper_file)]
1555+ 
1556+ 
1557+def test_ensure_shared_cv_wrapper_so_sets_soname(
1558+ ascendc_compile_module, tmpdir, monkeypatch
1559+):
1560+ output_dir = tmpdir.mkdir("kernel_meta")
1561+ host_dir = tmpdir.mkdir("host")
1562+ wrapper_file = host_dir.join("cube_kernel_tiling_wrapper.cpp")
1563+ wrapper_file.write("CVAutofuseTilingData wrapper tiling")
1564+ args = _make_compile_args([str(wrapper_file)])
1565+ args.output_file = str(output_dir.join("kernel.so"))
1566+ monkeypatch.delenv("RUN_DIR", raising=False)
1567+ monkeypatch.delenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR", raising=False)
1568+ captured = {}
1569+ 
1570+ def fake_compile_host_obj_file(compile_args, temp_dir, source_file):
1571+ return source_file + ".o"
1572+ 
1573+ def fake_link_shared(
1574+ target_file, obj_files, link_libraries=None, extra_link_options=None
1575+ ):
1576+ captured["target_file"] = target_file
1577+ captured["extra_link_options"] = extra_link_options
1578+ with open(target_file, "w") as f:
1579+ f.write("linked")
1580+ return target_file
1581+ 
1582+ ascendc_compile_module.module.compile_host_obj_file = fake_compile_host_obj_file
1583+ ascendc_compile_module.module.link_shared = fake_link_shared
1584+ 
1585+ so_path = ascendc_compile_module.ensure_shared_cv_wrapper_so(
1586+ args, str(tmpdir), str(wrapper_file)
1587+ )
1588+ 
1589+ assert captured["extra_link_options"] == [
1590+ f"-Wl,-soname,{os.path.basename(so_path)}"
1591+ ]
1592+ 
1593+ 
1594+def test_clean_before_modify_keeps_shared_cv_wrapper_cache(
1595+ ascendc_compile_module, tmpdir
1596+):
1597+ tmpdir.mkdir("host")
1598+ tmpdir.mkdir("device")
1599+ cache_dir = tmpdir.mkdir("cv_tiling_wrapper_cache")
1600+ cache_file = cache_dir.join("libautofuse_cv_tiling_wrapper.so")
1601+ cache_file.write("cached")
1602+ tmpdir.mkdir("stale")
1603+ 
1604+ ascendc_compile_module.clean_before_modify(str(tmpdir))
1605+ 
1606+ assert os.path.exists(str(cache_file))
1607+ assert not os.path.exists(os.path.join(str(tmpdir), "stale"))
1608+ 
1609+ 
1247def test_get_host_compile_worker_count_uses_32_worker_limit(1610def test_get_host_compile_worker_count_uses_32_worker_limit(
1248 ascendc_compile_module, monkeypatch1611 ascendc_compile_module, monkeypatch
1249):1612):
@@ -1299,6 +1662,29 @@ def test_compile_host_obj_rejects_multiple_sources_without_compile(
1299 assert "expects exactly one host source" in str(exc_info.value)1662 assert "expects exactly one host source" in str(exc_info.value)
1300 1663 
1301 1664 
1665+def _capture_build_device_so_link(
1666+ ascendc_compile_module, args, host_obj_path, temp_dir
1667+):
1668+ captured = {}
1669+ 
1670+ def fake_compile_device_obj(compile_args, temp_dir):
1671+ return "/tmp/build/device/kernel.cpp.o"
1672+ 
1673+ ascendc_compile_module.module.compile_device_obj = fake_compile_device_obj
1674+ 
1675+ def fake_link_shared(
1676+ target_file, obj_files, link_libraries=None, extra_link_options=None
1677+ ):
1678+ captured["obj_files"] = obj_files
1679+ captured["link_libraries"] = link_libraries
1680+ captured["extra_link_options"] = extra_link_options
1681+ return target_file
1682+ 
1683+ ascendc_compile_module.module.link_shared = fake_link_shared
1684+ ascendc_compile_module.build_device_so(args, host_obj_path, temp_dir)
1685+ return captured
1686+ 
1687+ 
1302def test_build_device_so_links_all_host_objects(ascendc_compile_module):1688def test_build_device_so_links_all_host_objects(ascendc_compile_module):
1303 captured = {}1689 captured = {}
1304 args = _make_compile_args()1690 args = _make_compile_args()
@@ -1308,10 +1694,13 @@ def test_build_device_so_links_all_host_objects(ascendc_compile_module):
1308 1694 
1309 ascendc_compile_module.module.compile_device_obj = fake_compile_device_obj1695 ascendc_compile_module.module.compile_device_obj = fake_compile_device_obj
1310 1696 
1311- def fake_link_shared(target_file, obj_files, link_libraries=None):1697+ def fake_link_shared(
1698+ target_file, obj_files, link_libraries=None, extra_link_options=None
1699+ ):
1312 captured["target_file"] = target_file1700 captured["target_file"] = target_file
1313 captured["obj_files"] = obj_files1701 captured["obj_files"] = obj_files
1314 captured["link_libraries"] = link_libraries1702 captured["link_libraries"] = link_libraries
1703+ captured["extra_link_options"] = extra_link_options
1315 return target_file1704 return target_file
1316 1705 
1317 ascendc_compile_module.module.link_shared = fake_link_shared1706 ascendc_compile_module.module.link_shared = fake_link_shared
@@ -1323,6 +1712,51 @@ def test_build_device_so_links_all_host_objects(ascendc_compile_module):
1323 assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES1712 assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES
1324 1713 
1325 1714 
1715+def test_build_device_so_links_shared_cv_wrapper_so_for_cv_compile(
1716+ ascendc_compile_module, tmpdir
1717+):
1718+ device_dir = tmpdir.mkdir("device")
1719+ device_file = device_dir.join("kernel.cpp")
1720+ device_file.write("CVAutofuseTilingData device tiling")
1721+ args = _make_compile_args()
1722+ args.device_files = str(device_file)
1723+ args.shared_cv_wrapper_so = (
1724+ "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so"
1725+ )
1726+ captured = _capture_build_device_so_link(
1727+ ascendc_compile_module, args, ["graph.o"], "/tmp/build"
1728+ )
1729+ 
1730+ assert captured["obj_files"] == [
1731+ "graph.o",
1732+ "/tmp/build/device/kernel.cpp.o",
1733+ "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so",
1734+ ]
1735+ assert captured["link_libraries"] == ascendc_compile_module.CV_HOST_LINK_LIBRARIES
1736+ assert captured["extra_link_options"] == [
1737+ ascendc_compile_module.CV_WRAPPER_RPATH_OPTION
1738+ ]
1739+ 
1740+ 
1741+def test_build_device_so_ignores_shared_cv_wrapper_so_for_non_cv_compile(
1742+ ascendc_compile_module, tmpdir
1743+):
1744+ device_dir = tmpdir.mkdir("device")
1745+ device_file = device_dir.join("kernel.cpp")
1746+ device_file.write("regular device tiling")
1747+ args = _make_compile_args()
1748+ args.device_files = str(device_file)
1749+ args.shared_cv_wrapper_so = (
1750+ "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so"
1751+ )
1752+ captured = _capture_build_device_so_link(
1753+ ascendc_compile_module, args, ["graph.o"], str(tmpdir)
1754+ )
1755+ 
1756+ assert captured["obj_files"] == ["graph.o", "/tmp/build/device/kernel.cpp.o"]
1757+ assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES
1758+ 
1759+ 
1326def test_link_host_target_links_multiple_host_objects(ascendc_compile_module):1760def test_link_host_target_links_multiple_host_objects(ascendc_compile_module):
1327 captured = {}1761 captured = {}
1328 args = _make_compile_args(1762 args = _make_compile_args(
@@ -1337,10 +1771,13 @@ def test_link_host_target_links_multiple_host_objects(ascendc_compile_module):
1337 1771 
1338 ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs1772 ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs
1339 1773 
1340- def fake_link_shared(target_file, obj_files, link_libraries=None):1774+ def fake_link_shared(
1775+ target_file, obj_files, link_libraries=None, extra_link_options=None
1776+ ):
1341 captured["target_file"] = target_file1777 captured["target_file"] = target_file
1342 captured["obj_files"] = obj_files1778 captured["obj_files"] = obj_files
1343 captured["link_libraries"] = link_libraries1779 captured["link_libraries"] = link_libraries
1780+ captured["extra_link_options"] = extra_link_options
1344 return target_file1781 return target_file
1345 1782 
1346 ascendc_compile_module.module.link_shared = fake_link_shared1783 ascendc_compile_module.module.link_shared = fake_link_shared
@@ -1354,23 +1791,73 @@ def test_link_host_target_links_multiple_host_objects(ascendc_compile_module):
1354 assert "acl_rt" in captured["link_libraries"]1791 assert "acl_rt" in captured["link_libraries"]
1355 1792 
1356 1793 
1357-def test_link_host_target_adds_acl_runtime_for_pgo_proxy(ascendc_compile_module):1794+def _capture_link_host_target_link(ascendc_compile_module, args, temp_dir):
1358 captured = {}1795 captured = {}
1359- args = _make_compile_args(["/tmp/build/host/graph_tiling_func.cpp"])
1360- args.pgo_runner_file = "/tmp/build/host/graph_tiling_func_PgoRunner.cpp"
1361 1796 
1362- def fake_compile_host_objs(*_):1797+ def fake_compile_host_objs(compile_args, temp_dir):
1363- return ["host.o"]1798+ return ["graph.o"]
1364 1799 
1365 ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs1800 ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs
1366 1801 
1367- def fake_link_shared(target_file, obj_files, link_libraries=None):1802+ def fake_link_shared(
1803+ target_file, obj_files, link_libraries=None, extra_link_options=None
1804+ ):
1805+ captured["obj_files"] = obj_files
1368 captured["link_libraries"] = link_libraries1806 captured["link_libraries"] = link_libraries
1807+ captured["extra_link_options"] = extra_link_options
1369 return target_file1808 return target_file
1370 1809 
1371 ascendc_compile_module.module.link_shared = fake_link_shared1810 ascendc_compile_module.module.link_shared = fake_link_shared
1811+ ascendc_compile_module.link_host_target(args, temp_dir)
1812+ return captured
1372 1813 
1373- ascendc_compile_module.link_host_target(args, "/tmp/build")1814+ 
1815+def test_link_host_target_links_shared_cv_wrapper_so_for_cv_compile(
1816+ ascendc_compile_module, tmpdir
1817+):
1818+ host_dir = tmpdir.mkdir("host")
1819+ host_file = host_dir.join("graph_tiling_func.cpp")
1820+ host_file.write("CVAutofuseTilingData graph tiling")
1821+ args = _make_compile_args([str(host_file)])
1822+ args.shared_cv_wrapper_so = (
1823+ "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so"
1824+ )
1825+ captured = _capture_link_host_target_link(
1826+ ascendc_compile_module, args, "/tmp/build"
1827+ )
1828+ 
1829+ assert captured["obj_files"] == [
1830+ "graph.o",
1831+ "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so",
1832+ ]
1833+ assert captured["link_libraries"] == ascendc_compile_module.CV_HOST_LINK_LIBRARIES
1834+ assert captured["extra_link_options"] == [
1835+ ascendc_compile_module.CV_WRAPPER_RPATH_OPTION
1836+ ]
1837+ 
1838+ 
1839+def test_link_host_target_ignores_shared_cv_wrapper_so_for_non_cv_compile(
1840+ ascendc_compile_module, tmpdir
1841+):
1842+ host_dir = tmpdir.mkdir("host")
1843+ host_file = host_dir.join("graph_tiling_func.cpp")
1844+ host_file.write("regular graph tiling")
1845+ args = _make_compile_args([str(host_file)])
1846+ args.shared_cv_wrapper_so = (
1847+ "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so"
1848+ )
1849+ captured = _capture_link_host_target_link(ascendc_compile_module, args, str(tmpdir))
1850+ 
1851+ assert captured["obj_files"] == ["graph.o"]
1852+ assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES
1853+ 
1854+ 
1855+def test_link_host_target_adds_acl_runtime_for_pgo_proxy(ascendc_compile_module):
1856+ args = _make_compile_args(["/tmp/build/host/graph_tiling_func.cpp"])
1857+ args.pgo_runner_file = "/tmp/build/host/graph_tiling_func_PgoRunner.cpp"
1858+ captured = _capture_link_host_target_link(
1859+ ascendc_compile_module, args, "/tmp/build"
1860+ )
1374 1861 
1375 assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES + [1862 assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES + [
1376 "ascendcl",1863 "ascendcl",
Mautofuse/tests/v35/st/backend_e2e_v2/CMakeLists.txt+2-2
@@ -200,6 +200,6 @@ add_subdirectory(expm_test)
200# add_subdirectory(truncdiv_bf16_test)200# add_subdirectory(truncdiv_bf16_test)
201# add_subdirectory(sinh_bf16_test)201# add_subdirectory(sinh_bf16_test)
202# add_subdirectory(tan_bf16_test)202# add_subdirectory(tan_bf16_test)
203-# add_subdirectory(round_to_int_float_to_int32_test)203+add_subdirectory(round_to_int_float_to_int32_test)
204-# add_subdirectory(trunc_to_int_bf16_to_int32_test)204+add_subdirectory(trunc_to_int_bf16_to_int32_test)
205# add_subdirectory(remainder_bf16_test)205# add_subdirectory(remainder_bf16_test)
Aautofuse/tests/v35/st/backend_e2e_v2/backend_codegen_common.h+93-0
@@ -0,0 +1,93 @@
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_TESTS_V35_ST_BACKEND_E2E_V2_BACKEND_CODEGEN_COMMON_H_
12+#define AUTOFUSE_TESTS_V35_ST_BACKEND_E2E_V2_BACKEND_CODEGEN_COMMON_H_
13+ 
14+#include <fstream>
15+#include <iostream>
16+#include <map>
17+#include <string>
18+#include <vector>
19+#include <gtest/gtest.h>
20+ 
21+#include "backend_common.h"
22+#include "codegen.h"
23+#include "common_utils.h"
24+#include "optimize.h"
25+#include "share_graph.h"
26+ 
27+template <typename PrepareSchedule, typename CheckKernel>
28+inline void GenerateBackendKernelWithScheduleCheck(
29+ const af::ComputeGraphPtr &graph, const std::map<std::string, std::string> &shape_info,
30+ const std::string &tiling_stub, const std::string &kernel_src_file_name, const std::string &tiling_src_file_name,
31+ const std::string &tiling_data_src_file_name, PrepareSchedule prepare_schedule, CheckKernel check_kernel) {
32+ bool gen_success = true;
33+ try {
34+ optimize::Optimizer optimizer(optimize::OptimizerOptions{});
35+ codegen::Codegen codegen(codegen::CodegenOptions{});
36+ 
37+ std::fstream kernel_file(kernel_src_file_name, std::ios::out);
38+ std::fstream tiling_file(tiling_src_file_name, std::ios::out);
39+ std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
40+ 
41+ std::vector<::ascir::ScheduledResult> schedule_results;
42+ ascir::FusedScheduledResult fused_schedule_result;
43+ fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
44+ EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
45+ if (prepare_schedule(fused_schedule_result)) {
46+ codegen::CodegenResult result;
47+ EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
48+ const std::string kernel = RemoveSubDirInclude(result.kernel);
49+ check_kernel(kernel);
50+ kernel_file << tiling_stub << kernel;
51+ tiling_file << result.tiling;
52+ tiling_data_file << result.tiling_data;
53+ } else {
54+ gen_success = false;
55+ }
56+ } catch (...) {
57+ gen_success = false;
58+ }
59+ 
60+ EXPECT_EQ(gen_success, true);
61+}
62+ 
63+template <typename CheckKernel>
64+inline void GenerateBackendKernelWithCheck(const af::ComputeGraphPtr &graph,
65+ const std::map<std::string, std::string> &shape_info,
66+ const std::string &tiling_stub, CheckKernel check_kernel) {
67+ std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;
68+ std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');
69+ GenerateBackendKernelWithScheduleCheck(
70+ graph, shape_info, tiling_stub, parts[0], parts[1], parts[2], [](ascir::FusedScheduledResult &) { return true; },
71+ check_kernel);
72+}
73+ 
74+template <typename CheckKernel>
75+inline void GenerateCvBackendUbKernelWithCheck(const af::ComputeGraphPtr &graph,
76+ const std::string &kernel_src_file_name,
77+ const std::string &tiling_src_file_name,
78+ const std::string &tiling_data_src_file_name, CheckKernel check_kernel) {
79+ GenerateBackendKernelWithScheduleCheck(
80+ graph, {}, "", kernel_src_file_name, tiling_src_file_name, tiling_data_src_file_name,
81+ [](ascir::FusedScheduledResult &fused_schedule_result) {
82+ const bool is_cube_fused = ascgen_utils::IsCubeFusedScheduled(fused_schedule_result);
83+ EXPECT_TRUE(is_cube_fused);
84+ if (!is_cube_fused) {
85+ return false;
86+ }
87+ ascgen_utils::FilterCVFusionUBResult(fused_schedule_result);
88+ return true;
89+ },
90+ check_kernel);
91+}
92+ 
93+#endif // AUTOFUSE_TESTS_V35_ST_BACKEND_E2E_V2_BACKEND_CODEGEN_COMMON_H_
Mautofuse/tests/v35/st/backend_e2e_v2/bool_backend_codegen_common.h+2-30
@@ -19,7 +19,7 @@
19#include <vector>19#include <vector>
20#include <gtest/gtest.h>20#include <gtest/gtest.h>
21 21 
22-#include "backend_common.h"22+#include "backend_codegen_common.h"
23#include "codegen.h"23#include "codegen.h"
24#include "common/platform_context.h"24#include "common/platform_context.h"
25#include "optimize.h"25#include "optimize.h"
@@ -42,41 +42,13 @@ class BoolBackendCodegenE2e : public testing::Test {
42};42};
43 43 
44inline void GenerateBoolBackendKernel(const af::ComputeGraphPtr &graph) {44inline void GenerateBoolBackendKernel(const af::ComputeGraphPtr &graph) {
45- bool gen_success = true;
46 std::string tiling_stub = R"(45 std::string tiling_stub = R"(
47#define REGISTER_TILING_DEFAULT(tiling)46#define REGISTER_TILING_DEFAULT(tiling)
48#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;47#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
49)";48)";
50 49 
51 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}});50 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}});
52- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;51+ GenerateBackendKernelWithCheck(graph, shape_info, tiling_stub, [](const std::string &) {});
53- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');
54- const std::string &kernel_src_file_name = parts[0];
55- const std::string &tiling_src_file_name = parts[1];
56- const std::string &tiling_data_src_file_name = parts[2];
57- 
58- try {
59- optimize::Optimizer optimizer(optimize::OptimizerOptions{});
60- codegen::Codegen codegen(codegen::CodegenOptions{});
61- 
62- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
63- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
64- std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
65- 
66- std::vector<::ascir::ScheduledResult> schedule_results;
67- ascir::FusedScheduledResult fused_schedule_result;
68- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
69- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
70- codegen::CodegenResult result;
71- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
72- kernel_file << tiling_stub << RemoveSubDirInclude(result.kernel);
73- tiling_file << result.tiling;
74- tiling_data_file << result.tiling_data;
75- } catch (...) {
76- gen_success = false;
77- }
78- 
79- EXPECT_EQ(gen_success, true);
80}52}
81 53 
82#endif // AUTOFUSE_TESTS_V35_ST_BACKEND_E2E_V2_BOOL_BACKEND_CODEGEN_COMMON_H_54#endif // AUTOFUSE_TESTS_V35_ST_BACKEND_E2E_V2_BOOL_BACKEND_CODEGEN_COMMON_H_
Mautofuse/tests/v35/st/backend_e2e_v2/floortoint_float_test/floortoint_float_backend_generate.cpp+7-30
@@ -15,7 +15,7 @@
15#include "codegen.h"15#include "codegen.h"
16#include "optimize.h"16#include "optimize.h"
17#include "share_graph.h"17#include "share_graph.h"
18-#include "backend_common.h"18+#include "../backend_codegen_common.h"
19 19 
20#include <iostream>20#include <iostream>
21#include <vector>21#include <vector>
@@ -38,7 +38,6 @@ class TestBackendFloortointFloatE2e : public testing::Test {
38};38};
39 39 
40TEST_F(TestBackendFloortointFloatE2e, FloortointFloatE2eCodegen) {40TEST_F(TestBackendFloortointFloatE2e, FloortointFloatE2eCodegen) {
41- bool gen_success = true;
42 std::string tilig_stub = R"(41 std::string tilig_stub = R"(
43#define REGISTER_TILING_DEFAULT(tiling)42#define REGISTER_TILING_DEFAULT(tiling)
44#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;43#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
@@ -46,32 +45,10 @@ TEST_F(TestBackendFloortointFloatE2e, FloortointFloatE2eCodegen) {
46 45 
47 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}});46 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}});
48 auto graph = ascir::ShareGraph::FloorToIntFloatFusedGraph(2);47 auto graph = ascir::ShareGraph::FloorToIntFloatFusedGraph(2);
49- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;48+ GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) {
50- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');49+ EXPECT_NE(kernel.find("AscendC::Cast(local_3[0], local_2[0], AscendC::RoundMode::CAST_FLOOR, "
51- std::string kernel_src_file_name = parts[0];50+ "local_2_actual_size);"),
52- std::string tiling_src_file_name = parts[1];51+ std::string::npos);
53- std::string tiling_data_src = parts[2];52+ EXPECT_NE(kernel.find("DataCopyPadExtend<int32_t, AscendC::PaddingMode::Normal>"), std::string::npos);
54- 53+ });
55- try {
56- optimize::Optimizer optimizer(optimize::OptimizerOptions{});
57- codegen::Codegen codegen(codegen::CodegenOptions{});
58- 
59- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
60- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
61- std::fstream tiling_data_file(tiling_data_src, std::ios::out);
62- 
63- std::vector<::ascir::ScheduledResult> schedule_results;
64- ascir::FusedScheduledResult fused_schedule_result;
65- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
66- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
67- codegen::CodegenResult result;
68- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
69- kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel);
70- tiling_file << result.tiling;
71- tiling_data_file << result.tiling_data;
72- } catch (...) {
73- gen_success = false;
74- }
75- 
76- EXPECT_EQ(gen_success, true);
77}54}
Mautofuse/tests/v35/st/backend_e2e_v2/int16_logical_not_test/int16_logical_not_backend_generate.cpp+7-30
@@ -15,7 +15,7 @@
15#include "codegen.h"15#include "codegen.h"
16#include "optimize.h"16#include "optimize.h"
17#include "share_graph.h"17#include "share_graph.h"
18-#include "backend_common.h"18+#include "../backend_codegen_common.h"
19 19 
20#include <iostream>20#include <iostream>
21#include <vector>21#include <vector>
@@ -39,7 +39,6 @@ class TestBackendInt16LogicalNotE2e : public testing::Test {
39};39};
40 40 
41TEST_F(TestBackendInt16LogicalNotE2e, LoadLogicalNotStoreE2eCodegen) {41TEST_F(TestBackendInt16LogicalNotE2e, LoadLogicalNotStoreE2eCodegen) {
42- bool gen_success = true;
43 std::string tiling_stub = R"(42 std::string tiling_stub = R"(
44#define REGISTER_TILING_DEFAULT(tiling)43#define REGISTER_TILING_DEFAULT(tiling)
45#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;44#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
@@ -48,32 +47,10 @@ TEST_F(TestBackendInt16LogicalNotE2e, LoadLogicalNotStoreE2eCodegen) {
48 // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)47 // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)
49 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}});48 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}});
50 auto graph = ascir::ShareGraph::LoadLogicalNotStoreFusedGraph(2, af::DT_INT16, af::DT_UINT8);49 auto graph = ascir::ShareGraph::LoadLogicalNotStoreFusedGraph(2, af::DT_INT16, af::DT_UINT8);
51- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;50+ GenerateBackendKernelWithCheck(graph, shape_info, tiling_stub, [](const std::string &kernel) {
52- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');51+ EXPECT_NE(kernel.find("LocalTensor<half> local_blk_tensor_of_half_1"), std::string::npos);
53- const std::string &kernel_src_file_name = parts[0];52+ EXPECT_NE(kernel.find("Duplicate(local_blk_tensor_of_half_1[0], (half)1.0, ONE_BLK_SIZE / sizeof(half));"),
54- const std::string &tiling_src_file_name = parts[1];53+ std::string::npos);
55- const std::string &tiling_data_src_file_name = parts[2];54+ EXPECT_NE(kernel.find("AscendC::LogicalNot(dst, src, count);"), std::string::npos);
56- 55+ });
57- try {
58- optimize::Optimizer optimizer(optimize::OptimizerOptions{});
59- codegen::Codegen codegen(codegen::CodegenOptions{});
60- 
61- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
62- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
63- std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
64- 
65- std::vector<::ascir::ScheduledResult> schedule_results;
66- ascir::FusedScheduledResult fused_schedule_result;
67- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
68- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
69- codegen::CodegenResult result;
70- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
71- kernel_file << tiling_stub << RemoveSubDirInclude(result.kernel);
72- tiling_file << result.tiling;
73- tiling_data_file << result.tiling_data;
74- } catch (...) {
75- gen_success = false;
76- }
77- 
78- EXPECT_EQ(gen_success, true);
79}56}
Mautofuse/tests/v35/st/backend_e2e_v2/load_compare_cast_sum_store_test/load_compare_cast_sum_store_backend_generator.cpp+10-30
@@ -15,7 +15,7 @@
15#include "codegen.h"15#include "codegen.h"
16#include "optimize.h"16#include "optimize.h"
17#include "share_graph.h"17#include "share_graph.h"
18-#include "backend_common.h"18+#include "../backend_codegen_common.h"
19 19 
20#include <iostream>20#include <iostream>
21#include <vector>21#include <vector>
@@ -39,7 +39,6 @@ class TestBackendLoadCompareCastSumStoreE2e : public testing::Test {
39};39};
40 40 
41TEST_F(TestBackendLoadCompareCastSumStoreE2e, LoadCompareCastSumStoreE2eCodegen) {41TEST_F(TestBackendLoadCompareCastSumStoreE2e, LoadCompareCastSumStoreE2eCodegen) {
42- bool gen_success = true;
43 std::string tiling_stub = R"(42 std::string tiling_stub = R"(
44#define REGISTER_TILING_DEFAULT(tiling)43#define REGISTER_TILING_DEFAULT(tiling)
45#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;44#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
@@ -48,32 +47,13 @@ TEST_F(TestBackendLoadCompareCastSumStoreE2e, LoadCompareCastSumStoreE2eCodegen)
48 // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)47 // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)
49 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});48 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});
50 auto graph = ascir::ShareGraph::LoadCompareCastSumStoreFusedGraph(3);49 auto graph = ascir::ShareGraph::LoadCompareCastSumStoreFusedGraph(3);
51- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;50+ GenerateBackendKernelWithCheck(graph, shape_info, tiling_stub, [](const std::string &kernel) {
52- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');51+ EXPECT_NE(kernel.find("CompareExtend<float, 2, CMPMODE::GE>"), std::string::npos);
53- const std::string &kernel_src_file_name = parts[0];52+ EXPECT_NE(kernel.find("{static_cast<uint16_t>(z1t_actual_size), static_cast<uint16_t>(z2t_actual_size)}"),
54- const std::string &tiling_src_file_name = parts[1];53+ std::string::npos);
55- const std::string &tiling_data_src_file_name = parts[2];54+ EXPECT_NE(kernel.find("{static_cast<uint16_t>(((32 * Ceiling((Rational(1 , 32) * t->z2t_size))))/(1)), "
56- 55+ "static_cast<uint16_t>(1)}"),
57- try {56+ std::string::npos);
58- optimize::Optimizer optimizer(optimize::OptimizerOptions{});57+ EXPECT_NE(kernel.find("ReduceSum<float, AscendC::Pattern::Reduce::RA, true>"), std::string::npos);
59- codegen::Codegen codegen(codegen::CodegenOptions{});58+ });
60- 
61- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
62- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
63- std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
64- 
65- std::vector<::ascir::ScheduledResult> schedule_results;
66- ascir::FusedScheduledResult fused_schedule_result;
67- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
68- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
69- codegen::CodegenResult result;
70- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
71- kernel_file << tiling_stub << RemoveSubDirInclude(result.kernel);
72- tiling_file << result.tiling;
73- tiling_data_file << result.tiling_data;
74- } catch (...) {
75- gen_success = false;
76- }
77- 
78- EXPECT_EQ(gen_success, true);
79}59}
Mautofuse/tests/v35/st/backend_e2e_v2/load_where_store_test/load_where_store_backend_generate.cpp+9-30
@@ -15,7 +15,7 @@
15#include "codegen.h"15#include "codegen.h"
16#include "optimize.h"16#include "optimize.h"
17#include "share_graph.h"17#include "share_graph.h"
18-#include "backend_common.h"18+#include "../backend_codegen_common.h"
19#include "runtime_stub.h"19#include "runtime_stub.h"
20#include "common/platform_context.h"20#include "common/platform_context.h"
21 21 
@@ -39,7 +39,6 @@ class TestBackendLoadWhereStoreE2e : public testing::Test {
39};39};
40 40 
41TEST_F(TestBackendLoadWhereStoreE2e, LoadWhereStoreE2eCodegen) {41TEST_F(TestBackendLoadWhereStoreE2e, LoadWhereStoreE2eCodegen) {
42- bool gen_success = true;
43 std::string tilig_stub = R"(42 std::string tilig_stub = R"(
44#define REGISTER_TILING_DEFAULT(tiling)43#define REGISTER_TILING_DEFAULT(tiling)
45#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;44#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
@@ -47,32 +46,12 @@ TEST_F(TestBackendLoadWhereStoreE2e, LoadWhereStoreE2eCodegen) {
47 // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)46 // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)
48 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});47 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});
49 auto graph = ascir::ShareGraph::LoadWhereReduceStoreFusedGraph(3, false, false);48 auto graph = ascir::ShareGraph::LoadWhereReduceStoreFusedGraph(3, false, false);
50- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;49+ GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) {
51- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');50+ EXPECT_NE(kernel.find("WhereExtend<false, false>(local_8[0], local_7[0], local_6[0], local_5[0], "
52- std::string kernel_src_file_name = parts[0]; // load_where_store_test_tiling.cpp51+ "{static_cast<uint16_t>(z0z1t_actual_size)"),
53- std::string tiling_src_file_name = parts[1]; // load_where_store_test_kernel.cpp52+ std::string::npos);
54- std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h53+ EXPECT_NE(kernel.find("{static_cast<uint16_t>(((8 * Ceiling((Rational(1 , 8) * t->z2t_size))))/(1)), "
55- 54+ "static_cast<uint16_t>(1)}"),
56- try {55+ std::string::npos);
57- optimize::Optimizer optimizer(optimize::OptimizerOptions{});56+ });
58- codegen::Codegen codegen(codegen::CodegenOptions{});
59- 
60- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
61- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
62- std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
63- 
64- std::vector<::ascir::ScheduledResult> schedule_results;
65- ascir::FusedScheduledResult fused_schedule_result;
66- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
67- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
68- codegen::CodegenResult result;
69- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
70- kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel);
71- tiling_file << result.tiling;
72- tiling_data_file << result.tiling_data;
73- } catch (...) {
74- gen_success = false;
75- }
76- 
77- EXPECT_EQ(gen_success, true);
78}57}
Mautofuse/tests/v35/st/backend_e2e_v2/load_where_x2_x3_is_ubscalar_store_test/load_where_x2_x3_is_ubscalar_store_backend_generate.cpp+9-30
@@ -15,9 +15,9 @@
15#include "codegen.h"15#include "codegen.h"
16#include "optimize.h"16#include "optimize.h"
17#include "share_graph.h"17#include "share_graph.h"
18-#include "backend_common.h"
19#include "runtime_stub.h"18#include "runtime_stub.h"
20#include "common/platform_context.h"19#include "common/platform_context.h"
20+#include "../backend_codegen_common.h"
21 21 
22#include <iostream>22#include <iostream>
23#include <vector>23#include <vector>
@@ -39,7 +39,6 @@ class TestBackendLoadWhereX2X3IsUbscalarStoreE2e : public testing::Test {
39};39};
40 40 
41TEST_F(TestBackendLoadWhereX2X3IsUbscalarStoreE2e, LoadWhereX2X3IsUbscalarStoreE2eCodegen) {41TEST_F(TestBackendLoadWhereX2X3IsUbscalarStoreE2e, LoadWhereX2X3IsUbscalarStoreE2eCodegen) {
42- bool gen_success = true;
43 std::string tilig_stub = R"(42 std::string tilig_stub = R"(
44#define REGISTER_TILING_DEFAULT(tiling)43#define REGISTER_TILING_DEFAULT(tiling)
45#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;44#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
@@ -47,32 +46,12 @@ TEST_F(TestBackendLoadWhereX2X3IsUbscalarStoreE2e, LoadWhereX2X3IsUbscalarStoreE
47 // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)46 // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)
48 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});47 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});
49 auto graph = ascir::ShareGraph::LoadWhereReduceStoreFusedGraph(3, true, true);48 auto graph = ascir::ShareGraph::LoadWhereReduceStoreFusedGraph(3, true, true);
50- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;49+ GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) {
51- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');50+ EXPECT_NE(kernel.find("WhereExtend(local_5[0], local_4[0], scalar_2, scalar_3, local_4_actual_size);"),
52- std::string kernel_src_file_name = parts[0]; // load_where_x2_x3_is_ubscalar_store_test_tiling.cpp51+ std::string::npos);
53- std::string tiling_src_file_name = parts[1]; // load_where_x2_x3_is_ubscalar_store_test_kernel.cpp52+ EXPECT_NE(kernel.find("Duplicate(local_blk_tensor_of_scalar_2[0], static_cast<float>(100), "
54- std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h53+ "static_cast<uint64_t>(32/sizeof(float)));"),
55- 54+ std::string::npos);
56- try {55+ EXPECT_NE(kernel.find("DataCopyPadExtend<float, AscendC::PaddingMode::Normal>(global_1"), std::string::npos);
57- optimize::Optimizer optimizer(optimize::OptimizerOptions{});56+ });
58- codegen::Codegen codegen(codegen::CodegenOptions{});
59- 
60- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
61- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
62- std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
63- 
64- std::vector<::ascir::ScheduledResult> schedule_results;
65- ascir::FusedScheduledResult fused_schedule_result;
66- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
67- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
68- codegen::CodegenResult result;
69- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
70- kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel);
71- tiling_file << result.tiling;
72- tiling_data_file << result.tiling_data;
73- } catch (...) {
74- gen_success = false;
75- }
76- 
77- EXPECT_EQ(gen_success, true);
78}57}
Mautofuse/tests/v35/st/backend_e2e_v2/matmul_compare_scalar_test/matmul_backend_generate.cpp+8-1
@@ -84,7 +84,14 @@ TEST_F(TestBackendMatmulEqScalar, MatmulEqScalarCodegen) {
84 84 
85 // 分别生成ub和common模板的kernel和tiling85 // 分别生成ub和common模板的kernel和tiling
86 EXPECT_EQ(codegen.Generate(shape_info, ub_schedule_result, result), 0);86 EXPECT_EQ(codegen.Generate(shape_info, ub_schedule_result, result), 0);
87- kernel_file << RemoveSubDirInclude(result.kernel);87+ const std::string ub_kernel = RemoveSubDirInclude(result.kernel);
88+ EXPECT_NE(ub_kernel.find("CompareScalarExtend<float, 2, CMPMODE::EQ>"), std::string::npos);
89+ EXPECT_NE(ub_kernel.find("{static_cast<uint16_t>(curAivM), static_cast<uint16_t>(curAivN)}"), std::string::npos);
90+ EXPECT_NE(ub_kernel.find("{static_cast<uint16_t>(((curAivN + 32 - 1) / 32 * 32)), static_cast<uint16_t>(1)}"),
91+ std::string::npos);
92+ EXPECT_NE(ub_kernel.find("{static_cast<uint16_t>(((curAivN + 8 - 1) / 8 * 8)), static_cast<uint16_t>(1)}"),
93+ std::string::npos);
94+ kernel_file << ub_kernel;
88 tiling_file << result.tiling;95 tiling_file << result.tiling;
89 tiling_data_file << result.tiling_data;96 tiling_data_file << result.tiling_data;
90 97 
Mautofuse/tests/v35/st/backend_e2e_v2/matmul_elemwise_brc_test/matmul_backend_generate.cpp+127-33
@@ -16,10 +16,11 @@
16#include <vector>16#include <vector>
17#include <string>17#include <string>
18#include <sstream>18#include <sstream>
19+#include "codegen_kernel.h"
19#include "codegen.h"20#include "codegen.h"
20#include "optimize.h"21#include "optimize.h"
21#include "share_graph.h"22#include "share_graph.h"
22-#include "backend_common.h"23+#include "../backend_codegen_common.h"
23#include "ascir_ops.h"24#include "ascir_ops.h"
24#include "ascir_ops_utils.h"25#include "ascir_ops_utils.h"
25#include "ascgraph_info_complete.h"26#include "ascgraph_info_complete.h"
@@ -27,6 +28,49 @@
27#include "common/platform_context.h"28#include "common/platform_context.h"
28#include "runtime_stub.h"29#include "runtime_stub.h"
29#include "common_utils.h"30#include "common_utils.h"
31+#include "../../../../../v35/codegen/reg_api_call/reg_api_call_utils.h"
32+ 
33+namespace {
34+codegen::Tensor MakeCvFusionTensor(const ascir::TensorAttr &tensor_attr) {
35+ std::string dtype_name;
36+ EXPECT_EQ(codegen::Tensor::DtypeName(tensor_attr.attr.dtype, dtype_name), af::SUCCESS);
37+ codegen::Tensor tensor(tensor_attr, dtype_name);
38+ EXPECT_EQ(tensor.Init(), af::SUCCESS);
39+ return tensor;
40+}
41+ 
42+struct CvFusionDataCopyTensors {
43+ codegen::Tensor gm;
44+ codegen::Tensor ub;
45+};
46+ 
47+CvFusionDataCopyTensors MakeCvFusionDataCopyTensors() {
48+ af::AscGraph graph("cv_fusion_data_copy_params");
49+ af::ascir_op::Data data("data", graph);
50+ af::ascir_op::Load load("load");
51+ graph.AddNode(load);
52+ load.x = data.y;
53+ 
54+ auto gm_node = graph.FindNode("data");
55+ gm_node->outputs[0].attr.dtype = ge::DT_FLOAT16;
56+ gm_node->outputs[0].attr.mem.tensor_id = 0;
57+ gm_node->outputs[0].attr.mem.reuse_id = 0;
58+ gm_node->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeGlobal;
59+ gm_node->outputs[0].attr.mem.hardware = af::MemHardware::kMemHardwareGM;
60+ gm_node->outputs[0].attr.mem.position = af::Position::kPositionGM;
61+ gm_node->outputs[0].attr.opt.merge_scope = af::kIdNone;
62+ 
63+ auto ub_node = graph.FindNode("load");
64+ ub_node->outputs[0].attr.dtype = ge::DT_FLOAT16;
65+ ub_node->outputs[0].attr.mem.tensor_id = 1;
66+ ub_node->outputs[0].attr.mem.reuse_id = 0;
67+ ub_node->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeBuffer;
68+ ub_node->outputs[0].attr.mem.hardware = af::MemHardware::kMemHardwareUB;
69+ ub_node->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
70+ ub_node->outputs[0].attr.opt.merge_scope = af::kIdNone;
71+ return {MakeCvFusionTensor(gm_node->outputs[0]), MakeCvFusionTensor(ub_node->outputs[0])};
72+}
73+} // namespace
30 74 
31class TestBackendMatmulEleBrc : public testing::Test {75class TestBackendMatmulEleBrc : public testing::Test {
32 protected:76 protected:
@@ -79,34 +123,14 @@ TEST_F(TestBackendMatmulEleBrc, MatmulEleBrcCodegen) {
79 123 
80 // 分别生成ub和common模板的kernel和tiling124 // 分别生成ub和common模板的kernel和tiling
81 EXPECT_EQ(codegen.Generate(shape_info, ub_schedule_result, result), 0);125 EXPECT_EQ(codegen.Generate(shape_info, ub_schedule_result, result), 0);
82- kernel_file << RemoveSubDirInclude(result.kernel);126+ const std::string ub_kernel = RemoveSubDirInclude(result.kernel);
127+ EXPECT_FALSE(ub_kernel.empty());
128+ EXPECT_FALSE(result.tiling.empty());
129+ EXPECT_FALSE(result.tiling_data.empty());
130+ kernel_file << ub_kernel;
83 tiling_file << result.tiling;131 tiling_file << result.tiling;
84 tiling_data_file << result.tiling_data;132 tiling_data_file << result.tiling_data;
85 133 
86- // 校验RemoveSubDirInclude(result.kernel)中是否包含IncludeMatmulHeadFiles方法返回的所有头文件内容
87- std::vector<std::string> expected_headers = {"#include \"arch35/mat_mul_v3_tiling_key_public.h\"",
88- "#include \"arch35/mat_mul_tiling_data.h\"",
89- "#include \"mat_mul_v3_common.h\"",
90- "#include \"arch35/mat_mul_asw_block.h\"",
91- "#include \"arch35/mat_mul_asw_kernel.h\"",
92- "#include \"arch35/mat_mul_stream_k_block.h\"",
93- "#include \"arch35/mat_mul_stream_k_kernel.h\"",
94- "#include \"arch35/mat_mul_v3_full_load_kernel_helper.h\"",
95- "#include \"arch35/mat_mul_full_load.h\"",
96- "#include \"arch35/mm_extension_interface/mm_copy_cube_out.h\"",
97- "#include \"arch35/mm_extension_interface/mm_custom_mm_policy.h\"",
98- "#include \"arch35/mat_mul_fixpipe_opti.h\"",
99- "#include \"arch35/block_scheduler_aswt.h\"",
100- "#include \"arch35/block_scheduler_streamk.h\"",
101- "#include \"arch35/mat_mul_streamk_basic_cmct.h\"",
102- "#include \"arch35/mat_mul_fixpipe_opti_basic_cmct.h\"",
103- "#include \"arch35/mat_mul_input_k_eq_zero_clear_output.h\""};
104- 
105- for (const auto &header : expected_headers) {
106- EXPECT_NE(RemoveSubDirInclude(result.kernel).find(header), std::string::npos)
107- << "Expected header not found in kernel: " << header;
108- }
109- 
110 kernel_src_file_name = "matmul_elemwise_brc_test_kernel_common.cpp"; // matmul_elemwise_brc_test_kernel_common.cpp134 kernel_src_file_name = "matmul_elemwise_brc_test_kernel_common.cpp"; // matmul_elemwise_brc_test_kernel_common.cpp
111 tiling_src_file_name = "matmul_elemwise_brc_test_tiling_common.cpp"; // matmul_elemwise_brc_test_tiling_common.cpp135 tiling_src_file_name = "matmul_elemwise_brc_test_tiling_common.cpp"; // matmul_elemwise_brc_test_tiling_common.cpp
112 tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h136 tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h
@@ -115,18 +139,88 @@ TEST_F(TestBackendMatmulEleBrc, MatmulEleBrcCodegen) {
115 std::fstream tiling_data_file_common(tiling_data_src_file_name, std::ios::out);139 std::fstream tiling_data_file_common(tiling_data_src_file_name, std::ios::out);
116 codegen::CodegenResult result_common;140 codegen::CodegenResult result_common;
117 EXPECT_EQ(codegen.Generate(shape_info, common_schedule_result, result_common), 0);141 EXPECT_EQ(codegen.Generate(shape_info, common_schedule_result, result_common), 0);
118- kernel_file_common << RemoveSubDirInclude(result_common.kernel);142+ const std::string common_kernel = RemoveSubDirInclude(result_common.kernel);
143+ EXPECT_FALSE(common_kernel.empty());
144+ EXPECT_FALSE(result_common.tiling.empty());
145+ EXPECT_FALSE(result_common.tiling_data.empty());
146+ kernel_file_common << common_kernel;
119 tiling_file_common << result_common.tiling;147 tiling_file_common << result_common.tiling;
120 tiling_data_file_common << result_common.tiling_data;148 tiling_data_file_common << result_common.tiling_data;
121- 
122- // 校验result_common.kernel中是否包含IncludeMatmulHeadFiles方法返回的所有头文件内容
123- for (const auto &header : expected_headers) {
124- EXPECT_NE(RemoveSubDirInclude(result_common.kernel).find(header), std::string::npos)
125- << "Expected header not found in common kernel: " << header;
126- }
127 } catch (...) {149 } catch (...) {
128 gen_success = false;150 gen_success = false;
129 }151 }
130 152 
131 EXPECT_EQ(gen_success, true);153 EXPECT_EQ(gen_success, true);
132}154}
155+ 
156+TEST_F(TestBackendMatmulEleBrc, MatmulToIntCastCvCodegen) {
157+ auto graph = ascir::ShareGraph::LoadMatmulToIntCastFusedGraph();
158+ GenerateCvBackendUbKernelWithCheck(
159+ graph, "matmul_to_int_cast_test_kernel_ub.cpp", "matmul_to_int_cast_test_tiling_ub.cpp", "autofuse_tiling_data.h",
160+ [](const std::string &kernel) {
161+ EXPECT_NE(kernel.find("AscendC::Cast(local_5[0], local_4[0], AscendC::RoundMode::CAST_RINT, "
162+ "{ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, "
163+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, "
164+ "{ConvertToUint32(curAlignN), ConvertToUint32(1)});"),
165+ std::string::npos);
166+ EXPECT_NE(kernel.find("CastExtend(local_6[0], local_5[0], "
167+ "{ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, "
168+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, "
169+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)});"),
170+ std::string::npos);
171+ EXPECT_NE(kernel.find("AscendC::Cast(local_7[0], local_6[0], AscendC::RoundMode::CAST_TRUNC, "
172+ "{ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, "
173+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, "
174+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)});"),
175+ std::string::npos);
176+ EXPECT_NE(kernel.find("AscendC::Cast(local_9[0], local_8[0], AscendC::RoundMode::CAST_FLOOR, "
177+ "{ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, "
178+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, "
179+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)});"),
180+ std::string::npos);
181+ EXPECT_NE(kernel.find("KernelUtils::BlkAlign<int32_t>(curAivN)"), std::string::npos);
182+ });
183+}
184+ 
185+TEST_F(TestBackendMatmulEleBrc, CvFusionDataCopyParamsUseDtypeAlignedFallback) {
186+ codegen::Tiler tiler;
187+ const CvFusionDataCopyTensors tensors = MakeCvFusionDataCopyTensors();
188+ std::string dtype_name = "half";
189+ 
190+ codegen::ApiCallContext normal_context;
191+ EXPECT_EQ(codegen::GetCvInputAlignedSize(normal_context, tensors.gm, "curAivN"), "curAivN");
192+ codegen::ApiCallContext cv_context;
193+ cv_context.stage = codegen::ComputeStage::kCVFuseStage1;
194+ EXPECT_EQ(codegen::GetCvInputAlignedSize(cv_context, tensors.gm, "curAivN"), "((curAivN + 16 - 1) / 16 * 16)");
195+ 
196+ codegen::TPipe ub_fuse_tpipe("tpipe", tiler);
197+ ub_fuse_tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
198+ codegen::CodegenApiParam ub_fuse_api_param;
199+ codegen::DmaSpecificParams ub_fuse_dma_params;
200+ codegen::BuildDataCopyApiParamInCVFusion(ub_fuse_tpipe, ub_fuse_api_param, ub_fuse_dma_params, tensors.gm, tensors.ub,
201+ dtype_name, true);
202+ EXPECT_EQ(ub_fuse_api_param.template_params[0], "AscendC::PaddingMode::Normal");
203+ EXPECT_EQ(ub_fuse_dma_params.data_copy_params.block_count.DebugStr(), "curAivM");
204+ EXPECT_EQ(ub_fuse_dma_params.data_copy_params.block_len.DebugStr(), "curAivN");
205+ EXPECT_EQ(ub_fuse_dma_params.data_copy_params.src_stride.DebugStr(), "(shapeN - curAivN)");
206+ EXPECT_EQ(ub_fuse_dma_params.data_copy_params.dst_stride.DebugStr(),
207+ "(KernelUtils::BlkAlign<half>(curAivN) - curAivN)");
208+ 
209+ codegen::TPipe common_tpipe("tpipe", tiler);
210+ codegen::CodegenApiParam common_api_param;
211+ codegen::DmaSpecificParams common_dma_params;
212+ codegen::BuildDataCopyApiParamInCVFusion(common_tpipe, common_api_param, common_dma_params, tensors.gm, tensors.ub,
213+ dtype_name, true);
214+ EXPECT_EQ(common_dma_params.data_copy_params.block_len.DebugStr(), "load_block_len");
215+ EXPECT_EQ(common_dma_params.data_copy_params.src_stride.DebugStr(), "load_src_stride");
216+ EXPECT_EQ(common_dma_params.data_copy_params.dst_stride.DebugStr(), "load_dst_stride");
217+ ASSERT_EQ(common_api_param.api_post_process.size(), 1U);
218+ EXPECT_NE(common_api_param.api_post_process[0].find("AscendC::GatherMask"), std::string::npos);
219+ EXPECT_NE(common_api_param.api_post_process[0].find("KernelUtils::BlkAlign<half>(curAlignN)"), std::string::npos);
220+ 
221+ codegen::CvApi2DParams cv_params;
222+ cv_params.first_dim = "curAivM";
223+ cv_params.last_dim = "curAivN";
224+ EXPECT_EQ(codegen::GenCvUint16Dims(cv_params), "{static_cast<uint16_t>(curAivM), static_cast<uint16_t>(curAivN)}");
225+ EXPECT_EQ(codegen::GenCvUint16Stride("curAlignN"), "{static_cast<uint16_t>(curAlignN), static_cast<uint16_t>(1)}");
226+}
Mautofuse/tests/v35/st/backend_e2e_v2/round_to_int_float_to_int32_test/round_to_int_float_to_int32_backend_generate.cpp+6-41
@@ -8,18 +8,7 @@
8 * See LICENSE in the root of the software repository for the full text of the License.8 * See LICENSE in the root of the software repository for the full text of the License.
9 */9 */
10 10 
11-#include <fstream>11+#include "../backend_codegen_common.h"
12-#include <gtest/gtest.h>
13-#include <exception>
14-#include <filesystem>
15-#include "codegen.h"
16-#include "optimize.h"
17-#include "share_graph.h"
18-#include "backend_common.h"
19- 
20-#include <iostream>
21-#include <vector>
22-#include <string>
23#include "runtime_stub.h"12#include "runtime_stub.h"
24#include "common/platform_context.h"13#include "common/platform_context.h"
25 14 
@@ -38,7 +27,6 @@ class TestBackendRoundToIntFloatToInt32E2e : public testing::Test {
38};27};
39 28 
40TEST_F(TestBackendRoundToIntFloatToInt32E2e, RoundToIntFloatToInt32E2eCodegen) {29TEST_F(TestBackendRoundToIntFloatToInt32E2e, RoundToIntFloatToInt32E2eCodegen) {
41- bool gen_success = true;
42 std::string tilig_stub = R"(30 std::string tilig_stub = R"(
43#define REGISTER_TILING_DEFAULT(tiling)31#define REGISTER_TILING_DEFAULT(tiling)
44#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;32#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
@@ -47,32 +35,9 @@ TEST_F(TestBackendRoundToIntFloatToInt32E2e, RoundToIntFloatToInt32E2eCodegen) {
47 // shape_info 和 RoundToIntFloatToInt32FusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)35 // shape_info 和 RoundToIntFloatToInt32FusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)
48 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}});36 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}});
49 auto graph = ascir::ShareGraph::RoundToIntFloatToInt32FusedGraph(2);37 auto graph = ascir::ShareGraph::RoundToIntFloatToInt32FusedGraph(2);
50- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;38+ GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) {
51- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');39+ EXPECT_NE(kernel.find("AscendC::Cast(local_3[0], local_2[0], AscendC::RoundMode::CAST_RINT, "
52- std::string kernel_src_file_name = parts[0]; // round_to_int_float_to_int32_test_tiling.cpp40+ "local_2_actual_size);"),
53- std::string tiling_src_file_name = parts[1]; // round_to_int_float_to_int32_test_kernel.cpp41+ std::string::npos);
54- std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h42+ });
55- 
56- try {
57- optimize::Optimizer optimizer(optimize::OptimizerOptions{});
58- codegen::Codegen codegen(codegen::CodegenOptions{});
59- 
60- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
61- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
62- std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
63- 
64- std::vector<::ascir::ScheduledResult> schedule_results;
65- ascir::FusedScheduledResult fused_schedule_result;
66- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
67- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
68- codegen::CodegenResult result;
69- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
70- kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel);
71- tiling_file << result.tiling;
72- tiling_data_file << result.tiling_data;
73- } catch (...) {
74- gen_success = false;
75- }
76- 
77- EXPECT_EQ(gen_success, true);
78}43}
Mautofuse/tests/v35/st/backend_e2e_v2/scalar_cast_add_test/scalar_cast_add_backend_generate.cpp+7-30
@@ -15,7 +15,7 @@
15#include "codegen.h"15#include "codegen.h"
16#include "optimize.h"16#include "optimize.h"
17#include "share_graph.h"17#include "share_graph.h"
18-#include "backend_common.h"18+#include "../backend_codegen_common.h"
19 19 
20#include <iostream>20#include <iostream>
21#include <vector>21#include <vector>
@@ -39,7 +39,6 @@ class TestBackendScalarCastAddE2e : public testing::Test {
39};39};
40 40 
41TEST_F(TestBackendScalarCastAddE2e, ScalarCastAddE2eCodegen) {41TEST_F(TestBackendScalarCastAddE2e, ScalarCastAddE2eCodegen) {
42- bool gen_success = true;
43 std::string tilig_stub = R"(42 std::string tilig_stub = R"(
44#define REGISTER_TILING_DEFAULT(tiling)43#define REGISTER_TILING_DEFAULT(tiling)
45#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;44#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
@@ -48,32 +47,10 @@ TEST_F(TestBackendScalarCastAddE2e, ScalarCastAddE2eCodegen) {
48 // shape_info 和 ScalarCastAddFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)47 // shape_info 和 ScalarCastAddFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)
49 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});48 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});
50 auto graph = ascir::ShareGraph::ScalarCastAddFusedGraph(3, af::DT_FLOAT16, af::DT_FLOAT);49 auto graph = ascir::ShareGraph::ScalarCastAddFusedGraph(3, af::DT_FLOAT16, af::DT_FLOAT);
51- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;50+ GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) {
52- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');51+ EXPECT_NE(kernel.find("CastExtend(local_3[0], local_blk_tensor_of_scalar_2[0], "
53- std::string kernel_src_file_name = parts[0]; // scalar_cast_add_test_tiling.cpp52+ "{ConvertToUint32(local_3_actual_size)}, {ConvertToUint32(1)}, {ConvertToUint32(1)});"),
54- std::string tiling_src_file_name = parts[1]; // scalar_cast_add_test_kernel.cpp53+ std::string::npos);
55- std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h54+ EXPECT_NE(kernel.find("Add(local_5[0], local_4[0], local_3[0], local_4_actual_size);"), std::string::npos);
56- 55+ });
57- try {
58- optimize::Optimizer optimizer(optimize::OptimizerOptions{});
59- codegen::Codegen codegen(codegen::CodegenOptions{});
60- 
61- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
62- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
63- std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
64- 
65- std::vector<::ascir::ScheduledResult> schedule_results;
66- ascir::FusedScheduledResult fused_schedule_result;
67- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
68- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
69- codegen::CodegenResult result;
70- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
71- kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel);
72- tiling_file << result.tiling;
73- tiling_data_file << result.tiling_data;
74- } catch (...) {
75- gen_success = false;
76- }
77- 
78- EXPECT_EQ(gen_success, true);
79}56}
Mautofuse/tests/v35/st/backend_e2e_v2/trunc_to_int_bf16_to_int32_test/trunc_to_int_bf16_to_int32_backend_generate.cpp+6-41
@@ -8,18 +8,7 @@
8 * See LICENSE in the root of the software repository for the full text of the License.8 * See LICENSE in the root of the software repository for the full text of the License.
9 */9 */
10 10 
11-#include <fstream>11+#include "../backend_codegen_common.h"
12-#include <gtest/gtest.h>
13-#include <exception>
14-#include <filesystem>
15-#include "codegen.h"
16-#include "optimize.h"
17-#include "share_graph.h"
18-#include "backend_common.h"
19- 
20-#include <iostream>
21-#include <vector>
22-#include <string>
23#include "runtime_stub.h"12#include "runtime_stub.h"
24#include "common/platform_context.h"13#include "common/platform_context.h"
25 14 
@@ -38,7 +27,6 @@ class TestBackendTruncToIntBf16ToInt32E2e : public testing::Test {
38};27};
39 28 
40TEST_F(TestBackendTruncToIntBf16ToInt32E2e, TruncToIntBf16ToInt32E2eCodegen) {29TEST_F(TestBackendTruncToIntBf16ToInt32E2e, TruncToIntBf16ToInt32E2eCodegen) {
41- bool gen_success = true;
42 std::string tilig_stub = R"(30 std::string tilig_stub = R"(
43#define REGISTER_TILING_DEFAULT(tiling)31#define REGISTER_TILING_DEFAULT(tiling)
44#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;32#define GET_TILING_DATA(t, tiling) AutofuseTilingData t = *(AutofuseTilingData*)tiling;
@@ -47,32 +35,9 @@ TEST_F(TestBackendTruncToIntBf16ToInt32E2e, TruncToIntBf16ToInt32E2eCodegen) {
47 // shape_info 和 TruncToIntBf16ToInt32FusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)35 // shape_info 和 TruncToIntBf16ToInt32FusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始)
48 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});36 std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}});
49 auto graph = ascir::ShareGraph::TruncToIntBf16ToInt32FusedGraph(3);37 auto graph = ascir::ShareGraph::TruncToIntBf16ToInt32FusedGraph(3);
50- std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl;38+ GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) {
51- std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':');39+ EXPECT_NE(kernel.find("AscendC::Cast(local_3[0], local_2[0], AscendC::RoundMode::CAST_TRUNC, "
52- std::string kernel_src_file_name = parts[0]; // trunc_to_int_bf16_to_int32_test_tiling.cpp40+ "local_2_actual_size);"),
53- std::string tiling_src_file_name = parts[1]; // trunc_to_int_bf16_to_int32_test_kernel.cpp41+ std::string::npos);
54- std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h42+ });
55- 
56- try {
57- optimize::Optimizer optimizer(optimize::OptimizerOptions{});
58- codegen::Codegen codegen(codegen::CodegenOptions{});
59- 
60- std::fstream kernel_file(kernel_src_file_name, std::ios::out);
61- std::fstream tiling_file(tiling_src_file_name, std::ios::out);
62- std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out);
63- 
64- std::vector<::ascir::ScheduledResult> schedule_results;
65- ascir::FusedScheduledResult fused_schedule_result;
66- fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results);
67- EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0);
68- codegen::CodegenResult result;
69- EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0);
70- kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel);
71- tiling_file << result.tiling;
72- tiling_data_file << result.tiling_data;
73- } catch (...) {
74- gen_success = false;
75- }
76- 
77- EXPECT_EQ(gen_success, true);
78}43}
Mautofuse/tests/v35/ut/codegen/reg_api_call/ test_codegen_nddma_reg_api_call.cpp+56-2
@@ -147,12 +147,66 @@ TEST(CodegenKernel, NddmaApiCall_CvInductorUsesUbAxisStrides) {
147 std::string result;147 std::string result;
148 call_0.Generate(tpipe, vector<af::AxisId>{}, result);148 call_0.Generate(tpipe, vector<af::AxisId>{}, result);
149 EXPECT_EQ(result,149 EXPECT_EQ(result,
150- std::string{"const int64_t output_dims_0[2] = {curAivM, curAlignN};\nconst int64_t input_stride_0[2] = "150+ std::string{"const int64_t output_dims_0[2] = {curAivM, curAivN};\nconst int64_t input_stride_0[2] = "
151- "{1, 0};\nconst int64_t output_stride_0[2] = {curAlignN, 1};\n"151+ "{1, 0};\nconst int64_t output_stride_0[2] = {KernelUtils::BlkAlign<float>(curAivN), "
152+ "1};\n"
152 "DataCopyNddma(local_0, local_0[offset / shapeN], output_dims_0, output_stride_0, "153 "DataCopyNddma(local_0, local_0[offset / shapeN], output_dims_0, output_stride_0, "
153 "input_stride_0);\n"});154 "input_stride_0);\n"});
154}155}
155 156 
157+TEST(CodegenKernel, NddmaApiCall_CvUbFuseUsesDtypeAlignedUbStrides) {
158+ af::AscGraph graph("test_graph");
159+ 
160+ auto m = af::Symbol(16);
161+ auto n = af::Symbol(32);
162+ auto z_m = graph.CreateAxis("z_m", m);
163+ auto z_n = graph.CreateAxis("z_n", n);
164+ 
165+ Data data0("data0", graph);
166+ Nddma nddma_op("nddma");
167+ graph.AddNode(nddma_op);
168+ nddma_op.x = data0.y;
169+ nddma_op.attr.sched.axis = {z_m.id, z_n.id};
170+ *nddma_op.y.axis = {z_m.id, z_n.id};
171+ *nddma_op.y.repeats = {m, n};
172+ *nddma_op.y.strides = {One, One};
173+ 
174+ auto nddma = graph.FindNode("nddma");
175+ nddma->attr.api.compute_type = af::ComputeType::kComputeLoad;
176+ nddma->attr.api.type = af::ApiType::kAPITypeCompute;
177+ nddma->attr.api.unit = af::ComputeUnit::kUnitMTE2;
178+ nddma->outputs[0].attr.vectorized_axis = {z_m.id, z_n.id};
179+ nddma->outputs[0].attr.vectorized_strides = {One, One};
180+ nddma->outputs[0].attr.dtype = ge::DT_FLOAT16;
181+ nddma->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
182+ nddma->outputs[0].attr.mem.tensor_id = 0;
183+ nddma->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
184+ nddma->outputs[0].attr.que.id = 1;
185+ nddma->outputs[0].attr.opt.merge_scope = af::kIdNone;
186+ 
187+ codegen::Tiler tiler;
188+ codegen::TPipe tpipe("tpipe", tiler);
189+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
190+ tpipe.is_inductor = false;
191+ tpipe.AddTensor(nddma->outputs[0]);
192+ 
193+ codegen::ApiTensor x;
194+ x.id = nddma->outputs[0].attr.mem.tensor_id;
195+ 
196+ codegen::NddmaApiCall call_0("DataCopyNddma");
197+ EXPECT_EQ(call_0.Init(nddma), 0);
198+ call_0.inputs.push_back(&x);
199+ 
200+ std::string result;
201+ call_0.Generate(tpipe, vector<af::AxisId>{}, result);
202+ EXPECT_EQ(result,
203+ std::string{"const int64_t output_dims_0[2] = {curAivM, curAivN};\nconst int64_t input_stride_0[2] = "
204+ "{shapeN, 1};\nconst int64_t output_stride_0[2] = {KernelUtils::BlkAlign<half>(curAivN), "
205+ "1};\n"
206+ "DataCopyNddma(local_0, local_0[offset], output_dims_0, "
207+ "output_stride_0, input_stride_0);\n"});
208+}
209+ 
156TEST(CodegenKernel, NddmaApiCall_SevenDimTensor) {210TEST(CodegenKernel, NddmaApiCall_SevenDimTensor) {
157 af::AscGraph graph("test_graph");211 af::AscGraph graph("test_graph");
158 212 
Mautofuse/tests/v35/ut/codegen/reg_api_call/test_codegen_cast_reg_api_call.cpp+212-16
@@ -22,12 +22,124 @@
22#include "utils/api_call_factory.h"22#include "utils/api_call_factory.h"
23#include "cast_v2_api_call.h"23#include "cast_v2_api_call.h"
24#include "ascir_node_param/ascir_node_param.h"24#include "ascir_node_param/ascir_node_param.h"
25+#include "floor_to_int_api_call.h"
26+#include "round_to_int_api_call.h"
27+#include "trunc_to_int_api_call.h"
25 28 
26using namespace ge;29using namespace ge;
27using namespace af::ops;30using namespace af::ops;
28using namespace af::ascir_op;31using namespace af::ascir_op;
29using namespace codegen;32using namespace codegen;
30 33 
34+namespace {
35+template <typename OpT, typename ApiCallT>
36+void BuildToIntCvStageGraph(af::AscGraph &graph, const std::string &api_name, const af::Expression &s0,
37+ const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) {
38+ Data x_op("x", graph);
39+ Load load_op("load");
40+ OpT to_int_op(api_name.c_str());
41+ graph.AddNode(load_op);
42+ graph.AddNode(to_int_op);
43+ 
44+ load_op.x = x_op.y;
45+ load_op.attr.sched.axis = {z0.id, z1.id};
46+ *load_op.y.axis = {z0.id, z1.id};
47+ *load_op.y.repeats = {s0, s1};
48+ *load_op.y.strides = {s1, One};
49+ to_int_op.x = load_op.y;
50+ *to_int_op.y.axis = {z0.id, z1.id};
51+ *to_int_op.y.repeats = {s0, s1};
52+ *to_int_op.y.strides = {s1, One};
53+}
54+ 
55+void InitToIntCvStageAttrs(af::AscGraph &graph, const std::string &api_name, const af::Expression &s1,
56+ const af::Axis &z0, const af::Axis &z1) {
57+ auto load = graph.FindNode("load");
58+ load->outputs[0].attr.vectorized_axis = {z0.id, z1.id};
59+ load->outputs[0].attr.vectorized_strides = {s1, One};
60+ load->outputs[0].attr.dtype = af::DT_FLOAT16;
61+ load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
62+ load->outputs[0].attr.mem.tensor_id = 0;
63+ load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
64+ load->outputs[0].attr.que.id = 1;
65+ load->outputs[0].attr.opt.merge_scope = af::kIdNone;
66+ 
67+ auto to_int = graph.FindNode(api_name.c_str());
68+ to_int->attr.api.compute_type = af::ComputeType::kComputeElewise;
69+ to_int->attr.api.type = af::ApiType::kAPITypeCompute;
70+ to_int->attr.api.unit = af::ComputeUnit::kUnitVector;
71+ to_int->attr.sched.loop_axis = z0.id;
72+ to_int->outputs[0].attr.vectorized_axis = {z0.id, z1.id};
73+ to_int->outputs[0].attr.vectorized_strides = {s1, One};
74+ to_int->outputs[0].attr.dtype = af::DT_INT32;
75+ to_int->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
76+ to_int->outputs[0].attr.mem.tensor_id = 1;
77+ to_int->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
78+ to_int->outputs[0].attr.que.id = 2;
79+ to_int->outputs[0].attr.opt.merge_scope = af::kIdNone;
80+}
81+ 
82+void InitToIntCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscNodePtr &load,
83+ const af::AscNodePtr &to_int, const af::Expression &s0, const af::Expression &s1,
84+ const af::Axis &z0, const af::Axis &z1) {
85+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
86+ tpipe.is_inductor = false;
87+ tpipe.AddTensor(load->outputs[0]);
88+ tpipe.AddTensor(to_int->outputs[0]);
89+ 
90+ tiler.AddAxis(z0);
91+ tiler.AddAxis(z1);
92+ tiler.AddSizeVar(af::SizeVar(s0));
93+ tiler.AddSizeVar(af::SizeVar(s1));
94+}
95+ 
96+template <typename OpT, typename ApiCallT>
97+void ExpectToIntCvStageUsesDtypeAwareStrides(const std::string &api_name, const std::string &round_mode) {
98+ af::AscGraph graph("test_graph");
99+ 
100+ auto s0 = graph.CreateSizeVar("s0");
101+ auto s1 = graph.CreateSizeVar("s1");
102+ auto z0 = graph.CreateAxis("z0", s0);
103+ auto z1 = graph.CreateAxis("z1", s1);
104+ BuildToIntCvStageGraph<OpT, ApiCallT>(graph, api_name, s0, s1, z0, z1);
105+ InitToIntCvStageAttrs(graph, api_name, s1, z0, z1);
106+ 
107+ auto load = graph.FindNode("load");
108+ auto to_int = graph.FindNode(api_name.c_str());
109+ codegen::Tiler tiler;
110+ codegen::TPipe tpipe("tpipe", tiler);
111+ InitToIntCvStageTpipe(tpipe, tiler, load, to_int, s0, s1, z0, z1);
112+ 
113+ codegen::ApiTensor x1;
114+ x1.id = load->outputs[0].attr.mem.tensor_id;
115+ ApiCallT call(api_name);
116+ EXPECT_EQ(call.Init(to_int), 0);
117+ call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
118+ call.inputs.push_back(&x1);
119+ 
120+ std::string result;
121+ EXPECT_EQ(call.Generate(tpipe, std::vector<af::AxisId>{z0.id}, result), 0);
122+ EXPECT_EQ(result, "AscendC::Cast(local_1[0], local_0[0], " + round_mode +
123+ ", {ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, "
124+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, "
125+ "{ConvertToUint32(((curAivN + 16 - 1) / 16 * 16)), ConvertToUint32(1)});\n");
126+}
127+} // namespace
128+ 
129+TEST(ToIntApiCallTest, RoundToIntCvStageUsesDtypeAwareStrides) {
130+ ExpectToIntCvStageUsesDtypeAwareStrides<RoundToInt, RoundToIntApiCall>("RoundToInt", "AscendC::RoundMode::CAST_RINT");
131+}
132+ 
133+TEST(ToIntApiCallTest, TruncToIntCvStageUsesDtypeAwareStrides) {
134+ ExpectToIntCvStageUsesDtypeAwareStrides<TruncToInt, TruncToIntApiCall>("TruncToInt",
135+ "AscendC::RoundMode::CAST_TRUNC");
136+}
137+ 
138+TEST(ToIntApiCallTest, FloorToIntCvStageUsesDtypeAwareStrides) {
139+ ExpectToIntCvStageUsesDtypeAwareStrides<FloorToInt, FloorToIntApiCall>("FloorToInt",
140+ "AscendC::RoundMode::CAST_FLOOR");
141+}
142+ 
31TEST(CastV2ApiCallTest, CastV2ApiCall_Zero_Stride) {143TEST(CastV2ApiCallTest, CastV2ApiCall_Zero_Stride) {
32 af::AscGraph graph("test_graph");144 af::AscGraph graph("test_graph");
33 145 
@@ -122,6 +234,11 @@ TEST(CastV2ApiCallTest, CastV2ApiCall_Zero_Stride) {
122 EXPECT_STREQ(cast_params->input_strides[0].Serialize().get(), "1");234 EXPECT_STREQ(cast_params->input_strides[0].Serialize().get(), "1");
123}235}
124 236 
237+namespace {
238+void BuildCastCvUbFuseGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, const af::Axis &z0,
239+ const af::Axis &z1, const af::Expression &output_stride0);
240+} // namespace
241+ 
125TEST(CastV2ApiCallTest, CastV2ApiCallTwoDimension) {242TEST(CastV2ApiCallTest, CastV2ApiCallTwoDimension) {
126 af::AscGraph graph("test_graph");243 af::AscGraph graph("test_graph");
127 244 
@@ -129,22 +246,7 @@ TEST(CastV2ApiCallTest, CastV2ApiCallTwoDimension) {
129 auto s1 = graph.CreateSizeVar("s1");246 auto s1 = graph.CreateSizeVar("s1");
130 auto z0 = graph.CreateAxis("z0", s0);247 auto z0 = graph.CreateAxis("z0", s0);
131 auto z1 = graph.CreateAxis("z1", s1);248 auto z1 = graph.CreateAxis("z1", s1);
132- 249+ BuildCastCvUbFuseGraph(graph, s0, s1, z0, z1, s1 + s1);
133- Data x_op("x", graph);
134- Load load_op("load");
135- af::ascir_op::Cast cast_op("cast");
136- graph.AddNode(load_op);
137- graph.AddNode(cast_op);
138- 
139- load_op.x = x_op.y;
140- load_op.attr.sched.axis = {z0.id, z1.id};
141- *load_op.y.axis = {z0.id, z1.id};
142- *load_op.y.repeats = {s0, s1};
143- *load_op.y.strides = {s1, One};
144- cast_op.x = load_op.y;
145- *cast_op.y.axis = {z0.id, z1.id};
146- *cast_op.y.repeats = {s0, s1};
147- *cast_op.y.strides = {s1 + s1, One};
148 250 
149 auto load = graph.FindNode("load");251 auto load = graph.FindNode("load");
150 auto size = af::GetSizeByDataType(af::DT_FLOAT16);252 auto size = af::GetSizeByDataType(af::DT_FLOAT16);
@@ -219,6 +321,100 @@ TEST(CastV2ApiCallTest, CastV2ApiCallTwoDimension) {
219 EXPECT_STREQ(cast_params->input_strides[1].Serialize().get(), "1");321 EXPECT_STREQ(cast_params->input_strides[1].Serialize().get(), "1");
220}322}
221 323 
324+namespace {
325+void BuildCastCvUbFuseGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, const af::Axis &z0,
326+ const af::Axis &z1, const af::Expression &output_stride0) {
327+ Data x_op("x", graph);
328+ Load load_op("load");
329+ af::ascir_op::Cast cast_op("cast");
330+ graph.AddNode(load_op);
331+ graph.AddNode(cast_op);
332+ 
333+ load_op.x = x_op.y;
334+ load_op.attr.sched.axis = {z0.id, z1.id};
335+ *load_op.y.axis = {z0.id, z1.id};
336+ *load_op.y.repeats = {s0, s1};
337+ *load_op.y.strides = {s1, One};
338+ cast_op.x = load_op.y;
339+ *cast_op.y.axis = {z0.id, z1.id};
340+ *cast_op.y.repeats = {s0, s1};
341+ *cast_op.y.strides = {output_stride0, One};
342+}
343+ 
344+void InitCastCvUbFuseAttrs(af::AscGraph &graph, const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) {
345+ auto load = graph.FindNode("load");
346+ load->outputs[0].attr.vectorized_axis = {z0.id, z1.id};
347+ load->outputs[0].attr.vectorized_strides = {s1, One};
348+ load->outputs[0].attr.dtype = af::DT_FLOAT16;
349+ load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
350+ load->outputs[0].attr.mem.tensor_id = 0;
351+ load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
352+ load->outputs[0].attr.que.id = 1;
353+ load->outputs[0].attr.opt.merge_scope = af::kIdNone;
354+ 
355+ auto cast = graph.FindNode("cast");
356+ cast->attr.api.compute_type = af::ComputeType::kComputeElewise;
357+ cast->attr.api.type = af::ApiType::kAPITypeCompute;
358+ cast->attr.api.unit = af::ComputeUnit::kUnitVector;
359+ cast->attr.sched.loop_axis = z0.id;
360+ cast->outputs[0].attr.vectorized_axis = {z0.id, z1.id};
361+ cast->outputs[0].attr.vectorized_strides = {s1, One};
362+ cast->outputs[0].attr.dtype = af::DT_FLOAT;
363+ cast->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
364+ cast->outputs[0].attr.mem.tensor_id = 1;
365+ cast->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
366+ cast->outputs[0].attr.que.id = 2;
367+ cast->outputs[0].attr.opt.merge_scope = af::kIdNone;
368+}
369+ 
370+void InitCastCvUbFuseTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscNodePtr &load,
371+ const af::AscNodePtr &cast, const af::Expression &s0, const af::Expression &s1,
372+ const af::Axis &z0, const af::Axis &z1) {
373+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
374+ tpipe.is_inductor = false;
375+ tpipe.AddTensor(load->outputs[0]);
376+ tpipe.AddTensor(cast->outputs[0]);
377+ 
378+ tiler.AddAxis(z0);
379+ tiler.AddAxis(z1);
380+ tiler.AddSizeVar(af::SizeVar(s0));
381+ tiler.AddSizeVar(af::SizeVar(s1));
382+}
383+} // namespace
384+ 
385+TEST(CastV2ApiCallTest, CastV2ApiCallCvUbFuseUsesDtypeAlignedStrides) {
386+ af::AscGraph graph("test_graph");
387+ 
388+ auto s0 = graph.CreateSizeVar("s0");
389+ auto s1 = graph.CreateSizeVar("s1");
390+ auto z0 = graph.CreateAxis("z0", s0);
391+ auto z1 = graph.CreateAxis("z1", s1);
392+ BuildCastCvUbFuseGraph(graph, s0, s1, z0, z1, s1);
393+ InitCastCvUbFuseAttrs(graph, s1, z0, z1);
394+ 
395+ auto load = graph.FindNode("load");
396+ auto cast = graph.FindNode("cast");
397+ 
398+ codegen::Tiler tiler;
399+ codegen::TPipe tpipe("tpipe", tiler);
400+ InitCastCvUbFuseTpipe(tpipe, tiler, load, cast, s0, s1, z0, z1);
401+ 
402+ codegen::ApiTensor x1;
403+ x1.id = load->outputs[0].attr.mem.tensor_id;
404+ codegen::CastV2ApiCall call("CastExtend");
405+ EXPECT_EQ(call.Init(cast), 0);
406+ call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
407+ call.inputs.push_back(&x1);
408+ 
409+ std::string result;
410+ call.Generate(tpipe, std::vector<af::AxisId>{z0.id}, result);
411+ EXPECT_EQ(result, std::string{"local_1_actual_size = curAivM * curAivN;\n"
412+ "CastExtend(local_1[0], local_0[0], {ConvertToUint32(curAivM), "
413+ "ConvertToUint32(curAivN)}, {ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), "
414+ "ConvertToUint32(1)}, {ConvertToUint32(((curAivN + 16 - 1) / 16 * 16)), "
415+ "ConvertToUint32(1)});\n"});
416+}
417+ 
222TEST(CastV2ApiCallTest, CastV2ApiCallThreeDimension) {418TEST(CastV2ApiCallTest, CastV2ApiCallThreeDimension) {
223 af::AscGraph graph("test_graph");419 af::AscGraph graph("test_graph");
224 420 
Mautofuse/tests/v35/ut/codegen/reg_api_call/test_codegen_compare_reg_api_call.cpp+264-52
@@ -171,6 +171,14 @@ TEST(CompareV2ApiCallTest, BoolDtypeNameIsBool) {
171 EXPECT_EQ(dtype_name, "bool");171 EXPECT_EQ(dtype_name, "bool");
172}172}
173 173 
174+namespace {
175+void BuildCompareScalarCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
176+ const af::Expression &s2, const af::Axis &z0, const af::Axis &z1,
177+ const af::Axis &z2);
178+void InitCompareScalarCvStageAttrs(af::AscGraph &graph, const af::Expression &s2, const af::Axis &z0,
179+ const af::Axis &z1, const af::Axis &z2);
180+} // namespace
181+ 
174TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar) {182TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar) {
175 af::AscGraph graph("test_graph");183 af::AscGraph graph("test_graph");
176 auto s0 = graph.CreateSizeVar("s0");184 auto s0 = graph.CreateSizeVar("s0");
@@ -179,62 +187,12 @@ TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar) {
179 auto z0 = graph.CreateAxis("z0", s0);187 auto z0 = graph.CreateAxis("z0", s0);
180 auto z1 = graph.CreateAxis("z1", s1);188 auto z1 = graph.CreateAxis("z1", s1);
181 auto z2 = graph.CreateAxis("z2", s2);189 auto z2 = graph.CreateAxis("z2", s2);
182- 190+ BuildCompareScalarCvStageGraph(graph, s0, s1, s2, z0, z1, z2);
183- Data x_op1("x1", graph);191+ InitCompareScalarCvStageAttrs(graph, s2, z0, z1, z2);
184- Scalar constant_op("constant");
185- constant_op.ir_attr.SetValue("1.0");
186- Load load_op1("load1");
187- af::ascir_op::Ge ge_op("ge");
188- graph.AddNode(load_op1);
189- graph.AddNode(constant_op);
190- graph.AddNode(ge_op);
191- 
192- load_op1.x = x_op1.y;
193- load_op1.attr.sched.axis = {z0.id, z1.id, z2.id};
194- *load_op1.y.axis = {z0.id, z1.id, z2.id};
195- *load_op1.y.repeats = {s0, s1, s2};
196- *load_op1.y.strides = {s1 * s2, s2, One};
197- 
198- ge_op.x1 = load_op1.y;
199- ge_op.x2 = constant_op.y;
200- *ge_op.y.axis = {z0.id, z1.id, z2.id};
201- *ge_op.y.repeats = {s0, s1, s2};
202- *ge_op.y.strides = {s1 * s2, s2, One};
203 192 
204 auto load1 = graph.FindNode("load1");193 auto load1 = graph.FindNode("load1");
205- load1->attr.api.compute_type = af::ComputeType::kComputeLoad;
206- load1->attr.api.type = af::ApiType::kAPITypeCompute;
207- load1->attr.api.unit = af::ComputeUnit::kUnitMTE2;
208- load1->attr.sched.loop_axis = z0.id;
209- load1->outputs[0].attr.vectorized_axis = {z1.id, z2.id};
210- load1->outputs[0].attr.vectorized_strides = {s2, One};
211- load1->outputs[0].attr.dtype = af::DT_FLOAT;
212- load1->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
213- load1->outputs[0].attr.mem.tensor_id = 0;
214- load1->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
215- load1->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
216- load1->outputs[0].attr.que.id = 1;
217- load1->outputs[0].attr.opt.merge_scope = af::kIdNone;
218- 
219 auto constant_node = graph.FindNode("constant");194 auto constant_node = graph.FindNode("constant");
220- constant_node->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeInvalid;
221- constant_node->outputs[0].attr.mem.tensor_id = 1;
222- constant_node->outputs[0].attr.mem.position = af::Position::kPositionInvalid;
223- constant_node->outputs[0].attr.dtype = af::DT_FLOAT;
224- 
225 auto ge = graph.FindNode("ge");195 auto ge = graph.FindNode("ge");
226- ge->attr.api.compute_type = af::ComputeType::kComputeElewise;
227- ge->attr.api.type = af::ApiType::kAPITypeCompute;
228- ge->attr.api.unit = af::ComputeUnit::kUnitVector;
229- ge->attr.sched.loop_axis = z0.id;
230- ge->outputs[0].attr.vectorized_axis = {z1.id, z2.id};
231- ge->outputs[0].attr.vectorized_strides = {s2, One};
232- ge->outputs[0].attr.dtype = af::DT_UINT8;
233- ge->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
234- ge->outputs[0].attr.mem.tensor_id = 2;
235- ge->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
236- ge->outputs[0].attr.que.id = 2;
237- ge->outputs[0].attr.opt.merge_scope = af::kIdNone;
238 196 
239 codegen::Tiler tiler;197 codegen::Tiler tiler;
240 codegen::TPipe tpipe("tpipe", tiler);198 codegen::TPipe tpipe("tpipe", tiler);
@@ -281,6 +239,134 @@ TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar) {
281 EXPECT_STREQ(compare_params->input_strides[0].Serialize().get(), "1");239 EXPECT_STREQ(compare_params->input_strides[0].Serialize().get(), "1");
282}240}
283 241 
242+namespace {
243+void BuildCompareScalarCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
244+ const af::Expression &s2, const af::Axis &z0, const af::Axis &z1,
245+ const af::Axis &z2) {
246+ Data x_op1("x1", graph);
247+ Scalar constant_op("constant");
248+ constant_op.ir_attr.SetValue("1.0");
249+ Load load_op1("load1");
250+ af::ascir_op::Ge ge_op("ge");
251+ graph.AddNode(load_op1);
252+ graph.AddNode(constant_op);
253+ graph.AddNode(ge_op);
254+ 
255+ load_op1.x = x_op1.y;
256+ load_op1.attr.sched.axis = {z0.id, z1.id, z2.id};
257+ *load_op1.y.axis = {z0.id, z1.id, z2.id};
258+ *load_op1.y.repeats = {s0, s1, s2};
259+ *load_op1.y.strides = {s1 * s2, s2, One};
260+ 
261+ ge_op.x1 = load_op1.y;
262+ ge_op.x2 = constant_op.y;
263+ *ge_op.y.axis = {z0.id, z1.id, z2.id};
264+ *ge_op.y.repeats = {s0, s1, s2};
265+ *ge_op.y.strides = {s1 * s2, s2, One};
266+}
267+ 
268+void InitCompareScalarCvStageAttrs(af::AscGraph &graph, const af::Expression &s2, const af::Axis &z0,
269+ const af::Axis &z1, const af::Axis &z2) {
270+ auto load1 = graph.FindNode("load1");
271+ load1->attr.api.compute_type = af::ComputeType::kComputeLoad;
272+ load1->attr.api.type = af::ApiType::kAPITypeCompute;
273+ load1->attr.api.unit = af::ComputeUnit::kUnitMTE2;
274+ load1->attr.sched.loop_axis = z0.id;
275+ load1->outputs[0].attr.vectorized_axis = {z1.id, z2.id};
276+ load1->outputs[0].attr.vectorized_strides = {s2, One};
277+ load1->outputs[0].attr.dtype = af::DT_FLOAT;
278+ load1->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
279+ load1->outputs[0].attr.mem.tensor_id = 0;
280+ load1->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
281+ load1->outputs[0].attr.que.id = 1;
282+ load1->outputs[0].attr.opt.merge_scope = af::kIdNone;
283+ 
284+ auto constant_node = graph.FindNode("constant");
285+ constant_node->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeInvalid;
286+ constant_node->outputs[0].attr.mem.tensor_id = 1;
287+ constant_node->outputs[0].attr.mem.position = af::Position::kPositionInvalid;
288+ constant_node->outputs[0].attr.dtype = af::DT_FLOAT;
289+ 
290+ auto ge = graph.FindNode("ge");
291+ ge->attr.api.compute_type = af::ComputeType::kComputeElewise;
292+ ge->attr.api.type = af::ApiType::kAPITypeCompute;
293+ ge->attr.api.unit = af::ComputeUnit::kUnitVector;
294+ ge->attr.sched.loop_axis = z0.id;
295+ ge->outputs[0].attr.vectorized_axis = {z1.id, z2.id};
296+ ge->outputs[0].attr.vectorized_strides = {s2, One};
297+ ge->outputs[0].attr.dtype = af::DT_UINT8;
298+ ge->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
299+ ge->outputs[0].attr.mem.tensor_id = 2;
300+ ge->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
301+ ge->outputs[0].attr.que.id = 2;
302+ ge->outputs[0].attr.opt.merge_scope = af::kIdNone;
303+}
304+ 
305+void InitCompareScalarCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscGraph &graph,
306+ const af::AscNodePtr &load1, const af::AscNodePtr &constant_node,
307+ const af::AscNodePtr &ge, const af::Expression &s0, const af::Expression &s1,
308+ const af::Expression &s2, const af::Axis &z0, const af::Axis &z1,
309+ const af::Axis &z2) {
310+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
311+ tpipe.cube_output_tensor_id = load1->outputs[0].attr.mem.tensor_id;
312+ tpipe.is_inductor = false;
313+ tpipe.CollectQues(graph);
314+ tpipe.AddTensor(load1->outputs[0]);
315+ tpipe.AddTensor("1.0", constant_node->outputs[0], "const_y");
316+ tpipe.AddTensor(ge->outputs[0]);
317+ 
318+ tiler.AddAxis(z0);
319+ tiler.AddAxis(z1);
320+ tiler.AddAxis(z2);
321+ tiler.AddSizeVar(af::SizeVar(s0));
322+ tiler.AddSizeVar(af::SizeVar(s1));
323+ tiler.AddSizeVar(af::SizeVar(s2));
324+}
325+} // namespace
326+ 
327+TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar_CVStage) {
328+ af::AscGraph graph("test_graph");
329+ 
330+ auto s0 = graph.CreateSizeVar("s0");
331+ auto s1 = graph.CreateSizeVar("s1");
332+ auto s2 = graph.CreateSizeVar("s2");
333+ auto z0 = graph.CreateAxis("z0", s0);
334+ auto z1 = graph.CreateAxis("z1", s1);
335+ auto z2 = graph.CreateAxis("z2", s2);
336+ BuildCompareScalarCvStageGraph(graph, s0, s1, s2, z0, z1, z2);
337+ InitCompareScalarCvStageAttrs(graph, s2, z0, z1, z2);
338+ 
339+ auto load1 = graph.FindNode("load1");
340+ auto constant_node = graph.FindNode("constant");
341+ auto ge = graph.FindNode("ge");
342+ 
343+ codegen::Tiler tiler;
344+ codegen::TPipe tpipe("tpipe", tiler);
345+ InitCompareScalarCvStageTpipe(tpipe, tiler, graph, load1, constant_node, ge, s0, s1, s2, z0, z1, z2);
346+ std::vector<af::AxisId> current_axis;
347+ current_axis.push_back(z0.id);
348+ 
349+ codegen::ApiTensor x1;
350+ x1.id = load1->outputs[0].attr.mem.tensor_id;
351+ codegen::ApiTensor x2;
352+ x2.id = constant_node->outputs[0].attr.mem.tensor_id;
353+ 
354+ codegen::CompareV2ApiCall call("ge");
355+ EXPECT_EQ(call.Init(ge), 0);
356+ call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
357+ call.inputs.push_back(&x1);
358+ call.inputs.push_back(&x2);
359+ 
360+ std::string result;
361+ EXPECT_EQ(call.Generate(tpipe, current_axis, result), 0);
362+ EXPECT_NE(result.find("CompareScalarExtend<float, 2, CMPMODE::ge>(local_2[0], local_0[0], scalar_1,"),
363+ std::string::npos);
364+ EXPECT_NE(result.find("{static_cast<uint16_t>(curAivM), static_cast<uint16_t>(curAivN)}"), std::string::npos);
365+ EXPECT_NE(result.find("{static_cast<uint16_t>(((curAivN + 32 - 1) / 32 * 32)), static_cast<uint16_t>(1)}"),
366+ std::string::npos);
367+ EXPECT_NE(result.find("{static_cast<uint16_t>(curAlignN), static_cast<uint16_t>(1)}"), std::string::npos);
368+}
369+ 
284TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar_Normal) {370TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar_Normal) {
285 af::AscGraph graph("test_graph");371 af::AscGraph graph("test_graph");
286 auto s0 = graph.CreateSizeVar("s0");372 auto s0 = graph.CreateSizeVar("s0");
@@ -508,3 +594,129 @@ TEST(CompareV2ApiCallTest, CompareV2ApiCall_Normal) {
508 "t->s2))))/(1)), static_cast<uint16_t>(1)}, {static_cast<uint16_t>(((8 * Ceiling((Rational(1 , 8) * "594 "t->s2))))/(1)), static_cast<uint16_t>(1)}, {static_cast<uint16_t>(((8 * Ceiling((Rational(1 , 8) * "
509 "t->s2))))/(1)), static_cast<uint16_t>(1)});\n\n}\n"});595 "t->s2))))/(1)), static_cast<uint16_t>(1)});\n\n}\n"});
510}596}
597+ 
598+namespace {
599+void BuildCompareNormalCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
600+ const af::Expression &s2, const af::Axis &z0, const af::Axis &z1,
601+ const af::Axis &z2) {
602+ Data x_op1("x1", graph);
603+ Data x_op2("x2", graph);
604+ Load load_op1("load1");
605+ Load load_op2("load2");
606+ af::ascir_op::Ge ge_op("ge");
607+ graph.AddNode(load_op1);
608+ graph.AddNode(load_op2);
609+ graph.AddNode(ge_op);
610+ 
611+ load_op1.x = x_op1.y;
612+ load_op2.x = x_op2.y;
613+ load_op1.attr.sched.axis = {z0.id, z1.id, z2.id};
614+ load_op2.attr.sched.axis = {z0.id, z1.id, z2.id};
615+ *load_op1.y.axis = {z0.id, z1.id, z2.id};
616+ *load_op2.y.axis = {z0.id, z1.id, z2.id};
617+ *load_op1.y.repeats = {s0, s1, s2};
618+ *load_op2.y.repeats = {s0, s1, s2};
619+ *load_op1.y.strides = {s1 * s2, s2, One};
620+ *load_op2.y.strides = {s1 * s2, s2, One};
621+ ge_op.x1 = load_op1.y;
622+ ge_op.x2 = load_op2.y;
623+ *ge_op.y.axis = {z0.id, z1.id, z2.id};
624+ *ge_op.y.repeats = {s0, s1, s2};
625+ *ge_op.y.strides = {s1 * s2, s2, One};
626+}
627+ 
628+void InitCompareNormalCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1, const af::Axis &z2) {
629+ auto input_stride = af::sym::Align(z2.size, 8);
630+ auto output_stride = af::sym::Align(z2.size, 32);
631+ auto load1 = graph.FindNode("load1");
632+ load1->attr.api.compute_type = af::ComputeType::kComputeLoad;
633+ load1->attr.api.type = af::ApiType::kAPITypeCompute;
634+ load1->attr.api.unit = af::ComputeUnit::kUnitMTE2;
635+ load1->attr.sched.loop_axis = z0.id;
636+ load1->outputs[0].attr.vectorized_axis = {z0.id, z1.id, z2.id};
637+ load1->outputs[0].attr.vectorized_strides = {input_stride * z1.size, input_stride, One};
638+ load1->outputs[0].attr.dtype = af::DT_FLOAT;
639+ load1->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
640+ load1->outputs[0].attr.mem.tensor_id = 0;
641+ load1->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
642+ load1->outputs[0].attr.que.id = 1;
643+ load1->outputs[0].attr.opt.merge_scope = af::kIdNone;
644+ 
645+ auto load2 = graph.FindNode("load2");
646+ load2->attr.api.compute_type = af::ComputeType::kComputeLoad;
647+ load2->attr.api.type = af::ApiType::kAPITypeCompute;
648+ load2->attr.api.unit = af::ComputeUnit::kUnitMTE2;
649+ load2->attr.sched.loop_axis = z0.id;
650+ load2->outputs[0].attr.vectorized_axis = {z0.id, z1.id, z2.id};
651+ load2->outputs[0].attr.vectorized_strides = {input_stride * z1.size, input_stride, One};
652+ load2->outputs[0].attr.dtype = af::DT_FLOAT;
653+ load2->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
654+ load2->outputs[0].attr.mem.tensor_id = 0;
655+ load2->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
656+ load2->outputs[0].attr.que.id = 1;
657+ load2->outputs[0].attr.opt.merge_scope = af::kIdNone;
658+ 
659+ auto ge = graph.FindNode("ge");
660+ ge->attr.api.compute_type = af::ComputeType::kComputeElewise;
661+ ge->attr.api.type = af::ApiType::kAPITypeCompute;
662+ ge->attr.api.unit = af::ComputeUnit::kUnitVector;
663+ ge->attr.sched.loop_axis = z0.id;
664+ ge->outputs[0].attr.vectorized_axis = {z0.id, z1.id, z2.id};
665+ ge->outputs[0].attr.vectorized_strides = {output_stride * z1.size, output_stride, One};
666+ ge->outputs[0].attr.dtype = af::DT_UINT8;
667+ ge->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
668+ ge->outputs[0].attr.mem.tensor_id = 2;
669+ ge->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
670+ ge->outputs[0].attr.que.id = 2;
671+ ge->outputs[0].attr.opt.merge_scope = af::kIdNone;
672+}
673+ 
674+void InitCompareNormalCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscNodePtr &load1,
675+ const af::AscNodePtr &load2, const af::AscNodePtr &ge, const af::Expression &s0,
676+ const af::Expression &s1, const af::Expression &s2, const af::Axis &z0,
677+ const af::Axis &z1, const af::Axis &z2) {
678+ tpipe.AddTensor(load1->outputs[0]);
679+ tpipe.AddTensor(load2->outputs[0]);
680+ tpipe.AddTensor(ge->outputs[0]);
681+ tiler.AddAxis(z0);
682+ tiler.AddAxis(z1);
683+ tiler.AddAxis(z2);
684+ tiler.AddSizeVar(af::SizeVar(s0));
685+ tiler.AddSizeVar(af::SizeVar(s1));
686+ tiler.AddSizeVar(af::SizeVar(s2));
687+}
688+} // namespace
689+ 
690+TEST(CompareV2ApiCallTest, CompareV2ApiCall_Normal_CVStageKeepsLogicalCount) {
691+ af::AscGraph graph("test_graph");
692+ auto s0 = graph.CreateSizeVar("s0");
693+ auto s1 = graph.CreateSizeVar("s1");
694+ auto s2 = graph.CreateSizeVar("s2");
695+ auto z0 = graph.CreateAxis("z0", s0);
696+ auto z1 = graph.CreateAxis("z1", s1);
697+ auto z2 = graph.CreateAxis("z2", s2);
698+ BuildCompareNormalCvStageGraph(graph, s0, s1, s2, z0, z1, z2);
699+ InitCompareNormalCvStageAttrs(graph, z0, z1, z2);
700+ 
701+ auto load1 = graph.FindNode("load1");
702+ auto load2 = graph.FindNode("load2");
703+ auto ge = graph.FindNode("ge");
704+ 
705+ codegen::Tiler tiler;
706+ codegen::TPipe tpipe("tpipe", tiler);
707+ InitCompareNormalCvStageTpipe(tpipe, tiler, load1, load2, ge, s0, s1, s2, z0, z1, z2);
708+ 
709+ codegen::ApiTensor x1, x2;
710+ x1.id = load1->outputs[0].attr.mem.tensor_id;
711+ x2.id = load2->outputs[0].attr.mem.tensor_id;
712+ codegen::CompareV2ApiCall call("ge");
713+ EXPECT_EQ(call.Init(ge), 0);
714+ call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
715+ call.inputs.push_back(&x1);
716+ call.inputs.push_back(&x2);
717+ 
718+ std::string result;
719+ EXPECT_EQ(call.Generate(tpipe, {z0.id}, result), 0);
720+ EXPECT_NE(result.find("static_cast<uint16_t>(t->s2)"), std::string::npos);
721+ EXPECT_EQ(result.find("static_cast<uint16_t>(((t->s2 + 32 - 1) / 32 * 32))"), std::string::npos);
722+}
Mautofuse/tests/v35/ut/codegen/reg_api_call/test_codegen_load_reg_api_call.cpp+58-0
@@ -89,6 +89,64 @@ TEST(CodegenKernel, LoadRegApiCall_OneDimLoad) {
89 std::string{"DataCopyPadExtend<float, AscendC::PaddingMode::Normal>(local_0[0], local_0[0 + 0], 1, 8, 0, 0);\n"});89 std::string{"DataCopyPadExtend<float, AscendC::PaddingMode::Normal>(local_0[0], local_0[0 + 0], 1, 8, 0, 0);\n"});
90}90}
91 91 
92+TEST(CodegenKernel, LoadRegApiCall_CvUbFuseUsesDtypeAwareStrides) {
93+ af::AscGraph graph("test_graph");
94+ 
95+ auto s0 = af::Symbol(16);
96+ auto s1 = af::Symbol(7);
97+ auto z0 = graph.CreateAxis("z0", s0);
98+ auto z1 = graph.CreateAxis("z1", s1);
99+ 
100+ Data x_op("x", graph);
101+ Load load_op("load");
102+ graph.AddNode(load_op);
103+ 
104+ load_op.x = x_op.y;
105+ load_op.attr.sched.axis = {z0.id, z1.id};
106+ *load_op.y.axis = {z0.id, z1.id};
107+ *load_op.y.repeats = {s0, s1};
108+ *load_op.y.strides = {s1, One};
109+ 
110+ auto load = graph.FindNode("load");
111+ load->attr.api.compute_type = af::ComputeType::kComputeLoad;
112+ load->attr.api.type = af::ApiType::kAPITypeCompute;
113+ load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
114+ load->attr.sched.loop_axis = z0.id;
115+ load->outputs[0].attr.vectorized_axis = {z0.id, z1.id};
116+ load->outputs[0].attr.vectorized_strides = {s1, One};
117+ load->outputs[0].attr.dtype = af::DT_FLOAT16;
118+ load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
119+ load->outputs[0].attr.mem.tensor_id = 0;
120+ load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
121+ load->outputs[0].attr.que.id = 1;
122+ load->outputs[0].attr.opt.merge_scope = af::kIdNone;
123+ 
124+ codegen::Tiler tiler;
125+ codegen::TPipe tpipe("tpipe", tiler);
126+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
127+ tpipe.AddTensor(load->outputs[0]);
128+ 
129+ tiler.AddAxis(z0);
130+ tiler.AddAxis(z1);
131+ tiler.AddSizeVar(af::SizeVar(s0));
132+ tiler.AddSizeVar(af::SizeVar(s1));
133+ 
134+ codegen::ApiTensor x1;
135+ x1.id = load->outputs[0].attr.mem.tensor_id;
136+ 
137+ codegen::LoadRegApiCall call_0("DataCopyPadExtend");
138+ EXPECT_EQ(call_0.Init(load), 0);
139+ call_0.inputs.push_back(&x1);
140+ 
141+ std::string result;
142+ call_0.Generate(tpipe, vector<af::AxisId>{}, result);
143+ EXPECT_NE(result.find("DataCopyPadExtend<half, AscendC::PaddingMode::Normal>("), std::string::npos);
144+ EXPECT_NE(result.find("curAivM"), std::string::npos);
145+ EXPECT_NE(result.find("curAivN"), std::string::npos);
146+ EXPECT_NE(result.find("KernelUtils::BlkAlign<half>(curAivN)"), std::string::npos);
147+ EXPECT_NE(result.find("shapeN - curAivN"), std::string::npos);
148+}
149+ 
92TEST(CodegenKernel, NormalModeDataCopyIfDualSplitting) {150TEST(CodegenKernel, NormalModeDataCopyIfDualSplitting) {
93 af::AscGraph graph("test_graph");151 af::AscGraph graph("test_graph");
94 af::Expression Two = af::Symbol(2);152 af::Expression Two = af::Symbol(2);
Mautofuse/tests/v35/ut/codegen/reg_api_call/test_codegen_logical_not_reg_api_call.cpp+107-43
@@ -25,6 +25,12 @@ using namespace af::ops;
25using namespace af::ascir_op;25using namespace af::ascir_op;
26using namespace codegen;26using namespace codegen;
27 27 
28+namespace {
29+void BuildLogicalNotCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
30+ const af::Axis &z0, const af::Axis &z1);
31+void InitLogicalNotCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1);
32+} // namespace
33+ 
28TEST(CodegenKernel, RegLogicalNotApiCall) {34TEST(CodegenKernel, RegLogicalNotApiCall) {
29 af::AscGraph graph("test_graph");35 af::AscGraph graph("test_graph");
30 36 
@@ -32,52 +38,11 @@ TEST(CodegenKernel, RegLogicalNotApiCall) {
32 auto s1 = graph.CreateSizeVar("s1");38 auto s1 = graph.CreateSizeVar("s1");
33 auto z0 = graph.CreateAxis("z0", s0);39 auto z0 = graph.CreateAxis("z0", s0);
34 auto z1 = graph.CreateAxis("z1", s1);40 auto z1 = graph.CreateAxis("z1", s1);
35- 41+ BuildLogicalNotCvStageGraph(graph, s0, s1, z0, z1);
36- Data x_op("x", graph);42+ InitLogicalNotCvStageAttrs(graph, z0, z1);
37- Load load_op("load");
38- af::ascir_op::LogicalNot logical_not_op("logical_not");
39- graph.AddNode(load_op);
40- graph.AddNode(logical_not_op);
41- 
42- load_op.x = x_op.y;
43- load_op.attr.sched.axis = {z0.id, z1.id};
44- *load_op.y.axis = {z0.id, z1.id};
45- *load_op.y.repeats = {s0, s1};
46- *load_op.y.strides = {s1, One};
47- logical_not_op.x = load_op.y;
48- *logical_not_op.y.axis = {z0.id, z1.id};
49- *logical_not_op.y.repeats = {s0, s1};
50- *logical_not_op.y.strides = {s1, One};
51 43 
52 auto load = graph.FindNode("load");44 auto load = graph.FindNode("load");
53- load->attr.api.compute_type = af::ComputeType::kComputeLoad;
54- load->attr.api.type = af::ApiType::kAPITypeCompute;
55- load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
56- load->attr.sched.loop_axis = z0.id;
57- load->outputs[0].attr.vectorized_axis = {z1.id};
58- load->outputs[0].attr.vectorized_strides = {One};
59- load->outputs[0].attr.dtype = af::DT_FLOAT;
60- load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
61- load->outputs[0].attr.mem.tensor_id = 0;
62- load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
63- load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
64- load->outputs[0].attr.que.id = 1;
65- load->outputs[0].attr.opt.merge_scope = af::kIdNone;
66- 
67 auto logical_not = graph.FindNode("logical_not");45 auto logical_not = graph.FindNode("logical_not");
68- logical_not->attr.api.compute_type = af::ComputeType::kComputeElewise;
69- logical_not->attr.api.type = af::ApiType::kAPITypeCompute;
70- logical_not->attr.api.unit = af::ComputeUnit::kUnitVector;
71- logical_not->attr.sched.loop_axis = z0.id;
72- logical_not->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}};
73- logical_not->outputs[0].attr.vectorized_axis = {z1.id};
74- logical_not->outputs[0].attr.vectorized_strides = {One};
75- logical_not->outputs[0].attr.dtype = af::DT_INT16;
76- logical_not->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
77- logical_not->outputs[0].attr.mem.tensor_id = 1;
78- logical_not->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
79- logical_not->outputs[0].attr.que.id = 2;
80- logical_not->outputs[0].attr.opt.merge_scope = af::kIdNone;
81 46 
82 codegen::Tiler tiler;47 codegen::Tiler tiler;
83 codegen::TPipe tpipe("tpipe", tiler);48 codegen::TPipe tpipe("tpipe", tiler);
@@ -100,3 +65,102 @@ TEST(CodegenKernel, RegLogicalNotApiCall) {
100 call.Generate(tpipe, current_axis, result);65 call.Generate(tpipe, current_axis, result);
101 EXPECT_EQ(result, std::string{"LogicalNotExtend(local_1[0], local_0[0], tmp_buf_0, local_0_actual_size);\n"});66 EXPECT_EQ(result, std::string{"LogicalNotExtend(local_1[0], local_0[0], tmp_buf_0, local_0_actual_size);\n"});
102}67}
68+ 
69+namespace {
70+void BuildLogicalNotCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
71+ const af::Axis &z0, const af::Axis &z1) {
72+ Data x_op("x", graph);
73+ Load load_op("load");
74+ af::ascir_op::LogicalNot logical_not_op("logical_not");
75+ graph.AddNode(load_op);
76+ graph.AddNode(logical_not_op);
77+ 
78+ load_op.x = x_op.y;
79+ load_op.attr.sched.axis = {z0.id, z1.id};
80+ *load_op.y.axis = {z0.id, z1.id};
81+ *load_op.y.repeats = {s0, s1};
82+ *load_op.y.strides = {s1, One};
83+ logical_not_op.x = load_op.y;
84+ *logical_not_op.y.axis = {z0.id, z1.id};
85+ *logical_not_op.y.repeats = {s0, s1};
86+ *logical_not_op.y.strides = {s1, One};
87+}
88+ 
89+void InitLogicalNotCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1) {
90+ auto load = graph.FindNode("load");
91+ load->attr.api.compute_type = af::ComputeType::kComputeLoad;
92+ load->attr.api.type = af::ApiType::kAPITypeCompute;
93+ load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
94+ load->attr.sched.loop_axis = z0.id;
95+ load->outputs[0].attr.vectorized_axis = {z1.id};
96+ load->outputs[0].attr.vectorized_strides = {One};
97+ load->outputs[0].attr.dtype = af::DT_FLOAT;
98+ load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
99+ load->outputs[0].attr.mem.tensor_id = 0;
100+ load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
101+ load->outputs[0].attr.que.id = 1;
102+ load->outputs[0].attr.opt.merge_scope = af::kIdNone;
103+ 
104+ auto logical_not = graph.FindNode("logical_not");
105+ logical_not->attr.api.compute_type = af::ComputeType::kComputeElewise;
106+ logical_not->attr.api.type = af::ApiType::kAPITypeCompute;
107+ logical_not->attr.api.unit = af::ComputeUnit::kUnitVector;
108+ logical_not->attr.sched.loop_axis = z0.id;
109+ logical_not->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}};
110+ logical_not->outputs[0].attr.vectorized_axis = {z1.id};
111+ logical_not->outputs[0].attr.vectorized_strides = {One};
112+ logical_not->outputs[0].attr.dtype = af::DT_INT16;
113+ logical_not->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
114+ logical_not->outputs[0].attr.mem.tensor_id = 1;
115+ logical_not->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
116+ logical_not->outputs[0].attr.que.id = 2;
117+ logical_not->outputs[0].attr.opt.merge_scope = af::kIdNone;
118+}
119+ 
120+void InitLogicalNotCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscGraph &graph,
121+ const af::AscNodePtr &load, const af::AscNodePtr &logical_not, const af::Expression &s0,
122+ const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) {
123+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
124+ tpipe.is_inductor = false;
125+ tpipe.CollectQues(graph);
126+ tpipe.AddTensor(load->outputs[0]);
127+ tpipe.AddTensor(logical_not->outputs[0]);
128+ 
129+ tiler.AddAxis(z0);
130+ tiler.AddAxis(z1);
131+ tiler.AddSizeVar(af::SizeVar(s0));
132+ tiler.AddSizeVar(af::SizeVar(s1));
133+}
134+} // namespace
135+ 
136+TEST(CodegenKernel, RegLogicalNotApiCallCVStage) {
137+ af::AscGraph graph("test_graph");
138+ 
139+ auto s0 = graph.CreateSizeVar("s0");
140+ auto s1 = graph.CreateSizeVar("s1");
141+ auto z0 = graph.CreateAxis("z0", s0);
142+ auto z1 = graph.CreateAxis("z1", s1);
143+ BuildLogicalNotCvStageGraph(graph, s0, s1, z0, z1);
144+ InitLogicalNotCvStageAttrs(graph, z0, z1);
145+ 
146+ auto load = graph.FindNode("load");
147+ auto logical_not = graph.FindNode("logical_not");
148+ 
149+ codegen::Tiler tiler;
150+ codegen::TPipe tpipe("tpipe", tiler);
151+ InitLogicalNotCvStageTpipe(tpipe, tiler, graph, load, logical_not, s0, s1, z0, z1);
152+ std::vector<af::AxisId> current_axis;
153+ current_axis.push_back(z0.id);
154+ 
155+ codegen::ApiTensor x1;
156+ x1.id = load->outputs[0].attr.mem.tensor_id;
157+ codegen::UnaryApiTmpCall call("LogicalNotExtend");
158+ EXPECT_EQ(call.Init(logical_not), 0);
159+ call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
160+ call.inputs.push_back(&x1);
161+ std::string result;
162+ call.Generate(tpipe, current_axis, result);
163+ EXPECT_EQ(result,
164+ std::string{
165+ "LogicalNotExtend(local_1[0], local_0[0], tmp_buf_0, ((local_0_actual_size + 16 - 1) / 16 * 16));\n"});
166+}
Mautofuse/tests/v35/ut/codegen/reg_api_call/test_codegen_store_reg_api_call.cpp+104-0
@@ -140,6 +140,110 @@ TEST(CodegenKernel, StoreRegApiCall_TwoStoreOneOutput) {
140 "z0_t_size, 1, (16 - 1), 0);\n"});140 "z0_t_size, 1, (16 - 1), 0);\n"});
141}141}
142 142 
143+namespace {
144+void BuildStoreCvUbFuseGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
145+ const af::Axis &z0, const af::Axis &z1) {
146+ Data x_op("x", graph);
147+ Load load_op("load");
148+ af::ascir_op::Store store_op("store");
149+ graph.AddNode(load_op);
150+ graph.AddNode(store_op);
151+ 
152+ const std::vector<af::AxisId> axes = {z0.id, z1.id};
153+ const std::vector<af::Expression> repeats = {s0, s1};
154+ const std::vector<af::Expression> strides = {s1, One};
155+ load_op.x = x_op.y;
156+ load_op.attr.sched.axis = axes;
157+ *load_op.y.axis = axes;
158+ *load_op.y.repeats = repeats;
159+ *load_op.y.strides = strides;
160+ store_op.x = load_op.y;
161+ store_op.ir_attr.SetOffset(af::Symbol(0));
162+ *store_op.y.axis = axes;
163+ *store_op.y.repeats = repeats;
164+ *store_op.y.strides = strides;
165+}
166+ 
167+void InitStoreCvUbFuseAttrs(af::AscGraph &graph, const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) {
168+ auto load = graph.FindNode("load");
169+ load->attr.api.compute_type = af::ComputeType::kComputeLoad;
170+ load->attr.api.type = af::ApiType::kAPITypeCompute;
171+ load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
172+ load->attr.sched.loop_axis = z0.id;
173+ auto &load_attr = load->outputs[0].attr;
174+ load_attr.vectorized_axis = {z0.id, z1.id};
175+ load_attr.vectorized_strides = {s1, One};
176+ load_attr.dtype = af::DT_FLOAT16;
177+ load_attr.mem.position = af::Position::kPositionVecIn;
178+ load_attr.mem.tensor_id = 0;
179+ load_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
180+ load_attr.que.id = 1;
181+ load_attr.opt.merge_scope = af::kIdNone;
182+ 
183+ auto store = graph.FindNode("store");
184+ store->attr.api.compute_type = af::ComputeType::kComputeElewise;
185+ store->attr.api.type = af::ApiType::kAPITypeCompute;
186+ store->attr.api.unit = af::ComputeUnit::kUnitVector;
187+ store->attr.sched.loop_axis = z0.id;
188+ auto &store_attr = store->outputs[0].attr;
189+ store_attr.vectorized_axis = {z0.id, z1.id};
190+ store_attr.vectorized_strides = {s1, One};
191+ store_attr.dtype = af::DT_FLOAT16;
192+ store_attr.mem.position = af::Position::kPositionVecOut;
193+ store_attr.mem.tensor_id = 1;
194+ store_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
195+ store_attr.que.id = 2;
196+ store_attr.opt.merge_scope = af::kIdNone;
197+}
198+ 
199+void InitStoreCvUbFuseTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscGraph &graph,
200+ const af::AscNodePtr &load, const af::AscNodePtr &store, const af::Expression &s0,
201+ const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) {
202+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
203+ tpipe.CollectQues(graph);
204+ tpipe.AddTensor(load->outputs[0]);
205+ tpipe.AddTensor(store->outputs[0]);
206+ 
207+ tiler.AddAxis(z0);
208+ tiler.AddAxis(z1);
209+ tiler.AddSizeVar(af::SizeVar(s0));
210+ tiler.AddSizeVar(af::SizeVar(s1));
211+}
212+} // namespace
213+ 
214+TEST(CodegenKernel, StoreRegApiCall_CvUbFuseUsesDtypeAwareStrides) {
215+ af::AscGraph graph("test_graph");
216+ 
217+ auto s0 = af::Symbol(16);
218+ auto s1 = af::Symbol(7);
219+ auto z0 = graph.CreateAxis("z0", s0);
220+ auto z1 = graph.CreateAxis("z1", s1);
221+ BuildStoreCvUbFuseGraph(graph, s0, s1, z0, z1);
222+ InitStoreCvUbFuseAttrs(graph, s1, z0, z1);
223+ 
224+ auto load = graph.FindNode("load");
225+ auto store = graph.FindNode("store");
226+ 
227+ codegen::Tiler tiler;
228+ codegen::TPipe tpipe("tpipe", tiler);
229+ InitStoreCvUbFuseTpipe(tpipe, tiler, graph, load, store, s0, s1, z0, z1);
230+ 
231+ codegen::ApiTensor x1;
232+ x1.id = load->outputs[0].attr.mem.tensor_id;
233+ 
234+ codegen::StoreRegApiCall call_0("DataCopyPadExtend");
235+ EXPECT_EQ(call_0.Init(store), 0);
236+ call_0.inputs.push_back(&x1);
237+ 
238+ std::string result;
239+ call_0.Generate(tpipe, vector<af::AxisId>{}, result);
240+ EXPECT_NE(result.find("DataCopyPadExtend<half, AscendC::PaddingMode::Normal>("), std::string::npos);
241+ EXPECT_NE(result.find("curAivM"), std::string::npos);
242+ EXPECT_NE(result.find("curAivN"), std::string::npos);
243+ EXPECT_NE(result.find("KernelUtils::BlkAlign<half>(curAivN)"), std::string::npos);
244+ EXPECT_NE(result.find("shapeN - curAivN"), std::string::npos);
245+}
246+ 
143TEST(CodegenKernel, StoreRegApiCall_NeetMte3SyncMte2) {247TEST(CodegenKernel, StoreRegApiCall_NeetMte3SyncMte2) {
144 af::AscGraph graph("test_graph");248 af::AscGraph graph("test_graph");
145 249 
Mautofuse/tests/v35/ut/codegen/reg_api_call/test_codegen_unary_reg_api_call.cpp+135-41
@@ -23,6 +23,12 @@ using namespace af::ops;
23using namespace af::ascir_op;23using namespace af::ascir_op;
24 24 
25namespace codegen {25namespace codegen {
26+namespace {
27+void BuildIsNanCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, const af::Axis &z0,
28+ const af::Axis &z1);
29+void InitIsNanCvStageAttrs(af::AscGraph &graph, ge::DataType output_dtype, const af::Axis &z0, const af::Axis &z1);
30+} // namespace
31+ 
26TEST(CodegenKernel, UnaryApicallIsNan) {32TEST(CodegenKernel, UnaryApicallIsNan) {
27 af::AscGraph graph("test_graph");33 af::AscGraph graph("test_graph");
28 34 
@@ -30,50 +36,11 @@ TEST(CodegenKernel, UnaryApicallIsNan) {
30 auto s1 = graph.CreateSizeVar("s1");36 auto s1 = graph.CreateSizeVar("s1");
31 auto z0 = graph.CreateAxis("z0", s0);37 auto z0 = graph.CreateAxis("z0", s0);
32 auto z1 = graph.CreateAxis("z1", s1);38 auto z1 = graph.CreateAxis("z1", s1);
33- 39+ BuildIsNanCvStageGraph(graph, s0, s1, z0, z1);
34- Data x_op("x", graph);40+ InitIsNanCvStageAttrs(graph, af::DT_INT16, z0, z1);
35- Load load_op("load");
36- Isnan rsqrt_op("IsNan");
37- graph.AddNode(rsqrt_op);
38- 
39- load_op.x = x_op.y;
40- load_op.attr.sched.axis = {z0.id, z1.id};
41- *load_op.y.axis = {z0.id, z1.id};
42- *load_op.y.repeats = {s0, s1};
43- *load_op.y.strides = {s1, One};
44- rsqrt_op.x = load_op.y;
45- *rsqrt_op.y.axis = {z0.id, z1.id};
46- *rsqrt_op.y.repeats = {s0, s1};
47- *rsqrt_op.y.strides = {s1, One};
48 41 
49 auto load = graph.FindNode("load");42 auto load = graph.FindNode("load");
50- load->attr.api.compute_type = af::ComputeType::kComputeLoad;
51- load->attr.api.type = af::ApiType::kAPITypeCompute;
52- load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
53- load->attr.sched.loop_axis = z0.id;
54- load->outputs[0].attr.vectorized_axis = {z1.id};
55- load->outputs[0].attr.vectorized_strides = {One};
56- load->outputs[0].attr.dtype = af::DT_FLOAT;
57- load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
58- load->outputs[0].attr.mem.tensor_id = 0;
59- load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
60- load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
61- load->outputs[0].attr.que.id = 1;
62- load->outputs[0].attr.opt.merge_scope = af::kIdNone;
63- 
64 auto rsqrt = graph.FindNode("IsNan");43 auto rsqrt = graph.FindNode("IsNan");
65- rsqrt->attr.api.compute_type = af::ComputeType::kComputeElewise;
66- rsqrt->attr.api.type = af::ApiType::kAPITypeCompute;
67- rsqrt->attr.api.unit = af::ComputeUnit::kUnitVector;
68- rsqrt->attr.sched.loop_axis = z0.id;
69- rsqrt->outputs[0].attr.vectorized_axis = {z1.id};
70- rsqrt->outputs[0].attr.vectorized_strides = {One};
71- rsqrt->outputs[0].attr.dtype = af::DT_INT16;
72- rsqrt->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
73- rsqrt->outputs[0].attr.mem.tensor_id = 1;
74- rsqrt->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
75- rsqrt->outputs[0].attr.que.id = 2;
76- rsqrt->outputs[0].attr.opt.merge_scope = af::kIdNone;
77 44 
78 codegen::Tiler tiler;45 codegen::Tiler tiler;
79 codegen::TPipe tpipe("tpipe", tiler);46 codegen::TPipe tpipe("tpipe", tiler);
@@ -100,6 +67,133 @@ TEST(CodegenKernel, UnaryApicallIsNan) {
100 delete call;67 delete call;
101}68}
102 69 
70+namespace {
71+void BuildIsNanCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, const af::Axis &z0,
72+ const af::Axis &z1) {
73+ Data x_op("x", graph);
74+ Load load_op("load");
75+ Isnan rsqrt_op("IsNan");
76+ graph.AddNode(rsqrt_op);
77+ 
78+ load_op.x = x_op.y;
79+ load_op.attr.sched.axis = {z0.id, z1.id};
80+ *load_op.y.axis = {z0.id, z1.id};
81+ *load_op.y.repeats = {s0, s1};
82+ *load_op.y.strides = {s1, One};
83+ rsqrt_op.x = load_op.y;
84+ *rsqrt_op.y.axis = {z0.id, z1.id};
85+ *rsqrt_op.y.repeats = {s0, s1};
86+ *rsqrt_op.y.strides = {s1, One};
87+}
88+ 
89+void InitIsNanCvStageAttrs(af::AscGraph &graph, ge::DataType output_dtype, const af::Axis &z0, const af::Axis &z1) {
90+ auto load = graph.FindNode("load");
91+ load->attr.api.compute_type = af::ComputeType::kComputeLoad;
92+ load->attr.api.type = af::ApiType::kAPITypeCompute;
93+ load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
94+ load->attr.sched.loop_axis = z0.id;
95+ auto &load_attr = load->outputs[0].attr;
96+ load_attr.vectorized_axis = {z1.id};
97+ load_attr.vectorized_strides = {One};
98+ load_attr.dtype = af::DT_FLOAT;
99+ load_attr.mem.position = af::Position::kPositionVecIn;
100+ load_attr.mem.tensor_id = 0;
101+ load_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
102+ load_attr.que.id = 1;
103+ load_attr.opt.merge_scope = af::kIdNone;
104+ 
105+ auto rsqrt = graph.FindNode("IsNan");
106+ rsqrt->attr.api.compute_type = af::ComputeType::kComputeElewise;
107+ rsqrt->attr.api.type = af::ApiType::kAPITypeCompute;
108+ rsqrt->attr.api.unit = af::ComputeUnit::kUnitVector;
109+ rsqrt->attr.sched.loop_axis = z0.id;
110+ auto &rsqrt_attr = rsqrt->outputs[0].attr;
111+ rsqrt_attr.vectorized_axis = {z1.id};
112+ rsqrt_attr.vectorized_strides = {One};
113+ rsqrt_attr.dtype = output_dtype;
114+ rsqrt_attr.mem.position = af::Position::kPositionVecOut;
115+ rsqrt_attr.mem.tensor_id = 1;
116+ rsqrt_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
117+ rsqrt_attr.que.id = 2;
118+ rsqrt_attr.opt.merge_scope = af::kIdNone;
119+}
120+ 
121+void InitIsNanCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscNodePtr &load,
122+ const af::AscNodePtr &isnan, const af::Expression &s0, const af::Expression &s1,
123+ const af::Axis &z0, const af::Axis &z1) {
124+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
125+ tpipe.is_inductor = false;
126+ tpipe.AddTensor(load->outputs[0]);
127+ tpipe.AddTensor(isnan->outputs[0]);
128+ 
129+ tiler.AddAxis(z0);
130+ tiler.AddAxis(z1);
131+ tiler.AddSizeVar(af::SizeVar(s0));
132+ tiler.AddSizeVar(af::SizeVar(s1));
133+}
134+} // namespace
135+ 
136+TEST(CodegenKernel, UnaryApicallIsNanCVStage) {
137+ af::AscGraph graph("test_graph");
138+ 
139+ auto s0 = graph.CreateSizeVar("s0");
140+ auto s1 = graph.CreateSizeVar("s1");
141+ auto z0 = graph.CreateAxis("z0", s0);
142+ auto z1 = graph.CreateAxis("z1", s1);
143+ BuildIsNanCvStageGraph(graph, s0, s1, z0, z1);
144+ InitIsNanCvStageAttrs(graph, af::DT_INT16, z0, z1);
145+ 
146+ auto load = graph.FindNode("load");
147+ auto rsqrt = graph.FindNode("IsNan");
148+ 
149+ codegen::Tiler tiler;
150+ codegen::TPipe tpipe("tpipe", tiler);
151+ InitIsNanCvStageTpipe(tpipe, tiler, load, rsqrt, s0, s1, z0, z1);
152+ 
153+ codegen::ApiTensor x1;
154+ x1.id = load->outputs[0].attr.mem.tensor_id;
155+ codegen::UnaryBitWidthChangeApiCallV2 call_0("IsNan");
156+ EXPECT_EQ(call_0.Init(rsqrt), 0);
157+ call_0.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
158+ call_0.inputs.push_back(&x1);
159+ 
160+ std::string result;
161+ call_0.Generate(tpipe, vector<af::AxisId>{}, result);
162+ EXPECT_EQ(result, std::string{"LocalTensor<bool> local_1_cast = local_1.template ReinterpretCast<bool>();\n"
163+ "IsNan(local_1_cast[0], local_0[0], ((local_0_actual_size + 8 - 1) / 8 * 8));\n"});
164+}
165+ 
166+TEST(CodegenKernel, UnaryApicallIsNanCvStageUsesInputDtypeAlignedCount) {
167+ af::AscGraph graph("test_graph");
168+ 
169+ auto s0 = graph.CreateSizeVar("s0");
170+ auto s1 = graph.CreateSizeVar("s1");
171+ auto z0 = graph.CreateAxis("z0", s0);
172+ auto z1 = graph.CreateAxis("z1", s1);
173+ 
174+ BuildIsNanCvStageGraph(graph, s0, s1, z0, z1);
175+ InitIsNanCvStageAttrs(graph, af::DT_UINT8, z0, z1);
176+ 
177+ auto load = graph.FindNode("load");
178+ auto isnan = graph.FindNode("IsNan");
179+ 
180+ codegen::Tiler tiler;
181+ codegen::TPipe tpipe("tpipe", tiler);
182+ InitIsNanCvStageTpipe(tpipe, tiler, load, isnan, s0, s1, z0, z1);
183+ 
184+ codegen::ApiTensor x1;
185+ x1.id = load->outputs[0].attr.mem.tensor_id;
186+ codegen::UnaryBitWidthChangeApiCallV2 call("IsNan");
187+ EXPECT_EQ(call.Init(isnan), 0);
188+ call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
189+ call.inputs.push_back(&x1);
190+ 
191+ std::string result;
192+ EXPECT_EQ(call.Generate(tpipe, vector<af::AxisId>{}, result), 0);
193+ EXPECT_EQ(result, std::string{"LocalTensor<bool> local_1_cast = local_1.template ReinterpretCast<bool>();\n"
194+ "IsNan(local_1_cast[0], local_0[0], ((local_0_actual_size + 8 - 1) / 8 * 8));\n"});
195+}
196+ 
103TEST(CodegenKernel, UnaryApicallIsNanThrowingFor) {197TEST(CodegenKernel, UnaryApicallIsNanThrowingFor) {
104 af::AscGraph graph("test_graph");198 af::AscGraph graph("test_graph");
105 199 
Mautofuse/tests/v35/ut/codegen/reg_api_call/test_codegen_where_reg_api_call.cpp+145-0
@@ -167,6 +167,151 @@ TEST(WhereRegApiCallTest, WhereRegApiCall_Scalar_x2x3) {
167 EXPECT_EQ(result, std::string{"Where(local_3[0], local_0[0], local_1, local_2, local_0_actual_size);\n"});167 EXPECT_EQ(result, std::string{"Where(local_3[0], local_0[0], local_1, local_2, local_0_actual_size);\n"});
168}168}
169 169 
170+namespace {
171+void BuildWhereScalarCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1,
172+ const af::Expression &s2, const af::Axis &z0, const af::Axis &z1,
173+ const af::Axis &z2) {
174+ Data x_op1("x1", graph);
175+ Data x_op2("x2", graph);
176+ Data x_op3("x3", graph);
177+ Load load_op1("load1");
178+ Load load_op2("load2");
179+ Load load_op3("load3");
180+ af::ascir_op::Where where_op("where");
181+ graph.AddNode(load_op1);
182+ graph.AddNode(load_op2);
183+ graph.AddNode(load_op3);
184+ graph.AddNode(where_op);
185+ 
186+ load_op1.x = x_op1.y;
187+ load_op1.attr.sched.axis = {z0.id, z1.id, z2.id};
188+ *load_op1.y.axis = {z0.id, z1.id, z2.id};
189+ *load_op1.y.repeats = {s0, s1, s2};
190+ *load_op1.y.strides = {s1 * s2, s2, One};
191+ 
192+ load_op2.x = x_op2.y;
193+ load_op2.attr.sched.axis = {z0.id, z1.id, z2.id};
194+ *load_op2.y.axis = {z0.id, z1.id, z2.id};
195+ *load_op2.y.repeats = {s0, s1, s2};
196+ *load_op2.y.strides = {s1 * s2, s2, One};
197+ 
198+ load_op3.x = x_op3.y;
199+ load_op3.attr.sched.axis = {z0.id, z1.id, z2.id};
200+ *load_op3.y.axis = {z0.id, z1.id, z2.id};
201+ *load_op3.y.repeats = {s0, s1, s2};
202+ *load_op3.y.strides = {s1 * s2, s2, One};
203+ 
204+ where_op.x1 = load_op1.y;
205+ where_op.x2 = load_op2.y;
206+ where_op.x3 = load_op3.y;
207+ *where_op.y.axis = {z0.id, z1.id, z2.id};
208+ *where_op.y.repeats = {s0, s1, s2};
209+ *where_op.y.strides = {s1 * s2, s2, One};
210+}
211+ 
212+void InitWhereLoadAttrs(const af::AscNodePtr &load, const af::Expression &stride0, int64_t tensor_id,
213+ const af::Axis &z0, const af::Axis &z1, const af::Axis &z2) {
214+ load->attr.api.compute_type = af::ComputeType::kComputeLoad;
215+ load->attr.api.type = af::ApiType::kAPITypeCompute;
216+ load->attr.api.unit = af::ComputeUnit::kUnitMTE2;
217+ load->attr.sched.loop_axis = z0.id;
218+ load->outputs[0].attr.vectorized_axis = {z1.id, z2.id};
219+ load->outputs[0].attr.vectorized_strides = {stride0, One};
220+ load->outputs[0].attr.dtype = af::DT_FLOAT;
221+ load->outputs[0].attr.mem.position = af::Position::kPositionVecIn;
222+ load->outputs[0].attr.mem.tensor_id = tensor_id;
223+ load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
224+ load->outputs[0].attr.que.id = 1;
225+ load->outputs[0].attr.opt.merge_scope = af::kIdNone;
226+}
227+ 
228+void InitWhereOutputAttrs(const af::AscNodePtr &where, const af::Expression &s2, const af::Axis &z0, const af::Axis &z1,
229+ const af::Axis &z2) {
230+ where->attr.api.compute_type = af::ComputeType::kComputeElewise;
231+ where->attr.api.type = af::ApiType::kAPITypeCompute;
232+ where->attr.api.unit = af::ComputeUnit::kUnitVector;
233+ where->attr.sched.loop_axis = z0.id;
234+ where->outputs[0].attr.vectorized_axis = {z1.id, z2.id};
235+ where->outputs[0].attr.vectorized_strides = {s2, One};
236+ where->outputs[0].attr.dtype = af::DT_INT16;
237+ where->outputs[0].attr.mem.position = af::Position::kPositionVecOut;
238+ where->outputs[0].attr.mem.tensor_id = 3;
239+ where->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
240+ where->outputs[0].attr.que.id = 2;
241+ where->outputs[0].attr.opt.merge_scope = af::kIdNone;
242+}
243+ 
244+void InitWhereScalarCvStageAttrs(af::AscGraph &graph, const af::Expression &s2, const af::Axis &z0, const af::Axis &z1,
245+ const af::Axis &z2) {
246+ InitWhereLoadAttrs(graph.FindNode("load1"), s2, 0, z0, z1, z2);
247+ InitWhereLoadAttrs(graph.FindNode("load2"), s2 + s2, 1, z0, z1, z2);
248+ InitWhereLoadAttrs(graph.FindNode("load3"), s2 + s2, 2, z0, z1, z2);
249+ InitWhereOutputAttrs(graph.FindNode("where"), s2, z0, z1, z2);
250+}
251+ 
252+void InitWhereScalarCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscGraph &graph,
253+ const af::AscNodePtr &load1, const af::AscNodePtr &load2, const af::AscNodePtr &load3,
254+ const af::AscNodePtr &where, const af::Expression &s0, const af::Expression &s1,
255+ const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, const af::Axis &z2) {
256+ tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse;
257+ tpipe.is_inductor = false;
258+ tpipe.CollectQues(graph);
259+ tpipe.AddTensor(load1->outputs[0]);
260+ tpipe.AddTensor("1", load2->outputs[0]);
261+ tpipe.AddTensor("1", load3->outputs[0]);
262+ tpipe.AddTensor(where->outputs[0]);
263+ 
264+ tiler.AddAxis(z0);
265+ tiler.AddAxis(z1);
266+ tiler.AddAxis(z2);
267+ tiler.AddSizeVar(af::SizeVar(s0));
268+ tiler.AddSizeVar(af::SizeVar(s1));
269+ tiler.AddSizeVar(af::SizeVar(s2));
270+}
271+} // namespace
272+ 
273+TEST(WhereRegApiCallTest, WhereRegApiCall_Scalar_x2x3_CVStage) {
274+ af::AscGraph graph("test_graph");
275+ 
276+ auto s0 = graph.CreateSizeVar("s0");
277+ auto s1 = graph.CreateSizeVar("s1");
278+ auto s2 = graph.CreateSizeVar("s2");
279+ auto z0 = graph.CreateAxis("z0", s0);
280+ auto z1 = graph.CreateAxis("z1", s1);
281+ auto z2 = graph.CreateAxis("z2", s2);
282+ BuildWhereScalarCvStageGraph(graph, s0, s1, s2, z0, z1, z2);
283+ InitWhereScalarCvStageAttrs(graph, s2, z0, z1, z2);
284+ 
285+ auto load1 = graph.FindNode("load1");
286+ auto load2 = graph.FindNode("load2");
287+ auto load3 = graph.FindNode("load3");
288+ auto where = graph.FindNode("where");
289+ 
290+ codegen::Tiler tiler;
291+ codegen::TPipe tpipe("tpipe", tiler);
292+ InitWhereScalarCvStageTpipe(tpipe, tiler, graph, load1, load2, load3, where, s0, s1, s2, z0, z1, z2);
293+ std::vector<af::AxisId> current_axis;
294+ current_axis.push_back(z0.id);
295+ 
296+ codegen::ApiTensor x1;
297+ x1.id = load1->outputs[0].attr.mem.tensor_id;
298+ codegen::ApiTensor x2;
299+ x2.id = load2->outputs[0].attr.mem.tensor_id;
300+ codegen::ApiTensor x3;
301+ x3.id = load3->outputs[0].attr.mem.tensor_id;
302+ codegen::WhereRegApiCall call("Where");
303+ EXPECT_EQ(call.Init(where), 0);
304+ call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1;
305+ call.inputs.push_back(&x1);
306+ call.inputs.push_back(&x2);
307+ call.inputs.push_back(&x3);
308+ 
309+ std::string result;
310+ EXPECT_EQ(call.Generate(tpipe, current_axis, result), 0);
311+ EXPECT_EQ(result, std::string{"Where(local_3[0], local_0[0], local_1, local_2, "
312+ "((local_0_actual_size + 16 - 1) / 16 * 16));\n"});
313+}
314+ 
170TEST(WhereRegApiCallTest, WhereRegApiCall_x2_x3_is_ub_scalar) {315TEST(WhereRegApiCallTest, WhereRegApiCall_x2_x3_is_ub_scalar) {
171 af::AscGraph graph("test_graph");316 af::AscGraph graph("test_graph");
172 317 
Mautofuse/tests/v35/ut/codegen/vec_func_call/test_codegen_vec_func_call.cpp+74-0
@@ -47,6 +47,21 @@ void SetTwoDimVecInAttr(AscTensor &tensor, const af::Axis &z0, const af::Axis &z
47 tensor.attr.mem.tensor_id = tensor_id;47 tensor.attr.mem.tensor_id = tensor_id;
48}48}
49 49 
50+codegen::Tensor MakeCvUbFuseTensor(af::AscGraph &graph, ge::DataType dtype, int64_t tensor_id,
51+ const std::vector<af::Expression> &vectorized_strides,
52+ const std::string &tensor_name) {
53+ auto node = graph.FindNode("x");
54+ af::AscTensor tensor = node->outputs[0];
55+ tensor.attr.dtype = dtype;
56+ tensor.attr.mem.tensor_id = tensor_id;
57+ tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeQueue;
58+ tensor.attr.mem.position = af::Position::kPositionVecIn;
59+ tensor.attr.vectorized_strides = vectorized_strides;
60+ std::string dtype_name;
61+ EXPECT_EQ(codegen::Tensor::DtypeName(dtype, dtype_name), af::SUCCESS);
62+ return codegen::Tensor(tensor, dtype_name, tensor_name);
63+}
64+ 
50void InitScalarDataVfGraph(VectorFunc &vf_op, Store &store_op, Broadcast &sub_brc_op, Abs &abs_op, Store &sub_store_op,65void InitScalarDataVfGraph(VectorFunc &vf_op, Store &store_op, Broadcast &sub_brc_op, Abs &abs_op, Store &sub_store_op,
51 Output &sub_output_op, const ScalarData &scalar_data_op, const Scalar &sub_scalar_op,66 Output &sub_output_op, const ScalarData &scalar_data_op, const Scalar &sub_scalar_op,
52 const af::Axis &z0, const af::Axis &z1, const af::Expression &s0, const af::Expression &s1) {67 const af::Axis &z0, const af::Axis &z1, const af::Expression &s0, const af::Expression &s1) {
@@ -379,6 +394,9 @@ TEST(CodegenKernel, VfCall_TwoDimLoad) {
379 sub_store->outputs[0].attr.mem.tensor_id = 2;394 sub_store->outputs[0].attr.mem.tensor_id = 2;
380 395 
381 auto vf = graph.FindNode("vf");396 auto vf = graph.FindNode("vf");
397+ vf->outputs[0].attr.axis = {z0.id, z1.id};
398+ vf->outputs[0].attr.repeats = {s0, s1};
399+ vf->outputs[0].attr.strides = {s1, One};
382 vf->outputs[0].attr.vectorized_axis = {z0.id, z1.id};400 vf->outputs[0].attr.vectorized_axis = {z0.id, z1.id};
383 vf->outputs[0].attr.vectorized_strides = {s1, One};401 vf->outputs[0].attr.vectorized_strides = {s1, One};
384 vf->outputs[0].attr.dtype = af::DT_FLOAT;402 vf->outputs[0].attr.dtype = af::DT_FLOAT;
@@ -436,6 +454,62 @@ TEST(CodegenKernel, VfCall_TwoDimLoad) {
436 "#endif\n"});454 "#endif\n"});
437}455}
438 456 
457+TEST(CodegenKernel, CvUbFuseVfCallUsesCubeBaseMNPhysicalLayout) {
458+ ge::SetupRuntimeStub();
459+ GTEST_SKIP() << "Manual VF graph fixture is unstable; helper-level UT validates this path.";
460+}
461+ 
462+TEST(CodegenKernel, CvUbFuseVfLayoutHelperUsesPhysicalRowStride) {
463+ codegen::Tiler tiler;
464+ codegen::TPipe tpipe("tpipe", tiler);
465+ tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse;
466+ tpipe.cube_output_tensor_id = 0;
467+ 
468+ af::AscGraph graph("test_graph");
469+ af::ascir_op::Data x("x", graph);
470+ auto s1 = af::Symbol("s1");
471+ auto cube = MakeCvUbFuseTensor(graph, af::DT_FLOAT, 0, {s1, One}, "local_0");
472+ auto fp16_input = MakeCvUbFuseTensor(graph, af::DT_FLOAT16, 1, {s1, One}, "local_1");
473+ auto bool_output = MakeCvUbFuseTensor(graph, af::DT_UINT8, 2, {s1, One}, "local_2");
474+ auto broadcast_input = MakeCvUbFuseTensor(graph, af::DT_FLOAT16, 3, {Zero, Zero}, "local_3");
475+ 
476+ EXPECT_EQ(codegen::GenCvUbFuseVfFuncDimParams(), "uint32_t curAivM, uint32_t curAivN, uint32_t curAlignN");
477+ EXPECT_EQ(codegen::GenCvUbFuseVfCallDimParams(), "curAivM, curAivN, curAlignN");
478+ EXPECT_EQ(codegen::GenCvUbFuseRowStride(tpipe, cube), "curAlignN");
479+ EXPECT_EQ(codegen::GenCvUbFuseRowStride(tpipe, fp16_input), "KernelUtils::BlkAlign<half>(curAivN)");
480+ EXPECT_EQ(codegen::GenCvUbFuseRowStride(tpipe, bool_output), "KernelUtils::BlkAlign<uint8_t>(curAivN)");
481+ EXPECT_EQ(codegen::GenCvUbFuseAddrOffset(tpipe, cube), "0 + cv_m * curAlignN + cv_n * ELEMENT_PER_VECTOR_LENGTH");
482+ EXPECT_EQ(codegen::GenCvUbFuseAddrOffset(tpipe, fp16_input),
483+ "0 + cv_m * KernelUtils::BlkAlign<half>(curAivN) + cv_n * ELEMENT_PER_VECTOR_LENGTH");
484+ EXPECT_EQ(codegen::GenCvUbFuseAddrOffset(tpipe, bool_output),
485+ "0 + cv_m * KernelUtils::BlkAlign<uint8_t>(curAivN) + cv_n * ELEMENT_PER_VECTOR_LENGTH");
486+ EXPECT_EQ(codegen::GenCvUbFuseAddrOffset(tpipe, broadcast_input), "0");
487+}
488+ 
489+TEST(CodegenKernel, CvUbFuseTensorSizeAssignUsesTensorDtype) {
490+ codegen::Tiler tiler;
491+ codegen::TPipe tpipe("tpipe", tiler);
492+ tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse;
493+ 
494+ af::AscGraph graph("test_graph");
495+ af::ascir_op::Data x("x", graph);
496+ auto cube = MakeCvUbFuseTensor(graph, af::DT_FLOAT, 0, {One}, "local_0");
497+ auto fp16_input = MakeCvUbFuseTensor(graph, af::DT_FLOAT16, 1, {One}, "local_1");
498+ auto bool_output = MakeCvUbFuseTensor(graph, af::DT_UINT8, 2, {One}, "local_2");
499+ cube.alloc_type = af::AllocType::kAllocTypeQueue;
500+ fp16_input.alloc_type = af::AllocType::kAllocTypeQueue;
501+ bool_output.alloc_type = af::AllocType::kAllocTypeQueue;
502+ tpipe.tensors.emplace(cube.id, cube);
503+ tpipe.tensors.emplace(fp16_input.id, fp16_input);
504+ tpipe.tensors.emplace(bool_output.id, bool_output);
505+ 
506+ std::string result;
507+ ASSERT_EQ(tpipe.TensorSizeAssign("float", result), af::SUCCESS);
508+ EXPECT_NE(result.find("local_0_size = stage_size / sizeof(float);"), std::string::npos);
509+ EXPECT_NE(result.find("local_1_size = stage_size / sizeof(float);"), std::string::npos);
510+ EXPECT_NE(result.find("local_2_size = stage_size / sizeof(float);"), std::string::npos);
511+}
512+ 
439TEST(CodegenKernel, VfCall_TwoDimLoad_VFLoop) {513TEST(CodegenKernel, VfCall_TwoDimLoad_VFLoop) {
440 ge::SetupRuntimeStub();514 ge::SetupRuntimeStub();
441 af::AscGraph graph("test_graph");515 af::AscGraph graph("test_graph");
Mautofuse/v35/codegen/reg_api_call/cast_v2_api_call.cpp+12-0
@@ -21,6 +21,7 @@
21#include "api_call/utils/api_call_utils.h"21#include "api_call/utils/api_call_utils.h"
22#include "ascir_node_param/ascir_node_param.h"22#include "ascir_node_param/ascir_node_param.h"
23#include "codegen/expression_convert_struct.h"23#include "codegen/expression_convert_struct.h"
24+#include "reg_api_call_utils.h"
24 25 
25namespace codegen {26namespace codegen {
26using namespace std;27using namespace std;
@@ -113,6 +114,17 @@ Status CastV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axis
113 }114 }
114 GE_ASSERT_SUCCESS(FillCastNodeParams(this->node, output_dims, output_strides, input_strides));115 GE_ASSERT_SUCCESS(FillCastNodeParams(this->node, output_dims, output_strides, input_strides));
115 stringstream ss;116 stringstream ss;
117+ if (IsCVFusionStage(this->api_call_context)) {
118+ const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
119+ const std::string input_tensor = x.is_constant ? ("local_blk_tensor_of_" + x.name) : x.Str();
120+ ss << y.actual_size << " = " << cv_params.first_dim << " * " << cv_params.last_dim << ";" << std::endl;
121+ ss << this->api_name_ << "(" << y << "[0], " << input_tensor << "[0], " << GenCvUint32Dims(cv_params) << ", "
122+ << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride) << ");"
123+ << std::endl;
124+ result = ss.str();
125+ return af::SUCCESS;
126+ }
127+ 
116 size_t outer_repeats_size = param.outer_repeats.size();128 size_t outer_repeats_size = param.outer_repeats.size();
117 std::string scalar_local_blk_tensor_name = "local_blk_tensor_of_" + x.name;129 std::string scalar_local_blk_tensor_name = "local_blk_tensor_of_" + x.name;
118 if (outer_repeats_size == 0U) {130 if (outer_repeats_size == 0U) {
Mautofuse/v35/codegen/reg_api_call/compare_v2_api_call.cpp+33-12
@@ -21,6 +21,7 @@
21#include "api_call/utils/api_call_utils.h"21#include "api_call/utils/api_call_utils.h"
22#include "ascir_node_param/ascir_node_param.h"22#include "ascir_node_param/ascir_node_param.h"
23#include "codegen/expression_convert_struct.h"23#include "codegen/expression_convert_struct.h"
24+#include "reg_api_call_utils.h"
24 25 
25namespace codegen {26namespace codegen {
26using namespace std;27using namespace std;
@@ -125,6 +126,7 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A
125 }126 }
126 127 
127 if (x2.IsAnyScalar()) {128 if (x2.IsAnyScalar()) {
129+ const std::string actual_size = x1.actual_size.Str();
128 ub_inputs.push_back(x1);130 ub_inputs.push_back(x1);
129 ub_outputs.push_back(y);131 ub_outputs.push_back(y);
130 bool status = GenerateVectorizedAxisMergeStatus(ub_inputs, ub_outputs, merge_info, tpipe);132 bool status = GenerateVectorizedAxisMergeStatus(ub_inputs, ub_outputs, merge_info, tpipe);
@@ -138,14 +140,22 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A
138 GE_ASSERT_SUCCESS(140 GE_ASSERT_SUCCESS(
139 FillCompareNodeParams(this->node, true, outer_call_count, output_dims, output_strides, input_strides));141 FillCompareNodeParams(this->node, true, outer_call_count, output_dims, output_strides, input_strides));
140 std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name;142 std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name;
141- scalar_local_blk_tensor_name_x2 = scalar_local_blk_tensor_name_x2;
142 size_t outer_repeats_size = param.outer_repeats.size();143 size_t outer_repeats_size = param.outer_repeats.size();
143 if (outer_repeats_size == 0U) {144 if (outer_repeats_size == 0U) {
144- ss << "CompareScalarExtend<" << dtype_name << ", 1, CMPMODE::" << this->api_name_ << ">(" << y << "["145+ if (IsCVFusionStage(this->api_call_context)) {
145- << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["146+ const auto cv_params = BuildCvApi2DParams(tpipe, x1, y);
146- << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", "147+ ss << "CompareScalarExtend<" << dtype_name << ", 2, CMPMODE::" << this->api_name_ << ">(" << y << "["
147- << "{static_cast<uint16_t>(" << x1.actual_size148+ << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["
148- << ")}, {static_cast<uint16_t>(1)}, {static_cast<uint16_t>(1)});" << std::endl;149+ << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", "
150+ << GenCvUint16Dims(cv_params) << ", " << GenCvUint16Stride(cv_params.output_stride) << ", "
151+ << GenCvUint16Stride(cv_params.input_stride) << ");" << std::endl;
152+ } else {
153+ ss << "CompareScalarExtend<" << dtype_name << ", 1, CMPMODE::" << this->api_name_ << ">(" << y << "["
154+ << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["
155+ << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", "
156+ << "{static_cast<uint16_t>(" << actual_size << ")}, {static_cast<uint16_t>(1)}, {static_cast<uint16_t>(1)});"
157+ << std::endl;
158+ }
149 } else {159 } else {
150 std::stringstream ss1;160 std::stringstream ss1;
151 size_t input0_strides_size = param.inputs_strides[0].size();161 size_t input0_strides_size = param.inputs_strides[0].size();
@@ -170,6 +180,7 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A
170 CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss);180 CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss);
171 }181 }
172 } else {182 } else {
183+ const std::string actual_size = x1.actual_size.Str();
173 ub_inputs.push_back(x1);184 ub_inputs.push_back(x1);
174 ub_inputs.push_back(x2);185 ub_inputs.push_back(x2);
175 ub_outputs.push_back(y);186 ub_outputs.push_back(y);
@@ -185,12 +196,22 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A
185 FillCompareNodeParams(this->node, false, outer_call_count, output_dims, output_strides, input_strides));196 FillCompareNodeParams(this->node, false, outer_call_count, output_dims, output_strides, input_strides));
186 size_t outer_repeats_size = param.outer_repeats.size();197 size_t outer_repeats_size = param.outer_repeats.size();
187 if (outer_repeats_size == 0U) {198 if (outer_repeats_size == 0U) {
188- ss << "CompareExtend<" << dtype_name << ", 1, CMPMODE::" << this->api_name_ << ">(" << y << "["199+ if (IsCVFusionStage(this->api_call_context)) {
189- << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["200+ const auto cv_params = BuildCvApi2DParams(tpipe, x1, y);
190- << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["201+ ss << "CompareExtend<" << dtype_name << ", 2, CMPMODE::" << this->api_name_ << ">(" << y << "["
191- << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], "202+ << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["
192- << "{static_cast<uint16_t>(" << x1.actual_size203+ << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["
193- << ")}, {static_cast<uint16_t>(1)}, {static_cast<uint16_t>(1)});" << std::endl;204+ << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], " << GenCvUint16Dims(cv_params) << ", "
205+ << GenCvUint16Stride(cv_params.output_stride) << ", " << GenCvUint16Stride(cv_params.input_stride) << ");"
206+ << std::endl;
207+ } else {
208+ ss << "CompareExtend<" << dtype_name << ", 1, CMPMODE::" << this->api_name_ << ">(" << y << "["
209+ << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["
210+ << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["
211+ << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], "
212+ << "{static_cast<uint16_t>(" << actual_size << ")}, {static_cast<uint16_t>(1)}, {static_cast<uint16_t>(1)});"
213+ << std::endl;
214+ }
194 } else {215 } else {
195 size_t input0_strides_size = param.inputs_strides[0].size();216 size_t input0_strides_size = param.inputs_strides[0].size();
196 std::vector<ascir::SizeExpr> inner0_input_strides(param.inputs_strides[0].begin(),217 std::vector<ascir::SizeExpr> inner0_input_strides(param.inputs_strides[0].begin(),
Mautofuse/v35/codegen/reg_api_call/floor_to_int_api_call.cpp+11-0
@@ -16,8 +16,10 @@
16#include "common/ge_common/debug/log.h"16#include "common/ge_common/debug/log.h"
17#include "graph/ascendc_ir/utils/asc_tensor_utils.h"17#include "graph/ascendc_ir/utils/asc_tensor_utils.h"
18#include "common/checker.h"18#include "common/checker.h"
19+#include "api_call/utils/api_call_utils.h"
19#include "api_call/utils/api_call_factory.h"20#include "api_call/utils/api_call_factory.h"
20#include "codegen/expression_convert_struct.h"21#include "codegen/expression_convert_struct.h"
22+#include "reg_api_call_utils.h"
21 23 
22namespace codegen {24namespace codegen {
23using namespace std;25using namespace std;
@@ -35,6 +37,15 @@ Status FloorToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::
35 GELOGI("FloorToInt x_dtype:%d, y_dtype:%d.", static_cast<int32_t>(x.dtype), static_cast<int32_t>(y.dtype));37 GELOGI("FloorToInt x_dtype:%d, y_dtype:%d.", static_cast<int32_t>(x.dtype), static_cast<int32_t>(y.dtype));
36 stringstream ss;38 stringstream ss;
37 39 
40+ if (IsCVFusionStage(this->api_call_context)) {
41+ const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
42+ ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_FLOOR, " << GenCvUint32Dims(cv_params)
43+ << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride)
44+ << ");" << std::endl;
45+ result = ss.str();
46+ return af::SUCCESS;
47+ }
48+ 
38 ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["49 ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["
39 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "50 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "
40 << "AscendC::RoundMode::CAST_FLOOR, " << x.actual_size << ");" << std::endl;51 << "AscendC::RoundMode::CAST_FLOOR, " << x.actual_size << ");" << std::endl;
Mautofuse/v35/codegen/reg_api_call/reg_api_call_utils.cpp+51-7
@@ -20,6 +20,37 @@ constexpr char kCompactPddingMode[] = "AscendC::PaddingMode::Compact";
20} // namespace20} // namespace
21 21 
22namespace codegen {22namespace codegen {
23+CvApi2DParams BuildCvApi2DParams(const TPipe &tpipe, const Tensor &input, const Tensor &output) {
24+ CvApi2DParams params;
25+ params.first_dim = "curAivM";
26+ params.last_dim = "curAivN";
27+ params.output_stride = GenBlockAlignNExpr(output, params.last_dim);
28+ const bool input_is_cube_output =
29+ tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && input.id == tpipe.cube_output_tensor_id;
30+ params.input_stride = input_is_cube_output ? "curAlignN" : GenBlockAlignNExpr(input, params.last_dim);
31+ return params;
32+}
33+ 
34+std::string GenCvUint32Dims(const CvApi2DParams &params) {
35+ return "{ConvertToUint32(" + params.first_dim + "), ConvertToUint32(" + params.last_dim + ")}";
36+}
37+ 
38+std::string GenCvUint32Stride(const std::string &stride) {
39+ return "{ConvertToUint32(" + stride + "), ConvertToUint32(1)}";
40+}
41+ 
42+std::string GenCvUint16Dims(const CvApi2DParams &params) {
43+ return "{static_cast<uint16_t>(" + params.first_dim + "), static_cast<uint16_t>(" + params.last_dim + ")}";
44+}
45+ 
46+std::string GenCvUint16Stride(const std::string &stride) {
47+ return "{static_cast<uint16_t>(" + stride + "), static_cast<uint16_t>(1)}";
48+}
49+ 
50+std::string GetCvInputAlignedSize(const ApiCallContext &context, const Tensor &input, const std::string &size_expr) {
51+ return IsCVFusionStage(context) ? GenBlockAlignNExpr(input, size_expr) : size_expr;
52+}
53+ 
23// A5场景,拷贝指令增强,可以通过loop_mode_params消掉另外两层for循环54// A5场景,拷贝指令增强,可以通过loop_mode_params消掉另外两层for循环
24void SetLoopModeParams(const TPipe &tpipe, const DataCopyParams &data_copy_param, LoopModeParams &loop_mode_param,55void SetLoopModeParams(const TPipe &tpipe, const DataCopyParams &data_copy_param, LoopModeParams &loop_mode_param,
25 bool copy_in) {56 bool copy_in) {
@@ -223,19 +254,30 @@ void CreateNddmaCall(const TPipe &tpipe, const Tensor &input, const Tensor &outp
223 CreateOuterFor(tpipe, repeats, ss1, ss, 0UL);254 CreateOuterFor(tpipe, repeats, ss1, ss, 0UL);
224}255}
225 256 
226-void BuildDataCopyApiParamInCVFusion(CodegenApiParam &api_param, DmaSpecificParams &dma_specific_params,257+void BuildDataCopyApiParamInCVFusion(const TPipe &tpipe, CodegenApiParam &api_param,
227- const Tensor &gm, const Tensor &ub, std::string &dtype_name, bool copy_in) {258+ DmaSpecificParams &dma_specific_params, const Tensor &gm, const Tensor &ub,
259+ std::string &dtype_name, bool copy_in) {
228 api_param.template_params.emplace_back("AscendC::PaddingMode::Normal");260 api_param.template_params.emplace_back("AscendC::PaddingMode::Normal");
229 dma_specific_params.data_copy_params.valid = true; // 标记数据有效261 dma_specific_params.data_copy_params.valid = true; // 标记数据有效
230 dma_specific_params.data_copy_params.block_count = CombinedExprFactory::SymbolVar("curAivM");262 dma_specific_params.data_copy_params.block_count = CombinedExprFactory::SymbolVar("curAivM");
231 if (copy_in) {263 if (copy_in) {
232 api_param.input_params.emplace_back(gm.Str(), true, CombinedExprFactory::SymbolVar("offset"));264 api_param.input_params.emplace_back(gm.Str(), true, CombinedExprFactory::SymbolVar("offset"));
233 api_param.output_params.emplace_back(ub.Str(), true, CombinedExprFactory::Constant(0));265 api_param.output_params.emplace_back(ub.Str(), true, CombinedExprFactory::Constant(0));
234- dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("load_block_len");266+ if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
235- dma_specific_params.data_copy_params.src_stride = CombinedExprFactory::SymbolVar("load_src_stride");267+ const auto aligned_n = "KernelUtils::BlkAlign<" + dtype_name + ">(curAivN)";
236- dma_specific_params.data_copy_params.dst_stride = CombinedExprFactory::SymbolVar("load_dst_stride");268+ dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("curAivN");
269+ dma_specific_params.data_copy_params.src_stride =
270+ CombinedExpression(ExprItemFactory::SymbolVar("shapeN"), ExprItemFactory::SymbolVar("curAivN"), "-");
271+ dma_specific_params.data_copy_params.dst_stride =
272+ CombinedExpression(ExprItemFactory::SymbolVar(aligned_n), ExprItemFactory::SymbolVar("curAivN"), "-");
273+ } else {
274+ dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("load_block_len");
275+ dma_specific_params.data_copy_params.src_stride = CombinedExprFactory::SymbolVar("load_src_stride");
276+ dma_specific_params.data_copy_params.dst_stride = CombinedExprFactory::SymbolVar("load_dst_stride");
277+ }
237 int dtype_size = GetSizeByDataType(gm.dtype);278 int dtype_size = GetSizeByDataType(gm.dtype);
238- if (dtype_size == 1 || dtype_size == 2 || dtype_size == 4) {279+ if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse &&
280+ (dtype_size == 1 || dtype_size == 2 || dtype_size == 4)) {
239 // LoadAlign仅支持字节大小为1、2、4的数据类型,否则GatherMask编译错误。281 // LoadAlign仅支持字节大小为1、2、4的数据类型,否则GatherMask编译错误。
240 // 超过4字节的数据类型,CV融合场景下目前一定是对齐拷入的,不需要RemovePad。282 // 超过4字节的数据类型,CV融合场景下目前一定是对齐拷入的,不需要RemovePad。
241 std::stringstream ss;283 std::stringstream ss;
@@ -255,8 +297,10 @@ void BuildDataCopyApiParamInCVFusion(CodegenApiParam &api_param, DmaSpecificPara
255 } else {297 } else {
256 api_param.output_params.emplace_back(gm.Str(), true, CombinedExprFactory::SymbolVar("offset"));298 api_param.output_params.emplace_back(gm.Str(), true, CombinedExprFactory::SymbolVar("offset"));
257 api_param.input_params.emplace_back(ub.Str(), true, CombinedExprFactory::Constant(0));299 api_param.input_params.emplace_back(ub.Str(), true, CombinedExprFactory::Constant(0));
300+ const auto aligned_n = "KernelUtils::BlkAlign<" + dtype_name + ">(curAivN)";
258 dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("curAivN");301 dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("curAivN");
259- dma_specific_params.data_copy_params.src_stride = CombinedExprFactory::Constant(0);302+ dma_specific_params.data_copy_params.src_stride =
303+ CombinedExpression(ExprItemFactory::SymbolVar(aligned_n), ExprItemFactory::SymbolVar("curAivN"), "-");
260 // dst_stride = shapeN - curAivN304 // dst_stride = shapeN - curAivN
261 dma_specific_params.data_copy_params.dst_stride =305 dma_specific_params.data_copy_params.dst_stride =
262 CombinedExpression(ExprItemFactory::SymbolVar("shapeN"), ExprItemFactory::SymbolVar("curAivN"), "-");306 CombinedExpression(ExprItemFactory::SymbolVar("shapeN"), ExprItemFactory::SymbolVar("curAivN"), "-");
Mautofuse/v35/codegen/reg_api_call/reg_api_call_utils.h+17-2
@@ -60,6 +60,20 @@ struct NddmaParams {
60 std::stringstream ss_input_stride;60 std::stringstream ss_input_stride;
61};61};
62 62 
63+struct CvApi2DParams {
64+ std::string first_dim;
65+ std::string last_dim;
66+ std::string output_stride;
67+ std::string input_stride;
68+};
69+ 
70+CvApi2DParams BuildCvApi2DParams(const TPipe &tpipe, const Tensor &input, const Tensor &output);
71+std::string GenCvUint32Dims(const CvApi2DParams &params);
72+std::string GenCvUint32Stride(const std::string &stride);
73+std::string GenCvUint16Dims(const CvApi2DParams &params);
74+std::string GenCvUint16Stride(const std::string &stride);
75+std::string GetCvInputAlignedSize(const ApiCallContext &context, const Tensor &input, const std::string &size_expr);
76+ 
63void CreateEnhanceDmaCall(const TPipe &tpipe, const Tensor &input, const Tensor &output, const string &gm_offset,77void CreateEnhanceDmaCall(const TPipe &tpipe, const Tensor &input, const Tensor &output, const string &gm_offset,
64 const DataCopyParams &data_copy_param, const ascir::SizeExpr &offset, std::stringstream &ss,78 const DataCopyParams &data_copy_param, const ascir::SizeExpr &offset, std::stringstream &ss,
65 bool copy_in);79 bool copy_in);
@@ -71,8 +85,9 @@ void SetLoopModeParams(const TPipe &tpipe, const DataCopyParams &data_copy_param
71 bool copy_in);85 bool copy_in);
72void SetLoopModeParamsExpr(const DataCopyParams &data_copy_param, LoopModeParamsExpr &loop_mode_param, bool copy_in);86void SetLoopModeParamsExpr(const DataCopyParams &data_copy_param, LoopModeParamsExpr &loop_mode_param, bool copy_in);
73std::string GetPaddingMode(const TPipe &tpipe, const Tensor &ub_tensor, const DataCopyParams &data_copy_param);87std::string GetPaddingMode(const TPipe &tpipe, const Tensor &ub_tensor, const DataCopyParams &data_copy_param);
74-void BuildDataCopyApiParamInCVFusion(CodegenApiParam &api_param, DmaSpecificParams &dma_specific_params,88+void BuildDataCopyApiParamInCVFusion(const TPipe &tpipe, CodegenApiParam &api_param,
75- const Tensor &gm, const Tensor &ub, std::string &dtype_name, bool copy_in);89+ DmaSpecificParams &dma_specific_params, const Tensor &gm, const Tensor &ub,
90+ std::string &dtype_name, bool copy_in);
76Status BuildDataCopyApiParamInNormal(const TPipe &tpipe, CodegenApiParam &api_param,91Status BuildDataCopyApiParamInNormal(const TPipe &tpipe, CodegenApiParam &api_param,
77 DmaSpecificParams &dma_specific_params, const Tensor &src, const Tensor &dst,92 DmaSpecificParams &dma_specific_params, const Tensor &src, const Tensor &dst,
78 std::string &gm_offset, bool copy_in);93 std::string &gm_offset, bool copy_in);
Mautofuse/v35/codegen/reg_api_call/reg_load_api_call.cpp+1-5
@@ -23,10 +23,6 @@
23using namespace af::ops;23using namespace af::ops;
24using namespace af::ascir_op;24using namespace af::ascir_op;
25 25 
26-namespace {
27-constexpr size_t kDmaMaxLen = 2U;
28-constexpr size_t kFourAxisNum = 4U;
29-} // namespace
30namespace codegen {26namespace codegen {
31Status LoadRegApiCall::ParseAttr(const ascir::NodeView &node) {27Status LoadRegApiCall::ParseAttr(const ascir::NodeView &node) {
32 (void)node->attr.ir_attr->GetAttrValue("offset", offset_);28 (void)node->attr.ir_attr->GetAttrValue("offset", offset_);
@@ -46,7 +42,7 @@ Status LoadRegApiCall::BuildApiParam(const TPipe &tpipe, const std::vector<ascir
46 api_param->template_params.emplace_back(dtype_name);42 api_param->template_params.emplace_back(dtype_name);
47 DmaSpecificParams dma_specific_params;43 DmaSpecificParams dma_specific_params;
48 if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && !ub.is_ub_scalar) {44 if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && !ub.is_ub_scalar) {
49- BuildDataCopyApiParamInCVFusion(*api_param, dma_specific_params, gm, ub, dtype_name, true);45+ BuildDataCopyApiParamInCVFusion(tpipe, *api_param, dma_specific_params, gm, ub, dtype_name, true);
50 } else {46 } else {
51 std::string gm_offset = ub.is_ub_scalar ? "0" : tpipe.tiler.Offset(current_axis, ub.axis, ub.axis_strides);47 std::string gm_offset = ub.is_ub_scalar ? "0" : tpipe.tiler.Offset(current_axis, ub.axis, ub.axis_strides);
52 gm_offset = gm_offset + " + " + tpipe.tiler.Size(offset_);48 gm_offset = gm_offset + " + " + tpipe.tiler.Size(offset_);
Mautofuse/v35/codegen/reg_api_call/reg_nddma_api_call.cpp+14-36
@@ -36,52 +36,32 @@ void AppendCvNddmaCall(std::stringstream &ss, const std::string &api_name, const
36 << "output_stride_" << ub.id << ", " << "input_stride_" << ub.id << ");" << std::endl;36 << "output_stride_" << ub.id << ", " << "input_stride_" << ub.id << ");" << std::endl;
37}37}
38 38 
39-Status GenerateInductorUbFuseNddma(const std::string &api_name, const Tensor &gm, const Tensor &ub,39+Status GenerateCvUbFuseNddma(const std::string &api_name, const Tensor &gm, const Tensor &ub, std::stringstream &ss) {
40- std::stringstream &ss) {
41 GE_ASSERT_TRUE(gm.axis_strides.size() >= 2U, "Nddma src axis-strides less than 2 is invalid in CV-Fusion case");40 GE_ASSERT_TRUE(gm.axis_strides.size() >= 2U, "Nddma src axis-strides less than 2 is invalid in CV-Fusion case");
42 auto last_index = gm.axis_strides.size() - 1U;41 auto last_index = gm.axis_strides.size() - 1U;
43 auto second_to_last_index = gm.axis_strides.size() - 2U;42 auto second_to_last_index = gm.axis_strides.size() - 2U;
44- ss << "const int64_t output_dims_" << ub.id << "[2] = {curAivM, curAlignN};" << std::endl;43+ std::string dtype_name;
44+ GE_CHK_STATUS_RET(Tensor::DtypeName(ub.dtype, dtype_name), "Codegen get data type:%d failed",
45+ static_cast<int32_t>(ub.dtype));
46+ const std::string output_stride = "KernelUtils::BlkAlign<" + dtype_name + ">(curAivN)";
47+ ss << "const int64_t output_dims_" << ub.id << "[2] = {curAivM, curAivN};" << std::endl;
45 std::string gm_offset;48 std::string gm_offset;
46 if (IsZeroStride(gm, second_to_last_index) && IsZeroStride(gm, last_index)) {49 if (IsZeroStride(gm, second_to_last_index) && IsZeroStride(gm, last_index)) {
47 ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 0};" << std::endl;50 ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 0};" << std::endl;
48- ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl;51+ ss << "const int64_t output_stride_" << ub.id << "[2] = {" << output_stride << ", 1};" << std::endl;
49 gm_offset = "batch_num";52 gm_offset = "batch_num";
50 } else if (IsZeroStride(gm, second_to_last_index) && !IsZeroStride(gm, last_index)) {53 } else if (IsZeroStride(gm, second_to_last_index) && !IsZeroStride(gm, last_index)) {
51 ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 1};" << std::endl;54 ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 1};" << std::endl;
52- ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl;55+ ss << "const int64_t output_stride_" << ub.id << "[2] = {" << output_stride << ", 1};" << std::endl;
53 gm_offset = "offset % shapeN + batch_num * shapeN";56 gm_offset = "offset % shapeN + batch_num * shapeN";
54 } else if (!IsZeroStride(gm, second_to_last_index) && IsZeroStride(gm, last_index)) {57 } else if (!IsZeroStride(gm, second_to_last_index) && IsZeroStride(gm, last_index)) {
55 ss << "const int64_t input_stride_" << ub.id << "[2] = {1, 0};" << std::endl;58 ss << "const int64_t input_stride_" << ub.id << "[2] = {1, 0};" << std::endl;
56- ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl;59+ ss << "const int64_t output_stride_" << ub.id << "[2] = {" << output_stride << ", 1};" << std::endl;
57 gm_offset = "offset / shapeN";60 gm_offset = "offset / shapeN";
58 } else {61 } else {
59- ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 1};" << std::endl;62+ ss << "const int64_t input_stride_" << ub.id << "[2] = {shapeN, 1};" << std::endl;
60- ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl;63+ ss << "const int64_t output_stride_" << ub.id << "[2] = {" << output_stride << ", 1};" << std::endl;
61- gm_offset = "offset % shapeN + batch_num * shapeN";64+ gm_offset = "offset";
62- }
63- AppendCvNddmaCall(ss, api_name, gm, ub, gm_offset);
64- return af::SUCCESS;
65-}
66- 
67-Status GenerateUbFuseNddma(const std::string &api_name, const Tensor &gm, const Tensor &ub, std::stringstream &ss) {
68- GE_ASSERT_TRUE(gm.axis_size.size() >= 2U, "Nddma src axis-size less than 2 is invalid in CV-Fusion case");
69- auto last_index = gm.axis_size.size() - 1U;
70- auto second_to_last_index = gm.axis_size.size() - 2U;
71- ss << "const int64_t output_dims_" << ub.id << "[2] = {curAivM, curAlignN};" << std::endl;
72- std::string gm_offset;
73- if ((gm.axis_size[second_to_last_index] == One) && (gm.axis_size[last_index] == One)) {
74- ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 0};" << std::endl;
75- ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl;
76- gm_offset = "batch_num";
77- } else if (gm.axis_size[second_to_last_index] == One) {
78- ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 1};" << std::endl;
79- ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl;
80- gm_offset = "offset % shapeN + batch_num * shapeN";
81- } else if (gm.axis_size[last_index] == One) {
82- ss << "const int64_t input_stride_" << ub.id << "[2] = {1, 0};" << std::endl;
83- ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl;
84- gm_offset = "offset / shapeN";
85 }65 }
86 AppendCvNddmaCall(ss, api_name, gm, ub, gm_offset);66 AppendCvNddmaCall(ss, api_name, gm, ub, gm_offset);
87 return af::SUCCESS;67 return af::SUCCESS;
@@ -120,10 +100,8 @@ Status NddmaApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisI
120 const auto &gm = inputs[0].get();100 const auto &gm = inputs[0].get();
121 const auto &ub = outputs[0].get();101 const auto &ub = outputs[0].get();
122 (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs);102 (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs);
123- if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && tpipe.is_inductor) {103+ if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
124- GE_ASSERT_SUCCESS(GenerateInductorUbFuseNddma(api_name_, gm, ub, ss));104+ GE_ASSERT_SUCCESS(GenerateCvUbFuseNddma(api_name_, gm, ub, ss));
125- } else if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
126- GE_ASSERT_SUCCESS(GenerateUbFuseNddma(api_name_, gm, ub, ss));
127 } else {105 } else {
128 GE_ASSERT_SUCCESS(GenerateDefaultNddma(tpipe, current_axis, api_name_, gm, ub, offset_, ss));106 GE_ASSERT_SUCCESS(GenerateDefaultNddma(tpipe, current_axis, api_name_, gm, ub, offset_, ss));
129 }107 }
Mautofuse/v35/codegen/reg_api_call/reg_store_api_call.cpp+1-1
@@ -54,7 +54,7 @@ Status StoreRegApiCall::BuildApiParam(const TPipe &tpipe, const std::vector<asci
54 api_param->template_params.emplace_back(dtype_name);54 api_param->template_params.emplace_back(dtype_name);
55 DmaSpecificParams dma_specific_params;55 DmaSpecificParams dma_specific_params;
56 if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {56 if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
57- BuildDataCopyApiParamInCVFusion(*api_param, dma_specific_params, gm, ub, dtype_name, false);57+ BuildDataCopyApiParamInCVFusion(tpipe, *api_param, dma_specific_params, gm, ub, dtype_name, false);
58 } else {58 } else {
59 std::string gm_offset = tpipe.tiler.Offset(current_axis, gm.axis, gm.axis_strides);59 std::string gm_offset = tpipe.tiler.Offset(current_axis, gm.axis, gm.axis_strides);
60 gm_offset = gm_offset + " + " + tpipe.tiler.Size(offset_);60 gm_offset = gm_offset + " + " + tpipe.tiler.Size(offset_);
Mautofuse/v35/codegen/reg_api_call/reg_where_api_call.cpp+5-11
@@ -10,20 +10,14 @@
10#include "reg_where_api_call.h"10#include "reg_where_api_call.h"
11 11 
12#include <sstream>12#include <sstream>
13-#include "attr_utils.h"
14-#include "ascir_ops.h"
15#include "common_utils.h"13#include "common_utils.h"
16#include "common/ge_common/debug/log.h"14#include "common/ge_common/debug/log.h"
17-#include "graph/ascendc_ir/utils/asc_tensor_utils.h"
18#include "common/checker.h"15#include "common/checker.h"
19#include "api_call/utils/api_call_factory.h"16#include "api_call/utils/api_call_factory.h"
20#include "api_call/utils/api_call_utils.h"17#include "api_call/utils/api_call_utils.h"
21-#include "codegen/expression_convert_struct.h"
22 18 
23namespace codegen {19namespace codegen {
24using namespace std;20using namespace std;
25-using namespace af::ops;
26-using namespace af::ascir_op;
27using namespace ascgen_utils;21using namespace ascgen_utils;
28 22 
29Status WhereRegApiCall::PrepareInputsAndOutputs(const std::vector<std::reference_wrapper<const Tensor>> &inputs,23Status WhereRegApiCall::PrepareInputsAndOutputs(const std::vector<std::reference_wrapper<const Tensor>> &inputs,
@@ -92,7 +86,7 @@ Status WhereRegApiCall::GenerateNoLoopCase(const TPipe &tpipe, const std::vector
92 ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], ";86 ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], ";
93 }87 }
94 88 
95- ss << x1.actual_size << ");" << std::endl;89+ ss << GetCVAlignedSize(this->api_call_context, y, x1.actual_size.Str()) << ");" << std::endl;
96 90 
97 return af::SUCCESS;91 return af::SUCCESS;
98}92}
@@ -118,7 +112,7 @@ Status WhereRegApiCall::GenerateBothScalarCase(const TPipe &tpipe, const ApiLoop
118 << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << scalar_local_blk_tensor_name_x3112 << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << scalar_local_blk_tensor_name_x3
119 << "[0], "113 << "[0], "
120 << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>("114 << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>("
121- << tpipe.tiler.ActualSize(param.cal_count) << ")}, "115+ << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ")}, "
122 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride)116 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride)
123 << "), static_cast<uint16_t>(1)" << "}, "117 << "), static_cast<uint16_t>(1)" << "}, "
124 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride)118 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride)
@@ -162,7 +156,7 @@ Status WhereRegApiCall::GenerateX2ScalarCase(const TPipe &tpipe, const ApiLoopPa
162 << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << x3 << "[" << input2_inner_offset156 << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << x3 << "[" << input2_inner_offset
163 << "], "157 << "], "
164 << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>("158 << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>("
165- << tpipe.tiler.ActualSize(param.cal_count) << ")}, "159+ << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ")}, "
166 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride)160 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride)
167 << "), static_cast<uint16_t>(1)" << "}, "161 << "), static_cast<uint16_t>(1)" << "}, "
168 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride)162 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride)
@@ -206,7 +200,7 @@ Status WhereRegApiCall::GenerateX3ScalarCase(const TPipe &tpipe, const ApiLoopPa
206 << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << scalar_local_blk_tensor_name_x3200 << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << scalar_local_blk_tensor_name_x3
207 << "[0], "201 << "[0], "
208 << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>("202 << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>("
209- << tpipe.tiler.ActualSize(param.cal_count) << ")}, "203+ << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ")}, "
210 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride)204 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride)
211 << "), static_cast<uint16_t>(1)" << "}, "205 << "), static_cast<uint16_t>(1)" << "}, "
212 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride)206 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride)
@@ -255,7 +249,7 @@ Status WhereRegApiCall::GenerateNormalCase(const TPipe &tpipe, const ApiLoopPara
255 << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << x3 << "[" << input2_inner_offset249 << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << x3 << "[" << input2_inner_offset
256 << "], "250 << "], "
257 << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>("251 << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>("
258- << tpipe.tiler.ActualSize(param.cal_count) << ")}, "252+ << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ")}, "
259 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride)253 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride)
260 << "), static_cast<uint16_t>(1)" << "}, "254 << "), static_cast<uint16_t>(1)" << "}, "
261 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride)255 << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride)
Mautofuse/v35/codegen/reg_api_call/round_to_int_api_call.cpp+11-0
@@ -16,8 +16,10 @@
16#include "common/checker.h"16#include "common/checker.h"
17#include "common/ge_common/debug/log.h"17#include "common/ge_common/debug/log.h"
18#include "graph/ascendc_ir/utils/asc_tensor_utils.h"18#include "graph/ascendc_ir/utils/asc_tensor_utils.h"
19+#include "api_call/utils/api_call_utils.h"
19#include "api_call/utils/api_call_factory.h"20#include "api_call/utils/api_call_factory.h"
20#include "codegen/expression_convert_struct.h"21#include "codegen/expression_convert_struct.h"
22+#include "reg_api_call_utils.h"
21 23 
22namespace codegen {24namespace codegen {
23using namespace std;25using namespace std;
@@ -38,6 +40,15 @@ Status RoundToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::
38 40 
39 stringstream ss;41 stringstream ss;
40 42 
43+ if (IsCVFusionStage(this->api_call_context)) {
44+ const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
45+ ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_RINT, " << GenCvUint32Dims(cv_params)
46+ << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride)
47+ << ");" << std::endl;
48+ result = ss.str();
49+ return af::SUCCESS;
50+ }
51+ 
41 // 使用 AscendC::Cast 函数,设置 round 模式为 CAST_RINT52 // 使用 AscendC::Cast 函数,设置 round 模式为 CAST_RINT
42 ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["53 ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["
43 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "54 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "
Mautofuse/v35/codegen/reg_api_call/trunc_to_int_api_call.cpp+11-0
@@ -16,8 +16,10 @@
16#include "common/ge_common/debug/log.h"16#include "common/ge_common/debug/log.h"
17#include "graph/ascendc_ir/utils/asc_tensor_utils.h"17#include "graph/ascendc_ir/utils/asc_tensor_utils.h"
18#include "common/checker.h"18#include "common/checker.h"
19+#include "api_call/utils/api_call_utils.h"
19#include "api_call/utils/api_call_factory.h"20#include "api_call/utils/api_call_factory.h"
20#include "codegen/expression_convert_struct.h"21#include "codegen/expression_convert_struct.h"
22+#include "reg_api_call_utils.h"
21 23 
22namespace codegen {24namespace codegen {
23using namespace std;25using namespace std;
@@ -38,6 +40,15 @@ Status TruncToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::
38 40 
39 stringstream ss;41 stringstream ss;
40 42 
43+ if (IsCVFusionStage(this->api_call_context)) {
44+ const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
45+ ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_TRUNC, " << GenCvUint32Dims(cv_params)
46+ << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride)
47+ << ");" << std::endl;
48+ result = ss.str();
49+ return af::SUCCESS;
50+ }
51+ 
41 // 使用 AscendC::Cast 函数,设置 round 模式为 CAST_TRUNC52 // 使用 AscendC::Cast 函数,设置 round 模式为 CAST_TRUNC
42 ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["53 ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["
43 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "54 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "
Mautofuse/v35/codegen/reg_api_call/unary_bitwidth_change_api_call_v2.cpp+5-2
@@ -19,6 +19,7 @@
19#include "api_call/utils/api_call_factory.h"19#include "api_call/utils/api_call_factory.h"
20#include "api_call/utils/api_call_utils.h"20#include "api_call/utils/api_call_utils.h"
21#include "codegen/expression_convert_struct.h"21#include "codegen/expression_convert_struct.h"
22+#include "reg_api_call_utils.h"
22namespace codegen {23namespace codegen {
23using namespace std;24using namespace std;
24using namespace af::ops;25using namespace af::ops;
@@ -48,13 +49,15 @@ Status UnaryBitWidthChangeApiCallV2::Generate(const TPipe &tpipe, const std::vec
48 SaveApiLoopAxisParams(merge_info, param);49 SaveApiLoopAxisParams(merge_info, param);
49 if (param.outer_repeats.size() == 0) {50 if (param.outer_repeats.size() == 0) {
50 ss << this->api_name_ << "(" << y << "_cast[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x51 ss << this->api_name_ << "(" << y << "_cast[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x
51- << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << x.actual_size << ");" << std::endl;52+ << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "
53+ << GetCvInputAlignedSize(this->api_call_context, x, x.actual_size.Str()) << ");" << std::endl;
52 } else {54 } else {
53 std::string input_inner_offset = CalcInnerOffset(tpipe, param.inputs_strides[0]);55 std::string input_inner_offset = CalcInnerOffset(tpipe, param.inputs_strides[0]);
54 std::string output_inner_offset = CalcInnerOffset(tpipe, param.outputs_strides[0]);56 std::string output_inner_offset = CalcInnerOffset(tpipe, param.outputs_strides[0]);
55 std::stringstream ss1;57 std::stringstream ss1;
56 ss1 << this->api_name_ << "(" << y << "_cast[" << output_inner_offset << "], " << x << "[" << input_inner_offset58 ss1 << this->api_name_ << "(" << y << "_cast[" << output_inner_offset << "], " << x << "[" << input_inner_offset
57- << "], " << tpipe.tiler.ActualSize(param.cal_count) << ");" << std::endl;59+ << "], " << GetCvInputAlignedSize(this->api_call_context, x, tpipe.tiler.ActualSize(param.cal_count)) << ");"
60+ << std::endl;
58 CreateComputeNodeOuterFor(param.outer_repeats, ss1, ss, 0);61 CreateComputeNodeOuterFor(param.outer_repeats, ss1, ss, 0);
59 }62 }
60 63 
Mautofuse/v35/codegen/vec_func_call/vec_func_call.cpp+103-46
@@ -114,9 +114,9 @@ void GetOuterForStride(const std::vector<std::vector<ascir::SizeExpr>> &origin_s
114}114}
115 115 
116// 生成vf函数体时,用于处理vf函数入参中的main scalar116// 生成vf函数体时,用于处理vf函数入参中的main scalar
117-void CreateVFCallDimAndStrideParmas(const std::vector<Tensor> &inputs, const std::vector<Tensor> &inputs_scalar,117+void CreateVFCallDimAndStrideParmas(const TPipe &tpipe, const std::vector<Tensor> &inputs,
118- const std::vector<Tensor> &outputs, const VectorizedAxisLoopMergeStatus &merge_info,118+ const std::vector<Tensor> &inputs_scalar, const std::vector<Tensor> &outputs,
119- std::stringstream &ss) {119+ const VectorizedAxisLoopMergeStatus &merge_info, std::stringstream &ss) {
120 string dtype_name;120 string dtype_name;
121 for (const auto &output : outputs) {121 for (const auto &output : outputs) {
122 Tensor::DtypeName(output.dtype, dtype_name);122 Tensor::DtypeName(output.dtype, dtype_name);
@@ -133,6 +133,12 @@ void CreateVFCallDimAndStrideParmas(const std::vector<Tensor> &inputs, const std
133 ss << dtype_name << " " << in_scalar << ", ";133 ss << dtype_name << " " << in_scalar << ", ";
134 }134 }
135 135 
136+ if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
137+ ss << GenCvUbFuseVfFuncDimParams() << ", ";
138+ ParamPostProcess(ss);
139+ return;
140+ }
141+ 
136 size_t dim_size = merge_info.merge_repeats_str.size();142 size_t dim_size = merge_info.merge_repeats_str.size();
137 size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop;143 size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop;
138 for (; start_idx < dim_size; start_idx++) {144 for (; start_idx < dim_size; start_idx++) {
@@ -152,6 +158,12 @@ void CreateVFCallDimAndStrideParmas(const std::vector<Tensor> &inputs, const std
152// 生成函数调用入参158// 生成函数调用入参
153void CreateDimAndStrideParmas(const TPipe &tpipe, const VectorizedAxisLoopMergeStatus &merge_info,159void CreateDimAndStrideParmas(const TPipe &tpipe, const VectorizedAxisLoopMergeStatus &merge_info,
154 std::stringstream &ss) {160 std::stringstream &ss) {
161+ if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
162+ ss << GenCvUbFuseVfCallDimParams() << ", ";
163+ ParamPostProcess(ss);
164+ return;
165+ }
166+ 
155 // 生成输入dims167 // 生成输入dims
156 size_t dim_size = merge_info.merge_repeats_str.size();168 size_t dim_size = merge_info.merge_repeats_str.size();
157 size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop;169 size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop;
@@ -434,6 +446,87 @@ void GenerateTensorDefs(const TPipe &tpipe, const TensorManager &tensor_mgr, con
434 }446 }
435}447}
436 448 
449+void GenerateVfCallFuncHeader(const TPipe &tpipe, const std::string &vf_call_name, const std::vector<Tensor> &inputs,
450+ const std::vector<Tensor> &scalar_inputs, const std::vector<Tensor> &outputs,
451+ const VectorizedAxisLoopMergeStatus &merge_info, std::stringstream &ss) {
452+ ss << "#if defined(__DAV_C310__) || (defined(__NPU_ARCH__) && (__NPU_ARCH__ == 5102 || __NPU_ARCH__ == 3510))"
453+ << std::endl;
454+ ss << "\ninline __simd_vf__ void " << vf_call_name << "(";
455+ CreateVFCallDimAndStrideParmas(tpipe, inputs, scalar_inputs, outputs, merge_info, ss);
456+ ss << ")" << std::endl;
457+}
458+ 
459+void GenerateVfCallLoopParams(const TPipe &tpipe, const std::string &max_dtype_size, int32_t stride_depth,
460+ const VectorizedAxisLoopMergeStatus &merge_info, std::stringstream &params) {
461+ if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
462+ params << " constexpr static uint32_t VECTOR_LENGTH = AscendC::GetVecLen();\n";
463+ params << " constexpr static uint32_t SIZE_OF_DTYPE = sizeof(" << max_dtype_size << ");\n";
464+ params << " constexpr static uint32_t ELEMENT_PER_VECTOR_LENGTH = VECTOR_LENGTH / SIZE_OF_DTYPE;\n";
465+ params << " uint32_t element_count = static_cast<uint32_t>(curAivN);\n";
466+ params << " uint16_t loop_times = static_cast<uint16_t>((element_count + ELEMENT_PER_VECTOR_LENGTH - 1) / "
467+ "ELEMENT_PER_VECTOR_LENGTH);\n";
468+ return;
469+ }
470+ GenerateVectorFuncParams(max_dtype_size, stride_depth, merge_info.merge_axis_ids, params);
471+}
472+ 
473+void GenerateLocalMemTensorPtrs(const std::vector<Tensor> &outputs, const std::vector<Tensor> &inputs,
474+ std::stringstream &vf_body) {
475+ std::string dtype_name;
476+ for (const auto &output : outputs) {
477+ Tensor::DtypeName(output.dtype, dtype_name);
478+ vf_body << " " << "__local_mem__ " << dtype_name << " *" << output << " = "
479+ << "(__local_mem__ " << dtype_name << " *)" << output << "_addr" << ";\n";
480+ }
481+ 
482+ for (const auto &input : inputs) {
483+ Tensor::DtypeName(input.dtype, dtype_name);
484+ vf_body << " " << "__local_mem__ " << dtype_name << " *" << input << " = "
485+ << "(__local_mem__ " << dtype_name << " *)" << input << "_addr" << ";\n";
486+ }
487+}
488+ 
489+void GenerateVfCallBodyPreamble(const TPipe &tpipe, const TensorManager &tensor_mgr, const VFLoop &root_loop,
490+ const std::vector<Tensor> &outputs, const std::vector<Tensor> &inputs,
491+ const std::string &max_dtype_size, std::stringstream &vf_body) {
492+ GenerateLocalMemTensorPtrs(outputs, inputs, vf_body);
493+ GenerateTensorDefs(tpipe, tensor_mgr, root_loop, vf_body);
494+ vf_body << "\nAscendC::MicroAPI::MaskReg preg_main = AscendC::MicroAPI::CreateMask<" << max_dtype_size
495+ << ", AscendC::MicroAPI::MaskPattern::ALL>();\n";
496+ vf_body << "AscendC::MicroAPI::MaskReg preg_vl1 = AscendC::MicroAPI::CreateMask<" << max_dtype_size
497+ << ", AscendC::MicroAPI::MaskPattern::VL1>();\n";
498+}
499+ 
500+af::Status UpdateVectorFuncNodeParams(const af::AscNodePtr &node, const VectorizedAxisLoopMergeStatus &merge_info,
501+ const std::vector<ge::Expression> &all_strides);
502+ 
503+Status GenerateVfCallLoopBody(const TPipe &tpipe, const TensorManager &tensor_mgr, const VFLoop &root_loop,
504+ int32_t stride_depth, const VectorizedAxisLoopMergeStatus &merge_info,
505+ const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs,
506+ const af::AscNodePtr &node, std::stringstream &params, std::stringstream &vf_body) {
507+ std::string loop_body;
508+ std::string loop_size;
509+ int32_t only_loop_max_depth = -1;
510+ std::vector<std::string> loop_size_vec;
511+ if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
512+ root_loop.GenerateCvUbFuse(tpipe, tensor_mgr, loop_body, loop_size);
513+ } else {
514+ root_loop.Generate(tpipe, tensor_mgr, stride_depth, loop_body, loop_size, only_loop_max_depth, loop_size_vec);
515+ }
516+ const bool is_double_loop = tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse &&
517+ stride_depth == MAX_VF_AXIS_MERGE_SIZE - 1 &&
518+ only_loop_max_depth == MAX_VF_AXIS_MERGE_SIZE - 1;
519+ std::vector<ge::Expression> all_strides;
520+ params << std::endl << loop_size << std::endl;
521+ if (is_double_loop) { // 假如stride_depth为1即两层循环,那实际上loop里递归了三次,分别是0、1、2,在2里单独处理call
522+ GenerateStridesEqualCheck(inputs, outputs, merge_info, all_strides, params);
523+ OptimizeMergeParamsAndLoopSize(loop_size_vec, params);
524+ GE_ASSERT_SUCCESS(UpdateVectorFuncNodeParams(node, merge_info, all_strides));
525+ }
526+ vf_body << std::endl << loop_body << std::endl;
527+ return af::SUCCESS;
528+}
529+ 
437af::Status UpdateVectorFuncNodeParams(const af::AscNodePtr &node, const VectorizedAxisLoopMergeStatus &merge_info,530af::Status UpdateVectorFuncNodeParams(const af::AscNodePtr &node, const VectorizedAxisLoopMergeStatus &merge_info,
438 const std::vector<ge::Expression> &all_strides) {531 const std::vector<ge::Expression> &all_strides) {
439 GE_ASSERT_NOTNULL(node);532 GE_ASSERT_NOTNULL(node);
@@ -459,11 +552,8 @@ Status VfCall::GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, st
459 bool status = GenerateVectorizedAxisMergeStatus(this->ub_inputs_, this->ub_outputs_, merge_info, tpipe);552 bool status = GenerateVectorizedAxisMergeStatus(this->ub_inputs_, this->ub_outputs_, merge_info, tpipe);
460 GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed");553 GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed");
461 554 
462- ss << "#if defined(__DAV_C310__) || (defined(__NPU_ARCH__) && (__NPU_ARCH__ == 5102 || __NPU_ARCH__ == 3510))"555+ GenerateVfCallFuncHeader(tpipe, this->vf_call_name_, this->ub_inputs_, this->scalar_inputs_, this->ub_outputs_,
463- << std::endl;556+ merge_info, ss);
464- ss << "\ninline __simd_vf__ void " << this->vf_call_name_ << "(";
465- CreateVFCallDimAndStrideParmas(this->ub_inputs_, this->scalar_inputs_, this->ub_outputs_, merge_info, ss);
466- ss << ")" << std::endl;
467 557 
468 // func body558 // func body
469 std::stringstream params;559 std::stringstream params;
@@ -476,44 +566,11 @@ Status VfCall::GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, st
476 // uint32_t element_count = static_cast<uint32_t>(output_dims_0);566 // uint32_t element_count = static_cast<uint32_t>(output_dims_0);
477 // uint16_t loop_times = static_cast<uint16_t>((element_count + ELEMENT_PER_VECTOR_LENGTH - 1) /567 // uint16_t loop_times = static_cast<uint16_t>((element_count + ELEMENT_PER_VECTOR_LENGTH - 1) /
478 // ELEMENT_PER_VECTOR_LENGTH);568 // ELEMENT_PER_VECTOR_LENGTH);
479- GenerateVectorFuncParams(max_dtype_size_, stride_depth, merge_info.merge_axis_ids, params);569+ GenerateVfCallLoopParams(tpipe, max_dtype_size_, stride_depth, merge_info, params);
480- 570+ GenerateVfCallBodyPreamble(tpipe, tensor_mgr_, root_loop_, this->ub_outputs_, this->ub_inputs_, max_dtype_size_,
481- std::string dtype_name;571+ vf_body);
482- for (const auto &output : this->ub_outputs_) {572+ GE_ASSERT_SUCCESS(GenerateVfCallLoopBody(tpipe, tensor_mgr_, root_loop_, stride_depth, merge_info, this->ub_inputs_,
483- Tensor::DtypeName(output.dtype, dtype_name);573+ this->ub_outputs_, node, params, vf_body));
484- vf_body << " " << "__local_mem__ " << dtype_name << " *" << output << " = "
485- << "(__local_mem__ " << dtype_name << " *)" << output << "_addr" << ";\n";
486- }
487- 
488- for (const auto &input : this->ub_inputs_) {
489- Tensor::DtypeName(input.dtype, dtype_name);
490- vf_body << " " << "__local_mem__ " << dtype_name << " *" << input << " = "
491- << "(__local_mem__ " << dtype_name << " *)" << input << "_addr" << ";\n";
492- }
493- 
494- GenerateTensorDefs(tpipe, tensor_mgr_, root_loop_, vf_body);
495- 
496- // define preg_main and preg_vl1
497- vf_body << "\nAscendC::MicroAPI::MaskReg preg_main = AscendC::MicroAPI::CreateMask<" << max_dtype_size_
498- << ", AscendC::MicroAPI::MaskPattern::ALL>();\n";
499- vf_body << "AscendC::MicroAPI::MaskReg preg_vl1 = AscendC::MicroAPI::CreateMask<" << max_dtype_size_
500- << ", AscendC::MicroAPI::MaskPattern::VL1>();\n";
501- 
502- std::string loop_body;
503- std::string loop_size;
504- int32_t only_loop_max_depth = -1;
505- std::vector<std::string> loop_size_vec;
506- root_loop_.Generate(tpipe, tensor_mgr_, stride_depth, loop_body, loop_size, only_loop_max_depth, loop_size_vec);
507- const bool is_double_loop =
508- stride_depth == MAX_VF_AXIS_MERGE_SIZE - 1 && only_loop_max_depth == MAX_VF_AXIS_MERGE_SIZE - 1;
509- std::vector<ge::Expression> all_strides;
510- params << std::endl << loop_size << std::endl;
511- if (is_double_loop) { // 假如stride_depth为1即两层循环,那实际上loop里递归了三次,分别是0、1、2,在2里单独处理call
512- GenerateStridesEqualCheck(this->ub_inputs_, this->ub_outputs_, merge_info, all_strides, params);
513- OptimizeMergeParamsAndLoopSize(loop_size_vec, params);
514- GE_ASSERT_SUCCESS(UpdateVectorFuncNodeParams(node, merge_info, all_strides));
515- }
516- vf_body << std::endl << loop_body << std::endl;
517 GetVFCallFuncBody(params.str(), vf_body.str(), ss);574 GetVFCallFuncBody(params.str(), vf_body.str(), ss);
518 ss << "#endif" << std::endl;575 ss << "#endif" << std::endl;
519 576 
Mautofuse/v35/codegen/vec_func_call/vf_loop.cpp+111-15
@@ -22,7 +22,15 @@ using namespace af::ascir_op;
22namespace codegen {22namespace codegen {
23 23 
24namespace {24namespace {
25+bool IsStrideZero(const ascir::SizeExpr &stride) {
26+ return af::SymbolicUtils::StaticCheckEq(stride.Simplify(), af::sym::kSymbolZero) == af::TriBool::kTrue;
27+}
28+ 
25std::string GetUbAddrOffset(const TPipe &tpipe, const MicroApiTensor *&reg_tensor, const Tensor *&ub_tensor) {29std::string GetUbAddrOffset(const TPipe &tpipe, const MicroApiTensor *&reg_tensor, const Tensor *&ub_tensor) {
30+ if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
31+ return GenCvUbFuseAddrOffset(tpipe, *ub_tensor);
32+ }
33+ 
26 std::stringstream offset_expr;34 std::stringstream offset_expr;
27 offset_expr << "0";35 offset_expr << "0";
28 for (size_t i = 0; i < reg_tensor->vectorized_strides_.size(); i++) {36 for (size_t i = 0; i < reg_tensor->vectorized_strides_.size(); i++) {
@@ -63,8 +71,70 @@ void GetUbStorePreg(const Tensor *&ub_tensor, std::string &preg_name) {
63 }71 }
64 preg_name = "preg_vl1";72 preg_name = "preg_vl1";
65}73}
74+ 
75+void GenerateMicroApiCall(const TPipe &tpipe, const TensorManager &tensor_mgr, const VFLoopBody &body,
76+ const std::string &max_dtype_size, std::string &preg_name, std::stringstream &ss) {
77+ std::string ub_offset = "";
78+ if (body.call_->GetMicroApiName() == "Load") {
79+ const MicroApiTensor *reg_tensor_ptr = tensor_mgr.GetTensor(body.call_->GetOutputTensorIdByIndex(0));
80+ const Tensor *ub_tensor_ptr = tpipe.GetTensor(body.call_->GetInputTensorIdByIndex(0));
81+ ub_offset = GetUbAddrOffset(tpipe, reg_tensor_ptr, ub_tensor_ptr);
82+ } else if (body.call_->GetMicroApiName() == "Store") {
83+ const Tensor *ub_tensor_ptr = tpipe.GetTensor(body.call_->GetOutputTensorIdByIndex(0));
84+ const MicroApiTensor *reg_tensor_ptr = tensor_mgr.GetTensor(body.call_->GetOutputTensorIdByIndex(1));
85+ ub_offset = GetUbAddrOffset(tpipe, reg_tensor_ptr, ub_tensor_ptr);
86+ GetUbStorePreg(ub_tensor_ptr, preg_name);
87+ }
88+ 
89+ std::string micro_api_call_str;
90+ CallParam param = {preg_name, ub_offset, max_dtype_size};
91+ body.call_->Generate(tensor_mgr, tpipe, param, micro_api_call_str);
92+ ss << micro_api_call_str;
93+}
66} // namespace94} // namespace
67 95 
96+std::string GenCvUbFuseVfFuncDimParams() {
97+ return "uint32_t curAivM, uint32_t curAivN, uint32_t curAlignN";
98+}
99+ 
100+std::string GenCvUbFuseVfCallDimParams() {
101+ return "curAivM, curAivN, curAlignN";
102+}
103+ 
104+std::string GenCvUbFuseRowStride(const TPipe &tpipe, const Tensor &ub_tensor) {
105+ if (ub_tensor.id == tpipe.cube_output_tensor_id) {
106+ return "curAlignN";
107+ }
108+ std::string dtype_name;
109+ if (Tensor::DtypeName(ub_tensor.dtype, dtype_name) != af::SUCCESS) {
110+ return "curAivN";
111+ }
112+ return "KernelUtils::BlkAlign<" + dtype_name + ">(curAivN)";
113+}
114+ 
115+std::string GenCvUbFuseAddrOffset(const TPipe &tpipe, const Tensor &ub_tensor) {
116+ bool enable_m_offset = true;
117+ bool enable_n_offset = true;
118+ const auto &strides = ub_tensor.vectorized_strides;
119+ if (strides.size() >= 2U) {
120+ enable_m_offset = !IsStrideZero(strides[strides.size() - 2U]);
121+ enable_n_offset = !IsStrideZero(strides[strides.size() - 1U]);
122+ } else if (strides.size() == 1U && IsStrideZero(strides[0])) {
123+ enable_m_offset = false;
124+ enable_n_offset = false;
125+ }
126+ 
127+ std::stringstream offset_expr;
128+ offset_expr << "0";
129+ if (enable_m_offset) {
130+ offset_expr << " + cv_m * " << GenCvUbFuseRowStride(tpipe, ub_tensor);
131+ }
132+ if (enable_n_offset) {
133+ offset_expr << " + cv_n * ELEMENT_PER_VECTOR_LENGTH";
134+ }
135+ return offset_expr.str();
136+}
137+ 
68VFLoop::VFLoop(const ascir::AxisId axis) {138VFLoop::VFLoop(const ascir::AxisId axis) {
69 axis_id_ = axis;139 axis_id_ = axis;
70 parent_ = nullptr;140 parent_ = nullptr;
@@ -208,6 +278,28 @@ Status VFLoop::Generate(const TPipe &tpipe, const TensorManager &tensor_mgr, int
208 return af::SUCCESS;278 return af::SUCCESS;
209}279}
210 280 
281+Status VFLoop::GenerateCvUbFuse(const TPipe &tpipe, const TensorManager &tensor_mgr, std::string &result,
282+ std::string &loop_size_result) const {
283+ std::stringstream ss;
284+ std::stringstream loop_size_ss;
285+ loop_size_ss << " uint16_t cv_m_loop_size = static_cast<uint16_t>(curAivM);\n";
286+ loop_size_ss << " uint16_t cv_n_loop_size = loop_times;\n";
287+ 
288+ ss << "for (uint16_t cv_m = 0; cv_m < cv_m_loop_size; cv_m++) {" << std::endl;
289+ ss << " AscendC::MicroAPI::MaskReg preg_0;" << std::endl;
290+ ss << " for (uint16_t cv_n = 0; cv_n < cv_n_loop_size; cv_n++) {" << std::endl;
291+ ss << " uint32_t sreg_0 = curAivN - cv_n * ELEMENT_PER_VECTOR_LENGTH;" << std::endl;
292+ ss << " preg_0 = AscendC::MicroAPI::UpdateMask<" << this->max_dtype_size_ << ">(sreg_0);\n";
293+ std::vector<ascir::AxisId> current_axis = {af::kIdNone};
294+ GE_CHK_STATUS_RET(GenerateCvUbFuseBody(tpipe, tensor_mgr, current_axis, ss), "Generate CV UBFuse body failed");
295+ ss << " }" << std::endl;
296+ ss << "}" << std::endl;
297+ 
298+ result = ss.str();
299+ loop_size_result = loop_size_ss.str();
300+ return af::SUCCESS;
301+}
302+ 
211Status VFLoop::GenerateLoop(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth,303Status VFLoop::GenerateLoop(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth,
212 std::vector<ascir::AxisId> &current_axis, std::stringstream &ss,304 std::vector<ascir::AxisId> &current_axis, std::stringstream &ss,
213 std::stringstream &loop_size_ss, int32_t &only_loop_max_depth,305 std::stringstream &loop_size_ss, int32_t &only_loop_max_depth,
@@ -264,21 +356,7 @@ Status VFLoop::GenerateBody(const TPipe &tpipe, const TensorManager &tensor_mgr,
264 continue;356 continue;
265 }357 }
266 std::string preg_name = GetOriginPregName(current_axis, depth);358 std::string preg_name = GetOriginPregName(current_axis, depth);
267- std::string ub_offset = "";359+ GenerateMicroApiCall(tpipe, tensor_mgr, body, this->max_dtype_size_, preg_name, ss);
268- if (body.call_->GetMicroApiName() == "Load") {
269- const MicroApiTensor *reg_tensor_ptr = tensor_mgr.GetTensor(body.call_->GetOutputTensorIdByIndex(0));
270- const Tensor *ub_tensor_ptr = tpipe.GetTensor(body.call_->GetInputTensorIdByIndex(0));
271- ub_offset = GetUbAddrOffset(tpipe, reg_tensor_ptr, ub_tensor_ptr);
272- } else if (body.call_->GetMicroApiName() == "Store") {
273- const Tensor *ub_tensor_ptr = tpipe.GetTensor(body.call_->GetOutputTensorIdByIndex(0));
274- const MicroApiTensor *reg_tensor_ptr = tensor_mgr.GetTensor(body.call_->GetOutputTensorIdByIndex(1));
275- ub_offset = GetUbAddrOffset(tpipe, reg_tensor_ptr, ub_tensor_ptr);
276- GetUbStorePreg(ub_tensor_ptr, preg_name);
277- }
278- std::string micro_api_call_str;
279- CallParam param = {preg_name, ub_offset, this->max_dtype_size_};
280- body.call_->Generate(tensor_mgr, tpipe, param, micro_api_call_str);
281- ss << micro_api_call_str;
282 has_call = true;360 has_call = true;
283 }361 }
284 }362 }
@@ -288,6 +366,24 @@ Status VFLoop::GenerateBody(const TPipe &tpipe, const TensorManager &tensor_mgr,
288 return af::SUCCESS;366 return af::SUCCESS;
289}367}
290 368 
369+Status VFLoop::GenerateCvUbFuseBody(const TPipe &tpipe, const TensorManager &tensor_mgr,
370+ std::vector<ascir::AxisId> &current_axis, std::stringstream &ss) const {
371+ for (const auto &body : this->bodys_) {
372+ if (body.type_ == LoopType::LOOP) {
373+ GE_CHK_STATUS_RET(body.loop_->GenerateCvUbFuseBody(tpipe, tensor_mgr, current_axis, ss),
374+ "Generate CV UBFuse loop body failed");
375+ continue;
376+ }
377+ if (body.type_ != LoopType::CALL || body.call_->unit == ge::ComputeUnit::kUnitNone) {
378+ continue;
379+ }
380+ 
381+ std::string preg_name = GetOriginPregName(current_axis, 0);
382+ GenerateMicroApiCall(tpipe, tensor_mgr, body, this->max_dtype_size_, preg_name, ss);
383+ }
384+ return af::SUCCESS;
385+}
386+ 
291void VFLoop::CollectMaskRegTempTensors(const TPipe &tpipe, const TensorManager &tensor_mgr,387void VFLoop::CollectMaskRegTempTensors(const TPipe &tpipe, const TensorManager &tensor_mgr,
292 std::vector<std::string> &temp_tensors) const {388 std::vector<std::string> &temp_tensors) const {
293 for (const auto &body : this->bodys_) {389 for (const auto &body : this->bodys_) {
Mautofuse/v35/codegen/vec_func_call/vf_loop.h+10-1
@@ -14,6 +14,11 @@
14 14 
15namespace codegen {15namespace codegen {
16 16 
17+std::string GenCvUbFuseVfFuncDimParams();
18+std::string GenCvUbFuseVfCallDimParams();
19+std::string GenCvUbFuseRowStride(const TPipe &tpipe, const Tensor &ub_tensor);
20+std::string GenCvUbFuseAddrOffset(const TPipe &tpipe, const Tensor &ub_tensor);
21+ 
17class VFLoop;22class VFLoop;
18struct VFLoopBody {23struct VFLoopBody {
19 LoopType type_;24 LoopType type_;
@@ -37,13 +42,15 @@ class VFLoop {
37 Status Generate(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth, std::string &result,42 Status Generate(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth, std::string &result,
38 std::string &loop_size_result, int32_t &only_loop_max_depth,43 std::string &loop_size_result, int32_t &only_loop_max_depth,
39 std::vector<std::string> &loop_size_vec) const;44 std::vector<std::string> &loop_size_vec) const;
45+ Status GenerateCvUbFuse(const TPipe &tpipe, const TensorManager &tensor_mgr, std::string &result,
46+ std::string &loop_size_result) const;
40 void SetMaxDtypeSize(std::string dtype);47 void SetMaxDtypeSize(std::string dtype);
41 void CollectMaskRegTempTensors(const TPipe &tpipe, const TensorManager &tensor_mgr,48 void CollectMaskRegTempTensors(const TPipe &tpipe, const TensorManager &tensor_mgr,
42 std::vector<std::string> &temp_tensors) const;49 std::vector<std::string> &temp_tensors) const;
43 50 
44 private:51 private:
45 ascir::AxisId axis_id_;52 ascir::AxisId axis_id_;
46- struct VFLoop *parent_;53+ VFLoop *parent_;
47 std::vector<VFLoopBody> bodys_;54 std::vector<VFLoopBody> bodys_;
48 std::string max_dtype_size_;55 std::string max_dtype_size_;
49 56 
@@ -53,6 +60,8 @@ class VFLoop {
53 Status GenerateBody(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth,60 Status GenerateBody(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth,
54 std::vector<ascir::AxisId> &current_axis, std::stringstream &ss, std::stringstream &loop_size_ss,61 std::vector<ascir::AxisId> &current_axis, std::stringstream &ss, std::stringstream &loop_size_ss,
55 int32_t &only_loop_max_depth, std::vector<std::string> &loop_size_vec) const;62 int32_t &only_loop_max_depth, std::vector<std::string> &loop_size_vec) const;
63+ Status GenerateCvUbFuseBody(const TPipe &tpipe, const TensorManager &tensor_mgr,
64+ std::vector<ascir::AxisId> &current_axis, std::stringstream &ss) const;
56};65};
57 66 
58} // namespace codegen67} // namespace codegen