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/abckit.h"
17 #include "ir_impl.h"
18 #include "libabckit/include/c/metadata_core.h"
19 #include "libabckit/include/c/ir_core.h"
20 #include "libabckit/include/c/isa/isa_dynamic.h"
21
22 #include "helpers/helpers.h"
23 #include "helpers/helpers_runtime.h"
24 #include "libabckit/src/logger.h"
25
26 #include <gtest/gtest.h>
27
28 namespace {
29
30 auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
31 auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
32 auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
33 auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
34 auto g_dynG = AbckitGetIsaApiDynamicImpl(ABCKIT_VERSION_RELEASE_1_0_0);
35
36 using CB = std::function<void(AbckitCoreFunction *)>;
37
EnumerateAllMethodsInModule(AbckitFile * file,std::function<void (AbckitCoreNamespace *)> & cbNamespace,std::function<void (AbckitCoreClass *)> & cbClass,std::function<void (AbckitCoreFunction *)> & cbFunc)38 void EnumerateAllMethodsInModule(AbckitFile *file, std::function<void(AbckitCoreNamespace *)> &cbNamespace,
39 std::function<void(AbckitCoreClass *)> &cbClass,
40 std::function<void(AbckitCoreFunction *)> &cbFunc)
41 {
42 std::function<void(AbckitCoreModule *)> cbModule = [&](AbckitCoreModule *m) {
43 g_implI->moduleEnumerateNamespaces(m, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
44 (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
45 return true;
46 });
47 g_implI->moduleEnumerateClasses(m, &cbClass, [](AbckitCoreClass *c, void *cb) {
48 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
49 return true;
50 });
51 g_implI->moduleEnumerateTopLevelFunctions(m, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
52 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m);
53
54 return true;
55 });
56 };
57
58 g_implI->fileEnumerateModules(file, &cbModule, [](AbckitCoreModule *m, void *cb) {
59 (*reinterpret_cast<std::function<void(AbckitCoreModule *)> *>(cb))(m);
60 return true;
61 });
62 }
63
EnumerateAllMethods(AbckitFile * file,const CB & cbUserFunc)64 void EnumerateAllMethods(AbckitFile *file, const CB &cbUserFunc)
65 {
66 CB cbFunc;
67 std::function<void(AbckitCoreClass *)> cbClass;
68
69 cbFunc = [&](AbckitCoreFunction *f) {
70 cbUserFunc(f);
71 g_implI->functionEnumerateNestedFunctions(f, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
72 (*reinterpret_cast<CB *>(cb))(f);
73 return true;
74 });
75 g_implI->functionEnumerateNestedClasses(f, &cbClass, [](AbckitCoreClass *c, void *cb) {
76 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
77 return true;
78 });
79 };
80
81 cbClass = [&](AbckitCoreClass *c) {
82 g_implI->classEnumerateMethods(c, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
83 (*reinterpret_cast<CB *>(cb))(m);
84 return true;
85 });
86 };
87
88 std::function<void(AbckitCoreNamespace *)> cbNamespace = [&](AbckitCoreNamespace *n) {
89 g_implI->namespaceEnumerateNamespaces(n, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
90 (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
91 return true;
92 });
93 g_implI->namespaceEnumerateClasses(n, &cbClass, [](AbckitCoreClass *c, void *cb) {
94 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
95 return true;
96 });
97 g_implI->namespaceEnumerateTopLevelFunctions(n, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
98 (*reinterpret_cast<CB *>(cb))(f);
99 return true;
100 });
101 };
102
103 EnumerateAllMethodsInModule(file, cbNamespace, cbClass, cbFunc);
104 }
105
106 } // namespace
107
108 namespace libabckit::test {
109
110 class AbckitScenarioCTestClean : public ::testing::Test {};
111
112 struct UserData {
113 AbckitString *print = nullptr;
114 AbckitString *date = nullptr;
115 AbckitString *getTime = nullptr;
116 AbckitString *str = nullptr;
117 AbckitString *consume = nullptr;
118 };
119
120 struct VisitData {
121 UserData *ud = nullptr;
122 AbckitInst *time = nullptr;
123 };
124
125 // CC-OFFNXT(G.FUN.01-CPP) huge function
CreateEpilog(AbckitInst * inst,AbckitBasicBlock * bb,UserData * userData,AbckitInst * time)126 static void CreateEpilog(AbckitInst *inst, AbckitBasicBlock *bb, UserData *userData, AbckitInst *time)
127 {
128 auto *graph = g_implG->bbGetGraph(bb);
129 while (inst != nullptr) {
130 if (g_dynG->iGetOpcode(inst) == ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED) {
131 // Epilog
132 auto *dateClass2 = g_dynG->iCreateTryldglobalbyname(graph, userData->date);
133 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
134 g_implG->iInsertBefore(dateClass2, inst);
135 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
136 auto *dateObj2 = g_dynG->iCreateNewobjrange(graph, 1, dateClass2);
137 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
138 g_implG->iInsertAfter(dateObj2, dateClass2);
139 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
140 auto *getTime2 = g_dynG->iCreateLdobjbyname(graph, dateObj2, userData->getTime);
141 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
142 g_implG->iInsertAfter(getTime2, dateObj2);
143 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
144 auto *time2 = g_dynG->iCreateCallthis0(graph, getTime2, dateObj2);
145 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
146 g_implG->iInsertAfter(time2, getTime2);
147 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
148 auto *consume = g_dynG->iCreateLoadString(graph, userData->consume);
149 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
150 g_implG->iInsertAfter(consume, time2);
151 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
152
153 auto *print2 = g_dynG->iCreateTryldglobalbyname(graph, userData->print);
154 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
155 g_implG->iInsertAfter(print2, consume);
156 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
157 auto *callArg2 = g_dynG->iCreateCallarg1(graph, print2, consume);
158 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
159 g_implG->iInsertAfter(callArg2, print2);
160 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
161 auto *sub = g_dynG->iCreateSub2(graph, time, time2);
162 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
163 g_implG->iInsertAfter(sub, callArg2);
164 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
165
166 auto *print3 = g_dynG->iCreateTryldglobalbyname(graph, userData->print);
167 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
168 g_implG->iInsertAfter(print3, sub);
169 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
170 auto *callArg3 = g_dynG->iCreateCallarg1(graph, print3, sub);
171 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
172 g_implG->iInsertAfter(callArg3, print3);
173 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
174 }
175 inst = g_implG->iGetNext(inst);
176 }
177 }
178
BBgetSuccBlocks(AbckitBasicBlock * bb)179 static std::vector<AbckitBasicBlock *> BBgetSuccBlocks(AbckitBasicBlock *bb)
180 {
181 std::vector<AbckitBasicBlock *> succBBs;
182 g_implG->bbVisitSuccBlocks(bb, &succBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
183 auto *succs = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
184 succs->emplace_back(succBasicBlock);
185 return true;
186 });
187 return succBBs;
188 }
189
TransformIr(AbckitGraph * graph,UserData * userData)190 static void TransformIr(AbckitGraph *graph, UserData *userData)
191 {
192 AbckitBasicBlock *startBB = g_implG->gGetStartBasicBlock(graph);
193 std::vector<AbckitBasicBlock *> succBBs = BBgetSuccBlocks(startBB);
194 auto *bb = succBBs[0];
195
196 // Prolog
197 auto *str = g_dynG->iCreateLoadString(graph, userData->str);
198 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
199 g_implG->bbAddInstFront(bb, str);
200 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
201 auto *print = g_dynG->iCreateTryldglobalbyname(graph, userData->print);
202 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
203 g_implG->iInsertAfter(print, str);
204 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
205 auto *callArg = g_dynG->iCreateCallarg1(graph, print, str);
206 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
207 g_implG->iInsertAfter(callArg, print);
208 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
209
210 auto *dateClass = g_dynG->iCreateTryldglobalbyname(graph, userData->date);
211 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
212 g_implG->iInsertAfter(dateClass, callArg);
213 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
214 auto *dateObj = g_dynG->iCreateNewobjrange(graph, 1, dateClass);
215 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
216 g_implG->iInsertAfter(dateObj, dateClass);
217 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
218 auto *getTime = g_dynG->iCreateLdobjbyname(graph, dateObj, userData->getTime);
219 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
220 g_implG->iInsertAfter(getTime, dateObj);
221 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
222 auto *time = g_dynG->iCreateCallthis0(graph, getTime, dateObj);
223 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
224 g_implG->iInsertAfter(time, getTime);
225 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
226
227 VisitData vd;
228 vd.ud = userData;
229 vd.time = time;
230
231 g_implG->gVisitBlocksRpo(graph, &vd, [](AbckitBasicBlock *bb, void *data) {
232 auto *inst = g_implG->bbGetFirstInst(bb);
233
234 auto *visitData = reinterpret_cast<VisitData *>(data);
235 CreateEpilog(inst, bb, visitData->ud, visitData->time);
236 return true;
237 });
238 }
239
GetMethodName(AbckitCoreFunction * method)240 static std::string GetMethodName(AbckitCoreFunction *method)
241 {
242 auto mname = g_implI->functionGetName(method);
243 std::string fullSig = g_implI->abckitStringToString(mname);
244 auto fullName = fullSig.substr(0, fullSig.find(':'));
245 return fullName;
246 }
247
248 // CC-OFFNXT(huge_method, C_RULE_ID_FUNCTION_SIZE) test, solid logic
249 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioCTestClean,LibAbcKitTestDynamicAddLogClean)250 TEST_F(AbckitScenarioCTestClean, LibAbcKitTestDynamicAddLogClean)
251 {
252 // ExecuteDynamicAbc is helper function needed for testing. Вoes not affect the logic of IR transformation
253 auto output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/add_log/add_log_dynamic.abc",
254 "add_log_dynamic");
255 EXPECT_TRUE(helpers::Match(output, "abckit\n"));
256
257 constexpr auto INPUT_PATH = ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/add_log/add_log_dynamic.abc";
258 AbckitFile *file = g_impl->openAbc(INPUT_PATH, strlen(INPUT_PATH));
259 UserData data = {};
260 data.print = g_implM->createString(file, "print", strlen("print"));
261 data.date = g_implM->createString(file, "Date", strlen("Date"));
262 data.getTime = g_implM->createString(file, "getTime", strlen("getTime"));
263 data.str = g_implM->createString(file, "file: src/MyClass, function: MyClass.handle",
264 strlen("file: src/MyClass, function: MyClass.handle"));
265 data.consume = g_implM->createString(file, "Ellapsed time:", strlen("Ellapsed time:"));
266
267 AbckitCoreFunction *handleMethod;
268 EnumerateAllMethods(file, [&](AbckitCoreFunction *method) {
269 auto methodName = GetMethodName(method);
270 if (methodName == "handle") {
271 handleMethod = method;
272 }
273 });
274
275 AbckitGraph *graph = g_implI->createGraphFromFunction(handleMethod);
276 TransformIr(graph, &data);
277 g_implM->functionSetGraph(handleMethod, graph);
278 constexpr auto OUTPUT_PATH = ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/add_log/add_log_dynamic_modified.abc";
279 g_impl->writeAbc(file, OUTPUT_PATH, strlen(OUTPUT_PATH));
280 g_impl->destroyGraph(graph);
281 g_impl->closeFile(file);
282
283 output = helpers::ExecuteDynamicAbc(OUTPUT_PATH, "add_log_dynamic");
284 EXPECT_TRUE(helpers::Match(output,
285 "file: src/MyClass, function: MyClass.handle\n"
286 "abckit\n"
287 "Ellapsed time:\n"
288 "\\d+\n"));
289 }
290
291 } // namespace libabckit::test
292