已合并
fix(cv-ubfuse): align UB physical layout for mixed-dtype vector tensors #2177
fix(cv-ubfuse): align UB physical layout for mixed-dtype vector tensors #2177
已合并
tianbaolin创建于 9月18日
共 22 个文件变更+251-49
@@ -18,6 +18,7 @@
18#include "graph/symbolizer/symbolic_utils.h"18#include "graph/symbolizer/symbolic_utils.h"
19#include "common/checker.h"19#include "common/checker.h"
20#include "api_call/utils/api_call_factory.h"20#include "api_call/utils/api_call_factory.h"
21+#include "api_call/utils/api_call_utils.h"
21#include "codegen/expression_convert_struct.h"22#include "codegen/expression_convert_struct.h"
22 23 
23namespace codegen {24namespace codegen {
@@ -95,6 +96,25 @@ Status BinaryApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axis
95 ss << ");" << std::endl;96 ss << ");" << std::endl;
96 }97 }
97 } else { // 两个输入都不是Scalar98 } else { // 两个输入都不是Scalar
99+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
100+ // CV UBFuse 下 flat 1D 调用的 count 取自 stage 尺寸, 无法覆盖按输出 dtype 对齐的二维布局
101+ // (如 bool 输入 N=4: 行距32, 总量 M*32, stage 仅 M*8), 尾部行读到未初始化数据。
102+ // 按 per-dtype 物理行距逐行调用, 与 UnaryApiCall/位宽类 API 的 CV 修复方式一致。
103+ const std::string output_stride = GenBlockAlignNExpr(y, "curAivN");
104+ const auto gen_input_stride = [&](const Tensor &t) {
105+ return (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && t.id == tpipe.cube_output_tensor_id)
106+ ? std::string("curAlignN")
107+ : GenBlockAlignNExpr(t, "curAivN");
108+ };
109+ ss << y.actual_size << " = curAivM * " << output_stride << ";" << std::endl;
110+ ss << "for (uint32_t cv_row = 0; cv_row < ConvertToUint32(curAivM); cv_row++) {" << std::endl;
111+ ss << " " << this->api_name_ << "(" << y << "[cv_row * ConvertToUint32(" << output_stride << ")], " << x1
112+ << "[cv_row * ConvertToUint32(" << gen_input_stride(x1) << ")], " << x2 << "[cv_row * ConvertToUint32("
113+ << gen_input_stride(x2) << ")], ConvertToUint32(curAivN));" << std::endl;
114+ ss << "}" << std::endl;
115+ result = ss.str();
116+ return af::SUCCESS;
117+ }
98 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1118 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1
99 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["119 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["
100 << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], " << x1.actual_size << ");" << std::endl;120 << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], " << x1.actual_size << ");" << std::endl;
@@ -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 {
@@ -35,6 +36,22 @@ Status UnaryApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisI
35 (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs, CombinedExprFactory::SymbolVar(x.actual_size.Str()));36 (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs, CombinedExprFactory::SymbolVar(x.actual_size.Str()));
36 37 
37 stringstream ss;38 stringstream ss;
39+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
40+ // CV UBFuse 下 flat 1D 调用的 count 取自 stage 尺寸, 无法覆盖按输出 dtype 对齐的二维布局
41+ // (如 bool 输入 N=4: 行距32, 总量 M*32, stage 仅 M*8), 尾部行读到未初始化数据。
42+ // 按 per-dtype 物理行距逐行调用, 输出按输出 dtype 行距落位, 与 stage 写出/下游消费侧行距一致。
43+ const std::string output_stride = GenBlockAlignNExpr(y, "curAivN");
44+ const bool input_is_cube_output =
45+ tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && x.id == tpipe.cube_output_tensor_id;
46+ const std::string input_stride = input_is_cube_output ? "curAlignN" : GenBlockAlignNExpr(x, "curAivN");
47+ ss << y.actual_size << " = curAivM * " << output_stride << ";" << std::endl;
48+ ss << "for (uint32_t cv_row = 0; cv_row < ConvertToUint32(curAivM); cv_row++) {" << std::endl;
49+ ss << " " << this->api_name_ << "(" << y << "[cv_row * ConvertToUint32(" << output_stride << ")], " << x
50+ << "[cv_row * ConvertToUint32(" << input_stride << ")], ConvertToUint32(curAivN));" << std::endl;
51+ ss << "}" << std::endl;
52+ result = ss.str();
53+ return af::SUCCESS;
54+ }
38 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["55 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "["
39 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << x.actual_size << ");" << std::endl;56 << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << x.actual_size << ");" << std::endl;
40 result = ss.str();57 result = ss.str();
@@ -195,6 +195,14 @@ std::string GetVectorGroupWorkspaceOutputName(const ascir::ScheduleGroup &schedu
195 if (GetSingleWorkspaceName(impl_graph) != workspace_name) {195 if (GetSingleWorkspaceName(impl_graph) != workspace_name) {
196 return "";196 return "";
197 }197 }
198+ 
199+ // vector读取外部输入时, 输出buffer可能与该输入复用, 复用会覆盖输入, 故禁用
200+ for (const auto &node : impl_graph.GetAllNodes()) {
201+ if (IsOps<Data>(node)) {
202+ return "";
203+ }
204+ }
205+ 
198 const auto current_output_name = GetWorkspacePathOutputName(impl_graph, workspace_name);206 const auto current_output_name = GetWorkspacePathOutputName(impl_graph, workspace_name);
199 if (current_output_name.empty() || (!output_name.empty() && output_name != current_output_name)) {207 if (current_output_name.empty() || (!output_name.empty() && output_name != current_output_name)) {
200 return "";208 return "";
@@ -2165,6 +2173,33 @@ Status Kernel::ParseWorkspaceTensor(const ascir::TensorAttr *tensor,
2165 return af::SUCCESS;2173 return af::SUCCESS;
2166}2174}
2167 2175 
2176+namespace {
2177+// GetTmpBuffer 会为 tmp 公式套上 v1 repeat cap 壳: Min(size, 65312)。CV UBFuse 的 tmp
2178+// 内联公式不走 tiling 求解, stage 尺寸由 cube tiling 决定, 需求无法缩到 cap 以内, 因此
2179+// 在 CV 收集点剥掉该壳取原始需求。数值须与 GetTmpBuffer 的 cap(255 * 256 + 32)保持一致。
2180+// 非 cap 形态(无壳或常量非该值)原样返回; VV 路径不经此处理, 继续使用 capped size 参与
2181+// host tiling 求解。
2182+constexpr int64_t kMaxV1RepeatTmpBytes = 255LL * 256LL + 32LL;
2183+ 
2184+// GetArgs 为非 const 接口, 此处按值传递以便调用。
2185+af::Expression StripV1RepeatCap(af::Expression size) {
2186+ if (!size.IsValid()) {
2187+ return size;
2188+ }
2189+ auto args = size.GetArgs();
2190+ if (args.size() != 2UL) {
2191+ return size;
2192+ }
2193+ for (size_t i = 0UL; i < args.size(); i++) {
2194+ int64_t cap_value = 0;
2195+ if (args[i].IsConstExpr() && args[i].GetConstValue(cap_value) && cap_value == kMaxV1RepeatTmpBytes) {
2196+ return args[1UL - i];
2197+ }
2198+ }
2199+ return size;
2200+}
2201+} // namespace
2202+ 
2168Status Kernel::ParseGraph(const ascir::ImplGraph &graph, const ascir::FusedScheduledResult &fused_schedule_result,2203Status Kernel::ParseGraph(const ascir::ImplGraph &graph, const ascir::FusedScheduledResult &fused_schedule_result,
2169 Kernel &kernel) {2204 Kernel &kernel) {
2170 // Parse kernel input output2205 // Parse kernel input output
@@ -2359,16 +2394,24 @@ Status Kernel::ParseGraph(const ascir::ImplGraph &graph, const ascir::FusedSched
2359 }2394 }
2360 auto it = kernel.tpipe.bufs.find(tmp_buffer.id);2395 auto it = kernel.tpipe.bufs.find(tmp_buffer.id);
2361 GELOGD("reuse tmp buffer id is %ld.", tmp_buffer.id);2396 GELOGD("reuse tmp buffer id is %ld.", tmp_buffer.id);
2397+ // CV UBFuse 使用无 v1 repeat cap 的原始 tmp 需求; 其余路径(含 VV 的 host tiling
2398+ // 求解)保持 capped size 原样, 不引入额外拷贝。
2399+ af::Expression stripped;
2400+ const af::Expression *tmp_size = &tmp_buffer.buf_desc.size;
2401+ if (kernel.tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
2402+ stripped = StripV1RepeatCap(tmp_buffer.buf_desc.size);
2403+ tmp_size = &stripped;
2404+ }
2362 if (it == kernel.tpipe.bufs.end()) {2405 if (it == kernel.tpipe.bufs.end()) {
2363 std::string position = "TPosition::VECCALC";2406 std::string position = "TPosition::VECCALC";
2364 ascir::Position tensor_position = af::Position::kPositionVecCalc;2407 ascir::Position tensor_position = af::Position::kPositionVecCalc;
2365 auto [new_buf, is_insert5] =2408 auto [new_buf, is_insert5] =
2366 kernel.tpipe.bufs.emplace(tmp_buffer.id, TBuf{tmp_buffer.id, tensor_position, position});2409 kernel.tpipe.bufs.emplace(tmp_buffer.id, TBuf{tmp_buffer.id, tensor_position, position});
2367 GE_CHK_BOOL_RET_STATUS(is_insert5, af::FAILED, "Codegen emplace tbuf [%ld] failed", tmp_buffer.id);2410 GE_CHK_BOOL_RET_STATUS(is_insert5, af::FAILED, "Codegen emplace tbuf [%ld] failed", tmp_buffer.id);
2368- new_buf->second.tmp_buf_size_list.emplace_back(tmp_buffer.buf_desc.size);2411+ new_buf->second.tmp_buf_size_list.emplace_back(*tmp_size);
2369 new_buf->second.tmp_buf_reuse = true;2412 new_buf->second.tmp_buf_reuse = true;
2370 } else {2413 } else {
2371- it->second.tmp_buf_size_list.emplace_back(tmp_buffer.buf_desc.size);2414+ it->second.tmp_buf_size_list.emplace_back(*tmp_size);
2372 it->second.tmp_buf_reuse = true;2415 it->second.tmp_buf_reuse = true;
2373 }2416 }
2374 }2417 }
@@ -3944,6 +3987,7 @@ std::string TPipe::TensorSizeDefine() const {
3944 3987 
3945Status TPipe::TensorSizeAssign(std::string dtype_name, std::string &result) const {3988Status TPipe::TensorSizeAssign(std::string dtype_name, std::string &result) const {
3946 stringstream ss;3989 stringstream ss;
3990+ (void)dtype_name;
3947 3991 
3948 for (auto &pair : this->tensors) {3992 for (auto &pair : this->tensors) {
3949 auto &t = pair.second;3993 auto &t = pair.second;
@@ -3954,7 +3998,10 @@ Status TPipe::TensorSizeAssign(std::string dtype_name, std::string &result) cons
3954 static_cast<int32_t>(t.dtype));3998 static_cast<int32_t>(t.dtype));
3955 ss << t.size.Str() << " = KernelUtils::BlkAlign<" << tensor_dtype_name << ">(1);" << std::endl;3999 ss << t.size.Str() << " = KernelUtils::BlkAlign<" << tensor_dtype_name << ">(1);" << std::endl;
3956 } else {4000 } else {
3957- ss << t.size.Str() << " = stage_size / sizeof(" << dtype_name << ");" << std::endl;4001+ // stage_size(元素个数)已归一: 主路径 = 求解器预算a0a1t(=行数*basen_align, 任意dtype的32B行对齐
4002+ // 行宽均<=basen_align, 按此元素数分配即覆盖compute size且不超求解器预算);
4003+ // 小a0a1t兜底时 = cube_ub元素数(容量, 更保守). CV与非CV统一使用stage_size.
4004+ ss << t.size.Str() << " = stage_size;" << std::endl;
3958 }4005 }
3959 }4006 }
3960 }4007 }
@@ -4101,6 +4148,7 @@ class AutoFusionVector {
4101 if (is_inductor) {4148 if (is_inductor) {
4102 result << " uint32_t stage_size_name{0};" << std::endl;4149 result << " uint32_t stage_size_name{0};" << std::endl;
4103 result << " uint32_t cube_ub_stage_size{0};" << std::endl;4150 result << " uint32_t cube_ub_stage_size{0};" << std::endl;
4151+ result << " uint32_t cube_m_stage_size{0};" << std::endl;
4104 } else {4152 } else {
4105 result << " const CVAutofuseTilingData *cv_tiling_data{nullptr};" << std::endl;4153 result << " const CVAutofuseTilingData *cv_tiling_data{nullptr};" << std::endl;
4106 }4154 }
@@ -4119,6 +4167,7 @@ class AutoFusionVector {
4119 if (is_inductor) {4167 if (is_inductor) {
4120 result << " uint32_t stage_size_name{0};" << std::endl;4168 result << " uint32_t stage_size_name{0};" << std::endl;
4121 result << " uint32_t cube_ub_stage_size{0};" << std::endl;4169 result << " uint32_t cube_ub_stage_size{0};" << std::endl;
4170+ result << " uint32_t cube_m_stage_size{0};" << std::endl;
4122 } else {4171 } else {
4123 result << " const CVAutofuseTilingData *cv_tiling_data{nullptr};" << std::endl;4172 result << " const CVAutofuseTilingData *cv_tiling_data{nullptr};" << std::endl;
4124 }4173 }
@@ -4135,6 +4184,7 @@ class AutoFusionVector {
4135 if (is_inductor) {4184 if (is_inductor) {
4136 result << " uint32_t stage_size_name{0};" << std::endl;4185 result << " uint32_t stage_size_name{0};" << std::endl;
4137 result << " uint32_t cube_ub_stage_size{0};" << std::endl;4186 result << " uint32_t cube_ub_stage_size{0};" << std::endl;
4187+ result << " uint32_t cube_m_stage_size{0};" << std::endl;
4138 } else {4188 } else {
4139 result << " const CVAutofuseTilingData *cv_tiling_data{nullptr};" << std::endl;4189 result << " const CVAutofuseTilingData *cv_tiling_data{nullptr};" << std::endl;
4140 }4190 }
@@ -4219,7 +4269,7 @@ class AutoFusionVector {
4219 result << "const uint32_t stage_size_name = autofuse_tiling_size.STAGE_SIZE_NAME;" << std::endl;4269 result << "const uint32_t stage_size_name = autofuse_tiling_size.STAGE_SIZE_NAME;" << std::endl;
4220 }4270 }
4221 result << "const int32_t compute_size = stage_size_name > 144 ? stage_size_name : 144;" << std::endl;4271 result << "const int32_t compute_size = stage_size_name > 144 ? stage_size_name : 144;" << std::endl;
4222- result << "int32_t stage_size = compute_size * sizeof(" << dtype_name << ");" << std::endl;4272+ result << "int32_t stage_size = compute_size;" << std::endl;
4223 result << "stage_size2 = compute_size;" << std::endl;4273 result << "stage_size2 = compute_size;" << std::endl;
4224 } else {4274 } else {
4225 result << "__aicore__ inline void Init(Params const& params, AscendC::LocalTensor<" << dtype_name4275 result << "__aicore__ inline void Init(Params const& params, AscendC::LocalTensor<" << dtype_name
@@ -4231,27 +4281,42 @@ class AutoFusionVector {
4231 result << "const uint32_t stage_size_name = autofuse_tiling_size.STAGE_SIZE_NAME;" << std::endl;4281 result << "const uint32_t stage_size_name = autofuse_tiling_size.STAGE_SIZE_NAME;" << std::endl;
4232 result << "const int32_t basen_basem_align = kConstTilingData.cube_ub_stage_size * sizeof(" << dtype_name << ");"4282 result << "const int32_t basen_basem_align = kConstTilingData.cube_ub_stage_size * sizeof(" << dtype_name << ");"
4233 << std::endl;4283 << std::endl;
4284+ result << "stage_size_type = static_cast<int64_t>(kConstTilingData.cube_m_stage_size);" << std::endl;
4234 result << "#else" << std::endl;4285 result << "#else" << std::endl;
4235 result << "const uint32_t stage_size_name = params.stage_size_name;" << std::endl;4286 result << "const uint32_t stage_size_name = params.stage_size_name;" << std::endl;
4236 result << "const int32_t basen_basem_align = params.cube_ub_stage_size * sizeof(" << dtype_name << ");"4287 result << "const int32_t basen_basem_align = params.cube_ub_stage_size * sizeof(" << dtype_name << ");"
4237 << std::endl;4288 << std::endl;
4289+ result << "stage_size_type = static_cast<int64_t>(params.cube_m_stage_size);" << std::endl;
4238 result << "#endif" << std::endl;4290 result << "#endif" << std::endl;
4239 } else {4291 } else {
4240 result << "GET_TILING_DATA_WITH_STRUCT(MatMulV3BasicTilingData, tmpTilingData, tmpTilingGM);" << std::endl;4292 result << "GET_TILING_DATA_WITH_STRUCT(MatMulV3BasicTilingData, tmpTilingData, tmpTilingGM);" << std::endl;
4241- result << "AutofuseTilingData autofuse_tiling_size;" << std::endl;4293+ result << "const int32_t ub_align_value = 32;" << std::endl;
4242- result << "const int32_t ub_align_value = 32 / sizeof(" << dtype_name << ");" << std::endl;
4243 result4294 result
4244 << "const int32_t basen_align = (tmpTilingData.baseN + ub_align_value - 1) / ub_align_value * ub_align_value;"4295 << "const int32_t basen_align = (tmpTilingData.baseN + ub_align_value - 1) / ub_align_value * ub_align_value;"
4245 << std::endl;4296 << std::endl;
4246 result << "const int32_t basen_basem_align = (tmpTilingData.baseM * basen_align * sizeof(" << dtype_name4297 result << "const int32_t basen_basem_align = (tmpTilingData.baseM * basen_align * sizeof(" << dtype_name
4247 << ")) / 2 + basen_align * sizeof(" << dtype_name << ");" << std::endl;4298 << ")) / 2 + basen_align * sizeof(" << dtype_name << ");" << std::endl;
4248- result << "const uint32_t stage_size_name = autofuse_tiling_size.STAGE_SIZE_NAME;" << std::endl;4299+ // 非inductor: ascbc静态流程在device头烧录kConstTilingData(求解器完整结果);
4300+ // 动态shape时params携带cv_tiling_data指针读GM tiling; TF等前端在线GE编译的
4301+ // 静态图两者皆无, 回退到autofuse_tiling_data.h中烧录的求解器结果
4302+ // (z0z1t预算), 行数按 预算/上确界行宽 就地推导, 与conv2d分支同一模式
4303+ result << "#ifdef INDUCTOR_CONST_TILING_DATA" << std::endl;
4304+ result << "stage_size_type = static_cast<int64_t>(kConstTilingData.cube_m_stage_size);" << std::endl;
4305+ result << "const uint32_t stage_size_name = kConstTilingData.stage_size_name;" << std::endl;
4306+ result << "#else" << std::endl;
4307+ if (is_dynamic) {
4308+ result << "stage_size_type = static_cast<int64_t>(params.cv_tiling_data->cube_m_stage_size);" << std::endl;
4309+ result << "const uint32_t stage_size_name = params.cv_tiling_data->stage_size_name;" << std::endl;
4310+ } else {
4311+ result << "AutofuseTilingData autofuse_tiling_size;" << std::endl;
4312+ result << "const uint32_t stage_size_name = autofuse_tiling_size.STAGE_SIZE_NAME;" << std::endl;
4313+ result << "stage_size_type = static_cast<int64_t>(stage_size_name / basen_align);" << std::endl;
4314+ }
4315+ result << "#endif" << std::endl;
4249 }4316 }
4250- // 下面的144为16*16/2+16,按照cube tiling最小块16*16计算得到4317+ // stage_size 统一为元素个数: 求解器预算 a0a1t, 过小时兜底到 C fragment 容量(cube_ub元素数)
4251- result << "int32_t stage_size = stage_size_name > 144 ? " << std::endl;4318+ result << "int32_t stage_size = stage_size_name > 144 ? stage_size_name : " << std::endl;
4252- result << "stage_size_name * sizeof(" << dtype_name << ") : basen_basem_align;" << std::endl;4319+ result << "static_cast<int32_t>(basen_basem_align / sizeof(" << dtype_name << "));" << std::endl;
4253- result << "stage_size_type = static_cast<int64_t>(stage_size_name > 144 ? " << std::endl;
4254- result << "stage_size_name : basen_basem_align / sizeof(" << dtype_name << "));" << std::endl;
4255 }4320 }
4256 GE_CHK_STATUS_RET(this->root_loop.ActualSizeDefine(this->tiler, this->tpipe, dtype_name, tmp),4321 GE_CHK_STATUS_RET(this->root_loop.ActualSizeDefine(this->tiler, this->tpipe, dtype_name, tmp),
4257 "actual size define failed");4322 "actual size define failed");
@@ -4259,7 +4324,7 @@ class AutoFusionVector {
4259 if (is_conv2d) {4324 if (is_conv2d) {
4260 result << ub_tensor->Str() << "_actual_size = stage_size2;" << std::endl << std::endl;4325 result << ub_tensor->Str() << "_actual_size = stage_size2;" << std::endl << std::endl;
4261 } else {4326 } else {
4262- result << ub_tensor->Str() << "_actual_size = stage_size_type;" << std::endl << std::endl;4327+ result << ub_tensor->Str() << "_actual_size = stage_size;" << std::endl << std::endl;
4263 }4328 }
4264 GE_CHK_STATUS_RET(this->tpipe.TensorSizeAssign(dtype_name, tmp), "Tensor size assign failed");4329 GE_CHK_STATUS_RET(this->tpipe.TensorSizeAssign(dtype_name, tmp), "Tensor size assign failed");
4265 result << tmp;4330 result << tmp;
@@ -4275,9 +4340,9 @@ class AutoFusionVector {
4275 if (is_conv2d) {4340 if (is_conv2d) {
4276 result << "GetTPipePtr()->InitBuffer(buf_cube, stage_size1 * sizeof(" << dtype_name << "));" << std::endl;4341 result << "GetTPipePtr()->InitBuffer(buf_cube, stage_size1 * sizeof(" << dtype_name << "));" << std::endl;
4277 } else {4342 } else {
4278- result << "const uint32_t cv_ub_vector_queue_size = KernelUtils::BlkAlign<uint8_t>(stage_size);" << std::endl;4343+ // 行语义下 epilogue 读取 cLocal_ 上界 stageOffset+stageSize <= inputSize <= cube_ub,
4279- result << "tpipe.InitBuffer(buf_cube, KernelUtils::Max(static_cast<uint32_t>(basen_basem_align), "4344+ // buf_cube 只需 C fragment 容量 basen_basem_align, 不再按 stage_size 撑大
4280- << "cv_ub_vector_queue_size));" << std::endl;4345+ result << "tpipe.InitBuffer(buf_cube, static_cast<uint32_t>(basen_basem_align));" << std::endl;
4281 }4346 }
4282 result << ub_tensor->name << " = buf_cube.Get<" << dtype_name << ">();" << std::endl;4347 result << ub_tensor->name << " = buf_cube.Get<" << dtype_name << ">();" << std::endl;
4283 result << "cLocal = " << ub_tensor->name << ";" << std::endl << std::endl;4348 result << "cLocal = " << ub_tensor->name << ";" << std::endl << std::endl;
@@ -4437,9 +4502,11 @@ Status Kernel::InitCVFusionAddr(std::stringstream &result, bool vector_no_db_fla
4437 result << "#ifdef INDUCTOR_CONST_TILING_DATA" << std::endl;4502 result << "#ifdef INDUCTOR_CONST_TILING_DATA" << std::endl;
4438 result << " CV_FUSION_ADDR.stage_size_name = kConstTilingData.stage_size_name;" << std::endl;4503 result << " CV_FUSION_ADDR.stage_size_name = kConstTilingData.stage_size_name;" << std::endl;
4439 result << " CV_FUSION_ADDR.cube_ub_stage_size = kConstTilingData.cube_ub_stage_size;" << std::endl;4504 result << " CV_FUSION_ADDR.cube_ub_stage_size = kConstTilingData.cube_ub_stage_size;" << std::endl;
4505+ result << " CV_FUSION_ADDR.cube_m_stage_size = kConstTilingData.cube_m_stage_size;" << std::endl;
4440 result << "#else" << std::endl;4506 result << "#else" << std::endl;
4441 result << " CV_FUSION_ADDR.stage_size_name = t.stage_size_name;" << std::endl;4507 result << " CV_FUSION_ADDR.stage_size_name = t.stage_size_name;" << std::endl;
4442 result << " CV_FUSION_ADDR.cube_ub_stage_size = t.cube_ub_stage_size;" << std::endl;4508 result << " CV_FUSION_ADDR.cube_ub_stage_size = t.cube_ub_stage_size;" << std::endl;
4509+ result << " CV_FUSION_ADDR.cube_m_stage_size = t.cube_m_stage_size;" << std::endl;
4443 result << "#endif" << std::endl;4510 result << "#endif" << std::endl;
4444 result << " }" << std::endl;4511 result << " }" << std::endl;
4445 } else {4512 } else {
@@ -4464,9 +4531,11 @@ Status Kernel::InitCVFusionAddr(std::stringstream &result, bool vector_no_db_fla
4464 result << "#ifdef INDUCTOR_CONST_TILING_DATA" << std::endl;4531 result << "#ifdef INDUCTOR_CONST_TILING_DATA" << std::endl;
4465 result << " CV_FUSION_ADDR_DB.stage_size_name = kConstTilingData.stage_size_name;" << std::endl;4532 result << " CV_FUSION_ADDR_DB.stage_size_name = kConstTilingData.stage_size_name;" << std::endl;
4466 result << " CV_FUSION_ADDR_DB.cube_ub_stage_size = kConstTilingData.cube_ub_stage_size;" << std::endl;4533 result << " CV_FUSION_ADDR_DB.cube_ub_stage_size = kConstTilingData.cube_ub_stage_size;" << std::endl;
4534+ result << " CV_FUSION_ADDR_DB.cube_m_stage_size = kConstTilingData.cube_m_stage_size;" << std::endl;
4467 result << "#else" << std::endl;4535 result << "#else" << std::endl;
4468 result << " CV_FUSION_ADDR_DB.stage_size_name = t.stage_size_name;" << std::endl;4536 result << " CV_FUSION_ADDR_DB.stage_size_name = t.stage_size_name;" << std::endl;
4469 result << " CV_FUSION_ADDR_DB.cube_ub_stage_size = t.cube_ub_stage_size;" << std::endl;4537 result << " CV_FUSION_ADDR_DB.cube_ub_stage_size = t.cube_ub_stage_size;" << std::endl;
4538+ result << " CV_FUSION_ADDR_DB.cube_m_stage_size = t.cube_m_stage_size;" << std::endl;
4470 result << "#endif" << std::endl;4539 result << "#endif" << std::endl;
4471 result << " }" << std::endl;4540 result << " }" << std::endl;
4472 } else {4541 } else {
@@ -1032,6 +1032,7 @@ Status Loop::Generate(const Tiler &tiler, const TPipe &tpipe, std::string &resul
1032 1032 
1033Status Loop::ActualSizeDefine(const Tiler &tiler, const TPipe &tpipe, std::string dtype_name, std::string &result) {1033Status Loop::ActualSizeDefine(const Tiler &tiler, const TPipe &tpipe, std::string dtype_name, std::string &result) {
1034 std::stringstream ss;1034 std::stringstream ss;
1035+ (void)dtype_name;
1035 if (this->axis_id == af::kIdNone) {1036 if (this->axis_id == af::kIdNone) {
1036 for (const auto &body : this->bodys) {1037 for (const auto &body : this->bodys) {
1037 if (body.type == LoopType::LOOP) {1038 if (body.type == LoopType::LOOP) {
@@ -1045,7 +1046,7 @@ Status Loop::ActualSizeDefine(const Tiler &tiler, const TPipe &tpipe, std::strin
1045 const auto &tile_inner = tiler.GetAxis(axis.split_pair_other_id);1046 const auto &tile_inner = tiler.GetAxis(axis.split_pair_other_id);
1046 af::Expression actual_size = af::Symbol(tile_inner.actual_size.name.c_str());1047 af::Expression actual_size = af::Symbol(tile_inner.actual_size.name.c_str());
1047 tpipe.tiler.actual_sizes.emplace_back(std::make_pair(tile_inner.size_expr, actual_size));1048 tpipe.tiler.actual_sizes.emplace_back(std::make_pair(tile_inner.size_expr, actual_size));
1048- ss << tile_inner.actual_size.AsArg() << " = stage_size / sizeof(" << dtype_name << ");" << std::endl;1049+ ss << tile_inner.actual_size.AsArg() << " = stage_size;" << std::endl;
1049 }1050 }
1050 result = ss.str();1051 result = ss.str();
1051 return af::SUCCESS;1052 return af::SUCCESS;
@@ -48,7 +48,7 @@ using namespace ascgen_utils;
48namespace {48namespace {
49constexpr uint64_t kMaxPgoTilingKeyCount = 10000U;49constexpr uint64_t kMaxPgoTilingKeyCount = 10000U;
50constexpr uint64_t kInt64TilingKeyCapacity = static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1U;50constexpr uint64_t kInt64TilingKeyCapacity = static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) + 1U;
51-// fp32且K轴大于该阈值且未启用hf32时, CV融合UB模板存在精度问题, 需走common兜底模板51+// fp32且K轴不小于该阈值且未启用hf32时, CV融合UB模板存在精度问题, 需走common兜底模板
52constexpr int64_t kFp32LargeKThreshold = 2048;52constexpr int64_t kFp32LargeKThreshold = 2048;
53 53 
54std::string GenUint64Literal(uint64_t value) {54std::string GenUint64Literal(uint64_t value) {
@@ -100,8 +100,14 @@ void GenInductorCvSafetyFallback(std::stringstream &ss, uint64_t count, const st
100}100}
101 101 
102// 生成cv_tiling_data字段重置代码, ub_mode区分UB模板(1)与common模板(0)102// 生成cv_tiling_data字段重置代码, ub_mode区分UB模板(1)与common模板(0)
103+// 仅在求解器成功选出STAGE_SIZE_NAME(a0a1t)后调用: 此时行数按预算覆盖为
104+// STAGE_SIZE_NAME / basen_align, kernel侧队列申请与vector计算长度均以此为准
103void GenCvTilingDataReset(std::stringstream &ss, const std::string &indent, uint32_t ub_mode) {105void GenCvTilingDataReset(std::stringstream &ss, const std::string &indent, uint32_t ub_mode) {
104 ss << indent << "tiling->stage_size_name = tiling->tiling_data.STAGE_SIZE_NAME;" << std::endl;106 ss << indent << "tiling->stage_size_name = tiling->tiling_data.STAGE_SIZE_NAME;" << std::endl;
107+ ss << indent
108+ << "tiling->cube_m_stage_size = (uint32_t)std::max(1, static_cast<int32_t>(tiling->stage_size_name / "
109+ "basen_align));"
110+ << std::endl;
105 ss << indent << "tiling->cv_tiling_data.fusion_mode = 0;" << std::endl;111 ss << indent << "tiling->cv_tiling_data.fusion_mode = 0;" << std::endl;
106 ss << indent << "tiling->cv_tiling_data.ub_mode = " << ub_mode << ";" << std::endl;112 ss << indent << "tiling->cv_tiling_data.ub_mode = " << ub_mode << ";" << std::endl;
107 ss << indent << "tiling->cv_tiling_data.mix_mode = 0;" << std::endl;113 ss << indent << "tiling->cv_tiling_data.mix_mode = 0;" << std::endl;
@@ -1138,14 +1144,14 @@ std::string TilingLib::GenFp32LargeKCondition(const MatMulCubeInfo &cube_info) c
1138 std::string k_str = std::string(k_expr.Str().get());1144 std::string k_str = std::string(k_expr.Str().get());
1139 try {1145 try {
1140 int64_t k_value = std::stoll(k_str);1146 int64_t k_value = std::stoll(k_str);
1141- return k_value > kFp32LargeKThreshold ? "true" : "false";1147+ return k_value >= kFp32LargeKThreshold ? "true" : "false";
1142 } catch (...) {1148 } catch (...) {
1143 return "false";1149 return "false";
1144 }1150 }
1145 }1151 }
1146 // K轴为动态变量: 生成运行时判断1152 // K轴为动态变量: 生成运行时判断
1147 std::string k_var = std::string(k_expr.Str().get());1153 std::string k_var = std::string(k_expr.Str().get());
1148- return "(static_cast<int64_t>(" + k_var + ") > " + std::to_string(kFp32LargeKThreshold) + ")";1154+ return "(static_cast<int64_t>(" + k_var + ") >= " + std::to_string(kFp32LargeKThreshold) + ")";
1149}1155}
1150 1156 
1151std::string TilingLib::GenCubeFusionTilingBodyInductor(const ascir::FusedScheduledResult &fused_schedule_result,1157std::string TilingLib::GenCubeFusionTilingBodyInductor(const ascir::FusedScheduledResult &fused_schedule_result,
@@ -1165,11 +1171,15 @@ std::string TilingLib::GenCubeFusionTilingBodyInductor(const ascir::FusedSchedul
1165 << std::endl;1171 << std::endl;
1166 ss << " tiling->cube_tiling_key = cube_tiling_key;" << std::endl;1172 ss << " tiling->cube_tiling_key = cube_tiling_key;" << std::endl;
1167 ss << " int64_t cube_tiling_key_ub = cube_tiling_key & ~0xF0;" << std::endl;1173 ss << " int64_t cube_tiling_key_ub = cube_tiling_key & ~0xF0;" << std::endl;
1168- ss << " const int32_t ub_align_value = 32 / " << cube_info.type_size << ";" << std::endl;1174+ // 32元素对齐: 最坏dtype(bool)的32B行对齐行宽也是basen_align, 保证按行宽申请的
1175+ // queue tensor在任何dtype下都不超过求解器按STAGE_SIZE_NAME给出的UB元素预算
1176+ ss << " const int32_t ub_align_value = 32;" << std::endl;
1169 ss << " const int32_t basen_align = (basen + ub_align_value - 1) / ub_align_value * ub_align_value;" << std::endl;1177 ss << " const int32_t basen_align = (basen + ub_align_value - 1) / ub_align_value * ub_align_value;" << std::endl;
1170 ss << " const int32_t basen_basem_align = (basem * basen_align) / 2 + basen_align;" << std::endl;1178 ss << " const int32_t basen_basem_align = (basem * basen_align) / 2 + basen_align;" << std::endl;
1171 ss << " set_g_basen_basem_align(basen_basem_align);" << std::endl;1179 ss << " set_g_basen_basem_align(basen_basem_align);" << std::endl;
1172 ss << " tiling->cube_ub_stage_size = (uint32_t)basen_basem_align;" << std::endl;1180 ss << " tiling->cube_ub_stage_size = (uint32_t)basen_basem_align;" << std::endl;
1181+ // 兜底默认值(容量行数); 求解成功后在GenCvTilingDataReset中按预算行数覆盖
1182+ ss << " tiling->cube_m_stage_size = (uint32_t)(basen_basem_align / basen_align);" << std::endl;
1173 ss << " tiling->tiling_data.set_block_dim(limit->aiv_num);" << std::endl;1183 ss << " tiling->tiling_data.set_block_dim(limit->aiv_num);" << std::endl;
1174 ss << " tiling->tiling_data.set_ub_size(limit->ub_size - 256);" << std::endl;1184 ss << " tiling->tiling_data.set_ub_size(limit->ub_size - 256);" << std::endl;
1175 1185 
@@ -1530,6 +1540,7 @@ static std::string GenLocalMemorySizeCode() {
1530 1540 
1531static void AppendCubeFusionInitCode(std::stringstream &ss, const std::string &shape_dim_param,1541static void AppendCubeFusionInitCode(std::stringstream &ss, const std::string &shape_dim_param,
1532 const MatMulCubeInfo &cube_info) {1542 const MatMulCubeInfo &cube_info) {
1543+ (void)cube_info;
1533 ss << " auto tiling_data = context->GetTilingData<CVAutofuseTilingData>();" << std::endl;1544 ss << " auto tiling_data = context->GetTilingData<CVAutofuseTilingData>();" << std::endl;
1534 ss << " int64_t ws_size = 0;" << std::endl;1545 ss << " int64_t ws_size = 0;" << std::endl;
1535 ss << " int64_t cube_tiling_key = 0;" << std::endl;1546 ss << " int64_t cube_tiling_key = 0;" << std::endl;
@@ -1542,10 +1553,11 @@ static void AppendCubeFusionInitCode(std::stringstream &ss, const std::string &s
1542 ss << " ResLimit limit;" << std::endl << " limit.aiv_num = parse->aiv_num;" << std::endl;1553 ss << " ResLimit limit;" << std::endl << " limit.aiv_num = parse->aiv_num;" << std::endl;
1543 ss << " limit.ub_size = (uint32_t)parse->ub_size;" << std::endl;1554 ss << " limit.ub_size = (uint32_t)parse->ub_size;" << std::endl;
1544 ss << " auto ret = ge::GRAPH_SUCCESS;" << std::endl;1555 ss << " auto ret = ge::GRAPH_SUCCESS;" << std::endl;
1545- ss << " const int32_t ub_align_value = 32 / " << cube_info.type_size << ";" << std::endl;1556+ ss << " const int32_t ub_align_value = 32;" << std::endl;
1546 ss << " const int32_t basen_align = (basen + ub_align_value - 1) / ub_align_value * ub_align_value;" << std::endl;1557 ss << " const int32_t basen_align = (basen + ub_align_value - 1) / ub_align_value * ub_align_value;" << std::endl;
1547 ss << " const int32_t basen_basem_align = (basem * basen_align) / 2 + basen_align;" << std::endl;1558 ss << " const int32_t basen_basem_align = (basem * basen_align) / 2 + basen_align;" << std::endl;
1548 ss << " tiling_data->cube_ub_stage_size = (uint32_t)basen_basem_align;" << std::endl;1559 ss << " tiling_data->cube_ub_stage_size = (uint32_t)basen_basem_align;" << std::endl;
1560+ ss << " tiling_data->cube_m_stage_size = (uint32_t)(basen_basem_align / basen_align);" << std::endl;
1549}1561}
1550 1562 
1551static void AppendCubeFusionUbModeCode(std::stringstream &ss) {1563static void AppendCubeFusionUbModeCode(std::stringstream &ss) {
@@ -1584,6 +1596,9 @@ static void AppendCubeFusionFallbackCode(std::stringstream &ss, const std::strin
1584 ss << "&(tiling_data->tiling_data), &workspace_size, &block_dim, &limit);" << std::endl;1596 ss << "&(tiling_data->tiling_data), &workspace_size, &block_dim, &limit);" << std::endl;
1585 ss << " if (ret == 0) {" << std::endl;1597 ss << " if (ret == 0) {" << std::endl;
1586 ss << " tiling_data->stage_size_name = tiling_data->tiling_data.STAGE_SIZE_NAME;" << std::endl;1598 ss << " tiling_data->stage_size_name = tiling_data->tiling_data.STAGE_SIZE_NAME;" << std::endl;
1599+ ss << " tiling_data->cube_m_stage_size = (uint32_t)std::max(1, static_cast<int32_t>(tiling_data->"
1600+ "stage_size_name / basen_align));"
1601+ << std::endl;
1587 ss << " context->SetBlockDim(cube_block_dim);" << std::endl;1602 ss << " context->SetBlockDim(cube_block_dim);" << std::endl;
1588 ss << " *context->GetWorkspaceSizes(1) = 16 * 1024 * 1024 + ws_size;" << std::endl;1603 ss << " *context->GetWorkspaceSizes(1) = 16 * 1024 * 1024 + ws_size;" << std::endl;
1589 ss << " tiling_data->cv_tiling_data.fusion_mode = 0;" << std::endl;1604 ss << " tiling_data->cv_tiling_data.fusion_mode = 0;" << std::endl;
@@ -1599,6 +1614,9 @@ static void AppendCubeFusionFallbackCode(std::stringstream &ss, const std::strin
1599 ss << " tiling_data->tiling_data.set_ub_size(limit.ub_size - 256);" << std::endl;1614 ss << " tiling_data->tiling_data.set_ub_size(limit.ub_size - 256);" << std::endl;
1600 ss << " if (!optiling::GetTiling(tiling_data->tiling_data, 1)) {return ge::GRAPH_FAILED;}" << std::endl;1615 ss << " if (!optiling::GetTiling(tiling_data->tiling_data, 1)) {return ge::GRAPH_FAILED;}" << std::endl;
1601 ss << " tiling_data->stage_size_name = tiling_data->tiling_data.STAGE_SIZE_NAME;" << std::endl;1616 ss << " tiling_data->stage_size_name = tiling_data->tiling_data.STAGE_SIZE_NAME;" << std::endl;
1617+ ss << " tiling_data->cube_m_stage_size = (uint32_t)std::max(1, static_cast<int32_t>(tiling_data->"
1618+ "stage_size_name / basen_align));"
1619+ << std::endl;
1602 ss << " context->SetBlockDim(cube_block_dim);" << std::endl;1620 ss << " context->SetBlockDim(cube_block_dim);" << std::endl;
1603 ss << " *context->GetWorkspaceSizes(1) = 16 * 1024 * 1024 + ws_size;" << std::endl;1621 ss << " *context->GetWorkspaceSizes(1) = 16 * 1024 * 1024 + ws_size;" << std::endl;
1604 ss << " tiling_data->cv_tiling_data.fusion_mode = 0;" << std::endl;1622 ss << " tiling_data->cv_tiling_data.fusion_mode = 0;" << std::endl;
@@ -29,6 +29,7 @@ void AppendCVAutofuseCommonTilingFields(std::stringstream &ss) {
29 ss << " };\n";29 ss << " };\n";
30 ss << " uint32_t stage_size_name;\n";30 ss << " uint32_t stage_size_name;\n";
31 ss << " uint32_t cube_ub_stage_size;\n";31 ss << " uint32_t cube_ub_stage_size;\n";
32+ ss << " uint32_t cube_m_stage_size;\n";
32}33}
33} // namespace34} // namespace
34 35 
@@ -263,6 +264,7 @@ std::string codegen::TilingData::Generate(const ascir::FusedScheduledResult &fus
263 << " static constexpr size_t kMatmulTilingBytes = CV_TILING_ALIGN_UP(sizeof(MatmulTilingT), 8);\n"264 << " static constexpr size_t kMatmulTilingBytes = CV_TILING_ALIGN_UP(sizeof(MatmulTilingT), 8);\n"
264 << " uint32_t stage_size_name;\n"265 << " uint32_t stage_size_name;\n"
265 << " uint32_t cube_ub_stage_size;\n"266 << " uint32_t cube_ub_stage_size;\n"
267+ << " uint32_t cube_m_stage_size;\n"
266 << " alignas(8) uint8_t matmul_tiling_data[kMatmulTilingBytes];\n"268 << " alignas(8) uint8_t matmul_tiling_data[kMatmulTilingBytes];\n"
267 << "};\n"269 << "};\n"
268 << "template <typename MatmulTilingT>\n"270 << "template <typename MatmulTilingT>\n"
@@ -273,6 +275,7 @@ std::string codegen::TilingData::Generate(const ascir::FusedScheduledResult &fus
273 << " CVTilingData cv_tiling_data;\n"275 << " CVTilingData cv_tiling_data;\n"
274 << " uint32_t stage_size_name;\n"276 << " uint32_t stage_size_name;\n"
275 << " uint32_t cube_ub_stage_size;\n"277 << " uint32_t cube_ub_stage_size;\n"
278+ << " uint32_t cube_m_stage_size;\n"
276 << " alignas(8) uint8_t matmul_tiling_data[kMatmulTilingBytes];\n"279 << " alignas(8) uint8_t matmul_tiling_data[kMatmulTilingBytes];\n"
277 << "};\n"280 << "};\n"
278 << "struct CVAutofuseExternTilingData {\n"281 << "struct CVAutofuseExternTilingData {\n"
@@ -284,6 +287,7 @@ std::string codegen::TilingData::Generate(const ascir::FusedScheduledResult &fus
284 287 
285 ss << " uint32_t stage_size_name;\n";288 ss << " uint32_t stage_size_name;\n";
286 ss << " uint32_t cube_ub_stage_size;\n";289 ss << " uint32_t cube_ub_stage_size;\n";
290+ ss << " uint32_t cube_m_stage_size;\n";
287 ss << " alignas(8) uint8_t matmul_tiling_data[MATMUL_TILING_DATA_STORAGE_SIZE];\n";291 ss << " alignas(8) uint8_t matmul_tiling_data[MATMUL_TILING_DATA_STORAGE_SIZE];\n";
288 292 
289 ss << "};\n"293 ss << "};\n"
@@ -707,7 +711,9 @@ std::string codegen::TilingData::GenCVConstReplace(const std::string &tiling_dat
707 ss << " k_const_tiling_data_ss << std::to_string((uint32_t)" << tiling_data_struct_name711 ss << " k_const_tiling_data_ss << std::to_string((uint32_t)" << tiling_data_struct_name
708 << ".stage_size_name) << \", \";" << std::endl;712 << ".stage_size_name) << \", \";" << std::endl;
709 ss << " k_const_tiling_data_ss << std::to_string((uint32_t)" << tiling_data_struct_name713 ss << " k_const_tiling_data_ss << std::to_string((uint32_t)" << tiling_data_struct_name
710- << ".cube_ub_stage_size) << \", {\";" << std::endl;714+ << ".cube_ub_stage_size) << \", \";" << std::endl;
715+ ss << " k_const_tiling_data_ss << std::to_string((uint32_t)" << tiling_data_struct_name
716+ << ".cube_m_stage_size) << \", {\";" << std::endl;
711 ss << " k_const_tiling_data_ss << matmul_bytes << \"}};\";" << std::endl;717 ss << " k_const_tiling_data_ss << matmul_bytes << \"}};\";" << std::endl;
712 ss << " replaceSubstring(tiling_data_const_gen_result, " << std::endl;718 ss << " replaceSubstring(tiling_data_const_gen_result, " << std::endl;
713 ss << " \"const CVAutofuseTilingData kConstTilingData = {};\", " << std::endl;719 ss << " \"const CVAutofuseTilingData kConstTilingData = {};\", " << std::endl;
@@ -1759,7 +1759,7 @@ def is_matmul_relu_fixpip(tiling_info, cube_info):
1759 1759 
1760 1760 
1761def _is_fp32_large_k(a_trans, a_shape, cube_output_type_size, enable_hf32):1761def _is_fp32_large_k(a_trans, a_shape, cube_output_type_size, enable_hf32):
1762- """fp32类型且K轴>2048且未启用hf32时, CV融合不能选择UB模板(精度问题), 需走common兜底"""1762+ """fp32类型且K轴>=2048且未启用hf32时, CV融合不能选择UB模板(精度问题), 需走common兜底"""
1763 if cube_output_type_size != 4: # 非fp321763 if cube_output_type_size != 4: # 非fp32
1764 return False1764 return False
1765 if enable_hf32: # 启用hf32时不走common兜底1765 if enable_hf32: # 启用hf32时不走common兜底
@@ -1770,7 +1770,7 @@ def _is_fp32_large_k(a_trans, a_shape, cube_output_type_size, enable_hf32):
1770 logger.info(1770 logger.info(
1771 "CV fusion op, fp32 large K check, a_trans=%s, k_value=%s", a_trans, k_value1771 "CV fusion op, fp32 large K check, a_trans=%s, k_value=%s", a_trans, k_value
1772 )1772 )
1773- return k_value > 20481773+ return k_value >= 2048
1774 1774 
1775 1775 
1776def is_fp32_large_k_matmul(tiling_info, cube_info, enable_hf32=False):1776def is_fp32_large_k_matmul(tiling_info, cube_info, enable_hf32=False):
@@ -2024,7 +2024,9 @@ GET_TILING_DATA_PTR_WITH_STRUCT({struct_name}, tmpTilingData, tmpTilingGM);
2024"""2024"""
2025 2025 
2026 # 构建class_body,使用data_prefix处理不同的数据访问路径2026 # 构建class_body,使用data_prefix处理不同的数据访问路径
2027- class_body = "const int32_t ub_align_value = 32 / cube_output_type_size;\n"2027+ # ub_align_value固定32元素: 与kernel侧de445b95的上确界行宽对齐(basen_align
2028+ # 为所有dtype的32B对齐行宽上确界), 保证host侧basen_basem_align与kernel一致
2029+ class_body = "const int32_t ub_align_value = 32;\n"
2028 class_body += (2030 class_body += (
2029 f"const int32_t basen_align = ({data_prefix}.baseN + ub_align_value - 1) "2031 f"const int32_t basen_align = ({data_prefix}.baseN + ub_align_value - 1) "
2030 f"/ ub_align_value * ub_align_value;\n"2032 f"/ ub_align_value * ub_align_value;\n"
@@ -1151,7 +1151,7 @@ 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) {1154+TEST(CodegenKernel, TPipe_TensorSizeAssignForCvUbFuseShouldUseStageSizeElements) {
1155 af::AscGraph graph("test");1155 af::AscGraph graph("test");
1156 af::ascir_op::Data x("x", graph);1156 af::ascir_op::Data x("x", graph);
1157 af::ascir_op::Data y("y", graph);1157 af::ascir_op::Data y("y", graph);
@@ -1182,8 +1182,8 @@ TEST(CodegenKernel, TPipe_TensorSizeAssignForCvUbFuseShouldUseCubeOutputElementC
1182 1182 
1183 std::string result;1183 std::string result;
1184 ASSERT_EQ(tpipe.TensorSizeAssign("float", result), af::SUCCESS);1184 ASSERT_EQ(tpipe.TensorSizeAssign("float", result), af::SUCCESS);
1185- EXPECT_EQ(result, std::string{"local_1_size = stage_size / sizeof(float);\n"1185+ EXPECT_EQ(result, std::string{"local_1_size = stage_size;\n"
1186- "local_2_size = stage_size / sizeof(float);\n"1186+ "local_2_size = stage_size;\n"
1187 "\n"});1187 "\n"});
1188}1188}
1189 1189 
@@ -2686,7 +2686,7 @@ TEST_F(TestCodegenTiling, GenFp32LargeKConditionShouldReturnRuntimeExprWhenDynam
2686 af::AscGraph graph("dynamic_k_matmul");2686 af::AscGraph graph("dynamic_k_matmul");
2687 CreateMatmulGraphForFp32LargeK(graph, 0, true, false, true, ge::DT_FLOAT);2687 CreateMatmulGraphForFp32LargeK(graph, 0, true, false, true, ge::DT_FLOAT);
2688 auto cube_info = EXTRACT_CUBE_INFO(graph);2688 auto cube_info = EXTRACT_CUBE_INFO(graph);
2689- EXPECT_EQ(this->GenFp32LargeKCondition(cube_info), "(static_cast<int64_t>(k_var) > 2048)");2689+ EXPECT_EQ(this->GenFp32LargeKCondition(cube_info), "(static_cast<int64_t>(k_var) >= 2048)");
2690}2690}
2691 2691 
2692TEST_F(TestCodegenTiling, GenFp32LargeKConditionShouldReturnTrueWhenNoTransposeStaticKGT2048) {2692TEST_F(TestCodegenTiling, GenFp32LargeKConditionShouldReturnTrueWhenNoTransposeStaticKGT2048) {
@@ -119,10 +119,13 @@ void ExpectToIntCvStageUsesDtypeAwareStrides(const std::string &api_name, const
119 119 
120 std::string result;120 std::string result;
121 EXPECT_EQ(call.Generate(tpipe, std::vector<af::AxisId>{z0.id}, result), 0);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 +122+ EXPECT_EQ(result,
123- ", {ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, "123+ "local_1_actual_size = curAivM * ((curAivN + 8 - 1) / 8 * 8);\n"
124- "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, "124+ "AscendC::Cast(local_1[0], local_0[0], " +
125- "{ConvertToUint32(((curAivN + 16 - 1) / 16 * 16)), ConvertToUint32(1)});\n");125+ round_mode +
126+ ", {ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, "
127+ "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, "
128+ "{ConvertToUint32(((curAivN + 16 - 1) / 16 * 16)), ConvertToUint32(1)});\n");
126}129}
127} // namespace130} // namespace
128 131 
@@ -408,7 +411,7 @@ TEST(CastV2ApiCallTest, CastV2ApiCallCvUbFuseUsesDtypeAlignedStrides) {
408 411 
409 std::string result;412 std::string result;
410 call.Generate(tpipe, std::vector<af::AxisId>{z0.id}, result);413 call.Generate(tpipe, std::vector<af::AxisId>{z0.id}, result);
411- EXPECT_EQ(result, std::string{"local_1_actual_size = curAivM * curAivN;\n"414+ EXPECT_EQ(result, std::string{"local_1_actual_size = curAivM * ((curAivN + 8 - 1) / 8 * 8);\n"
412 "CastExtend(local_1[0], local_0[0], {ConvertToUint32(curAivM), "415 "CastExtend(local_1[0], local_0[0], {ConvertToUint32(curAivM), "
413 "ConvertToUint32(curAivN)}, {ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), "416 "ConvertToUint32(curAivN)}, {ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), "
414 "ConvertToUint32(1)}, {ConvertToUint32(((curAivN + 16 - 1) / 16 * 16)), "417 "ConvertToUint32(1)}, {ConvertToUint32(((curAivN + 16 - 1) / 16 * 16)), "
@@ -160,7 +160,12 @@ TEST(CodegenKernel, UnaryApicallIsNanCVStage) {
160 std::string result;160 std::string result;
161 call_0.Generate(tpipe, vector<af::AxisId>{}, 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"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"});163+ "local_1_actual_size = curAivM * ((curAivN + 16 - 1) / 16 * 16);\n"
164+ "for (uint32_t cv_row = 0; cv_row < ConvertToUint32(curAivM); cv_row++) {\n"
165+ " IsNan(local_1_cast[cv_row * ConvertToUint32(((curAivN + 16 - 1) / 16 * 16))], "
166+ "local_0[cv_row * ConvertToUint32(((curAivN + 8 - 1) / 8 * 8))], "
167+ "ConvertToUint32(curAivN));\n"
168+ "}\n"});
164}169}
165 170 
166TEST(CodegenKernel, UnaryApicallIsNanCvStageUsesInputDtypeAlignedCount) {171TEST(CodegenKernel, UnaryApicallIsNanCvStageUsesInputDtypeAlignedCount) {
@@ -191,7 +196,12 @@ TEST(CodegenKernel, UnaryApicallIsNanCvStageUsesInputDtypeAlignedCount) {
191 std::string result;196 std::string result;
192 EXPECT_EQ(call.Generate(tpipe, vector<af::AxisId>{}, result), 0);197 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"198 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"});199+ "local_1_actual_size = curAivM * ((curAivN + 32 - 1) / 32 * 32);\n"
200+ "for (uint32_t cv_row = 0; cv_row < ConvertToUint32(curAivM); cv_row++) {\n"
201+ " IsNan(local_1_cast[cv_row * ConvertToUint32(((curAivN + 32 - 1) / 32 * 32))], "
202+ "local_0[cv_row * ConvertToUint32(((curAivN + 8 - 1) / 8 * 8))], "
203+ "ConvertToUint32(curAivN));\n"
204+ "}\n"});
195}205}
196 206 
197TEST(CodegenKernel, UnaryApicallIsNanThrowingFor) {207TEST(CodegenKernel, UnaryApicallIsNanThrowingFor) {
@@ -308,8 +308,13 @@ TEST(WhereRegApiCallTest, WhereRegApiCall_Scalar_x2x3_CVStage) {
308 308 
309 std::string result;309 std::string result;
310 EXPECT_EQ(call.Generate(tpipe, current_axis, result), 0);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, "311+ EXPECT_EQ(result, std::string{"local_3_actual_size = curAivM * ((curAivN + 16 - 1) / 16 * 16);\n"
312- "((local_0_actual_size + 16 - 1) / 16 * 16));\n"});312+ "Where<true, true, 2>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], "
313+ "local_blk_tensor_of_local_2[0], {static_cast<uint16_t>(curAivM), "
314+ "static_cast<uint16_t>(curAivN)}, {static_cast<uint16_t>(((curAivN + 16 - 1) / "
315+ "16 * 16)), static_cast<uint16_t>(1)}, {static_cast<uint16_t>(((curAivN + 8 - 1) "
316+ "/ 8 * 8)), static_cast<uint16_t>(1)}, {static_cast<uint16_t>(((curAivN + 8 - 1) "
317+ "/ 8 * 8)), static_cast<uint16_t>(1)});\n"});
313}318}
314 319 
315TEST(WhereRegApiCallTest, WhereRegApiCall_x2_x3_is_ub_scalar) {320TEST(WhereRegApiCallTest, WhereRegApiCall_x2_x3_is_ub_scalar) {
@@ -1145,9 +1145,9 @@ TEST(CodegenKernel, CvUbFuseTensorSizeAssignUsesTensorDtype) {
1145 1145 
1146 std::string result;1146 std::string result;
1147 ASSERT_EQ(tpipe.TensorSizeAssign("float", result), af::SUCCESS);1147 ASSERT_EQ(tpipe.TensorSizeAssign("float", result), af::SUCCESS);
1148- EXPECT_NE(result.find("local_0_size = stage_size / sizeof(float);"), std::string::npos);1148+ EXPECT_NE(result.find("local_0_size = stage_size;"), std::string::npos);
1149- EXPECT_NE(result.find("local_1_size = stage_size / sizeof(float);"), std::string::npos);1149+ EXPECT_NE(result.find("local_1_size = stage_size;"), std::string::npos);
1150- EXPECT_NE(result.find("local_2_size = stage_size / sizeof(float);"), std::string::npos);1150+ EXPECT_NE(result.find("local_2_size = stage_size;"), std::string::npos);
1151}1151}
1152 1152 
1153TEST(CodegenKernel, VfCall_TwoDimLoad_VFLoop) {1153TEST(CodegenKernel, VfCall_TwoDimLoad_VFLoop) {
@@ -105,10 +105,10 @@ Status CastV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axis
105 }105 }
106 GE_ASSERT_SUCCESS(FillCastNodeParams(this->node, output_dims, output_strides, input_strides));106 GE_ASSERT_SUCCESS(FillCastNodeParams(this->node, output_dims, output_strides, input_strides));
107 stringstream ss;107 stringstream ss;
108- if (IsCVFusionStage(this->api_call_context)) {108+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
109 const auto cv_params = BuildCvApi2DParams(tpipe, x, y);109 const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
110 const std::string input_tensor = x.is_constant ? ("local_blk_tensor_of_" + x.name) : x.Str();110 const std::string input_tensor = x.is_constant ? ("local_blk_tensor_of_" + x.name) : x.Str();
111- ss << y.actual_size << " = " << cv_params.first_dim << " * " << cv_params.last_dim << ";" << std::endl;111+ ss << y.actual_size << " = " << cv_params.output_compute_size << ";" << std::endl;
112 ss << this->api_name_ << "(" << y << "[0], " << input_tensor << "[0], " << GenCvUint32Dims(cv_params) << ", "112 ss << this->api_name_ << "(" << y << "[0], " << input_tensor << "[0], " << GenCvUint32Dims(cv_params) << ", "
113 << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride) << ");"113 << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride) << ");"
114 << std::endl;114 << std::endl;
@@ -133,8 +133,9 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A
133 std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name;133 std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name;
134 size_t outer_repeats_size = param.outer_repeats.size();134 size_t outer_repeats_size = param.outer_repeats.size();
135 if (outer_repeats_size == 0U) {135 if (outer_repeats_size == 0U) {
136- if (IsCVFusionStage(this->api_call_context)) {136+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
137 const auto cv_params = BuildCvApi2DParams(tpipe, x1, y);137 const auto cv_params = BuildCvApi2DParams(tpipe, x1, y);
138+ ss << y.actual_size << " = " << cv_params.output_compute_size << ";" << std::endl;
138 ss << "CompareScalarExtend<" << dtype_name << ", 2, CMPMODE::" << this->api_name_ << ">(" << y << "["139 ss << "CompareScalarExtend<" << dtype_name << ", 2, CMPMODE::" << this->api_name_ << ">(" << y << "["
139 << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["140 << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["
140 << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", "141 << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", "
@@ -187,8 +188,9 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A
187 FillCompareNodeParams(this->node, false, outer_call_count, output_dims, output_strides, input_strides));188 FillCompareNodeParams(this->node, false, outer_call_count, output_dims, output_strides, input_strides));
188 size_t outer_repeats_size = param.outer_repeats.size();189 size_t outer_repeats_size = param.outer_repeats.size();
189 if (outer_repeats_size == 0U) {190 if (outer_repeats_size == 0U) {
190- if (IsCVFusionStage(this->api_call_context)) {191+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
191 const auto cv_params = BuildCvApi2DParams(tpipe, x1, y);192 const auto cv_params = BuildCvApi2DParams(tpipe, x1, y);
193+ ss << y.actual_size << " = " << cv_params.output_compute_size << ";" << std::endl;
192 ss << "CompareExtend<" << dtype_name << ", 2, CMPMODE::" << this->api_name_ << ">(" << y << "["194 ss << "CompareExtend<" << dtype_name << ", 2, CMPMODE::" << this->api_name_ << ">(" << y << "["
193 << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["195 << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["
194 << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["196 << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "["
@@ -37,8 +37,9 @@ Status FloorToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::
37 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));
38 stringstream ss;38 stringstream ss;
39 39 
40- if (IsCVFusionStage(this->api_call_context)) {40+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
41 const auto cv_params = BuildCvApi2DParams(tpipe, x, y);41 const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
42+ ss << y.actual_size << " = " << cv_params.output_compute_size << ";" << std::endl;
42 ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_FLOOR, " << GenCvUint32Dims(cv_params)43 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 << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride)
44 << ");" << std::endl;45 << ");" << std::endl;
@@ -30,6 +30,9 @@ CvApi2DParams BuildCvApi2DParams(const TPipe &tpipe, const Tensor &input, const
30 const bool input_is_cube_output =30 const bool input_is_cube_output =
31 tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && input.id == tpipe.cube_output_tensor_id;31 tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && input.id == tpipe.cube_output_tensor_id;
32 params.input_stride = input_is_cube_output ? "curAlignN" : GenBlockAlignNExpr(input, params.last_dim);32 params.input_stride = input_is_cube_output ? "curAlignN" : GenBlockAlignNExpr(input, params.last_dim);
33+ params.valid_size = params.first_dim + " * " + params.last_dim;
34+ params.output_compute_size = params.first_dim + " * " + params.output_stride;
35+ params.input_compute_size = params.first_dim + " * " + params.input_stride;
33 return params;36 return params;
34}37}
35 38 
@@ -65,6 +65,9 @@ struct CvApi2DParams {
65 std::string last_dim;65 std::string last_dim;
66 std::string output_stride;66 std::string output_stride;
67 std::string input_stride;67 std::string input_stride;
68+ std::string valid_size;
69+ std::string output_compute_size;
70+ std::string input_compute_size;
68};71};
69 72 
70CvApi2DParams BuildCvApi2DParams(const TPipe &tpipe, const Tensor &input, const Tensor &output);73CvApi2DParams BuildCvApi2DParams(const TPipe &tpipe, const Tensor &input, const Tensor &output);
@@ -16,6 +16,7 @@
16#include "ascir_node_param/ascir_node_param.h"16#include "ascir_node_param/ascir_node_param.h"
17#include "api_call/utils/api_call_factory.h"17#include "api_call/utils/api_call_factory.h"
18#include "api_call/utils/api_call_utils.h"18#include "api_call/utils/api_call_utils.h"
19+#include "reg_api_call_utils.h"
19 20 
20namespace codegen {21namespace codegen {
21using namespace std;22using namespace std;
@@ -156,6 +157,31 @@ Status WhereRegApiCall::GenerateNoLoopCase(const TPipe &tpipe, const std::vector
156 const bool x2_is_scalar_scene = x2.IsAnyScalar();157 const bool x2_is_scalar_scene = x2.IsAnyScalar();
157 const bool x3_is_scalar_scene = x3.IsAnyScalar();158 const bool x3_is_scalar_scene = x3.IsAnyScalar();
158 159 
160+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
161+ // CV UBFuse: mask/src/output have different dtype-aligned row strides, must use 2D API.
162+ // For examples: (dst, mask, src0, src1, {curAivM, curAivN}, {out_stride,1}, {mask_stride,1}, {in_stride,1}).
163+ const auto cv_params = BuildCvApi2DParams(tpipe, x2, y);
164+ ss << y.actual_size << " = " << cv_params.output_compute_size << ";" << std::endl;
165+ ss << this->api_name_ << "<" << (x2_is_scalar_scene ? "true" : "false") << ", "
166+ << (x3_is_scalar_scene ? "true" : "false") << ", 2>(" << y << "["
167+ << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "["
168+ << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], ";
169+ if (x2_is_scalar_scene) {
170+ ss << (x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.Str()) << "[0], ";
171+ } else {
172+ ss << x2 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], ";
173+ }
174+ if (x3_is_scalar_scene) {
175+ ss << (x3.IsConstScalar() ? "local_blk_tensor_of_" + x3.name : x3.Str()) << "[0], ";
176+ } else {
177+ ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], ";
178+ }
179+ ss << GenCvUint16Dims(cv_params) << ", " << GenCvUint16Stride(cv_params.output_stride) << ", "
180+ << GenCvUint16Stride(GenBlockAlignNExpr(x1, cv_params.last_dim)) << ", "
181+ << GenCvUint16Stride(cv_params.input_stride) << ");" << std::endl;
182+ return af::SUCCESS;
183+ }
184+ 
159 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], ";185 ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], ";
160 ss << x1 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], ";186 ss << x1 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], ";
161 187 
@@ -40,8 +40,9 @@ Status RoundToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::
40 40 
41 stringstream ss;41 stringstream ss;
42 42 
43- if (IsCVFusionStage(this->api_call_context)) {43+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
44 const auto cv_params = BuildCvApi2DParams(tpipe, x, y);44 const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
45+ ss << y.actual_size << " = " << cv_params.output_compute_size << ";" << std::endl;
45 ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_RINT, " << GenCvUint32Dims(cv_params)46 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 << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride)
47 << ");" << std::endl;48 << ");" << std::endl;
@@ -40,8 +40,9 @@ Status TruncToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::
40 40 
41 stringstream ss;41 stringstream ss;
42 42 
43- if (IsCVFusionStage(this->api_call_context)) {43+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
44 const auto cv_params = BuildCvApi2DParams(tpipe, x, y);44 const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
45+ ss << y.actual_size << " = " << cv_params.output_compute_size << ";" << std::endl;
45 ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_TRUNC, " << GenCvUint32Dims(cv_params)46 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 << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride)
47 << ");" << std::endl;48 << ");" << std::endl;
@@ -83,6 +83,20 @@ Status UnaryBitWidthChangeApiCallV2::Generate(const TPipe &tpipe, const std::vec
83 GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed");83 GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed");
84 SaveApiLoopAxisParams(merge_info, param);84 SaveApiLoopAxisParams(merge_info, param);
85 GE_ASSERT_SUCCESS(FillUnaryBitWidthChangeNodeParams(this->node, param, merge_info));85 GE_ASSERT_SUCCESS(FillUnaryBitWidthChangeNodeParams(this->node, param, merge_info));
86+ if (IsCVFusionStage(this->api_call_context) || tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) {
87+ const auto cv_params = BuildCvApi2DParams(tpipe, x, y);
88+ ss << y.actual_size << " = " << cv_params.output_compute_size << ";" << std::endl;
89+ // 该类 API(如 IsFinite)输出与输入 dtype 的 32B 行对齐粒度不同(bool 为 32 元素, float 为
90+ // 8 元素), 1D flat 调用会在行宽非输出对齐整数倍的尾块错位。CANN 仅有 1D 形式, 按
91+ // per-dtype 物理行距逐行调用, 输出按输出 dtype 的行距落位, 与 stage 写出侧行距一致。
92+ ss << "for (uint32_t cv_row = 0; cv_row < ConvertToUint32(" << cv_params.first_dim << "); cv_row++) {" << std::endl;
93+ ss << " " << this->api_name_ << "(" << y << "_cast[cv_row * ConvertToUint32(" << cv_params.output_stride << ")], "
94+ << x << "[cv_row * ConvertToUint32(" << cv_params.input_stride << ")], ConvertToUint32(" << cv_params.last_dim
95+ << "));" << std::endl;
96+ ss << "}" << std::endl;
97+ result = ss.str();
98+ return af::SUCCESS;
99+ }
86 if (param.outer_repeats.size() == 0) {100 if (param.outer_repeats.size() == 0) {
87 ss << this->api_name_ << "(" << y << "_cast[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x101 ss << this->api_name_ << "(" << y << "_cast[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x
88 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "102 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], "