已合并
fix: 完善 Relu6D 和 SmoothL1LossGrad 的异常输入 Tiling 校验及 GE IR 验证覆盖 #8281
fix: 完善 Relu6D 和 SmoothL1LossGrad 的异常输入 Tiling 校验及 GE IR 验证覆盖 #8281
已合并
zhongheng创建于 8月5日
共 10 个文件变更+1702-102
@@ -86,6 +86,61 @@ static std::vector<float> MakeInput(int64_t n)
86 return v;86 return v;
87}87}
88 88 
89+static bool VerifyOutput(const std::vector<ge::Tensor>& output, const std::vector<int64_t>& expectedShape,
90+ ge::DataType expectedDtype, const std::vector<float>& input, const std::vector<float>& golden)
91+{
92+ if (output.size() != 1U) {
93+ std::cout << "[FAIL] Expected exactly 1 output, got " << output.size() << std::endl;
94+ return false;
95+ }
96+ 
97+ const ge::Tensor& result = output[0];
98+ const ge::TensorDesc resultDesc = result.GetTensorDesc();
99+ const auto actualShape = resultDesc.GetShape().GetDims();
100+ if (actualShape != expectedShape) {
101+ std::cout << "[FAIL] Output shape mismatch, actual=[";
102+ for (size_t i = 0; i < actualShape.size(); ++i) {
103+ std::cout << (i == 0U ? "" : ",") << actualShape[i];
104+ }
105+ std::cout << "], expected=[";
106+ for (size_t i = 0; i < expectedShape.size(); ++i) {
107+ std::cout << (i == 0U ? "" : ",") << expectedShape[i];
108+ }
109+ std::cout << "]" << std::endl;
110+ return false;
111+ }
112+ if (resultDesc.GetDataType() != expectedDtype) {
113+ std::cout << "[FAIL] Output dtype mismatch, actual=" << resultDesc.GetDataType()
114+ << ", expected=" << expectedDtype << std::endl;
115+ return false;
116+ }
117+ 
118+ const size_t expectedBytes = golden.size() * sizeof(float);
119+ if (result.GetData() == nullptr || result.GetSize() != expectedBytes) {
120+ std::cout << "[FAIL] Output buffer mismatch, data=" << static_cast<const void*>(result.GetData())
121+ << ", actual_bytes=" << result.GetSize() << ", expected_bytes=" << expectedBytes << std::endl;
122+ return false;
123+ }
124+ 
125+ const float* actual = reinterpret_cast<const float*>(result.GetData());
126+ const float rtol = 1e-4F;
127+ const float atol = 1e-4F;
128+ bool passed = true;
129+ for (size_t i = 0; i < golden.size(); ++i) {
130+ const float error = std::abs(actual[i] - golden[i]);
131+ const float tolerance = atol + rtol * std::abs(golden[i]);
132+ const bool ok = error <= tolerance;
133+ if (!ok) {
134+ passed = false;
135+ }
136+ if (i < 8U || !ok) {
137+ std::cout << " [" << i << "] x=" << input[i] << " -> y=" << actual[i] << " (expected " << golden[i]
138+ << ", err " << error << (ok ? " OK" : " FAIL") << ")" << std::endl;
139+ }
140+ }
141+ return passed;
142+}
143+ 
89int CreateRelu6DGraph(DataType inDtype, float scale, const std::vector<int64_t>& tensorShape,144int CreateRelu6DGraph(DataType inDtype, float scale, const std::vector<int64_t>& tensorShape,
90 std::vector<ge::Tensor>& input, std::vector<Operator>& inputs, std::vector<Operator>& outputs,145 std::vector<ge::Tensor>& input, std::vector<Operator>& inputs, std::vector<Operator>& outputs,
91 Graph& graph)146 Graph& graph)
@@ -130,6 +185,9 @@ int CreateRelu6DGraph(DataType inDtype, float scale, const std::vector<int64_t>&
130 185 
131int main(int argc, char* argv[])186int main(int argc, char* argv[])
132{187{
188+ (void)argc;
189+ (void)argv;
190+ 
133 const char* graph_name = "tc_ge_irrun_relu6_d";191 const char* graph_name = "tc_ge_irrun_relu6_d";
134 Graph graph(graph_name);192 Graph graph(graph_name);
135 std::vector<ge::Tensor> input;193 std::vector<ge::Tensor> input;
@@ -156,6 +214,7 @@ int main(int argc, char* argv[])
156 ret = CreateRelu6DGraph(inDtype, scale, tensorShape, input, inputs, outputs, graph);214 ret = CreateRelu6DGraph(inDtype, scale, tensorShape, input, inputs, outputs, graph);
157 if (ret != SUCCESS) {215 if (ret != SUCCESS) {
158 printf("%s - ERROR - [XIR]: Create operator in graph failed\n", GetTime().c_str());216 printf("%s - ERROR - [XIR]: Create operator in graph failed\n", GetTime().c_str());
217+ ge::GEFinalize();
159 return FAILED;218 return FAILED;
160 }219 }
161 220 
@@ -168,6 +227,7 @@ int main(int argc, char* argv[])
168 ge::Session* session = new Session(build_options);227 ge::Session* session = new Session(build_options);
169 if (session == nullptr) {228 if (session == nullptr) {
170 printf("%s - ERROR - [XIR]: Create ir session failed\n", GetTime().c_str());229 printf("%s - ERROR - [XIR]: Create ir session failed\n", GetTime().c_str());
230+ ge::GEFinalize();
171 return FAILED;231 return FAILED;
172 }232 }
173 printf("%s - INFO - [XIR]: Create ir session success\n", GetTime().c_str());233 printf("%s - INFO - [XIR]: Create ir session success\n", GetTime().c_str());
@@ -195,53 +255,31 @@ int main(int argc, char* argv[])
195 }255 }
196 printf("%s - INFO - [XIR]: Run graph success\n", GetTime().c_str());256 printf("%s - INFO - [XIR]: Run graph success\n", GetTime().c_str());
197 257 
198- // ---- 结果验证:GE IR 输出 vs CPU golden(fp32 双万分之一)258+ // ---- 结果验证:严格检查输出数量、完整 Shape、dtype 和全部数值
199- bool passed = true;259+ std::vector<float> hX = MakeInput(numElements);
200- if (output.empty()) {260+ std::vector<float> hGolden(static_cast<size_t>(numElements));
201- printf("%s - ERROR - [XIR]: No output tensor produced\n", GetTime().c_str());261+ ComputeGolden(hX.data(), hGolden.data(), numElements, scale);
202- passed = false;262+ std::cout << "=== Relu6D GE IR Test (y = min(max(x,0), 6*scale)) ===" << std::endl;
203- } else {263+ std::cout << "dtype: float32, shape: [4, 8], scale=" << scale << " (上界 " << 6.0 * scale << ")" << std::endl;
204- std::vector<float> hX = MakeInput(numElements);264+ bool passed = VerifyOutput(output, tensorShape, inDtype, hX, hGolden);
205- std::vector<float> hGolden(static_cast<size_t>(numElements));
206- ComputeGolden(hX.data(), hGolden.data(), numElements, scale);
207- 
208- const float* outData = reinterpret_cast<const float*>(output[0].GetData());
209- int64_t outNum = output[0].GetTensorDesc().GetShape().GetShapeSize();
210- std::cout << "=== Relu6D GE IR Test (y = min(max(x,0), 6*scale)) ===" << std::endl;
211- std::cout << "dtype: float32, shape: [4, 8], scale=" << scale << " (上界 " << 6.0 * scale << ")" << std::endl;
212- std::cout << "output shape size = " << outNum << std::endl;
213- 
214- const float rtol = 1e-4f;
215- const float atol = 1e-4f;
216- int64_t cmpNum = std::min<int64_t>(outNum, numElements);
217- for (int64_t i = 0; i < cmpNum; ++i) {
218- float err = std::abs(outData[i] - hGolden[i]);
219- float tol = atol + rtol * std::abs(hGolden[i]);
220- bool ok = (err <= tol);
221- if (!ok)
222- passed = false;
223- if (i < 8) { // 打印首 8 个(一个完整段模式)
224- std::cout << " [" << i << "] x=" << hX[i] << " -> y=" << outData[i] << " (expected " << hGolden[i]
225- << ", err " << err << (ok ? " OK" : " FAIL") << ")" << std::endl;
226- }
227- }
228- }
229- 
230- std::cout << std::endl;
231- if (passed) {
232- printf("%s - INFO - [XIR]: GE IR pathway verification PASSED\n", GetTime().c_str());
233- std::cout << "[PASS] GE IR results match golden reference." << std::endl;
234- } else {
235- std::cout << "[FAIL] GE IR results do not match golden reference." << std::endl;
236- }
237 265 
266+ delete session;
238 printf("%s - INFO - [XIR]: Start to finalize ge\n", GetTime().c_str());267 printf("%s - INFO - [XIR]: Start to finalize ge\n", GetTime().c_str());
239 Status finRet = ge::GEFinalize();268 Status finRet = ge::GEFinalize();
240 if (finRet != SUCCESS) {269 if (finRet != SUCCESS) {
241 printf("%s - ERROR - [XIR]: Finalize ge failed\n", GetTime().c_str());270 printf("%s - ERROR - [XIR]: Finalize ge failed\n", GetTime().c_str());
271+ passed = false;
272+ } else {
273+ printf("%s - INFO - [XIR]: Finalize ge success\n", GetTime().c_str());
274+ }
275+ std::cout << std::endl;
276+ if (passed) {
277+ std::cout << "Shape, dtype and values PASSED for [4,8]" << std::endl;
278+ std::cout << "Relu6D static GEIR verification PASSED" << std::endl;
279+ std::cout << "[PASS] GE IR results match golden reference." << std::endl;
280+ } else {
281+ std::cout << "[FAIL] Relu6D static GEIR verification failed" << std::endl;
242 }282 }
243- delete session;
244- printf("%s - INFO - [XIR]: Finalize ge success\n", GetTime().c_str());
245 283 
246 return passed ? SUCCESS : FAILED;284 return passed ? SUCCESS : FAILED;
247}285}
@@ -0,0 +1,284 @@
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+/* Generated By CANNBot */
12+ 
13+/**
14+ * @file test_geir_relu6_d_dynamic.cpp
15+ * @brief Relu6D dynamic-shape and dynamic-rank GE IR verification.
16+ *
17+ * Both scenarios reuse one GE Session. Each scenario adds one dynamic graph and
18+ * runs that graph three times with distinct concrete shapes. Every run checks
19+ * the only output's shape, dtype, and all values against the CPU formula
20+ * y = min(max(x, 0), 6 * scale).
21+ */
22+ 
23+#include <algorithm>
24+#include <cmath>
25+#include <cstdint>
26+#include <iostream>
27+#include <map>
28+#include <new>
29+#include <string>
30+#include <vector>
31+ 
32+#include "array_ops.h"
33+#include "ge_api.h"
34+#include "ge_api_types.h"
35+#include "ge_error_codes.h"
36+#include "ge_ir_build.h"
37+#include "graph.h"
38+#include "tensor.h"
39+#include "types.h"
40+ 
41+#include "../../op_graph/relu6_d_proto.h"
42+ 
43+namespace {
44+ 
45+constexpr int kSuccess = 0;
46+constexpr int kFailed = -1;
47+constexpr float kScale = 1.0F;
48+constexpr float kAtol = 1.0e-4F;
49+constexpr float kRtol = 1.0e-4F;
50+ 
51+using ShapeVector = std::vector<int64_t>;
52+using ShapeCases = std::vector<ShapeVector>;
53+ 
54+std::string ShapeToString(const ShapeVector& shape)
55+{
56+ std::string result = "[";
57+ for (size_t index = 0; index < shape.size(); ++index) {
58+ if (index != 0U) {
59+ result += ",";
60+ }
61+ result += std::to_string(shape[index]);
62+ }
63+ result += "]";
64+ return result;
65+}
66+ 
67+int64_t ElementCount(const ShapeVector& shape)
68+{
69+ int64_t count = 1;
70+ for (int64_t dim : shape) {
71+ count *= dim;
72+ }
73+ return count;
74+}
75+ 
76+std::vector<float> MakeInput(int64_t count)
77+{
78+ const std::vector<float> pattern = {-8.0F, -1.0F, 0.0F, 0.5F, 3.0F, 6.0F, 7.0F, 1000.0F};
79+ std::vector<float> input(static_cast<size_t>(count));
80+ for (int64_t index = 0; index < count; ++index) {
81+ input[static_cast<size_t>(index)] = pattern[static_cast<size_t>(index) % pattern.size()];
82+ }
83+ return input;
84+}
85+ 
86+std::vector<float> ComputeGolden(const std::vector<float>& input)
87+{
88+ const double upper = 6.0 * static_cast<double>(kScale);
89+ std::vector<float> golden(input.size());
90+ for (size_t index = 0; index < input.size(); ++index) {
91+ const double value = static_cast<double>(input[index]);
92+ golden[index] = static_cast<float>(std::min(std::max(value, 0.0), upper));
93+ }
94+ return golden;
95+}
96+ 
97+ge::TensorDesc MakeTensorDesc(const ShapeVector& shape, bool hostPlacement)
98+{
99+ ge::TensorDesc desc(ge::Shape(shape), ge::FORMAT_ND, ge::DT_FLOAT);
100+ if (hostPlacement) {
101+ desc.SetPlacement(ge::kPlacementHost);
102+ }
103+ desc.SetFormat(ge::FORMAT_ND);
104+ desc.SetRealDimCnt(shape.size());
105+ return desc;
106+}
107+ 
108+struct ReluFeeds {
109+ std::vector<float> input;
110+ std::vector<ge::Tensor> tensors;
111+};
112+ 
113+ReluFeeds MakeFeeds(const ShapeVector& shape)
114+{
115+ ReluFeeds feeds;
116+ feeds.input = MakeInput(ElementCount(shape));
117+ const ge::TensorDesc desc = MakeTensorDesc(shape, true);
118+ const uint32_t byteSize = static_cast<uint32_t>(feeds.input.size() * sizeof(float));
119+ feeds.tensors.emplace_back(desc, reinterpret_cast<uint8_t*>(feeds.input.data()), byteSize);
120+ return feeds;
121+}
122+ 
123+int BuildGraph(const std::string& scenarioName, const ShapeVector& declaredShape, ge::Graph& graph)
124+{
125+ const ge::TensorDesc inputDesc = MakeTensorDesc(declaredShape, false);
126+ 
127+ const std::string dataName = scenarioName + "_x";
128+ auto data = ge::op::Data(dataName.c_str()).set_attr_index(0);
129+ data.update_input_desc_x(inputDesc);
130+ data.update_output_desc_y(inputDesc);
131+ graph.AddOp(data);
132+ 
133+ const std::string opName = "relu6_d_" + scenarioName;
134+ auto relu6d = ge::op::Relu6D(opName.c_str());
135+ relu6d.set_input_x(data);
136+ relu6d.set_attr_scale(kScale);
137+ relu6d.update_input_desc_x(inputDesc);
138+ 
139+ const ge::TensorDesc outputDesc = MakeTensorDesc(declaredShape, false);
140+ relu6d.update_output_desc_y(outputDesc);
141+ graph.AddOp(relu6d);
142+ 
143+ std::vector<ge::Operator> inputs = {data};
144+ std::vector<ge::Operator> outputs = {relu6d};
145+ graph.SetInputs(inputs).SetOutputs(outputs);
146+ return kSuccess;
147+}
148+ 
149+bool HasExpectedShape(const ge::Shape& actual, const ShapeVector& expected)
150+{
151+ if (actual.GetDimNum() != expected.size()) {
152+ return false;
153+ }
154+ for (size_t index = 0; index < expected.size(); ++index) {
155+ if (actual.GetDim(index) != expected[index]) {
156+ return false;
157+ }
158+ }
159+ return true;
160+}
161+ 
162+bool VerifyOutput(const std::vector<ge::Tensor>& outputs, const ShapeVector& shape, const std::vector<float>& input)
163+{
164+ if (outputs.size() != 1U) {
165+ std::cerr << "Expected exactly one Relu6D output, got " << outputs.size() << std::endl;
166+ return false;
167+ }
168+ 
169+ const ge::Tensor& output = outputs[0];
170+ const ge::TensorDesc outputDesc = output.GetTensorDesc();
171+ if (!HasExpectedShape(outputDesc.GetShape(), shape)) {
172+ std::cerr << "Relu6D output shape mismatch for " << ShapeToString(shape) << std::endl;
173+ return false;
174+ }
175+ if (outputDesc.GetDataType() != ge::DT_FLOAT) {
176+ std::cerr << "Relu6D output dtype mismatch: expected DT_FLOAT, got " << outputDesc.GetDataType() << std::endl;
177+ return false;
178+ }
179+ 
180+ const std::vector<float> golden = ComputeGolden(input);
181+ const size_t expectedBytes = golden.size() * sizeof(float);
182+ const float* actual = reinterpret_cast<const float*>(output.GetData());
183+ if (actual == nullptr || output.GetSize() != expectedBytes) {
184+ std::cerr << "Relu6D output buffer mismatch: actual bytes=" << output.GetSize()
185+ << ", expected bytes=" << expectedBytes << std::endl;
186+ return false;
187+ }
188+ 
189+ for (size_t index = 0; index < golden.size(); ++index) {
190+ const float error = std::fabs(actual[index] - golden[index]);
191+ const float tolerance = kAtol + kRtol * std::fabs(golden[index]);
192+ if (!std::isfinite(actual[index]) || error > tolerance) {
193+ std::cerr << "Relu6D value mismatch at index " << index << ": actual=" << actual[index]
194+ << ", expected=" << golden[index] << ", tolerance=" << tolerance << std::endl;
195+ return false;
196+ }
197+ }
198+ return true;
199+}
200+ 
201+int RunScenario(ge::Session& session, uint32_t graphId, const std::string& scenarioName,
202+ const ShapeVector& declaredShape, const ShapeCases& concreteShapes)
203+{
204+ std::cout << "Scenario " << scenarioName << ", declared shape " << ShapeToString(declaredShape) << std::endl;
205+ 
206+ const std::string graphName = "relu6_d_" + scenarioName + "_graph";
207+ ge::Graph graph(graphName.c_str());
208+ if (BuildGraph(scenarioName, declaredShape, graph) != kSuccess) {
209+ std::cerr << "ERROR: unable to build graph for scenario " << scenarioName << std::endl;
210+ return kFailed;
211+ }
212+ 
213+ std::map<ge::AscendString, ge::AscendString> graphOptions;
214+ ge::Status status = session.AddGraph(graphId, graph, graphOptions);
215+ if (status != kSuccess) {
216+ std::cerr << "ERROR: AddGraph failed for scenario " << scenarioName << ": " << ge::GEGetErrorMsgV2().GetString()
217+ << std::endl;
218+ return kFailed;
219+ }
220+ 
221+ size_t passed = 0U;
222+ for (const ShapeVector& shape : concreteShapes) {
223+ std::cout << "Run concrete shape " << ShapeToString(shape) << std::endl;
224+ ReluFeeds feeds = MakeFeeds(shape);
225+ std::vector<ge::Tensor> outputs;
226+ status = session.RunGraph(graphId, feeds.tensors, outputs);
227+ if (status != kSuccess) {
228+ std::cerr << "ERROR: RunGraph failed for scenario " << scenarioName << ", shape " << ShapeToString(shape)
229+ << ": " << ge::GEGetErrorMsgV2().GetString() << std::endl;
230+ continue;
231+ }
232+ if (!VerifyOutput(outputs, shape, feeds.input)) {
233+ std::cerr << "ERROR: output verification failed for scenario " << scenarioName << ", shape "
234+ << ShapeToString(shape) << std::endl;
235+ continue;
236+ }
237+ 
238+ ++passed;
239+ std::cout << "Shape, dtype and values PASSED for " << ShapeToString(shape) << std::endl;
240+ }
241+ 
242+ std::cout << "Scenario " << scenarioName << " summary: " << passed << "/" << concreteShapes.size() << " passed"
243+ << std::endl;
244+ return passed == concreteShapes.size() ? kSuccess : kFailed;
245+}
246+ 
247+} // namespace
248+ 
249+int main()
250+{
251+ std::map<ge::AscendString, ge::AscendString> globalOptions = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
252+ ge::Status status = ge::GEInitialize(globalOptions);
253+ if (status != kSuccess) {
254+ std::cerr << "ERROR: GEInitialize failed: " << ge::GEGetErrorMsgV2().GetString() << std::endl;
255+ return kFailed;
256+ }
257+ 
258+ std::map<ge::AscendString, ge::AscendString> buildOptions;
259+ ge::Session* session = new (std::nothrow) ge::Session(buildOptions);
260+ if (session == nullptr) {
261+ std::cerr << "ERROR: unable to create GE Session" << std::endl;
262+ (void)ge::GEFinalize();
263+ return kFailed;
264+ }
265+ 
266+ const int dimResult = RunScenario(*session, 0U, "unknown_dim_minus_1", {-1, -1}, {{4, 2}, {1, 8}, {3, 5}});
267+ const int rankResult = RunScenario(*session, 1U, "unknown_rank_minus_2", {-2}, {{8}, {4, 2}, {2, 3, 4}});
268+ 
269+ delete session;
270+ session = nullptr;
271+ status = ge::GEFinalize();
272+ if (status != kSuccess) {
273+ std::cerr << "ERROR: GEFinalize failed" << std::endl;
274+ return kFailed;
275+ }
276+ 
277+ if (dimResult != kSuccess || rankResult != kSuccess) {
278+ std::cerr << "ERROR: Relu6D dynamic GEIR verification did not pass all scenarios" << std::endl;
279+ return kFailed;
280+ }
281+ 
282+ std::cout << "Relu6D dynamic GEIR verification PASSED (-1 and -2)" << std::endl;
283+ return kSuccess;
284+}
@@ -0,0 +1,314 @@
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+#include <algorithm>
12+#include <cmath>
13+#include <cstdint>
14+#include <cstring>
15+#include <iostream>
16+#include <map>
17+#include <string>
18+#include <vector>
19+ 
20+#include "array_ops.h"
21+#include "elewise_calculation_ops.h"
22+#include "ge_api.h"
23+#include "ge_api_types.h"
24+#include "ge_error_codes.h"
25+#include "ge_ir_build.h"
26+#include "graph.h"
27+#include "tensor.h"
28+#include "types.h"
29+ 
30+#include "../../op_graph/relu6_d_proto.h"
31+ 
32+namespace {
33+ 
34+std::string CurrentError()
35+{
36+ std::string error = ge::GEGetErrorMsgV2().GetString();
37+ std::replace(error.begin(), error.end(), '\n', ' ');
38+ std::replace(error.begin(), error.end(), '\r', ' ');
39+ return error;
40+}
41+ 
42+std::string FailureStage(const std::string& error)
43+{
44+ if (error.find("Tiling func") != std::string::npos || error.find("tiling failed") != std::string::npos) {
45+ return "tiling";
46+ }
47+ if (error.find("Unsupported_Operator") != std::string::npos ||
48+ error.find("No supported Ops kernel") != std::string::npos) {
49+ return "engine_selection";
50+ }
51+ if (error.find("para_check.py") != std::string::npos || error.find("num of dimensions") != std::string::npos) {
52+ return "parameter_check";
53+ }
54+ return "graph_compile";
55+}
56+ 
57+constexpr int SUCCESS = 0;
58+constexpr int FAILED = -1;
59+ 
60+struct CaseConfig {
61+ std::string id;
62+ std::string category;
63+ ge::DataType sourceDtype;
64+ ge::DataType opDtype;
65+ ge::Format inputFormat;
66+ ge::Format outputFormat;
67+ std::vector<int64_t> inputShape;
68+ std::vector<int64_t> outputShape;
69+ bool useCast;
70+ bool expectAccept;
71+ std::string error;
72+};
73+ 
74+int64_t ElementCount(const std::vector<int64_t>& shape)
75+{
76+ int64_t count = 1;
77+ for (const auto dim : shape) {
78+ count *= dim;
79+ }
80+ return count;
81+}
82+ 
83+ge::Tensor MakeInput(const ge::TensorDesc& desc, ge::DataType dtype, int64_t count)
84+{
85+ if (dtype == ge::DT_INT32) {
86+ std::vector<int32_t> values(static_cast<size_t>(count));
87+ const int32_t pattern[] = {-3, 0, 2, 8};
88+ for (int64_t i = 0; i < count; ++i) {
89+ values[static_cast<size_t>(i)] = pattern[i % 4];
90+ }
91+ return ge::Tensor(desc, reinterpret_cast<uint8_t*>(values.data()), values.size() * sizeof(int32_t));
92+ }
93+ if (dtype == ge::DT_INT8) {
94+ std::vector<int8_t> values(static_cast<size_t>(count), 1);
95+ return ge::Tensor(desc, reinterpret_cast<uint8_t*>(values.data()), values.size() * sizeof(int8_t));
96+ }
97+ std::vector<float> values(static_cast<size_t>(count));
98+ const float pattern[] = {-3.0F, 0.0F, 2.0F, 8.0F};
99+ for (int64_t i = 0; i < count; ++i) {
100+ values[static_cast<size_t>(i)] = pattern[i % 4];
101+ }
102+ return ge::Tensor(desc, reinterpret_cast<uint8_t*>(values.data()), values.size() * sizeof(float));
103+}
104+ 
105+bool VerifyOutput(const ge::Tensor& output, const CaseConfig& config)
106+{
107+ if (output.GetTensorDesc().GetDataType() != ge::DT_FLOAT ||
108+ output.GetTensorDesc().GetShape().GetDims() != config.outputShape) {
109+ return false;
110+ }
111+ const auto count = ElementCount(config.outputShape);
112+ const auto* actual = reinterpret_cast<const float*>(output.GetData());
113+ const float pattern[] = {-3.0F, 0.0F, 2.0F, 8.0F};
114+ for (int64_t i = 0; i < count; ++i) {
115+ const float expected = std::min(std::max(pattern[i % 4], 0.0F), 6.0F);
116+ if (std::abs(actual[i] - expected) > 1.0e-4F) {
117+ return false;
118+ }
119+ }
120+ return true;
121+}
122+ 
123+int BuildGraph(const CaseConfig& config, ge::Graph& graph, std::vector<ge::Tensor>& tensors,
124+ std::vector<ge::Operator>& inputs, std::vector<ge::Operator>& outputs)
125+{
126+ const auto count = ElementCount(config.inputShape);
127+ auto data = ge::op::Data((config.id + "_data").c_str()).set_attr_index(0);
128+ ge::TensorDesc sourceDesc(ge::Shape(config.inputShape), config.inputFormat, config.sourceDtype);
129+ sourceDesc.SetPlacement(ge::kPlacementHost);
130+ sourceDesc.SetFormat(config.inputFormat);
131+ sourceDesc.SetRealDimCnt(config.inputShape.size());
132+ data.update_input_desc_x(sourceDesc);
133+ data.update_output_desc_y(sourceDesc);
134+ tensors.push_back(MakeInput(sourceDesc, config.sourceDtype, count));
135+ graph.AddOp(data);
136+ inputs.push_back(data);
137+ 
138+ ge::Operator opInput = data;
139+ ge::TensorDesc opDesc(ge::Shape(config.inputShape), config.inputFormat, config.opDtype);
140+ opDesc.SetFormat(config.inputFormat);
141+ opDesc.SetRealDimCnt(config.inputShape.size());
142+ if (config.useCast) {
143+ auto cast = ge::op::Cast((config.id + "_cast").c_str()).set_input_x(data).set_attr_dst_type(config.opDtype);
144+ cast.update_input_desc_x(sourceDesc);
145+ cast.update_output_desc_y(opDesc);
146+ graph.AddOp(cast);
147+ opInput = cast;
148+ }
149+ 
150+ auto relu = ge::op::Relu6D((config.id + "_relu6_d").c_str());
151+ relu.set_input_x(opInput);
152+ relu.set_attr_scale(1.0F);
153+ relu.update_input_desc_x(opDesc);
154+ ge::TensorDesc outputDesc(ge::Shape(config.outputShape), config.outputFormat, config.opDtype);
155+ outputDesc.SetFormat(config.outputFormat);
156+ outputDesc.SetRealDimCnt(config.outputShape.size());
157+ relu.update_output_desc_y(outputDesc);
158+ graph.AddOp(relu);
159+ outputs.push_back(relu);
160+ return SUCCESS;
161+}
162+ 
163+bool RunCase(const CaseConfig& config)
164+{
165+ ge::Graph graph(("relu6_d_exception_" + config.id).c_str());
166+ std::vector<ge::Tensor> tensors;
167+ std::vector<ge::Operator> inputs;
168+ std::vector<ge::Operator> outputs;
169+ if (BuildGraph(config, graph, tensors, inputs, outputs) != SUCCESS) {
170+ return false;
171+ }
172+ graph.SetInputs(inputs).SetOutputs(outputs);
173+ 
174+ const std::map<ge::AscendString, ge::AscendString> sessionOptions;
175+ ge::Session session(sessionOptions);
176+ const uint32_t graphId = 0;
177+ const std::map<ge::AscendString, ge::AscendString> graphOptions;
178+ ge::Status status = session.AddGraph(graphId, graph, graphOptions);
179+ std::vector<ge::Tensor> result;
180+ if (status == ge::SUCCESS) {
181+ status = session.RunGraph(graphId, tensors, result);
182+ }
183+ 
184+ if (!config.expectAccept) {
185+ if (status == ge::SUCCESS) {
186+ std::cout << "EXCEPTION_CASE " << config.id << " FAIL expected=reject actual=accept" << std::endl;
187+ return false;
188+ }
189+ const std::string actualError = CurrentError();
190+ const std::string failureStage = FailureStage(actualError);
191+ if (failureStage != "tiling" ||
192+ (!config.error.empty() && actualError.find(config.error) == std::string::npos)) {
193+ std::cout << "EXCEPTION_CASE " << config.id
194+ << " FAIL expected=reject actual=reject failure_stage=" << failureStage
195+ << " expected_error=" << config.error << " actual_error=" << actualError << std::endl;
196+ return false;
197+ }
198+ std::cout << "EXCEPTION_CASE " << config.id << " PASS category=" << config.category
199+ << " expected=reject actual=reject failure_stage=" << failureStage
200+ << " kernel_launched=false actual_error=" << actualError;
201+ if (config.category == "rank_9_tensor") {
202+ std::cout << " rank=9";
203+ }
204+ std::cout << std::endl;
205+ return true;
206+ }
207+ 
208+ const bool verified = status == ge::SUCCESS && result.size() == 1 && VerifyOutput(result[0], config);
209+ if (!verified) {
210+ std::cout << "EXCEPTION_CASE " << config.id
211+ << " FAIL expected=accept actual=reject error=" << ge::GEGetErrorMsgV2().GetString() << std::endl;
212+ return false;
213+ }
214+ std::cout << "EXCEPTION_CASE " << config.id << " PASS category=" << config.category
215+ << " expected=accept actual=accept validation_stage=tiling kernel_launched=true output_verified=true"
216+ << " kernel_launch_observed=true";
217+ if (config.useCast) {
218+ std::cout << " source_dtype=int32 cast_dtype=float32 required_dtype=float32 observed_input_dtype=float32";
219+ }
220+ if (config.category == "rank_9_tensor") {
221+ std::cout << " rank=9";
222+ }
223+ std::cout << std::endl;
224+ return true;
225+}
226+ 
227+} // namespace
228+ 
229+int main(int argc, char* argv[])
230+{
231+ std::cout << "EXCEPTION_SUITE Relu6D Ascend950 GEIR" << std::endl;
232+ const std::map<ge::AscendString, ge::AscendString> options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
233+ if (ge::GEInitialize(options) != ge::SUCCESS) {
234+ return FAILED;
235+ }
236+ 
237+ const std::vector<CaseConfig> cases = {
238+ {"dtype_x_int8",
239+ "dtype_unsupported",
240+ ge::DT_INT8,
241+ ge::DT_INT8,
242+ ge::FORMAT_ND,
243+ ge::FORMAT_ND,
244+ {4},
245+ {4},
246+ false,
247+ false,
248+ "unsupported dtype"},
249+ {"cast_int32_to_float32",
250+ "dtype_geir_cast",
251+ ge::DT_INT32,
252+ ge::DT_FLOAT,
253+ ge::FORMAT_ND,
254+ ge::FORMAT_ND,
255+ {4},
256+ {4},
257+ true,
258+ true,
259+ ""},
260+ {"format_x_nchw",
261+ "format_unsupported",
262+ ge::DT_FLOAT,
263+ ge::DT_FLOAT,
264+ ge::FORMAT_NCHW,
265+ ge::FORMAT_ND,
266+ {1, 1, 2, 2},
267+ {1, 1, 2, 2},
268+ false,
269+ false,
270+ "input[0] format"},
271+ {"format_y_nchw",
272+ "format_unsupported",
273+ ge::DT_FLOAT,
274+ ge::DT_FLOAT,
275+ ge::FORMAT_ND,
276+ ge::FORMAT_NCHW,
277+ {1, 1, 2, 2},
278+ {1, 1, 2, 2},
279+ false,
280+ false,
281+ "output[0] format"},
282+ {"rank9_x",
283+ "rank_9_tensor",
284+ ge::DT_FLOAT,
285+ ge::DT_FLOAT,
286+ ge::FORMAT_ND,
287+ ge::FORMAT_ND,
288+ {1, 1, 1, 1, 1, 1, 1, 1, 1},
289+ {1, 1, 1, 1, 1, 1, 1, 1, 1},
290+ false,
291+ false,
292+ "input rank 9 exceeds supported range [0, 8]"},
293+ };
294+ 
295+ bool passed = true;
296+ bool matched = false;
297+ for (const auto& item : cases) {
298+ if (argc > 1 && item.id != argv[1]) {
299+ continue;
300+ }
301+ matched = true;
302+ passed = RunCase(item) && passed;
303+ }
304+ if (!matched) {
305+ std::cout << "EXCEPTION_SUITE Relu6D FAIL unknown_case=" << argv[1] << std::endl;
306+ passed = false;
307+ }
308+ const auto finalizeStatus = ge::GEFinalize();
309+ passed = finalizeStatus == ge::SUCCESS && passed;
310+ if (passed) {
311+ std::cout << "EXCEPTION_SUITE Relu6D PASSED" << std::endl;
312+ }
313+ return passed ? SUCCESS : FAILED;
314+}
@@ -54,6 +54,7 @@ constexpr int64_t ALIGN_256 = 256; // UB 对齐字节数
54constexpr int64_t BUFFER_NUM = 4; // double buffer:2×VECIN + 2×VECOUT54constexpr int64_t BUFFER_NUM = 4; // double buffer:2×VECIN + 2×VECOUT
55constexpr float RELU6_SCALE_FACTOR = 6.0f; // 上界阈值系数:upperThreshold = 6*scale55constexpr float RELU6_SCALE_FACTOR = 6.0f; // 上界阈值系数:upperThreshold = 6*scale
56constexpr float DEFAULT_SCALE = 1.0f; // scale 默认值56constexpr float DEFAULT_SCALE = 1.0f; // scale 默认值
57+constexpr size_t MAX_SUPPORTED_RANK = 8; // README 接口约束:最高支持 8 维
57 58 
58static const gert::Shape g_vec_1_shape = {1};59static const gert::Shape g_vec_1_shape = {1};
59 60 
@@ -86,6 +87,10 @@ static ge::graphStatus GetShapeAttrsInfo(gert::TilingContext* context, int64_t*
86 // 输入 x shape → 展平为 dim0(rank=0 → 1,空 Tensor → 0)87 // 输入 x shape → 展平为 dim0(rank=0 → 1,空 Tensor → 0)
87 auto inputX = context->GetInputShape(0);88 auto inputX = context->GetInputShape(0);
88 OP_CHECK_NULL_WITH_CONTEXT(context, inputX);89 OP_CHECK_NULL_WITH_CONTEXT(context, inputX);
90+ OP_CHECK_IF(inputX->GetStorageShape().GetDimNum() > MAX_SUPPORTED_RANK,
91+ OP_LOGE(context, "Relu6D: input rank %zu exceeds supported range [0, 8]; input name=x",
92+ inputX->GetStorageShape().GetDimNum()),
93+ return ge::GRAPH_FAILED);
89 auto inputShapeX = EnsureNotScalar(inputX->GetStorageShape());94 auto inputShapeX = EnsureNotScalar(inputX->GetStorageShape());
90 *dim0 = inputShapeX.GetShapeSize();95 *dim0 = inputShapeX.GetShapeSize();
91 96 
@@ -93,9 +98,25 @@ static ge::graphStatus GetShapeAttrsInfo(gert::TilingContext* context, int64_t*
93 const std::set<ge::DataType> supportedDtype = {ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT, ge::DT_INT32};98 const std::set<ge::DataType> supportedDtype = {ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT, ge::DT_INT32};
94 auto inputDesc = context->GetInputDesc(0);99 auto inputDesc = context->GetInputDesc(0);
95 OP_CHECK_NULL_WITH_CONTEXT(context, inputDesc);100 OP_CHECK_NULL_WITH_CONTEXT(context, inputDesc);
101+ const auto inputFormat = inputDesc->GetFormat().GetStorageFormat();
102+ OP_CHECK_IF(inputFormat != ge::FORMAT_ND,
103+ OP_LOGE(context, "Relu6D: input[0] format %d is unsupported; input name=x, legal format=ND",
104+ static_cast<int>(inputFormat)),
105+ return ge::GRAPH_FAILED);
106+ 
107+ auto outputDesc = context->GetOutputDesc(0);
108+ OP_CHECK_NULL_WITH_CONTEXT(context, outputDesc);
109+ const auto outputFormat = outputDesc->GetFormat().GetStorageFormat();
110+ OP_CHECK_IF(outputFormat != ge::FORMAT_ND,
111+ OP_LOGE(context, "Relu6D: output[0] format %d is unsupported; output name=y, legal format=ND",
112+ static_cast<int>(outputFormat)),
113+ return ge::GRAPH_FAILED);
114+ 
96 *dataType = inputDesc->GetDataType();115 *dataType = inputDesc->GetDataType();
97 OP_CHECK_IF(supportedDtype.count(*dataType) == 0,116 OP_CHECK_IF(supportedDtype.count(*dataType) == 0,
98- OP_LOGE(context, "Relu6D: unsupported dtype %d (supports FLOAT16/BF16/FLOAT/INT32)",117+ OP_LOGE(context,
118+ "Relu6D: unsupported dtype %d (supports FLOAT16/BF16/FLOAT/INT32); input name=x, legal "
119+ "dtypes={FLOAT16,BF16,FLOAT,INT32}",
99 static_cast<int>(*dataType)),120 static_cast<int>(*dataType)),
100 return ge::GRAPH_FAILED);121 return ge::GRAPH_FAILED);
101 122 
@@ -37,9 +37,10 @@ protected:
37};37};
38 38 
39static void Relu6DTilingTestCase(std::initializer_list<int64_t> inputShape, ge::DataType dtype, float scale,39static void Relu6DTilingTestCase(std::initializer_list<int64_t> inputShape, ge::DataType dtype, float scale,
40- ge::graphStatus expectedStatus)40+ ge::graphStatus expectedStatus, ge::Format inputFormat = ge::FORMAT_ND,
41+ ge::Format outputFormat = ge::FORMAT_ND)
41{42{
42- gert::StorageShape shape = {inputShape, inputShape};43+ gert::StorageShape inputStorageShape = {inputShape, inputShape};
43 std::map<std::string, std::string> soc_infos;44 std::map<std::string, std::string> soc_infos;
44 std::map<std::string, std::string> aicore_spec;45 std::map<std::string, std::string> aicore_spec;
45 std::map<std::string, std::string> intrinsics;46 std::map<std::string, std::string> intrinsics;
@@ -91,12 +92,12 @@ static void Relu6DTilingTestCase(std::initializer_list<int64_t> inputShape, ge::
91 .SetOpType(op_type)92 .SetOpType(op_type)
92 .NodeIoNum(1, 1)93 .NodeIoNum(1, 1)
93 .IrInstanceNum({1})94 .IrInstanceNum({1})
94- .InputShapes({&shape})95+ .InputShapes({&inputStorageShape})
95- .OutputShapes({&shape})96+ .OutputShapes({&inputStorageShape})
96 .CompileInfo(&compile_info)97 .CompileInfo(&compile_info)
97 .PlatformInfo(reinterpret_cast<char*>(&platform_info))98 .PlatformInfo(reinterpret_cast<char*>(&platform_info))
98- .NodeInputTd(0, dtype, ge::FORMAT_ND, ge::FORMAT_ND)99+ .NodeInputTd(0, dtype, inputFormat, inputFormat)
99- .NodeOutputTd(0, dtype, ge::FORMAT_ND, ge::FORMAT_ND)100+ .NodeOutputTd(0, dtype, outputFormat, outputFormat)
100 .NodeAttrs({{"scale", Ops::NN::AnyValue::CreateFrom<float>(scale)}})101 .NodeAttrs({{"scale", Ops::NN::AnyValue::CreateFrom<float>(scale)}})
101 .TilingData(param.get())102 .TilingData(param.get())
102 .Workspace(ws_size)103 .Workspace(ws_size)
@@ -181,3 +182,18 @@ TEST_F(Relu6DTilingTest, test_tiling_scale_negative_014)
181{182{
182 Relu6DTilingTestCase({4, 8}, ge::DT_INT32, -1.0f, ge::GRAPH_SUCCESS);183 Relu6DTilingTestCase({4, 8}, ge::DT_INT32, -1.0f, ge::GRAPH_SUCCESS);
183}184}
185+ 
186+TEST_F(Relu6DTilingTest, test_tiling_unsupported_format_015)
187+{
188+ Relu6DTilingTestCase({1, 2, 3, 4}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::FORMAT_NCHW);
189+}
190+ 
191+TEST_F(Relu6DTilingTest, test_tiling_rank_9_016)
192+{
193+ Relu6DTilingTestCase({1, 1, 1, 1, 1, 1, 1, 1, 2}, ge::DT_FLOAT16, 1.0f, ge::GRAPH_FAILED);
194+}
195+ 
196+TEST_F(Relu6DTilingTest, test_tiling_unsupported_output_format_017)
197+{
198+ Relu6DTilingTestCase({1, 2, 3, 4}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::FORMAT_ND, ge::FORMAT_NCHW);
199+}
@@ -91,6 +91,63 @@ static void MakeInputs(int64_t n, std::vector<float>& hPredict, std::vector<floa
91 }91 }
92}92}
93 93 
94+static bool VerifyOutput(const std::vector<ge::Tensor>& output, const std::vector<int64_t>& expectedShape,
95+ ge::DataType expectedDtype, const std::vector<float>& predict, const std::vector<float>& label,
96+ const std::vector<float>& dout, const std::vector<float>& golden)
97+{
98+ if (output.size() != 1U) {
99+ std::cout << "[FAIL] Expected exactly 1 output, got " << output.size() << std::endl;
100+ return false;
101+ }
102+ 
103+ const ge::Tensor& result = output[0];
104+ const ge::TensorDesc resultDesc = result.GetTensorDesc();
105+ const auto actualShape = resultDesc.GetShape().GetDims();
106+ if (actualShape != expectedShape) {
107+ std::cout << "[FAIL] Output shape mismatch, actual=[";
108+ for (size_t i = 0; i < actualShape.size(); ++i) {
109+ std::cout << (i == 0U ? "" : ",") << actualShape[i];
110+ }
111+ std::cout << "], expected=[";
112+ for (size_t i = 0; i < expectedShape.size(); ++i) {
113+ std::cout << (i == 0U ? "" : ",") << expectedShape[i];
114+ }
115+ std::cout << "]" << std::endl;
116+ return false;
117+ }
118+ if (resultDesc.GetDataType() != expectedDtype) {
119+ std::cout << "[FAIL] Output dtype mismatch, actual=" << resultDesc.GetDataType()
120+ << ", expected=" << expectedDtype << std::endl;
121+ return false;
122+ }
123+ 
124+ const size_t expectedBytes = golden.size() * sizeof(float);
125+ if (result.GetData() == nullptr || result.GetSize() != expectedBytes) {
126+ std::cout << "[FAIL] Output buffer mismatch, data=" << static_cast<const void*>(result.GetData())
127+ << ", actual_bytes=" << result.GetSize() << ", expected_bytes=" << expectedBytes << std::endl;
128+ return false;
129+ }
130+ 
131+ const float* actual = reinterpret_cast<const float*>(result.GetData());
132+ const float rtol = 1e-4F;
133+ const float atol = 1e-4F;
134+ bool passed = true;
135+ for (size_t i = 0; i < golden.size(); ++i) {
136+ const float error = std::abs(actual[i] - golden[i]);
137+ const float tolerance = atol + rtol * std::abs(golden[i]);
138+ const bool ok = error <= tolerance;
139+ if (!ok) {
140+ passed = false;
141+ }
142+ if (i < 8U || !ok) {
143+ std::cout << " [" << i << "] predict=" << predict[i] << " label=" << label[i] << " dout=" << dout[i]
144+ << " -> gradient=" << actual[i] << " (expected " << golden[i] << ", err " << error
145+ << (ok ? " OK" : " FAIL") << ")" << std::endl;
146+ }
147+ }
148+ return passed;
149+}
150+ 
94int CreateSmoothL1LossGradGraph(DataType inDtype, float sigma, const std::vector<int64_t>& tensorShape,151int CreateSmoothL1LossGradGraph(DataType inDtype, float sigma, const std::vector<int64_t>& tensorShape,
95 std::vector<ge::Tensor>& input, std::vector<Operator>& inputs,152 std::vector<ge::Tensor>& input, std::vector<Operator>& inputs,
96 std::vector<Operator>& outputs, Graph& graph)153 std::vector<Operator>& outputs, Graph& graph)
@@ -157,6 +214,9 @@ int CreateSmoothL1LossGradGraph(DataType inDtype, float sigma, const std::vector
157 214 
158int main(int argc, char* argv[])215int main(int argc, char* argv[])
159{216{
217+ (void)argc;
218+ (void)argv;
219+ 
160 const char* graph_name = "tc_ge_irrun_smooth_l1_loss_grad";220 const char* graph_name = "tc_ge_irrun_smooth_l1_loss_grad";
161 Graph graph(graph_name);221 Graph graph(graph_name);
162 std::vector<ge::Tensor> input;222 std::vector<ge::Tensor> input;
@@ -224,57 +284,33 @@ int main(int argc, char* argv[])
224 }284 }
225 printf("%s - INFO - [XIR]: Run graph success\n", GetTime().c_str());285 printf("%s - INFO - [XIR]: Run graph success\n", GetTime().c_str());
226 286 
227- // ---- 结果验证:GE IR 输出 vs CPU golden(fp32 双万分之一)287+ // ---- 结果验证:严格检查输出数量、完整 Shape、dtype 和全部数值
228- bool passed = true;288+ std::vector<float> hPredict, hLabel, hDout;
229- if (output.empty()) {289+ MakeInputs(numElements, hPredict, hLabel, hDout);
230- printf("%s - ERROR - [XIR]: No output tensor produced\n", GetTime().c_str());290+ std::vector<float> hGolden(static_cast<size_t>(numElements));
231- passed = false;291+ ComputeGolden(hPredict.data(), hLabel.data(), hDout.data(), hGolden.data(), numElements, sigma);
232- } else {292+ std::cout << "=== SmoothL1LossGrad GE IR Test"
233- std::vector<float> hPredict, hLabel, hDout;293+ << " (gradient = clamp((predict-label)/sigma, -1, 1) * dout) ===" << std::endl;
234- MakeInputs(numElements, hPredict, hLabel, hDout);294+ std::cout << "dtype: float32, shape: [4, 8], sigma=" << sigma << std::endl;
235- std::vector<float> hGolden(static_cast<size_t>(numElements));295+ bool passed = VerifyOutput(output, tensorShape, inDtype, hPredict, hLabel, hDout, hGolden);
236- ComputeGolden(hPredict.data(), hLabel.data(), hDout.data(), hGolden.data(), numElements, sigma);
237- 
238- const float* outData = reinterpret_cast<const float*>(output[0].GetData());
239- int64_t outNum = output[0].GetTensorDesc().GetShape().GetShapeSize();
240- std::cout << "=== SmoothL1LossGrad GE IR Test"
241- << " (gradient = clamp((predict-label)/sigma, -1, 1) * dout) ===" << std::endl;
242- std::cout << "dtype: float32, shape: [4, 8], sigma=" << sigma << std::endl;
243- std::cout << "output shape size = " << outNum << std::endl;
244- 
245- const float rtol = 1e-4f;
246- const float atol = 1e-4f;
247- int64_t cmpNum = std::min<int64_t>(outNum, numElements);
248- for (int64_t i = 0; i < cmpNum; ++i) {
249- float err = std::abs(outData[i] - hGolden[static_cast<size_t>(i)]);
250- float tol = atol + rtol * std::abs(hGolden[static_cast<size_t>(i)]);
251- bool ok = (err <= tol);
252- if (!ok)
253- passed = false;
254- if (i < 8) { // 打印首 8 个(一个完整段模式)
255- std::cout << " [" << i << "] predict=" << hPredict[static_cast<size_t>(i)]
256- << " label=" << hLabel[static_cast<size_t>(i)] << " dout=" << hDout[static_cast<size_t>(i)]
257- << " -> gradient=" << outData[i] << " (expected " << hGolden[static_cast<size_t>(i)]
258- << ", err " << err << (ok ? " OK" : " FAIL") << ")" << std::endl;
259- }
260- }
261- }
262- 
263- std::cout << std::endl;
264- if (passed) {
265- printf("%s - INFO - [XIR]: GE IR pathway verification PASSED\n", GetTime().c_str());
266- std::cout << "[PASS] GE IR results match golden reference." << std::endl;
267- } else {
268- std::cout << "[FAIL] GE IR results do not match golden reference." << std::endl;
269- }
270 296 
297+ delete session;
271 printf("%s - INFO - [XIR]: Start to finalize ge\n", GetTime().c_str());298 printf("%s - INFO - [XIR]: Start to finalize ge\n", GetTime().c_str());
272 Status finRet = ge::GEFinalize();299 Status finRet = ge::GEFinalize();
273 if (finRet != SUCCESS) {300 if (finRet != SUCCESS) {
274 printf("%s - ERROR - [XIR]: Finalize ge failed\n", GetTime().c_str());301 printf("%s - ERROR - [XIR]: Finalize ge failed\n", GetTime().c_str());
302+ passed = false;
303+ } else {
304+ printf("%s - INFO - [XIR]: Finalize ge success\n", GetTime().c_str());
305+ }
306+ std::cout << std::endl;
307+ if (passed) {
308+ std::cout << "Shape, dtype and values PASSED for [4,8]" << std::endl;
309+ std::cout << "SmoothL1LossGrad static GEIR verification PASSED" << std::endl;
310+ std::cout << "[PASS] GE IR results match golden reference." << std::endl;
311+ } else {
312+ std::cout << "[FAIL] SmoothL1LossGrad static GEIR verification failed" << std::endl;
275 }313 }
276- delete session;
277- printf("%s - INFO - [XIR]: Finalize ge success\n", GetTime().c_str());
278 314 
279 return passed ? SUCCESS : FAILED;315 return passed ? SUCCESS : FAILED;
280}316}
@@ -0,0 +1,315 @@
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+/* Generated By CANNBot */
12+ 
13+/**
14+ * @file test_geir_smooth_l1_loss_grad_dynamic.cpp
15+ * @brief SmoothL1LossGrad dynamic-shape and dynamic-rank GE IR verification.
16+ *
17+ * Both scenarios reuse one GE Session. Each scenario adds one dynamic graph and
18+ * runs that graph three times with distinct concrete shapes. Every run checks
19+ * the only output's shape, dtype, and all values against the CPU formula
20+ * gradient = clamp((predict - label) / sigma, -1, 1) * dout.
21+ */
22+ 
23+#include <algorithm>
24+#include <cmath>
25+#include <cstdint>
26+#include <iostream>
27+#include <map>
28+#include <new>
29+#include <string>
30+#include <vector>
31+ 
32+#include "array_ops.h"
33+#include "ge_api.h"
34+#include "ge_api_types.h"
35+#include "ge_error_codes.h"
36+#include "ge_ir_build.h"
37+#include "graph.h"
38+#include "tensor.h"
39+#include "types.h"
40+ 
41+#include "../../op_graph/smooth_l1_loss_grad_proto.h"
42+ 
43+namespace {
44+ 
45+constexpr int kSuccess = 0;
46+constexpr int kFailed = -1;
47+constexpr float kSigma = 1.0F;
48+constexpr float kAtol = 1.0e-4F;
49+constexpr float kRtol = 1.0e-4F;
50+ 
51+using ShapeVector = std::vector<int64_t>;
52+using ShapeCases = std::vector<ShapeVector>;
53+ 
54+std::string ShapeToString(const ShapeVector& shape)
55+{
56+ std::string result = "[";
57+ for (size_t index = 0; index < shape.size(); ++index) {
58+ if (index != 0U) {
59+ result += ",";
60+ }
61+ result += std::to_string(shape[index]);
62+ }
63+ result += "]";
64+ return result;
65+}
66+ 
67+int64_t ElementCount(const ShapeVector& shape)
68+{
69+ int64_t count = 1;
70+ for (int64_t dim : shape) {
71+ count *= dim;
72+ }
73+ return count;
74+}
75+ 
76+void MakeInputs(int64_t count, std::vector<float>& predict, std::vector<float>& label, std::vector<float>& dout)
77+{
78+ const std::vector<float> predictPattern = {3.0F, -2.0F, 0.5F, 1.0F, -0.5F, 5.0F, -5.0F, 2.0F};
79+ const std::vector<float> labelPattern = {0.0F, 0.0F, 0.0F, 0.5F, 0.5F, 0.0F, 0.0F, 2.0F};
80+ const std::vector<float> doutPattern = {1.0F, 1.0F, 1.0F, 2.0F, 2.0F, 0.5F, 0.5F, 3.0F};
81+ 
82+ predict.resize(static_cast<size_t>(count));
83+ label.resize(static_cast<size_t>(count));
84+ dout.resize(static_cast<size_t>(count));
85+ for (int64_t index = 0; index < count; ++index) {
86+ const size_t offset = static_cast<size_t>(index);
87+ predict[offset] = predictPattern[offset % predictPattern.size()];
88+ label[offset] = labelPattern[offset % labelPattern.size()];
89+ dout[offset] = doutPattern[offset % doutPattern.size()];
90+ }
91+}
92+ 
93+std::vector<float> ComputeGolden(const std::vector<float>& predict, const std::vector<float>& label,
94+ const std::vector<float>& dout)
95+{
96+ const double sigma = static_cast<double>(kSigma);
97+ std::vector<float> golden(predict.size());
98+ for (size_t index = 0; index < predict.size(); ++index) {
99+ const double diff = static_cast<double>(predict[index]) - static_cast<double>(label[index]);
100+ const double clamped = std::min(std::max(diff, -sigma), sigma);
101+ golden[index] = static_cast<float>((clamped / sigma) * static_cast<double>(dout[index]));
102+ }
103+ return golden;
104+}
105+ 
106+ge::TensorDesc MakeTensorDesc(const ShapeVector& shape, bool hostPlacement)
107+{
108+ ge::TensorDesc desc(ge::Shape(shape), ge::FORMAT_ND, ge::DT_FLOAT);
109+ if (hostPlacement) {
110+ desc.SetPlacement(ge::kPlacementHost);
111+ }
112+ desc.SetFormat(ge::FORMAT_ND);
113+ desc.SetRealDimCnt(shape.size());
114+ return desc;
115+}
116+ 
117+struct SmoothL1Feeds {
118+ std::vector<float> predict;
119+ std::vector<float> label;
120+ std::vector<float> dout;
121+ std::vector<ge::Tensor> tensors;
122+};
123+ 
124+SmoothL1Feeds MakeFeeds(const ShapeVector& shape)
125+{
126+ SmoothL1Feeds feeds;
127+ MakeInputs(ElementCount(shape), feeds.predict, feeds.label, feeds.dout);
128+ const ge::TensorDesc desc = MakeTensorDesc(shape, true);
129+ const uint32_t byteSize = static_cast<uint32_t>(feeds.predict.size() * sizeof(float));
130+ feeds.tensors.reserve(3U);
131+ feeds.tensors.emplace_back(desc, reinterpret_cast<uint8_t*>(feeds.predict.data()), byteSize);
132+ feeds.tensors.emplace_back(desc, reinterpret_cast<uint8_t*>(feeds.label.data()), byteSize);
133+ feeds.tensors.emplace_back(desc, reinterpret_cast<uint8_t*>(feeds.dout.data()), byteSize);
134+ return feeds;
135+}
136+ 
137+int BuildGraph(const std::string& scenarioName, const ShapeVector& declaredShape, ge::Graph& graph)
138+{
139+ const ge::TensorDesc inputDesc = MakeTensorDesc(declaredShape, false);
140+ 
141+ const std::string predictName = scenarioName + "_predict";
142+ auto predict = ge::op::Data(predictName.c_str()).set_attr_index(0);
143+ predict.update_input_desc_x(inputDesc);
144+ predict.update_output_desc_y(inputDesc);
145+ graph.AddOp(predict);
146+ 
147+ const std::string labelName = scenarioName + "_label";
148+ auto label = ge::op::Data(labelName.c_str()).set_attr_index(1);
149+ label.update_input_desc_x(inputDesc);
150+ label.update_output_desc_y(inputDesc);
151+ graph.AddOp(label);
152+ 
153+ const std::string doutName = scenarioName + "_dout";
154+ auto dout = ge::op::Data(doutName.c_str()).set_attr_index(2);
155+ dout.update_input_desc_x(inputDesc);
156+ dout.update_output_desc_y(inputDesc);
157+ graph.AddOp(dout);
158+ 
159+ const std::string opName = "smooth_l1_loss_grad_" + scenarioName;
160+ auto grad = ge::op::SmoothL1LossGrad(opName.c_str());
161+ grad.set_input_predict(predict);
162+ grad.set_input_label(label);
163+ grad.set_input_dout(dout);
164+ grad.set_attr_sigma(kSigma);
165+ grad.update_input_desc_predict(inputDesc);
166+ grad.update_input_desc_label(inputDesc);
167+ grad.update_input_desc_dout(inputDesc);
168+ 
169+ const ge::TensorDesc outputDesc = MakeTensorDesc(declaredShape, false);
170+ grad.update_output_desc_gradient(outputDesc);
171+ graph.AddOp(grad);
172+ 
173+ std::vector<ge::Operator> inputs = {predict, label, dout};
174+ std::vector<ge::Operator> outputs = {grad};
175+ graph.SetInputs(inputs).SetOutputs(outputs);
176+ return kSuccess;
177+}
178+ 
179+bool HasExpectedShape(const ge::Shape& actual, const ShapeVector& expected)
180+{
181+ if (actual.GetDimNum() != expected.size()) {
182+ return false;
183+ }
184+ for (size_t index = 0; index < expected.size(); ++index) {
185+ if (actual.GetDim(index) != expected[index]) {
186+ return false;
187+ }
188+ }
189+ return true;
190+}
191+ 
192+bool VerifyOutput(const std::vector<ge::Tensor>& outputs, const ShapeVector& shape, const SmoothL1Feeds& feeds)
193+{
194+ if (outputs.size() != 1U) {
195+ std::cerr << "Expected exactly one SmoothL1LossGrad output, got " << outputs.size() << std::endl;
196+ return false;
197+ }
198+ 
199+ const ge::Tensor& output = outputs[0];
200+ const ge::TensorDesc outputDesc = output.GetTensorDesc();
201+ if (!HasExpectedShape(outputDesc.GetShape(), shape)) {
202+ std::cerr << "SmoothL1LossGrad output shape mismatch for " << ShapeToString(shape) << std::endl;
203+ return false;
204+ }
205+ if (outputDesc.GetDataType() != ge::DT_FLOAT) {
206+ std::cerr << "SmoothL1LossGrad output dtype mismatch: expected DT_FLOAT, got " << outputDesc.GetDataType()
207+ << std::endl;
208+ return false;
209+ }
210+ 
211+ const std::vector<float> golden = ComputeGolden(feeds.predict, feeds.label, feeds.dout);
212+ const size_t expectedBytes = golden.size() * sizeof(float);
213+ const float* actual = reinterpret_cast<const float*>(output.GetData());
214+ if (actual == nullptr || output.GetSize() != expectedBytes) {
215+ std::cerr << "SmoothL1LossGrad output buffer mismatch: actual bytes=" << output.GetSize()
216+ << ", expected bytes=" << expectedBytes << std::endl;
217+ return false;
218+ }
219+ 
220+ for (size_t index = 0; index < golden.size(); ++index) {
221+ const float error = std::fabs(actual[index] - golden[index]);
222+ const float tolerance = kAtol + kRtol * std::fabs(golden[index]);
223+ if (!std::isfinite(actual[index]) || error > tolerance) {
224+ std::cerr << "SmoothL1LossGrad value mismatch at index " << index << ": actual=" << actual[index]
225+ << ", expected=" << golden[index] << ", tolerance=" << tolerance << std::endl;
226+ return false;
227+ }
228+ }
229+ return true;
230+}
231+ 
232+int RunScenario(ge::Session& session, uint32_t graphId, const std::string& scenarioName,
233+ const ShapeVector& declaredShape, const ShapeCases& concreteShapes)
234+{
235+ std::cout << "Scenario " << scenarioName << ", declared shape " << ShapeToString(declaredShape) << std::endl;
236+ 
237+ const std::string graphName = "smooth_l1_loss_grad_" + scenarioName + "_graph";
238+ ge::Graph graph(graphName.c_str());
239+ if (BuildGraph(scenarioName, declaredShape, graph) != kSuccess) {
240+ std::cerr << "ERROR: unable to build graph for scenario " << scenarioName << std::endl;
241+ return kFailed;
242+ }
243+ 
244+ std::map<ge::AscendString, ge::AscendString> graphOptions;
245+ ge::Status status = session.AddGraph(graphId, graph, graphOptions);
246+ if (status != kSuccess) {
247+ std::cerr << "ERROR: AddGraph failed for scenario " << scenarioName << ": " << ge::GEGetErrorMsgV2().GetString()
248+ << std::endl;
249+ return kFailed;
250+ }
251+ 
252+ size_t passed = 0U;
253+ for (const ShapeVector& shape : concreteShapes) {
254+ std::cout << "Run concrete shape " << ShapeToString(shape) << std::endl;
255+ SmoothL1Feeds feeds = MakeFeeds(shape);
256+ std::vector<ge::Tensor> outputs;
257+ status = session.RunGraph(graphId, feeds.tensors, outputs);
258+ if (status != kSuccess) {
259+ std::cerr << "ERROR: RunGraph failed for scenario " << scenarioName << ", shape " << ShapeToString(shape)
260+ << ": " << ge::GEGetErrorMsgV2().GetString() << std::endl;
261+ continue;
262+ }
263+ if (!VerifyOutput(outputs, shape, feeds)) {
264+ std::cerr << "ERROR: output verification failed for scenario " << scenarioName << ", shape "
265+ << ShapeToString(shape) << std::endl;
266+ continue;
267+ }
268+ 
269+ ++passed;
270+ std::cout << "Shape, dtype and values PASSED for " << ShapeToString(shape) << std::endl;
271+ }
272+ 
273+ std::cout << "Scenario " << scenarioName << " summary: " << passed << "/" << concreteShapes.size() << " passed"
274+ << std::endl;
275+ return passed == concreteShapes.size() ? kSuccess : kFailed;
276+}
277+ 
278+} // namespace
279+ 
280+int main()
281+{
282+ std::map<ge::AscendString, ge::AscendString> globalOptions = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
283+ ge::Status status = ge::GEInitialize(globalOptions);
284+ if (status != kSuccess) {
285+ std::cerr << "ERROR: GEInitialize failed: " << ge::GEGetErrorMsgV2().GetString() << std::endl;
286+ return kFailed;
287+ }
288+ 
289+ std::map<ge::AscendString, ge::AscendString> buildOptions;
290+ ge::Session* session = new (std::nothrow) ge::Session(buildOptions);
291+ if (session == nullptr) {
292+ std::cerr << "ERROR: unable to create GE Session" << std::endl;
293+ (void)ge::GEFinalize();
294+ return kFailed;
295+ }
296+ 
297+ const int dimResult = RunScenario(*session, 0U, "unknown_dim_minus_1", {-1, -1}, {{4, 2}, {1, 8}, {3, 5}});
298+ const int rankResult = RunScenario(*session, 1U, "unknown_rank_minus_2", {-2}, {{8}, {4, 2}, {2, 3, 4}});
299+ 
300+ delete session;
301+ session = nullptr;
302+ status = ge::GEFinalize();
303+ if (status != kSuccess) {
304+ std::cerr << "ERROR: GEFinalize failed" << std::endl;
305+ return kFailed;
306+ }
307+ 
308+ if (dimResult != kSuccess || rankResult != kSuccess) {
309+ std::cerr << "ERROR: SmoothL1LossGrad dynamic GEIR verification did not pass all scenarios" << std::endl;
310+ return kFailed;
311+ }
312+ 
313+ std::cout << "SmoothL1LossGrad dynamic GEIR verification PASSED (-1 and -2)" << std::endl;
314+ return kSuccess;
315+}
@@ -0,0 +1,338 @@
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+#include <algorithm>
12+#include <cmath>
13+#include <cstdint>
14+#include <iostream>
15+#include <map>
16+#include <string>
17+#include <vector>
18+ 
19+#include "array_ops.h"
20+#include "elewise_calculation_ops.h"
21+#include "ge_api.h"
22+#include "ge_ir_build.h"
23+#include "graph.h"
24+#include "tensor.h"
25+#include "types.h"
26+ 
27+#include "../../op_graph/smooth_l1_loss_grad_proto.h"
28+ 
29+namespace {
30+ 
31+std::string CurrentError()
32+{
33+ std::string error = ge::GEGetErrorMsgV2().GetString();
34+ std::replace(error.begin(), error.end(), '\n', ' ');
35+ std::replace(error.begin(), error.end(), '\r', ' ');
36+ return error;
37+}
38+ 
39+std::string FailureStage(const std::string& error)
40+{
41+ if (error.find("Tiling func") != std::string::npos || error.find("tiling failed") != std::string::npos) {
42+ return "tiling";
43+ }
44+ if (error.find("Unsupported_Operator") != std::string::npos ||
45+ error.find("No supported Ops kernel") != std::string::npos) {
46+ return "engine_selection";
47+ }
48+ if (error.find("para_check.py") != std::string::npos || error.find("num of dimensions") != std::string::npos) {
49+ return "parameter_check";
50+ }
51+ return "graph_compile";
52+}
53+ 
54+struct CaseConfig {
55+ std::string id;
56+ std::string category;
57+ ge::DataType predictDtype = ge::DT_FLOAT;
58+ ge::DataType labelDtype = ge::DT_FLOAT;
59+ ge::DataType doutDtype = ge::DT_FLOAT;
60+ ge::Format predictFormat = ge::FORMAT_ND;
61+ ge::Format labelFormat = ge::FORMAT_ND;
62+ ge::Format doutFormat = ge::FORMAT_ND;
63+ ge::Format outputFormat = ge::FORMAT_ND;
64+ std::vector<int64_t> predictShape = {4};
65+ std::vector<int64_t> labelShape = {4};
66+ std::vector<int64_t> doutShape = {4};
67+ std::vector<int64_t> outputShape = {4};
68+ float sigma = 1.0F;
69+ bool castPredict = false;
70+ bool expectAccept = false;
71+ std::string error;
72+};
73+ 
74+int64_t Count(const std::vector<int64_t>& shape)
75+{
76+ int64_t count = 1;
77+ for (const auto dim : shape) {
78+ count *= dim;
79+ }
80+ return count;
81+}
82+ 
83+ge::Tensor MakeTensor(const ge::TensorDesc& desc, ge::DataType dtype, int64_t count)
84+{
85+ if (dtype == ge::DT_INT32) {
86+ std::vector<int32_t> values(static_cast<size_t>(count), 1);
87+ return ge::Tensor(desc, reinterpret_cast<uint8_t*>(values.data()), values.size() * sizeof(int32_t));
88+ }
89+ if (dtype == ge::DT_INT8) {
90+ std::vector<int8_t> values(static_cast<size_t>(count), 1);
91+ return ge::Tensor(desc, reinterpret_cast<uint8_t*>(values.data()), values.size());
92+ }
93+ std::vector<float> values(static_cast<size_t>(count), 1.0F);
94+ return ge::Tensor(desc, reinterpret_cast<uint8_t*>(values.data()), values.size() * sizeof(float));
95+}
96+ 
97+ge::Operator AddData(const std::string& name, uint32_t index, const std::vector<int64_t>& shape, ge::DataType dtype,
98+ ge::Format format, ge::Graph& graph, std::vector<ge::Tensor>& tensors,
99+ std::vector<ge::Operator>& inputs)
100+{
101+ auto data = ge::op::Data(name.c_str()).set_attr_index(index);
102+ ge::TensorDesc desc(ge::Shape(shape), format, dtype);
103+ desc.SetPlacement(ge::kPlacementHost);
104+ desc.SetFormat(format);
105+ desc.SetRealDimCnt(shape.size());
106+ data.update_input_desc_x(desc);
107+ data.update_output_desc_y(desc);
108+ tensors.push_back(MakeTensor(desc, dtype, Count(shape)));
109+ graph.AddOp(data);
110+ inputs.push_back(data);
111+ return data;
112+}
113+ 
114+void BuildGraph(const CaseConfig& config, ge::Graph& graph, std::vector<ge::Tensor>& tensors,
115+ std::vector<ge::Operator>& inputs, std::vector<ge::Operator>& outputs)
116+{
117+ const auto sourceDtype = config.castPredict ? ge::DT_INT32 : config.predictDtype;
118+ auto predictData = AddData(config.id + "_predict", 0, config.predictShape, sourceDtype, config.predictFormat, graph,
119+ tensors, inputs);
120+ ge::Operator predict = predictData;
121+ ge::TensorDesc predictDesc(ge::Shape(config.predictShape), config.predictFormat, config.predictDtype);
122+ if (config.castPredict) {
123+ ge::TensorDesc sourceDesc(ge::Shape(config.predictShape), config.predictFormat, sourceDtype);
124+ auto cast = ge::op::Cast((config.id + "_cast").c_str())
125+ .set_input_x(predictData)
126+ .set_attr_dst_type(config.predictDtype);
127+ cast.update_input_desc_x(sourceDesc);
128+ cast.update_output_desc_y(predictDesc);
129+ graph.AddOp(cast);
130+ predict = cast;
131+ }
132+ auto label = AddData(config.id + "_label", 1, config.labelShape, config.labelDtype, config.labelFormat, graph,
133+ tensors, inputs);
134+ auto dout = AddData(config.id + "_dout", 2, config.doutShape, config.doutDtype, config.doutFormat, graph, tensors,
135+ inputs);
136+ ge::TensorDesc labelDesc(ge::Shape(config.labelShape), config.labelFormat, config.labelDtype);
137+ ge::TensorDesc doutDesc(ge::Shape(config.doutShape), config.doutFormat, config.doutDtype);
138+ 
139+ auto op = ge::op::SmoothL1LossGrad((config.id + "_op").c_str());
140+ op.set_input_predict(predict);
141+ op.set_input_label(label);
142+ op.set_input_dout(dout);
143+ op.set_attr_sigma(config.sigma);
144+ op.update_input_desc_predict(predictDesc);
145+ op.update_input_desc_label(labelDesc);
146+ op.update_input_desc_dout(doutDesc);
147+ ge::TensorDesc outputDesc(ge::Shape(config.outputShape), config.outputFormat, config.predictDtype);
148+ op.update_output_desc_gradient(outputDesc);
149+ graph.AddOp(op);
150+ outputs.push_back(op);
151+}
152+ 
153+bool VerifyOutput(const std::vector<ge::Tensor>& result, const CaseConfig& config)
154+{
155+ if (result.size() != 1 || result[0].GetTensorDesc().GetDataType() != ge::DT_FLOAT ||
156+ result[0].GetTensorDesc().GetShape().GetDims() != config.outputShape) {
157+ return false;
158+ }
159+ const auto count = Count(config.outputShape);
160+ const auto* gradient = reinterpret_cast<const float*>(result[0].GetData());
161+ for (int64_t i = 0; i < count; ++i) {
162+ if (gradient == nullptr || std::abs(gradient[i]) > 1.0e-6F) {
163+ return false;
164+ }
165+ }
166+ return true;
167+}
168+ 
169+bool RunCase(const CaseConfig& config)
170+{
171+ ge::Graph graph(("smooth_l1_loss_grad_exception_" + config.id).c_str());
172+ std::vector<ge::Tensor> tensors;
173+ std::vector<ge::Operator> inputs;
174+ std::vector<ge::Operator> outputs;
175+ BuildGraph(config, graph, tensors, inputs, outputs);
176+ graph.SetInputs(inputs).SetOutputs(outputs);
177+ const std::map<ge::AscendString, ge::AscendString> options;
178+ ge::Session session(options);
179+ ge::Status status = session.AddGraph(0, graph, options);
180+ std::vector<ge::Tensor> result;
181+ if (status == ge::SUCCESS) {
182+ status = session.RunGraph(0, tensors, result);
183+ }
184+ if (!config.expectAccept) {
185+ if (status == ge::SUCCESS) {
186+ std::cout << "EXCEPTION_CASE " << config.id << " FAIL expected=reject actual=accept" << std::endl;
187+ return false;
188+ }
189+ const std::string actualError = CurrentError();
190+ const std::string failureStage = FailureStage(actualError);
191+ if (failureStage != "tiling" ||
192+ (!config.error.empty() && actualError.find(config.error) == std::string::npos)) {
193+ std::cout << "EXCEPTION_CASE " << config.id
194+ << " FAIL expected=reject actual=reject failure_stage=" << failureStage
195+ << " expected_error=" << config.error << " actual_error=" << actualError << std::endl;
196+ return false;
197+ }
198+ std::cout << "EXCEPTION_CASE " << config.id << " PASS category=" << config.category
199+ << " expected=reject actual=reject failure_stage=" << failureStage
200+ << " kernel_launched=false actual_error=" << actualError;
201+ if (config.category == "rank_9_tensor") {
202+ std::cout << " rank=9";
203+ }
204+ std::cout << std::endl;
205+ return true;
206+ }
207+ if (status != ge::SUCCESS || !VerifyOutput(result, config)) {
208+ std::cout << "EXCEPTION_CASE " << config.id
209+ << " FAIL expected=accept actual=reject error=" << ge::GEGetErrorMsgV2().GetString() << std::endl;
210+ return false;
211+ }
212+ std::cout << "EXCEPTION_CASE " << config.id << " PASS category=" << config.category
213+ << " expected=accept actual=accept validation_stage=tiling kernel_launched=true output_verified=true"
214+ << " kernel_launch_observed=true";
215+ if (config.castPredict) {
216+ std::cout << " source_dtype=int32 cast_dtype=float32 required_dtype=float32 observed_input_dtype=float32";
217+ }
218+ std::cout << std::endl;
219+ return true;
220+}
221+ 
222+CaseConfig MakeCase(const std::string& id, const std::string& category, const std::string& error)
223+{
224+ CaseConfig config;
225+ config.id = id;
226+ config.category = category;
227+ config.error = error;
228+ return config;
229+}
230+ 
231+void SetAllShapes(CaseConfig& config, const std::vector<int64_t>& shape)
232+{
233+ config.predictShape = shape;
234+ config.labelShape = shape;
235+ config.doutShape = shape;
236+ config.outputShape = shape;
237+}
238+ 
239+std::vector<CaseConfig> MakeCases()
240+{
241+ std::vector<CaseConfig> cases;
242+ 
243+ auto config = MakeCase("dtype_predict_int8", "dtype_unsupported", "unsupported dtype");
244+ config.predictDtype = ge::DT_INT8;
245+ cases.push_back(config);
246+ 
247+ config = MakeCase("dtype_label_int8", "dtype_unsupported", "input[1] unsupported dtype");
248+ config.labelDtype = ge::DT_INT8;
249+ cases.push_back(config);
250+ 
251+ config = MakeCase("dtype_dout_int8", "dtype_unsupported", "input[2] unsupported dtype");
252+ config.doutDtype = ge::DT_INT8;
253+ cases.push_back(config);
254+ 
255+ config = MakeCase("dtype_predict_label_mismatch", "dtype_combination_mismatch",
256+ "dtype mismatch between predict and label");
257+ config.labelDtype = ge::DT_FLOAT16;
258+ cases.push_back(config);
259+ 
260+ config = MakeCase("dtype_predict_dout_mismatch", "dtype_combination_mismatch",
261+ "dtype mismatch between predict and dout");
262+ config.doutDtype = ge::DT_FLOAT16;
263+ cases.push_back(config);
264+ 
265+ config = MakeCase("cast_predict_int32_to_float32", "dtype_geir_cast", "");
266+ config.castPredict = true;
267+ config.expectAccept = true;
268+ cases.push_back(config);
269+ 
270+ const std::vector<int64_t> nchwShape = {1, 1, 1, 1};
271+ config = MakeCase("format_predict_nchw", "format_unsupported", "input[0] format");
272+ SetAllShapes(config, nchwShape);
273+ config.predictFormat = ge::FORMAT_NCHW;
274+ cases.push_back(config);
275+ 
276+ config = MakeCase("format_label_nchw", "format_unsupported", "input[1] format");
277+ SetAllShapes(config, nchwShape);
278+ config.labelFormat = ge::FORMAT_NCHW;
279+ cases.push_back(config);
280+ 
281+ config = MakeCase("format_dout_nchw", "format_unsupported", "input[2] format");
282+ SetAllShapes(config, nchwShape);
283+ config.doutFormat = ge::FORMAT_NCHW;
284+ cases.push_back(config);
285+ 
286+ config = MakeCase("format_gradient_nchw", "format_unsupported", "output[0] format");
287+ SetAllShapes(config, nchwShape);
288+ config.outputFormat = ge::FORMAT_NCHW;
289+ cases.push_back(config);
290+ 
291+ config = MakeCase("rank9_predict", "rank_9_tensor", "predict rank 9 exceeds supported range [0, 8]");
292+ SetAllShapes(config, {1, 1, 1, 1, 1, 1, 1, 1, 1});
293+ cases.push_back(config);
294+ 
295+ config = MakeCase("sigma_zero", "attribute_out_of_range", "sigma must be > 0");
296+ config.sigma = 0.0F;
297+ cases.push_back(config);
298+ 
299+ config = MakeCase("shape_label_mismatch", "shape_dimension_violation", "shape mismatch between predict and label");
300+ config.labelShape = {2, 2};
301+ cases.push_back(config);
302+ 
303+ config = MakeCase("shape_dout_mismatch", "shape_dimension_violation", "shape mismatch between predict and dout");
304+ config.doutShape = {2, 2};
305+ cases.push_back(config);
306+ 
307+ return cases;
308+}
309+ 
310+} // namespace
311+ 
312+int main(int argc, char* argv[])
313+{
314+ std::cout << "EXCEPTION_SUITE SmoothL1LossGrad Ascend950 GEIR" << std::endl;
315+ const std::map<ge::AscendString, ge::AscendString> options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
316+ if (ge::GEInitialize(options) != ge::SUCCESS) {
317+ return -1;
318+ }
319+ const auto cases = MakeCases();
320+ bool passed = true;
321+ bool matched = false;
322+ for (const auto& item : cases) {
323+ if (argc > 1 && item.id != argv[1]) {
324+ continue;
325+ }
326+ matched = true;
327+ passed = RunCase(item) && passed;
328+ }
329+ if (!matched) {
330+ std::cout << "EXCEPTION_SUITE SmoothL1LossGrad FAIL unknown_case=" << argv[1] << std::endl;
331+ passed = false;
332+ }
333+ passed = ge::GEFinalize() == ge::SUCCESS && passed;
334+ if (passed) {
335+ std::cout << "EXCEPTION_SUITE SmoothL1LossGrad PASSED" << std::endl;
336+ }
337+ return passed ? 0 : -1;
338+}
@@ -51,6 +51,7 @@ constexpr int64_t ELEM_ALIGN_FACTOR = 512; // 多核切分元素
51constexpr int64_t ALIGN_256 = 256; // UB 对齐字节数(亦作 extraSize 预留)51constexpr int64_t ALIGN_256 = 256; // UB 对齐字节数(亦作 extraSize 预留)
52constexpr int64_t BUFFER_NUM = 8; // double buffer:(3 VECIN + 1 VECOUT) × 252constexpr int64_t BUFFER_NUM = 8; // double buffer:(3 VECIN + 1 VECOUT) × 2
53constexpr float DEFAULT_SIGMA = 1.0f; // sigma 默认值53constexpr float DEFAULT_SIGMA = 1.0f; // sigma 默认值
54+constexpr size_t MAX_SUPPORTED_RANK = 8; // README 接口约束:支持 0-8 维
54 55 
55static const gert::Shape g_vec_1_shape = {1};56static const gert::Shape g_vec_1_shape = {1};
56 57 
@@ -83,6 +84,10 @@ static ge::graphStatus GetShapeAttrsInfo(gert::TilingContext* context, int64_t*
83 // 输入 predict shape → 展平为 totalLength(rank=0 → 1,空 Tensor → 0)84 // 输入 predict shape → 展平为 totalLength(rank=0 → 1,空 Tensor → 0)
84 auto inputPredict = context->GetInputShape(0);85 auto inputPredict = context->GetInputShape(0);
85 OP_CHECK_NULL_WITH_CONTEXT(context, inputPredict);86 OP_CHECK_NULL_WITH_CONTEXT(context, inputPredict);
87+ OP_CHECK_IF(inputPredict->GetStorageShape().GetDimNum() > MAX_SUPPORTED_RANK,
88+ OP_LOGE(context, "SmoothL1LossGrad: predict rank %zu exceeds supported range [0, 8]",
89+ inputPredict->GetStorageShape().GetDimNum()),
90+ return ge::GRAPH_FAILED);
86 auto predictShape = EnsureNotScalar(inputPredict->GetStorageShape());91 auto predictShape = EnsureNotScalar(inputPredict->GetStorageShape());
87 *totalLength = predictShape.GetShapeSize();92 *totalLength = predictShape.GetShapeSize();
88 93 
@@ -90,9 +95,17 @@ static ge::graphStatus GetShapeAttrsInfo(gert::TilingContext* context, int64_t*
90 const std::set<ge::DataType> supportedDtype = {ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT};95 const std::set<ge::DataType> supportedDtype = {ge::DT_FLOAT16, ge::DT_BF16, ge::DT_FLOAT};
91 auto inputDesc = context->GetInputDesc(0);96 auto inputDesc = context->GetInputDesc(0);
92 OP_CHECK_NULL_WITH_CONTEXT(context, inputDesc);97 OP_CHECK_NULL_WITH_CONTEXT(context, inputDesc);
98+ const auto predictFormat = inputDesc->GetFormat().GetStorageFormat();
99+ OP_CHECK_IF(
100+ predictFormat != ge::FORMAT_ND,
101+ OP_LOGE(context, "SmoothL1LossGrad: input[0] format %d is unsupported; input name=predict, legal format=ND",
102+ static_cast<int>(predictFormat)),
103+ return ge::GRAPH_FAILED);
93 *dataType = inputDesc->GetDataType();104 *dataType = inputDesc->GetDataType();
94 OP_CHECK_IF(supportedDtype.count(*dataType) == 0,105 OP_CHECK_IF(supportedDtype.count(*dataType) == 0,
95- OP_LOGE(context, "SmoothL1LossGrad: unsupported dtype %d (supports FLOAT16/BF16/FLOAT)",106+ OP_LOGE(context,
107+ "SmoothL1LossGrad: unsupported dtype %d (supports FLOAT16/BF16/FLOAT); input name=predict, "
108+ "legal dtypes={FLOAT16,BF16,FLOAT}",
96 static_cast<int>(*dataType)),109 static_cast<int>(*dataType)),
97 return ge::GRAPH_FAILED);110 return ge::GRAPH_FAILED);
98 111 
@@ -101,25 +114,76 @@ static ge::graphStatus GetShapeAttrsInfo(gert::TilingContext* context, int64_t*
101 auto inputLabel = context->GetInputShape(1);114 auto inputLabel = context->GetInputShape(1);
102 OP_CHECK_NULL_WITH_CONTEXT(context, inputLabel);115 OP_CHECK_NULL_WITH_CONTEXT(context, inputLabel);
103 OP_CHECK_IF(inputLabel->GetStorageShape() != inputPredict->GetStorageShape(),116 OP_CHECK_IF(inputLabel->GetStorageShape() != inputPredict->GetStorageShape(),
104- OP_LOGE(context, "SmoothL1LossGrad: shape mismatch between predict and label"),117+ OP_LOGE(context,
118+ "SmoothL1LossGrad: shape mismatch between predict and label; actual predict shape=%s, "
119+ "actual label shape=%s, legal relation=label shape must equal predict shape",
120+ Ops::Base::ToString(inputPredict->GetStorageShape()).c_str(),
121+ Ops::Base::ToString(inputLabel->GetStorageShape()).c_str()),
105 return ge::GRAPH_FAILED);122 return ge::GRAPH_FAILED);
106 123 
107 auto inputDout = context->GetInputShape(2);124 auto inputDout = context->GetInputShape(2);
108 OP_CHECK_NULL_WITH_CONTEXT(context, inputDout);125 OP_CHECK_NULL_WITH_CONTEXT(context, inputDout);
109 OP_CHECK_IF(inputDout->GetStorageShape() != inputPredict->GetStorageShape(),126 OP_CHECK_IF(inputDout->GetStorageShape() != inputPredict->GetStorageShape(),
110- OP_LOGE(context, "SmoothL1LossGrad: shape mismatch between predict and dout"), return ge::GRAPH_FAILED);127+ OP_LOGE(context,
128+ "SmoothL1LossGrad: shape mismatch between predict and dout; actual predict shape=%s, actual "
129+ "dout shape=%s, legal relation=dout shape must equal predict shape",
130+ Ops::Base::ToString(inputPredict->GetStorageShape()).c_str(),
131+ Ops::Base::ToString(inputDout->GetStorageShape()).c_str()),
132+ return ge::GRAPH_FAILED);
111 133 
112 // dtype 一致性校验134 // dtype 一致性校验
113 auto labelDesc = context->GetInputDesc(1);135 auto labelDesc = context->GetInputDesc(1);
114 OP_CHECK_NULL_WITH_CONTEXT(context, labelDesc);136 OP_CHECK_NULL_WITH_CONTEXT(context, labelDesc);
115- OP_CHECK_IF(labelDesc->GetDataType() != *dataType,137+ const auto labelFormat = labelDesc->GetFormat().GetStorageFormat();
116- OP_LOGE(context, "SmoothL1LossGrad: dtype mismatch between predict and label"),138+ OP_CHECK_IF(
139+ labelFormat != ge::FORMAT_ND,
140+ OP_LOGE(context, "SmoothL1LossGrad: input[1] format %d is unsupported; input name=label, legal format=ND",
141+ static_cast<int>(labelFormat)),
142+ return ge::GRAPH_FAILED);
143+ const auto labelDtype = labelDesc->GetDataType();
144+ OP_CHECK_IF(supportedDtype.count(labelDtype) == 0,
145+ OP_LOGE(context,
146+ "SmoothL1LossGrad: input[1] unsupported dtype %d (supports FLOAT16/BF16/FLOAT); input "
147+ "name=label, legal dtypes={FLOAT16,BF16,FLOAT}",
148+ static_cast<int>(labelDtype)),
149+ return ge::GRAPH_FAILED);
150+ OP_CHECK_IF(labelDtype != *dataType,
151+ OP_LOGE(context,
152+ "SmoothL1LossGrad: dtype mismatch between predict and label; actual predict dtype=%d, actual "
153+ "label dtype=%d, legal relation=label dtype must equal predict dtype",
154+ static_cast<int>(*dataType), static_cast<int>(labelDtype)),
117 return ge::GRAPH_FAILED);155 return ge::GRAPH_FAILED);
118 156 
119 auto doutDesc = context->GetInputDesc(2);157 auto doutDesc = context->GetInputDesc(2);
120 OP_CHECK_NULL_WITH_CONTEXT(context, doutDesc);158 OP_CHECK_NULL_WITH_CONTEXT(context, doutDesc);
121- OP_CHECK_IF(doutDesc->GetDataType() != *dataType,159+ const auto doutFormat = doutDesc->GetFormat().GetStorageFormat();
122- OP_LOGE(context, "SmoothL1LossGrad: dtype mismatch between predict and dout"), return ge::GRAPH_FAILED);160+ OP_CHECK_IF(
161+ doutFormat != ge::FORMAT_ND,
162+ OP_LOGE(context, "SmoothL1LossGrad: input[2] format %d is unsupported; input name=dout, legal format=ND",
163+ static_cast<int>(doutFormat)),
164+ return ge::GRAPH_FAILED);
165+ const auto doutDtype = doutDesc->GetDataType();
166+ OP_CHECK_IF(supportedDtype.count(doutDtype) == 0,
167+ OP_LOGE(context,
168+ "SmoothL1LossGrad: input[2] unsupported dtype %d (supports FLOAT16/BF16/FLOAT); input "
169+ "name=dout, legal dtypes={FLOAT16,BF16,FLOAT}",
170+ static_cast<int>(doutDtype)),
171+ return ge::GRAPH_FAILED);
172+ OP_CHECK_IF(doutDtype != *dataType,
173+ OP_LOGE(context,
174+ "SmoothL1LossGrad: dtype mismatch between predict and dout; actual predict dtype=%d, actual "
175+ "dout dtype=%d, legal relation=dout dtype must equal predict dtype",
176+ static_cast<int>(*dataType), static_cast<int>(doutDtype)),
177+ return ge::GRAPH_FAILED);
178+ 
179+ auto outputDesc = context->GetOutputDesc(0);
180+ OP_CHECK_NULL_WITH_CONTEXT(context, outputDesc);
181+ const auto outputFormat = outputDesc->GetFormat().GetStorageFormat();
182+ OP_CHECK_IF(
183+ outputFormat != ge::FORMAT_ND,
184+ OP_LOGE(context, "SmoothL1LossGrad: output[0] format %d is unsupported; output name=gradient, legal format=ND",
185+ static_cast<int>(outputFormat)),
186+ return ge::GRAPH_FAILED);
123 187 
124 // 属性 sigma(Float,index 0,默认 1.0)188 // 属性 sigma(Float,index 0,默认 1.0)
125 const auto* attrs = context->GetAttrs();189 const auto* attrs = context->GetAttrs();
@@ -131,8 +195,11 @@ static ge::graphStatus GetShapeAttrsInfo(gert::TilingContext* context, int64_t*
131 }195 }
132 196 
133 // sigma > 0 校验197 // sigma > 0 校验
134- OP_CHECK_IF(*sigma <= 0.0f, OP_LOGE(context, "SmoothL1LossGrad: sigma must be > 0, got %f", *sigma),198+ OP_CHECK_IF(
135- return ge::GRAPH_FAILED);199+ *sigma <= 0.0f,
200+ OP_LOGE(context, "SmoothL1LossGrad: sigma must be > 0, got %f; attribute name=sigma, legal range=(0, +inf)",
201+ *sigma),
202+ return ge::GRAPH_FAILED);
136 203 
137 return ge::GRAPH_SUCCESS;204 return ge::GRAPH_SUCCESS;
138}205}
@@ -0,0 +1,171 @@
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+#include <iostream>
12+#include <vector>
13+ 
14+#include <gtest/gtest.h>
15+#include "exe_graph/runtime/storage_format.h"
16+#include "exe_graph/runtime/storage_shape.h"
17+#include "kernel_run_context_facker.h"
18+#include "platform/platform_infos_def.h"
19+#include "test_cube_util.h"
20+#include "ut_op_util.h"
21+ 
22+using namespace ge;
23+using namespace ut_util;
24+ 
25+namespace optiling {
26+struct SmoothL1LossGradCompileInfo {};
27+} // namespace optiling
28+ 
29+class SmoothL1LossGradTilingTest : public testing::Test {
30+protected:
31+ static void SetUpTestCase() { std::cout << "SmoothL1LossGradTilingTest SetUp" << std::endl; }
32+ static void TearDownTestCase() { std::cout << "SmoothL1LossGradTilingTest TearDown" << std::endl; }
33+};
34+ 
35+static void DoTilingTest(std::initializer_list<int64_t> predictDims, std::initializer_list<int64_t> labelDims,
36+ std::initializer_list<int64_t> doutDims, ge::DataType predictDtype, float sigma,
37+ ge::graphStatus expectedStatus, ge::DataType labelDtype = ge::DT_UNDEFINED,
38+ ge::DataType doutDtype = ge::DT_UNDEFINED, ge::Format predictFormat = ge::FORMAT_ND,
39+ ge::Format labelFormat = ge::FORMAT_ND, ge::Format doutFormat = ge::FORMAT_ND,
40+ ge::Format outputFormat = ge::FORMAT_ND)
41+{
42+ std::string opType("SmoothL1LossGrad");
43+ ASSERT_NE(gert::OpImplRegistry::GetInstance().GetOpImpl(opType.c_str()), nullptr);
44+ auto tilingFunc = gert::OpImplRegistry::GetInstance().GetOpImpl(opType.c_str())->tiling;
45+ 
46+ std::string compileInfoStr = R"({
47+ "hardware_info": {"BT_SIZE": 0, "load3d_constraints": "1",
48+ "Intrinsic_fix_pipe_l0c2out": false, "Intrinsic_data_move_l12ub": true,
49+ "Intrinsic_data_move_l0c2ub": true, "Intrinsic_data_move_out2l1_nd2nz": false,
50+ "UB_SIZE": 245760, "L2_SIZE": 33554432, "L1_SIZE": 524288,
51+ "L0A_SIZE": 65536, "L0B_SIZE": 65536, "L0C_SIZE": 131072, "CORE_NUM": 64}
52+ })";
53+ std::map<std::string, std::string> socInfos, aicoreSpec, intrinsics;
54+ GetPlatFormInfos(compileInfoStr.c_str(), socInfos, aicoreSpec, intrinsics);
55+ 
56+ fe::PlatFormInfos platformInfo;
57+ platformInfo.Init();
58+ optiling::SmoothL1LossGradCompileInfo compileInfo;
59+ auto param = gert::TilingData::CreateCap(8192);
60+ ASSERT_NE(param, nullptr);
61+ auto wsHolder = gert::ContinuousVector::Create<size_t>(32);
62+ auto wsSize = reinterpret_cast<gert::ContinuousVector*>(wsHolder.get());
63+ 
64+ gert::StorageShape predictShape = {predictDims, predictDims};
65+ gert::StorageShape labelShape = {labelDims, labelDims};
66+ gert::StorageShape doutShape = {doutDims, doutDims};
67+ ge::DataType effectiveLabelDtype = labelDtype == ge::DT_UNDEFINED ? predictDtype : labelDtype;
68+ ge::DataType effectiveDoutDtype = doutDtype == ge::DT_UNDEFINED ? predictDtype : doutDtype;
69+ 
70+ auto holder = gert::TilingContextFaker()
71+ .SetOpType(opType)
72+ .NodeIoNum(3, 1)
73+ .IrInstanceNum({1, 1, 1})
74+ .InputShapes({&predictShape, &labelShape, &doutShape})
75+ .OutputShapes({&predictShape})
76+ .CompileInfo(&compileInfo)
77+ .PlatformInfo(reinterpret_cast<char*>(&platformInfo))
78+ .NodeInputTd(0, predictDtype, predictFormat, predictFormat)
79+ .NodeInputTd(1, effectiveLabelDtype, labelFormat, labelFormat)
80+ .NodeInputTd(2, effectiveDoutDtype, doutFormat, doutFormat)
81+ .NodeOutputTd(0, predictDtype, outputFormat, outputFormat)
82+ .NodeAttrs({{"sigma", Ops::NN::AnyValue::CreateFrom<float>(sigma)}})
83+ .TilingData(param.get())
84+ .Workspace(wsSize)
85+ .Build();
86+ 
87+ gert::TilingContext* ctx = holder.GetContext<gert::TilingContext>();
88+ ASSERT_NE(ctx, nullptr);
89+ ASSERT_NE(ctx->GetPlatformInfo(), nullptr);
90+ ctx->GetPlatformInfo()->SetPlatformRes("SoCInfo", socInfos);
91+ ctx->GetPlatformInfo()->SetPlatformRes("AICoreSpec", aicoreSpec);
92+ ctx->GetPlatformInfo()->SetCoreNumByCoreType("AICore");
93+ ctx->GetPlatformInfo()->SetPlatformRes("AICoreintrinsicDtypeMap", intrinsics);
94+ 
95+ EXPECT_EQ(tilingFunc(ctx), expectedStatus);
96+}
97+ 
98+TEST_F(SmoothL1LossGradTilingTest, tiling_fp32_accepted)
99+{
100+ DoTilingTest({4, 8}, {4, 8}, {4, 8}, ge::DT_FLOAT, 1.0f, ge::GRAPH_SUCCESS);
101+}
102+ 
103+TEST_F(SmoothL1LossGradTilingTest, tiling_unsupported_dtype_rejected)
104+{
105+ DoTilingTest({4, 8}, {4, 8}, {4, 8}, ge::DT_INT8, 1.0f, ge::GRAPH_FAILED);
106+}
107+ 
108+TEST_F(SmoothL1LossGradTilingTest, tiling_dtype_mismatch_rejected)
109+{
110+ DoTilingTest({4, 8}, {4, 8}, {4, 8}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::DT_FLOAT16);
111+}
112+ 
113+TEST_F(SmoothL1LossGradTilingTest, tiling_exact_shape_mismatch_rejected)
114+{
115+ DoTilingTest({2, 6}, {3, 4}, {2, 6}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED);
116+}
117+ 
118+TEST_F(SmoothL1LossGradTilingTest, tiling_sigma_zero_rejected)
119+{
120+ DoTilingTest({4, 8}, {4, 8}, {4, 8}, ge::DT_FLOAT, 0.0f, ge::GRAPH_FAILED);
121+}
122+ 
123+TEST_F(SmoothL1LossGradTilingTest, tiling_unsupported_format_rejected)
124+{
125+ DoTilingTest({1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::DT_UNDEFINED,
126+ ge::DT_UNDEFINED, ge::FORMAT_NCHW);
127+}
128+ 
129+TEST_F(SmoothL1LossGradTilingTest, tiling_rank_9_rejected)
130+{
131+ DoTilingTest({1, 1, 1, 1, 1, 1, 1, 1, 2}, {1, 1, 1, 1, 1, 1, 1, 1, 2}, {1, 1, 1, 1, 1, 1, 1, 1, 2}, ge::DT_FLOAT16,
132+ 1.0f, ge::GRAPH_FAILED);
133+}
134+ 
135+TEST_F(SmoothL1LossGradTilingTest, tiling_label_unsupported_dtype_rejected)
136+{
137+ DoTilingTest({4, 8}, {4, 8}, {4, 8}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::DT_INT8);
138+}
139+ 
140+TEST_F(SmoothL1LossGradTilingTest, tiling_dout_unsupported_dtype_rejected)
141+{
142+ DoTilingTest({4, 8}, {4, 8}, {4, 8}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::DT_UNDEFINED, ge::DT_INT8);
143+}
144+ 
145+TEST_F(SmoothL1LossGradTilingTest, tiling_dout_dtype_mismatch_rejected)
146+{
147+ DoTilingTest({4, 8}, {4, 8}, {4, 8}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::DT_UNDEFINED, ge::DT_FLOAT16);
148+}
149+ 
150+TEST_F(SmoothL1LossGradTilingTest, tiling_label_unsupported_format_rejected)
151+{
152+ DoTilingTest({1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::DT_UNDEFINED,
153+ ge::DT_UNDEFINED, ge::FORMAT_ND, ge::FORMAT_NCHW);
154+}
155+ 
156+TEST_F(SmoothL1LossGradTilingTest, tiling_dout_unsupported_format_rejected)
157+{
158+ DoTilingTest({1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::DT_UNDEFINED,
159+ ge::DT_UNDEFINED, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_NCHW);
160+}
161+ 
162+TEST_F(SmoothL1LossGradTilingTest, tiling_output_unsupported_format_rejected)
163+{
164+ DoTilingTest({1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED, ge::DT_UNDEFINED,
165+ ge::DT_UNDEFINED, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_ND, ge::FORMAT_NCHW);
166+}
167+ 
168+TEST_F(SmoothL1LossGradTilingTest, tiling_dout_shape_mismatch_rejected)
169+{
170+ DoTilingTest({4}, {4}, {2, 2}, ge::DT_FLOAT, 1.0f, ge::GRAPH_FAILED);
171+}