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 #include <iostream>
18
19 #include <gtest/gtest.h>
20
21 #include "libabckit/include/c/abckit.h"
22 #include "libabckit/include/c/isa/isa_dynamic.h"
23 #include "helpers/helpers_runtime.h"
24
25 #include "branch_eliminator.h"
26 #include "helpers/helpers.h"
27
28 namespace libabckit::test {
29
30 static constexpr auto VERSION = ABCKIT_VERSION_RELEASE_1_0_0;
31 static const AbckitApi *g_impl = AbckitGetApiImpl(VERSION);
32 static const AbckitInspectApi *g_implI = AbckitGetInspectApiImpl(VERSION);
33 static const AbckitGraphApi *g_implG = AbckitGetGraphApiImpl(VERSION);
34 static const AbckitIsaApiDynamic *g_dynG = AbckitGetIsaApiDynamicImpl(VERSION);
35
MethodHasBranch(const std::string & moduleName,const std::string & methodName,AbckitFile * file)36 static bool MethodHasBranch(const std::string &moduleName, const std::string &methodName, AbckitFile *file)
37 {
38 EXPECT_NE(file, nullptr);
39 EXPECT_NE(g_impl, nullptr);
40 EXPECT_NE(g_implI, nullptr);
41 EXPECT_NE(g_implG, nullptr);
42 EXPECT_NE(g_dynG, nullptr);
43 VisitHelper vh = VisitHelper(file, g_impl, g_implI, g_implG, g_dynG);
44 bool found = false;
45 bool ret = false;
46 vh.EnumerateModules([&](AbckitCoreModule *mod) {
47 if (vh.GetString(g_implI->moduleGetName(mod)) != moduleName) {
48 return;
49 }
50 vh.EnumerateModuleFunctions(mod, [&](AbckitCoreFunction *func) {
51 if (found || vh.GetString(g_implI->functionGetName(func)) != methodName) {
52 return;
53 }
54 found = true;
55 auto *graph = g_implI->createGraphFromFunction(func);
56 auto *ifInst = vh.GraphInstsFindIf(
57 graph, [&](AbckitInst *inst) { return g_dynG->iGetOpcode(inst) == ABCKIT_ISA_API_DYNAMIC_OPCODE_IF; });
58 ret = ifInst != nullptr;
59 g_impl->destroyGraph(graph);
60 });
61 });
62
63 EXPECT_TRUE(found);
64 return ret;
65 }
66
67 class AbckitScenarioTest : public ::testing::Test {};
68
69 static const std::string DIR = std::string(ABCKIT_ABC_DIR "scenarios/branch_eliminator/dynamic/");
70 static const std::string INPUT = DIR + "branch_eliminator.abc";
71 static constexpr bool CONFIG_IS_DEBUG_ORIGIN_VALUE = false;
72
73 /*
74 * @param value: the value of isDebug when we handle, it can be different from configIsDebugOriginValue
75 */
GetExpectOutput(bool value)76 static std::string GetExpectOutput(bool value)
77 {
78 std::stringstream expectOutput;
79 expectOutput << std::boolalpha;
80 expectOutput << "Config.isDebug = " << value << std::endl;
81 expectOutput << "myfoo: Config.isDebug is " << value << std::endl;
82 expectOutput << "Mybar.test1: Config.isDebug is " << value << std::endl;
83 expectOutput << "Mybar.test2: Config.isDebug is " << value << std::endl;
84 return expectOutput.str();
85 }
86
GeneralBranchEliminatorTest(bool configIsDebugFinal)87 static void GeneralBranchEliminatorTest(bool configIsDebugFinal)
88 {
89 auto *impl = AbckitGetApiImpl(VERSION);
90 const auto originOutput = helpers::ExecuteDynamicAbc(INPUT, "branch_eliminator");
91
92 auto expectOutput = GetExpectOutput(CONFIG_IS_DEBUG_ORIGIN_VALUE);
93 ASSERT_EQ(originOutput, expectOutput);
94
95 AbckitFile *file = impl->openAbc(INPUT.c_str(), INPUT.size());
96 ASSERT_NE(file, nullptr);
97 ASSERT_TRUE(MethodHasBranch("modules/myfoo", "myfoo", file));
98 ASSERT_TRUE(MethodHasBranch("modules/mybar", "test1", file));
99 ASSERT_TRUE(MethodHasBranch("modules/mybar", "test2", file));
100 // Delete true branch
101 const std::vector<ConstantInfo> infos = {{"modules/config", "Config", "isDebug", configIsDebugFinal}};
102 BranchEliminator b(VERSION, file, infos);
103 b.Run();
104 ASSERT_FALSE(MethodHasBranch("modules/myfoo", "myfoo", file));
105 ASSERT_FALSE(MethodHasBranch("modules/mybar", "test1", file));
106 ASSERT_FALSE(MethodHasBranch("modules/mybar", "test2", file));
107
108 const auto modifiedPath = DIR + "branch_eliminator_modified.abc";
109 impl->writeAbc(file, modifiedPath.c_str(), modifiedPath.size());
110 g_impl->closeFile(file);
111 auto output = helpers::ExecuteDynamicAbc(modifiedPath, "branch_eliminator");
112 auto expectOutput2 = GetExpectOutput(configIsDebugFinal);
113 ASSERT_EQ(output, expectOutput2);
114 }
115
116 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioTest,LibAbcKitTestBranchEliminatorDynamic1)117 TEST_F(AbckitScenarioTest, LibAbcKitTestBranchEliminatorDynamic1)
118 {
119 GeneralBranchEliminatorTest(false);
120 }
121
122 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioTest,LibAbcKitTestBranchEliminatorDynamic2)123 TEST_F(AbckitScenarioTest, LibAbcKitTestBranchEliminatorDynamic2)
124 {
125 GeneralBranchEliminatorTest(true);
126 }
127
128 } // namespace libabckit::test
129