1 /**
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "libabckit/include/c/metadata_core.h"
17 #include "libabckit/include/c/ir_core.h"
18 #include "helpers/helpers.h"
19 #include "helpers/helpers_runtime.h"
20 #include "libabckit/include/c/abckit.h"
21 #include "logger.h"
22
23 #include <gtest/gtest.h>
24
25 // NOLINTBEGIN(readability-magic-numbers)
26
27 namespace libabckit::test {
28
29 class LibAbcKitBasicBlocksDynTest : public ::testing::Test {};
30
31 namespace {
32
33 auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
34 auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
35 auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
36 auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
37 auto g_statG = AbckitGetIsaApiStaticImpl(ABCKIT_VERSION_RELEASE_1_0_0);
38 auto g_dynG = AbckitGetIsaApiDynamicImpl(ABCKIT_VERSION_RELEASE_1_0_0);
39
40 } // namespace
41
VerifyBbSchem1(AbckitGraph * graph)42 static void VerifyBbSchem1(AbckitGraph *graph)
43 {
44 std::vector<helpers::BBSchema<AbckitIsaApiDynamicOpcode>> bbSchemas = {
45 {{},
46 {1},
47 {{0, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
48 {1, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
49 {2, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
50 {3, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
51 {5, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}},
52 {9, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}},
53 {10, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}}}},
54 {{0},
55 {3, 2},
56 {{6, ABCKIT_ISA_API_DYNAMIC_OPCODE_GREATER, {5, 3}}, {8, ABCKIT_ISA_API_DYNAMIC_OPCODE_IF, {6, 9}}}},
57 {{1},
58 {4},
59 {{11, ABCKIT_ISA_API_DYNAMIC_OPCODE_LESS, {10, 3}},
60 {12, ABCKIT_ISA_API_DYNAMIC_OPCODE_TRYLDGLOBALBYNAME, {}},
61 {13, ABCKIT_ISA_API_DYNAMIC_OPCODE_ADD2, {10, 3}},
62 {14, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG1, {12, 13}}}},
63 {{1},
64 {4},
65 {{15, ABCKIT_ISA_API_DYNAMIC_OPCODE_TRYLDGLOBALBYNAME, {}},
66 {16, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG1, {15, 3}}}},
67 {{2, 3}, {5}, {{20, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED, {}}}},
68 {{4}, {}, {}}};
69 helpers::VerifyGraph(graph, bbSchemas);
70 }
71
72 // Test: test-kind=api, api=GraphApiImpl::gRunPassRemoveUnreachableBlocks, abc-kind=ArkTS1, category=positive,
73 // extension=c
TEST_F(LibAbcKitBasicBlocksDynTest,GrunPassRemoveUnreachableBlocks_1)74 TEST_F(LibAbcKitBasicBlocksDynTest, GrunPassRemoveUnreachableBlocks_1)
75 {
76 auto output = helpers::ExecuteDynamicAbc(
77 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic.abc", "graph_basic_block_dynamic");
78 EXPECT_TRUE(helpers::Match(output, "31\n51\n9\n"));
79
80 helpers::TransformMethod(
81 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic.abc",
82 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic_modified.abc", "test",
83 [&](AbckitFile * /*file*/, AbckitCoreFunction * /*method*/, AbckitGraph *graph) {
84 auto *bb2 = g_implG->gGetBasicBlock(graph, 2);
85 g_implG->iRemove(g_implG->bbGetLastInst(bb2));
86 g_implG->bbDisconnectSuccBlock(bb2, 0x0);
87 g_implG->gRunPassRemoveUnreachableBlocks(graph);
88 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
89 },
90 [&](AbckitGraph *graph) { VerifyBbSchem1(graph); });
91
92 output =
93 helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic_modified.abc",
94 "graph_basic_block_dynamic");
95 EXPECT_TRUE(helpers::Match(output, "31\n41\n9\n"));
96 }
97
VerifyBbSchem2(AbckitGraph * graph)98 static void VerifyBbSchem2(AbckitGraph *graph)
99 {
100 std::vector<helpers::BBSchema<AbckitIsaApiDynamicOpcode>> bbSchemas = {
101 {{},
102 {1},
103 {{0, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
104 {1, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
105 {2, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
106 {3, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
107 {4, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}},
108 {8, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}},
109 {9, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}},
110 {12, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}}}},
111 {{0},
112 {3, 2},
113 {{5, ABCKIT_ISA_API_DYNAMIC_OPCODE_GREATER, {4, 3}}, {7, ABCKIT_ISA_API_DYNAMIC_OPCODE_IF, {5, 8}}}},
114 {{1},
115 {4},
116 {{10, ABCKIT_ISA_API_DYNAMIC_OPCODE_LESS, {9, 3}},
117 {11, ABCKIT_ISA_API_DYNAMIC_OPCODE_TRYLDGLOBALBYNAME, {}},
118 {13, ABCKIT_ISA_API_DYNAMIC_OPCODE_ADD2, {12, 3}},
119 {14, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG1, {11, 13}}}},
120 {{1},
121 {4},
122 {{15, ABCKIT_ISA_API_DYNAMIC_OPCODE_TRYLDGLOBALBYNAME, {}},
123 {16, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG1, {15, 3}}}},
124 {{2, 3}, {5}, {{20, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED, {}}}},
125 {{4}, {}, {}}};
126 helpers::VerifyGraph(graph, bbSchemas);
127 }
128
129 // Test: test-kind=api, api=GraphApiImpl::gRunPassRemoveUnreachableBlocks, abc-kind=ArkTS1, category=positive,
130 // extension=c
TEST_F(LibAbcKitBasicBlocksDynTest,GrunPassRemoveUnreachableBlocks_2)131 TEST_F(LibAbcKitBasicBlocksDynTest, GrunPassRemoveUnreachableBlocks_2)
132 {
133 auto output = helpers::ExecuteDynamicAbc(
134 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic.abc", "graph_basic_block_dynamic");
135 EXPECT_TRUE(helpers::Match(output, "31\n51\n9\n"));
136
137 helpers::TransformMethod(
138 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic.abc",
139 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic_modified.abc", "test",
140 [&](AbckitFile * /*file*/, AbckitCoreFunction * /*method*/, AbckitGraph *graph) {
141 auto *bb2 = g_implG->gGetBasicBlock(graph, 2);
142 g_implG->iRemove(g_implG->bbGetLastInst(bb2));
143 g_implG->bbDisconnectSuccBlock(bb2, 0x1);
144 g_implG->gRunPassRemoveUnreachableBlocks(graph);
145 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
146 },
147 [&](AbckitGraph *graph) { VerifyBbSchem2(graph); });
148
149 output =
150 helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic_modified.abc",
151 "graph_basic_block_dynamic");
152 EXPECT_TRUE(helpers::Match(output, "41\n51\n9\n"));
153 }
154
VerifyBbSchem3(AbckitGraph * graph)155 static void VerifyBbSchem3(AbckitGraph *graph)
156 {
157 std::vector<helpers::BBSchema<AbckitIsaApiDynamicOpcode>> bbSchemas = {
158 {{},
159 {1},
160 {{0, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
161 {1, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
162 {2, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
163 {3, ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER, {}},
164 {4, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}},
165 {6, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}},
166 {10, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}},
167 {15, ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT, {}}}},
168 {{0},
169 {3, 2},
170 {{5, ABCKIT_ISA_API_DYNAMIC_OPCODE_GREATER, {4, 3}},
171 {7, ABCKIT_ISA_API_DYNAMIC_OPCODE_LESS, {6, 3}},
172 {9, ABCKIT_ISA_API_DYNAMIC_OPCODE_IF, {7, 10}}}},
173 {{1},
174 {4},
175 {{11, ABCKIT_ISA_API_DYNAMIC_OPCODE_TRYLDGLOBALBYNAME, {}},
176 {12, ABCKIT_ISA_API_DYNAMIC_OPCODE_ADD2, {6, 3}},
177 {13, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG1, {11, 12}}}},
178 {{1},
179 {4},
180 {{14, ABCKIT_ISA_API_DYNAMIC_OPCODE_TRYLDGLOBALBYNAME, {}},
181 {16, ABCKIT_ISA_API_DYNAMIC_OPCODE_ADD2, {15, 3}},
182 {17, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG1, {14, 16}}}},
183 {{2, 3}, {5}, {{21, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED, {}}}},
184 {{4}, {}, {}}};
185 helpers::VerifyGraph(graph, bbSchemas);
186 }
187
188 // Test: test-kind=api, api=GraphApiImpl::gRunPassRemoveUnreachableBlocks, abc-kind=ArkTS1, category=positive,
189 // extension=c
TEST_F(LibAbcKitBasicBlocksDynTest,GrunPassRemoveUnreachableBlocks_3)190 TEST_F(LibAbcKitBasicBlocksDynTest, GrunPassRemoveUnreachableBlocks_3)
191 {
192 auto output = helpers::ExecuteDynamicAbc(
193 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic.abc", "graph_basic_block_dynamic");
194 EXPECT_TRUE(helpers::Match(output, "31\n51\n9\n"));
195
196 helpers::TransformMethod(
197 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic.abc",
198 ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic_modified.abc", "test",
199 [&](AbckitFile * /*file*/, AbckitCoreFunction * /*method*/, AbckitGraph *graph) {
200 auto *bb0 = g_implG->gGetBasicBlock(graph, 0);
201 g_implG->iRemove(g_implG->bbGetLastInst(bb0));
202 g_implG->bbDisconnectSuccBlock(bb0, 0x0);
203 g_implG->gRunPassRemoveUnreachableBlocks(graph);
204 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
205 },
206 [&](AbckitGraph *graph) { VerifyBbSchem3(graph); });
207
208 output =
209 helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_dynamic_modified.abc",
210 "graph_basic_block_dynamic");
211 EXPECT_TRUE(helpers::Match(output, "31\n51\n29\n"));
212 }
213
VerifyGraphStart(AbckitFile * file)214 static void VerifyGraphStart(AbckitFile *file)
215 {
216 // Find transformed method
217 AbckitCoreFunction *testMethod = helpers::FindMethodByName(file, "foo");
218 ASSERT_NE(testMethod, nullptr);
219
220 // Get graph
221 AbckitGraph *graph = g_implI->createGraphFromFunction(testMethod);
222 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
223
224 AbckitBasicBlock *startBB = g_implG->gGetStartBasicBlock(graph);
225 ASSERT_NE(startBB, nullptr);
226
227 // Verify bb predecessors
228 ASSERT_EQ(helpers::BBgetPredBlocks(startBB).size(), 0);
229
230 // Verify bb successors
231 ASSERT_EQ(helpers::BBgetSuccBlocks(startBB).size(), 1);
232
233 // Verify instructions
234 auto *inst = g_implG->bbGetFirstInst(startBB);
235
236 ASSERT_EQ(g_dynG->iGetOpcode(inst), ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER);
237 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
238 ASSERT_EQ(g_implG->iGetId(inst), 0);
239 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
240
241 g_impl->destroyGraph(graph);
242 }
243
244 // Test: test-kind=api, api=GraphApiImpl::gGetStartBasicBlock, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitBasicBlocksDynTest,GgetStartBasicBlockValid)245 TEST_F(LibAbcKitBasicBlocksDynTest, GgetStartBasicBlockValid)
246 {
247 constexpr auto INPUT_PATH = ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_simple.abc";
248 AbckitFile *file = g_impl->openAbc(INPUT_PATH, strlen(INPUT_PATH));
249 LIBABCKIT_LOG(DEBUG) << "LibAbcKitBasicBlocksDynTest: " << INPUT_PATH << std::endl;
250
251 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
252
253 VerifyGraphStart(file);
254
255 g_impl->closeFile(file);
256 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
257 }
258
VerifyGraphEnd(AbckitFile * file)259 static void VerifyGraphEnd(AbckitFile *file)
260 {
261 // Find transformed method
262 AbckitCoreFunction *testMethod = helpers::FindMethodByName(file, "foo");
263 ASSERT_NE(testMethod, nullptr);
264
265 // Get graph
266 AbckitGraph *graph = g_implI->createGraphFromFunction(testMethod);
267 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
268
269 AbckitBasicBlock *endBB = g_implG->gGetEndBasicBlock(graph);
270 ASSERT_NE(endBB, nullptr);
271
272 // Verify bb predecessors
273 ASSERT_EQ(helpers::BBgetPredBlocks(endBB).size(), 1);
274
275 // Verify bb successors
276 ASSERT_EQ(helpers::BBgetSuccBlocks(endBB).size(), 0);
277
278 // Verify instructions
279 ASSERT_EQ(g_implG->bbGetFirstInst(endBB), nullptr);
280
281 g_impl->destroyGraph(graph);
282 }
283
284 // Test: test-kind=api, api=GraphApiImpl::gGetEndBasicBlock, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitBasicBlocksDynTest,GgetEndBasicBlockValid)285 TEST_F(LibAbcKitBasicBlocksDynTest, GgetEndBasicBlockValid)
286 {
287 constexpr auto INPUT_PATH = ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_simple.abc";
288 AbckitFile *file = g_impl->openAbc(INPUT_PATH, strlen(INPUT_PATH));
289 LIBABCKIT_LOG(DEBUG) << "LibAbcKitBasicBlocksDynTest: " << INPUT_PATH << std::endl;
290 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
291
292 VerifyGraphEnd(file);
293
294 g_impl->closeFile(file);
295 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
296 }
297
VerifyGraphVisitBlocks(AbckitFile * file)298 static void VerifyGraphVisitBlocks(AbckitFile *file)
299 {
300 // Find transformed method
301 AbckitCoreFunction *testMethod = helpers::FindMethodByName(file, "foo");
302 ASSERT_NE(testMethod, nullptr);
303
304 // Get graph
305 AbckitGraph *graph = g_implI->createGraphFromFunction(testMethod);
306 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
307
308 std::vector<AbckitBasicBlock *> bbs;
309
310 // Collect basic blocks
311 g_implG->gVisitBlocksRpo(graph, &bbs, [](AbckitBasicBlock *bb, void *data) {
312 reinterpret_cast<std::vector<AbckitBasicBlock *> *>(data)->emplace_back(bb);
313 return true;
314 });
315
316 ASSERT_EQ(bbs.size(), 3U);
317
318 auto *startBB = bbs[0];
319
320 // Verify bb predecessors
321 ASSERT_EQ(helpers::BBgetPredBlocks(startBB).size(), 0);
322
323 // Verify bb successors
324 ASSERT_EQ(helpers::BBgetSuccBlocks(startBB).size(), 1);
325
326 // Verify instructions
327 auto *inst = g_implG->bbGetFirstInst(startBB);
328
329 ASSERT_EQ(g_dynG->iGetOpcode(inst), ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER);
330 ASSERT_EQ(g_implG->iGetId(inst), 0);
331
332 startBB = bbs[1];
333
334 // Verify bb predecessors
335 ASSERT_EQ(helpers::BBgetPredBlocks(startBB).size(), 1);
336
337 // Verify bb successors
338 ASSERT_EQ(helpers::BBgetSuccBlocks(startBB).size(), 1);
339
340 // Verify instructions
341 inst = g_implG->bbGetFirstInst(startBB);
342
343 ASSERT_EQ(g_dynG->iGetOpcode(inst), ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURN);
344 ASSERT_EQ(g_implG->iGetId(inst), 4U);
345
346 startBB = bbs[2U];
347 ASSERT_NE(startBB, nullptr);
348
349 // Verify bb predecessors
350 ASSERT_EQ(helpers::BBgetPredBlocks(startBB).size(), 1);
351
352 // Verify bb successors
353 ASSERT_EQ(helpers::BBgetSuccBlocks(startBB).size(), 0);
354
355 // Verify instructions
356 inst = g_implG->bbGetFirstInst(startBB);
357 ASSERT_EQ(inst, nullptr);
358
359 g_impl->destroyGraph(graph);
360 }
361
362 // Test: test-kind=api, api=GraphApiImpl::gVisitBlocksRpo, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitBasicBlocksDynTest,GvisitBlocksRPO)363 TEST_F(LibAbcKitBasicBlocksDynTest, GvisitBlocksRPO)
364 {
365 constexpr auto INPUT_PATH = ABCKIT_ABC_DIR "ut/ir_core/graph_basic_block/graph_basic_block_simple.abc";
366 AbckitFile *file = g_impl->openAbc(INPUT_PATH, strlen(INPUT_PATH));
367 LIBABCKIT_LOG(DEBUG) << "LibAbcKitBasicBlocksDynTest: " << INPUT_PATH << std::endl;
368
369 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
370
371 VerifyGraphVisitBlocks(file);
372
373 g_impl->closeFile(file);
374 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
375 }
376
377 } // namespace libabckit::test
378
379 // NOLINTEND(readability-magic-numbers)
380