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 <sstream>
17
18 #include <gtest/gtest.h>
19
20 #include "libabckit/include/c/abckit.h"
21 #include "libabckit/include/c/isa/isa_dynamic.h"
22 #include "helpers/helpers_runtime.h"
23
24 #include "helpers/helpers.h"
25 #include "libabckit/src/logger.h"
26
27 namespace {
28
29 constexpr AbckitApiVersion VERSION = ABCKIT_VERSION_RELEASE_1_0_0;
30 auto *g_impl = AbckitGetApiImpl(VERSION);
31 const AbckitInspectApi *g_implI = AbckitGetInspectApiImpl(VERSION);
32 const AbckitGraphApi *g_implG = AbckitGetGraphApiImpl(VERSION);
33 const AbckitIsaApiDynamic *g_dynG = AbckitGetIsaApiDynamicImpl(VERSION);
34 const AbckitModifyApi *g_implM = AbckitGetModifyApiImpl(VERSION);
35
36 struct ConstantInfo {
37 std::string path;
38 std::string objName; // Config
39 std::string fieldName; // isDebug
40 bool fieldValue; // field is constant true or false
41 };
42
43 using ConstantInfoIndexType = uint32_t;
44 using SuspectsType = std::unordered_map<AbckitCoreImportDescriptor *, std::vector<ConstantInfoIndexType>>;
45 constexpr ConstantInfoIndexType INVALID_INDEX = std::numeric_limits<ConstantInfoIndexType>::max();
46
47 template <class ModuleCallBack>
EnumerateModules(const ModuleCallBack & cb,AbckitFile * file)48 inline void EnumerateModules(const ModuleCallBack &cb, AbckitFile *file)
49 {
50 LIBABCKIT_LOG_FUNC;
51
52 g_implI->fileEnumerateModules(file, (void *)(&cb), [](AbckitCoreModule *mod, void *data) {
53 const auto &cb = *((ModuleCallBack *)(data));
54 cb(mod);
55 return true;
56 });
57 }
58
59 template <class FunctionCallBack>
EnumerateModuleTopLevelFunctions(AbckitCoreModule * mod,const FunctionCallBack & cb)60 inline void EnumerateModuleTopLevelFunctions(AbckitCoreModule *mod, const FunctionCallBack &cb)
61 {
62 LIBABCKIT_LOG_FUNC;
63
64 g_implI->moduleEnumerateTopLevelFunctions(mod, (void *)(&cb), [](AbckitCoreFunction *method, void *data) {
65 const auto &cb = *((FunctionCallBack *)data);
66 cb(method);
67 return true;
68 });
69 }
70
71 template <class ClassCallBack>
EnumerateModuleClasses(AbckitCoreModule * mod,const ClassCallBack & cb)72 inline void EnumerateModuleClasses(AbckitCoreModule *mod, const ClassCallBack &cb)
73 {
74 LIBABCKIT_LOG_FUNC;
75
76 g_implI->moduleEnumerateClasses(mod, (void *)(&cb), [](AbckitCoreClass *klass, void *data) {
77 const auto &cb = *((ClassCallBack *)data);
78 cb(klass);
79 return true;
80 });
81 }
82
83 template <class MethodCallBack>
EnumerateClassMethods(AbckitCoreClass * klass,const MethodCallBack & cb)84 inline void EnumerateClassMethods(AbckitCoreClass *klass, const MethodCallBack &cb)
85 {
86 LIBABCKIT_LOG_FUNC;
87 g_implI->classEnumerateMethods(klass, (void *)(&cb), [](AbckitCoreFunction *method, void *data) {
88 const auto &cb = *((MethodCallBack *)data);
89 cb(method);
90 return true;
91 });
92 }
93
94 template <class FunctionCallBack>
EnumerateModuleFunctions(AbckitCoreModule * mod,const FunctionCallBack & cb)95 inline void EnumerateModuleFunctions(AbckitCoreModule *mod, const FunctionCallBack &cb)
96 {
97 LIBABCKIT_LOG_FUNC;
98 // NOTE: currently we can only enumerate class methods and top level functions. need to update.
99 EnumerateModuleTopLevelFunctions(mod, cb);
100 EnumerateModuleClasses(mod, [&](AbckitCoreClass *klass) { EnumerateClassMethods(klass, cb); });
101 }
102
103 template <class UserCallBack>
EnumerateInstUsers(AbckitInst * inst,const UserCallBack & cb)104 inline void EnumerateInstUsers(AbckitInst *inst, const UserCallBack &cb)
105 {
106 LIBABCKIT_LOG_FUNC;
107
108 g_implG->iVisitUsers(inst, (void *)(&cb), [](AbckitInst *user, void *data) {
109 const auto &cb = *((UserCallBack *)data);
110 cb(user);
111 return true;
112 });
113 }
114
115 struct CapturedData {
116 void *callback = nullptr;
117 const AbckitGraphApi *implG = nullptr;
118 };
119
120 template <class InstCallBack>
EnumerateGraphInsts(AbckitGraph * graph,const InstCallBack & cb)121 inline void EnumerateGraphInsts(AbckitGraph *graph, const InstCallBack &cb)
122 {
123 CapturedData captured {(void *)(&cb), g_implG};
124
125 g_implG->gVisitBlocksRpo(graph, &captured, [](AbckitBasicBlock *bb, void *data) {
126 auto *captured = reinterpret_cast<CapturedData *>(data);
127 const auto &cb = *((InstCallBack *)(captured->callback));
128 auto *implG = captured->implG;
129 for (auto *inst = implG->bbGetFirstInst(bb); inst != nullptr; inst = implG->iGetNext(inst)) {
130 cb(inst);
131 }
132 return true;
133 });
134 }
135
136 template <class InstCallBack>
GraphInstsFindIf(AbckitGraph * graph,const InstCallBack & cb)137 inline AbckitInst *GraphInstsFindIf(AbckitGraph *graph, const InstCallBack &cb)
138 {
139 AbckitInst *ret = nullptr;
140 bool found = false;
141 EnumerateGraphInsts(graph, [&](AbckitInst *inst) {
142 if (!found && cb(inst)) {
143 found = true;
144 ret = inst;
145 }
146 });
147
148 return ret;
149 }
150
151 template <class ImportCallBack>
EnumerateModuleImports(AbckitCoreModule * mod,const ImportCallBack & cb)152 inline void EnumerateModuleImports(AbckitCoreModule *mod, const ImportCallBack &cb)
153 {
154 LIBABCKIT_LOG_FUNC;
155
156 g_implI->moduleEnumerateImports(mod, (void *)(&cb), [](AbckitCoreImportDescriptor *i, void *data) {
157 const auto &cb = *((ImportCallBack *)(data));
158 cb(i);
159 return true;
160 });
161 }
162
GetSuspects(AbckitCoreModule * mod,const std::vector<ConstantInfo> & constants,SuspectsType & suspects)163 bool GetSuspects(AbckitCoreModule *mod, const std::vector<ConstantInfo> &constants, SuspectsType &suspects)
164 {
165 EnumerateModuleImports(mod, [&](AbckitCoreImportDescriptor *id) {
166 auto importName = g_implI->abckitStringToString(g_implI->importDescriptorGetName(id));
167 auto *importedModule = g_implI->importDescriptorGetImportedModule(id);
168 auto path = g_implI->abckitStringToString(g_implI->moduleGetName(importedModule));
169 for (ConstantInfoIndexType i = 0; i < constants.size(); ++i) {
170 const auto &constInfo = constants[i];
171 if (constInfo.path != path || constInfo.objName != importName) {
172 continue;
173 }
174 auto iter = suspects.find(id);
175 if (iter == suspects.end()) {
176 std::vector<ConstantInfoIndexType> vec = {i};
177 suspects.emplace(id, vec);
178 } else {
179 iter->second.push_back(i);
180 }
181 }
182 });
183 return !suspects.empty();
184 }
185
GetConstantInfoIndex(AbckitInst * inst,const std::vector<ConstantInfo> & constants,const SuspectsType & suspects)186 ConstantInfoIndexType GetConstantInfoIndex(AbckitInst *inst, const std::vector<ConstantInfo> &constants,
187 const SuspectsType &suspects)
188 {
189 if (g_dynG->iGetOpcode(inst) != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDOBJBYNAME) {
190 return INVALID_INDEX;
191 }
192 auto *ldExternalModuleVar = g_implG->iGetInput(inst, 0);
193 if (g_dynG->iGetOpcode(ldExternalModuleVar) != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDEXTERNALMODULEVAR) {
194 return INVALID_INDEX;
195 }
196 auto *id = g_dynG->iGetImportDescriptor(ldExternalModuleVar);
197 auto iter = suspects.find(id);
198 if (iter == suspects.end()) {
199 return INVALID_INDEX;
200 }
201 const auto &constInfoIndexes = iter->second;
202 const auto propName = g_implI->abckitStringToString(g_implG->iGetString(inst)); // "isDebug"
203 for (auto index : constInfoIndexes) {
204 EXPECT_TRUE(index >= 0);
205 EXPECT_TRUE(index < constants.size());
206 if (constants[index].fieldName == propName) {
207 return index;
208 }
209 }
210
211 return INVALID_INDEX;
212 }
213
ReplaceUsers(AbckitInst * oldInst,AbckitInst * newInst)214 void ReplaceUsers(AbckitInst *oldInst, AbckitInst *newInst)
215 {
216 EnumerateInstUsers(oldInst, [&](AbckitInst *user) {
217 auto inputCount = g_implG->iGetInputCount(user);
218 for (uint64_t i = 0; i < inputCount; ++i) {
219 if (g_implG->iGetInput(user, i) == oldInst) {
220 g_implG->iSetInput(user, newInst, i);
221 }
222 }
223 });
224 }
225
ReplaceLdObjByNameWithBoolean(AbckitInst * ldObjByName,ConstantInfoIndexType constInfoIndex,const std::vector<ConstantInfo> & constants)226 void ReplaceLdObjByNameWithBoolean(AbckitInst *ldObjByName, ConstantInfoIndexType constInfoIndex,
227 const std::vector<ConstantInfo> &constants)
228 {
229 bool fieldVal = constants[constInfoIndex].fieldValue;
230 auto *bb = g_implG->iGetBasicBlock(ldObjByName);
231 auto *graph = g_implG->bbGetGraph(bb);
232 auto *value = fieldVal ? g_dynG->iCreateLdtrue(graph) : g_dynG->iCreateLdfalse(graph);
233 g_implG->iInsertAfter(value, ldObjByName);
234 ReplaceUsers(ldObjByName, value);
235
236 auto *ldExternalModuleVar = g_implG->iGetInput(ldObjByName, 0);
237 bool isRemovable = true;
238 std::vector<AbckitInst *> checks;
239 EnumerateInstUsers(ldExternalModuleVar, [&](AbckitInst *inst) {
240 if (inst != ldObjByName) {
241 if (g_dynG->iGetOpcode(inst) != ABCKIT_ISA_API_DYNAMIC_OPCODE_THROW_UNDEFINEDIFHOLEWITHNAME) {
242 isRemovable = false;
243 } else {
244 checks.emplace_back(inst);
245 }
246 }
247 });
248
249 if (isRemovable) {
250 for (auto *check : checks) {
251 g_implG->iRemove(check);
252 }
253 g_implG->iRemove(ldExternalModuleVar);
254 }
255 g_implG->iRemove(ldObjByName);
256 }
257
ReplaceModuleVarByConstant(AbckitGraph * graph,const std::vector<ConstantInfo> & constants,const SuspectsType & suspects)258 bool ReplaceModuleVarByConstant(AbckitGraph *graph, const std::vector<ConstantInfo> &constants,
259 const SuspectsType &suspects)
260 {
261 // find the following patter:
262 // ...
263 // 1. ldExternalModuleVar (importdescriptor)
264 // 2. ldObjByName v1, "isDebug"
265 //
266 // and replace it by
267 // 3. ldtrue
268
269 std::unordered_map<AbckitInst *, ConstantInfoIndexType> moduleVars;
270 EnumerateGraphInsts(graph, [&](AbckitInst *inst) {
271 auto constInfoIndex = GetConstantInfoIndex(inst, constants, suspects);
272 if (constInfoIndex != INVALID_INDEX) {
273 moduleVars.emplace(inst, constInfoIndex);
274 }
275 });
276 for (auto &[ldObjByName, constInfoIndex] : moduleVars) {
277 EXPECT_TRUE(ldObjByName != nullptr);
278 EXPECT_TRUE(constInfoIndex != INVALID_INDEX);
279 ReplaceLdObjByNameWithBoolean(ldObjByName, constInfoIndex, constants);
280 }
281
282 return !moduleVars.empty();
283 }
284
GetInstAsBool(AbckitInst * inst)285 bool GetInstAsBool(AbckitInst *inst)
286 {
287 switch (g_dynG->iGetOpcode(inst)) {
288 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT:
289 return g_implG->iGetConstantValueI64(inst) != 0;
290 case ABCKIT_ISA_API_DYNAMIC_OPCODE_LDTRUE:
291 case ABCKIT_ISA_API_DYNAMIC_OPCODE_ISTRUE:
292 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLRUNTIME_ISTRUE:
293 return true;
294 case ABCKIT_ISA_API_DYNAMIC_OPCODE_LDFALSE:
295 case ABCKIT_ISA_API_DYNAMIC_OPCODE_ISFALSE:
296 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLRUNTIME_ISFALSE:
297 return false;
298 default:
299 EXPECT_TRUE(false); // UNREACHABLE
300 }
301 return false;
302 }
303
CanBeRemoved(AbckitInst * inst)304 bool CanBeRemoved(AbckitInst *inst)
305 {
306 switch (g_dynG->iGetOpcode(inst)) {
307 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT:
308 case ABCKIT_ISA_API_DYNAMIC_OPCODE_LDTRUE:
309 case ABCKIT_ISA_API_DYNAMIC_OPCODE_ISTRUE:
310 case ABCKIT_ISA_API_DYNAMIC_OPCODE_LDFALSE:
311 case ABCKIT_ISA_API_DYNAMIC_OPCODE_ISFALSE:
312 return true;
313 default:
314 return false;
315 }
316 }
317
RemoveUnusedInsts(AbckitGraph * graph)318 bool RemoveUnusedInsts(AbckitGraph *graph)
319 {
320 bool hasGraphChanged = false;
321 bool continueLoop = true;
322
323 while (continueLoop) {
324 std::vector<AbckitInst *> removableInsts;
325 EnumerateGraphInsts(graph, [&](AbckitInst *inst) {
326 if (g_implG->iGetUserCount(inst) == 0 && CanBeRemoved(inst)) {
327 removableInsts.emplace_back(inst);
328 }
329 });
330
331 if (removableInsts.empty()) {
332 continueLoop = false;
333 } else {
334 EXPECT_TRUE(!removableInsts.empty());
335 for (auto *inst : removableInsts) {
336 g_implG->iRemove(inst);
337 }
338 hasGraphChanged = true;
339 }
340 }
341
342 return hasGraphChanged;
343 }
344
LoweringConstants(AbckitGraph * graph)345 bool LoweringConstants(AbckitGraph *graph)
346 {
347 bool hasGraphChanged = false;
348 auto doCb = [graph, &hasGraphChanged]() -> bool {
349 std::vector<AbckitInst *> users;
350
351 auto instFindUsers = [&users](AbckitInst *user) {
352 auto userOp = g_dynG->iGetOpcode(user);
353 if (userOp == ABCKIT_ISA_API_DYNAMIC_OPCODE_ISTRUE || userOp == ABCKIT_ISA_API_DYNAMIC_OPCODE_ISFALSE ||
354 userOp == ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLRUNTIME_ISTRUE ||
355 userOp == ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLRUNTIME_ISFALSE) {
356 users.emplace_back(user);
357 }
358 };
359
360 AbckitInst *ldBool = GraphInstsFindIf(graph, [&](AbckitInst *inst) {
361 auto op = g_dynG->iGetOpcode(inst);
362 if (op != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDTRUE && op != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDFALSE) {
363 return false;
364 }
365
366 EnumerateInstUsers(inst, instFindUsers);
367
368 return !users.empty();
369 });
370
371 if (ldBool == nullptr) {
372 return false;
373 }
374
375 auto ldBoolVal = GetInstAsBool(ldBool);
376 for (auto *isBool : users) {
377 auto isBoolVal = GetInstAsBool(isBool);
378 auto *ldBool = ldBoolVal == isBoolVal ? g_dynG->iCreateLdtrue(graph) : g_dynG->iCreateLdfalse(graph);
379 g_implG->iInsertAfter(ldBool, isBool);
380 ReplaceUsers(isBool, ldBool);
381 g_implG->iRemove(isBool);
382 }
383
384 hasGraphChanged = true;
385
386 return true;
387 };
388
389 while (doCb()) {
390 }
391
392 hasGraphChanged |= RemoveUnusedInsts(graph);
393
394 return hasGraphChanged;
395 }
396
IsEliminatableIfInst(AbckitInst * inst)397 bool IsEliminatableIfInst(AbckitInst *inst)
398 {
399 if (g_dynG->iGetOpcode(inst) != ABCKIT_ISA_API_DYNAMIC_OPCODE_IF || g_implG->iGetInputCount(inst) != 2U) {
400 return false;
401 }
402 auto *ldBool = g_implG->iGetInput(inst, 0);
403 auto op = g_dynG->iGetOpcode(ldBool);
404 if (op != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDTRUE && op != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDFALSE) {
405 return false;
406 }
407 auto *constInst = g_implG->iGetInput(inst, 1);
408 return g_dynG->iGetOpcode(constInst) == ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT;
409 }
410
DeleteUnreachableBranch(AbckitInst * ifInst)411 void DeleteUnreachableBranch(AbckitInst *ifInst)
412 {
413 // compute result of If compare
414 auto *ldBool = g_implG->iGetInput(ifInst, 0); // 0: ldtrue or ldfalse
415 auto *constInst = g_implG->iGetInput(ifInst, 1); // 1: ConstantInst
416 auto valLeft = GetInstAsBool(ldBool);
417 auto valRight = GetInstAsBool(constInst);
418 auto conditionCode = g_dynG->iGetConditionCode(ifInst);
419
420 EXPECT_TRUE(conditionCode == ABCKIT_ISA_API_DYNAMIC_CONDITION_CODE_CC_EQ ||
421 conditionCode == ABCKIT_ISA_API_DYNAMIC_CONDITION_CODE_CC_NE);
422 bool result = (conditionCode == ABCKIT_ISA_API_DYNAMIC_CONDITION_CODE_CC_EQ && valLeft == valRight) ||
423 (conditionCode == ABCKIT_ISA_API_DYNAMIC_CONDITION_CODE_CC_NE && valLeft != valRight);
424
425 auto *bb = g_implG->iGetBasicBlock(ifInst);
426 // if true ==> delete false branch
427 g_implG->iRemove(ifInst);
428
429 g_implG->bbDisconnectSuccBlock(bb, result ? 1 : 0);
430 g_implG->gRunPassRemoveUnreachableBlocks(g_implG->bbGetGraph(bb));
431 }
432
433 template <class FunctionCallBack>
TransformMethod(AbckitCoreFunction * f,const FunctionCallBack & cb)434 inline void TransformMethod(AbckitCoreFunction *f, const FunctionCallBack &cb)
435 {
436 cb(g_implI->functionGetFile(f), f);
437 }
438
EliminateBranchWithSuspect(AbckitCoreFunction * method,const std::vector<ConstantInfo> & constants,const SuspectsType & suspects)439 void EliminateBranchWithSuspect(AbckitCoreFunction *method, const std::vector<ConstantInfo> &constants,
440 const SuspectsType &suspects)
441 {
442 TransformMethod(method, [&](AbckitFile *, AbckitCoreFunction *method) {
443 AbckitGraph *graph = g_implI->createGraphFromFunction(method);
444 bool hasGraphChanged = ReplaceModuleVarByConstant(graph, constants, suspects);
445 bool continueLoop = true;
446 while (continueLoop) {
447 hasGraphChanged |= LoweringConstants(graph);
448
449 auto *ifInst = GraphInstsFindIf(graph, [&](AbckitInst *inst) { return IsEliminatableIfInst(inst); });
450
451 if (ifInst == nullptr) {
452 continueLoop = false;
453 } else {
454 DeleteUnreachableBranch(ifInst);
455 hasGraphChanged = true;
456 }
457 }
458
459 if (hasGraphChanged) {
460 g_implM->functionSetGraph(method, graph);
461 }
462 g_impl->destroyGraph(graph);
463 });
464 }
465
Run(const std::vector<ConstantInfo> & constants,AbckitFile * file)466 void Run(const std::vector<ConstantInfo> &constants, AbckitFile *file)
467 {
468 if (constants.empty()) {
469 return;
470 }
471 EnumerateModules(
472 [&](AbckitCoreModule *mod) {
473 SuspectsType suspects;
474 if (!GetSuspects(mod, constants, suspects)) {
475 return;
476 }
477 EnumerateModuleFunctions(
478 mod, [&](AbckitCoreFunction *func) { EliminateBranchWithSuspect(func, constants, suspects); });
479 },
480 file);
481 }
482 } // namespace
483
484 namespace libabckit::test {
485
MethodHasBranch(const std::string & moduleName,const std::string & methodName,AbckitFile * file)486 static bool MethodHasBranch(const std::string &moduleName, const std::string &methodName, AbckitFile *file)
487 {
488 bool found = false;
489 bool ret = false;
490 EnumerateModules(
491 [&](AbckitCoreModule *mod) {
492 if (g_implI->abckitStringToString(g_implI->moduleGetName(mod)) != moduleName) {
493 return;
494 }
495 EnumerateModuleFunctions(mod, [&](AbckitCoreFunction *func) {
496 if (found || g_implI->abckitStringToString(g_implI->functionGetName(func)) != methodName) {
497 return;
498 }
499 found = true;
500 auto *graph = g_implI->createGraphFromFunction(func);
501 auto *ifInst = GraphInstsFindIf(graph, [&](AbckitInst *inst) {
502 return g_dynG->iGetOpcode(inst) == ABCKIT_ISA_API_DYNAMIC_OPCODE_IF;
503 });
504 ret = ifInst != nullptr;
505 g_impl->destroyGraph(graph);
506 });
507 },
508 file);
509
510 EXPECT_TRUE(found);
511 return ret;
512 }
513
514 class AbckitScenarioCTestClean : public ::testing::Test {};
515
516 static constexpr bool CONFIG_IS_DEBUG_ORIGIN_VALUE = false;
517
518 /*
519 * @param value: the value of isDebug when we handle, it can be different from configIsDebugOriginValue
520 */
GetExpectOutput(bool value)521 static std::string GetExpectOutput(bool value)
522 {
523 std::stringstream expectOutput;
524 expectOutput << std::boolalpha;
525 expectOutput << "Config.isDebug = " << value << std::endl;
526 expectOutput << "myfoo: Config.isDebug is " << value << std::endl;
527 expectOutput << "Mybar.test1: Config.isDebug is " << value << std::endl;
528 expectOutput << "Mybar.test2: Config.isDebug is " << value << std::endl;
529 return expectOutput.str();
530 }
531
GeneralBranchEliminatorTest(bool configIsDebugFinal)532 static void GeneralBranchEliminatorTest(bool configIsDebugFinal)
533 {
534 constexpr auto INPUT_PATH = ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/branch_eliminator/branch_eliminator.abc";
535 AbckitFile *file = g_impl->openAbc(INPUT_PATH, strlen(INPUT_PATH));
536 ASSERT_NE(file, nullptr);
537
538 const auto actualOutput = helpers::ExecuteDynamicAbc(INPUT_PATH, "branch_eliminator");
539 auto expectedOutput = GetExpectOutput(CONFIG_IS_DEBUG_ORIGIN_VALUE);
540 EXPECT_TRUE(helpers::Match(actualOutput, expectedOutput));
541
542 ASSERT_TRUE(MethodHasBranch("modules/myfoo", "myfoo", file));
543 ASSERT_TRUE(MethodHasBranch("modules/mybar", "test1", file));
544 ASSERT_TRUE(MethodHasBranch("modules/mybar", "test2", file));
545 // Delete true branch
546 const std::vector<ConstantInfo> infos = {{"modules/config", "Config", "isDebug", configIsDebugFinal}};
547 Run(infos, file);
548 ASSERT_FALSE(MethodHasBranch("modules/myfoo", "myfoo", file));
549 ASSERT_FALSE(MethodHasBranch("modules/mybar", "test1", file));
550 ASSERT_FALSE(MethodHasBranch("modules/mybar", "test2", file));
551
552 constexpr auto OUTPUT_PATH =
553 ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/branch_eliminator/branch_eliminator_modified.abc";
554 g_impl->writeAbc(file, OUTPUT_PATH, strlen(OUTPUT_PATH));
555 g_impl->closeFile(file);
556 auto output = helpers::ExecuteDynamicAbc(OUTPUT_PATH, "branch_eliminator");
557 auto expectOutput2 = GetExpectOutput(configIsDebugFinal);
558 ASSERT_EQ(output, expectOutput2);
559 }
560
561 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioCTestClean,LibAbcKitTestDynamicBranchEliminatorClean1)562 TEST_F(AbckitScenarioCTestClean, LibAbcKitTestDynamicBranchEliminatorClean1)
563 {
564 GeneralBranchEliminatorTest(false);
565 }
566
567 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioCTestClean,LibAbcKitTestDynamicBranchEliminatorClean2)568 TEST_F(AbckitScenarioCTestClean, LibAbcKitTestDynamicBranchEliminatorClean2)
569 {
570 GeneralBranchEliminatorTest(true);
571 }
572
573 } // namespace libabckit::test
574