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 "libabckit/include/c/isa/isa_dynamic.h"
19 #include "libabckit/include/c/abckit.h"
20
21 #include "helpers/helpers.h"
22 #include "helpers/helpers_runtime.h"
23
24 #include <gtest/gtest.h>
25
26 // NOLINTBEGIN(readability-magic-numbers)
27 namespace libabckit::test {
28
29 static auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
30 static auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
31 static auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
32 static auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
33 static auto g_dynG = AbckitGetIsaApiDynamicImpl(ABCKIT_VERSION_RELEASE_1_0_0);
34
35 class LibAbcKitCreateDynCall : public ::testing::Test {};
36
CreateBBSchemaForDynCall(AbckitIsaApiDynamicOpcode opcode)37 static std::vector<helpers::BBSchema<AbckitIsaApiDynamicOpcode>> CreateBBSchemaForDynCall(
38 AbckitIsaApiDynamicOpcode opcode)
39 {
40 auto paramOp = ABCKIT_ISA_API_DYNAMIC_OPCODE_PARAMETER;
41 auto constOp = ABCKIT_ISA_API_DYNAMIC_OPCODE_CONSTANT;
42 helpers::InstSchema<AbckitIsaApiDynamicOpcode> callInstSchema {0, ABCKIT_ISA_API_DYNAMIC_OPCODE_INVALID, {}};
43 std::vector<helpers::InstSchema<AbckitIsaApiDynamicOpcode>> params {
44 {0, paramOp, {}}, {1, paramOp, {}}, {2, paramOp, {}}};
45 switch (opcode) {
46 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG0:
47 callInstSchema = {4, opcode, {3}};
48 break;
49 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG1:
50 params = {{0, paramOp, {}}, {1, paramOp, {}}, {2, paramOp, {}}, {4, constOp, {}}};
51 callInstSchema = {4, opcode, {3, 4}};
52 break;
53 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARGS2:
54 params = {
55 {0, paramOp, {}}, {1, paramOp, {}}, {2, paramOp, {}}, {4, constOp, {}}, {5, constOp, {}},
56 };
57 callInstSchema = {4, opcode, {3, 4, 5}};
58 break;
59 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARGS3:
60 params = {
61 {0, paramOp, {}}, {1, paramOp, {}}, {2, paramOp, {}},
62 {4, constOp, {}}, {5, constOp, {}}, {6, constOp, {}},
63 };
64 callInstSchema = {4, opcode, {3, 4, 5, 6}};
65 break;
66 case ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLRANGE:
67 case ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_CALLRANGE:
68 params = {
69 {0, paramOp, {}}, {1, paramOp, {}}, {2, paramOp, {}}, {4, constOp, {}},
70 {5, constOp, {}}, {6, constOp, {}}, {7, constOp, {}},
71 };
72 callInstSchema = {4, opcode, {3, 4, 5, 6, 7}};
73 break;
74 case ABCKIT_ISA_API_DYNAMIC_OPCODE_INVALID:
75 break;
76 default:
77 LIBABCKIT_UNREACHABLE_TEST(DEBUG);
78 }
79 return {{{}, {1}, params},
80 {{0},
81 {2},
82 {
83 {3, ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINEFUNC, {}},
84 callInstSchema,
85 {8, ABCKIT_ISA_API_DYNAMIC_OPCODE_RETURNUNDEFINED, {}},
86 }},
87 {{1}, {}, {}}};
88 }
89
TestHelper(void (* transformIrCall)(AbckitGraph * graph),AbckitIsaApiDynamicOpcode opcode,const std::string & expectedOutput,bool execute=true)90 static void TestHelper(void (*transformIrCall)(AbckitGraph *graph), AbckitIsaApiDynamicOpcode opcode,
91 const std::string &expectedOutput, bool execute = true)
92 {
93 auto output =
94 helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/isa/isa_dynamic/dyn_call/call_dynamic.abc", "call_dynamic");
95 EXPECT_TRUE(helpers::Match(output, ""));
96
97 helpers::TransformMethod(
98 ABCKIT_ABC_DIR "ut/isa/isa_dynamic/dyn_call/call_dynamic.abc",
99 ABCKIT_ABC_DIR "ut/isa/isa_dynamic/dyn_call/call_dynamic_modified.abc", "call_dynamic.func_main_0",
100 [&](AbckitFile * /*file*/, AbckitCoreFunction * /*method*/, AbckitGraph *graph) {
101 transformIrCall(graph);
102 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
103 },
104 [&](AbckitGraph *graph) {
105 std::vector<helpers::BBSchema<AbckitIsaApiDynamicOpcode>> bbSchemas(CreateBBSchemaForDynCall(opcode));
106 helpers::VerifyGraph(graph, bbSchemas);
107 });
108
109 if (execute) {
110 output = helpers::ExecuteDynamicAbc(ABCKIT_ABC_DIR "ut/isa/isa_dynamic/dyn_call/call_dynamic_modified.abc",
111 "call_dynamic");
112 EXPECT_TRUE(helpers::Match(output, expectedOutput));
113 }
114 }
115
TransformIrCallarg0(AbckitGraph * graph)116 static void TransformIrCallarg0(AbckitGraph *graph)
117 {
118 auto func = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINEFUNC);
119 ASSERT_NE(func, nullptr);
120 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
121
122 auto call0 = g_dynG->iCreateCallarg0(graph, func);
123 ASSERT_NE(call0, nullptr);
124 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
125
126 g_implG->iInsertAfter(call0, func);
127 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
128 }
129
TransformIrCallarg1(AbckitGraph * graph)130 static void TransformIrCallarg1(AbckitGraph *graph)
131 {
132 auto func = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINEFUNC);
133 ASSERT_NE(func, nullptr);
134 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
135
136 auto param0 = g_implG->gFindOrCreateConstantI64(graph, 1);
137 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
138
139 auto call1 = g_dynG->iCreateCallarg1(graph, func, param0);
140 ASSERT_NE(call1, nullptr);
141 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
142
143 g_implG->iInsertAfter(call1, func);
144 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
145 }
146
TransformIrCallargs2(AbckitGraph * graph)147 static void TransformIrCallargs2(AbckitGraph *graph)
148 {
149 auto func = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINEFUNC);
150 ASSERT_NE(func, nullptr);
151 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
152
153 auto param0 = g_implG->gFindOrCreateConstantI64(graph, 1);
154 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
155 auto param1 = g_implG->gFindOrCreateConstantI64(graph, 2);
156 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
157
158 auto call2 = g_dynG->iCreateCallargs2(graph, func, param0, param1);
159 ASSERT_NE(call2, nullptr);
160 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
161
162 g_implG->iInsertAfter(call2, func);
163 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
164 }
165
TransformIrCallargs3(AbckitGraph * graph)166 static void TransformIrCallargs3(AbckitGraph *graph)
167 {
168 auto func = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINEFUNC);
169 ASSERT_NE(func, nullptr);
170 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
171
172 auto param0 = g_implG->gFindOrCreateConstantI64(graph, 1);
173 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
174 auto param1 = g_implG->gFindOrCreateConstantI64(graph, 2);
175 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
176 auto param2 = g_implG->gFindOrCreateConstantI64(graph, 3);
177 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
178
179 auto call3 = g_dynG->iCreateCallargs3(graph, func, param0, param1, param2);
180 ASSERT_NE(call3, nullptr);
181 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
182
183 g_implG->iInsertAfter(call3, func);
184 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
185 }
186
TransformIrCallrange(AbckitGraph * graph)187 static void TransformIrCallrange(AbckitGraph *graph)
188 {
189 auto func = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINEFUNC);
190 ASSERT_NE(func, nullptr);
191 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
192
193 auto param0 = g_implG->gFindOrCreateConstantI64(graph, 1);
194 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
195 auto param1 = g_implG->gFindOrCreateConstantI64(graph, 2);
196 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
197 auto param2 = g_implG->gFindOrCreateConstantI64(graph, 3);
198 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
199 auto param3 = g_implG->gFindOrCreateConstantI64(graph, 4);
200 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
201
202 auto call4 = g_dynG->iCreateCallrange(graph, func, 4, param0, param1, param2, param3);
203 ASSERT_NE(call4, nullptr);
204 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
205
206 g_implG->iInsertAfter(call4, func);
207 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
208 }
209
TransformIrWideCallrange(AbckitGraph * graph)210 static void TransformIrWideCallrange(AbckitGraph *graph)
211 {
212 auto func = helpers::FindFirstInst(graph, ABCKIT_ISA_API_DYNAMIC_OPCODE_DEFINEFUNC);
213 ASSERT_NE(func, nullptr);
214 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
215
216 auto param0 = g_implG->gFindOrCreateConstantI64(graph, 1);
217 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
218 auto param1 = g_implG->gFindOrCreateConstantI64(graph, 2);
219 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
220 auto param2 = g_implG->gFindOrCreateConstantI64(graph, 3);
221 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
222 auto param3 = g_implG->gFindOrCreateConstantI64(graph, 4);
223 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
224
225 auto call4 = g_dynG->iCreateWideCallrange(graph, func, 4, param0, param1, param2, param3);
226 ASSERT_NE(call4, nullptr);
227 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
228
229 g_implG->iInsertAfter(call4, func);
230 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
231 }
232
233 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateCallarg0, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynCall,CreateDynCallarg0)234 TEST_F(LibAbcKitCreateDynCall, CreateDynCallarg0)
235 {
236 TestHelper(TransformIrCallarg0, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG0, "func\n");
237 }
238
239 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateCallarg1, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynCall,CreateDynCallarg1)240 TEST_F(LibAbcKitCreateDynCall, CreateDynCallarg1)
241 {
242 TestHelper(TransformIrCallarg1, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARG1, "func\n1\n");
243 }
244
245 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateCallargs2, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynCall,CreateDynCallargs2)246 TEST_F(LibAbcKitCreateDynCall, CreateDynCallargs2)
247 {
248 TestHelper(TransformIrCallargs2, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARGS2, "func\n1\n2\n");
249 }
250
251 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateCallargs3, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynCall,CreateDynCallargs3)252 TEST_F(LibAbcKitCreateDynCall, CreateDynCallargs3)
253 {
254 TestHelper(TransformIrCallargs3, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLARGS3, "func\n1\n2\n3\n");
255 }
256
257 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateCallrange, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynCall,CreateDynCallrange)258 TEST_F(LibAbcKitCreateDynCall, CreateDynCallrange)
259 {
260 TestHelper(TransformIrCallrange, ABCKIT_ISA_API_DYNAMIC_OPCODE_CALLRANGE, "func\n1\n2\n3\n4\n");
261 }
262
263 // Test: test-kind=api, api=IsaApiDynamicImpl::iCreateWideCallrange, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(LibAbcKitCreateDynCall,CreateDynWideCallrange)264 TEST_F(LibAbcKitCreateDynCall, CreateDynWideCallrange)
265 {
266 // Temporary doesn't execute due to Dynamic VM runtime bug #IA954E
267 TestHelper(TransformIrWideCallrange, ABCKIT_ISA_API_DYNAMIC_OPCODE_WIDE_CALLRANGE, "func\n1\n2\n3\n4\n", false);
268 }
269
270 } // namespace libabckit::test
271 // NOLINTEND(readability-magic-numbers)
272