1 /*
2 * Copyright (c) 2023 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 <gtest/gtest.h>
17
18 #include "assembler/assembly-parser.h"
19 #include "codegen.h"
20 #include "compiler/optimizer/optimizations/cleanup.h"
21 #include "compiler/optimizer/optimizations/lowering.h"
22 #include "compiler/optimizer/optimizations/move_constants.h"
23 #include "compiler/optimizer/optimizations/regalloc/reg_alloc.h"
24 #include "compiler/optimizer/optimizations/vn.h"
25 #include "reg_acc_alloc.h"
26 #include "reg_encoder.h"
27 #include "graph_test.h"
28 #include "mem/pool_manager.h"
29
30 using namespace testing::ext;
31
32 namespace panda::bytecodeopt {
33 using namespace compiler;
34 using namespace pandasm;
35 using namespace panda;
36 class CodegenTest : public testing::Test {
37 public:
SetUpTestCase(void)38 static void SetUpTestCase(void) {}
TearDownTestCase(void)39 static void TearDownTestCase(void) {}
SetUp()40 void SetUp() {}
TearDown()41 void TearDown() {}
42
43 GraphTest graph_test_;
44 };
45
ParseAndEmit(const std::string & source)46 std::unique_ptr<const panda_file::File> ParseAndEmit(const std::string &source)
47 {
48 panda::pandasm::Parser parser;
49 auto res = parser.Parse(source);
50 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
51 auto &program = res.Value();
52 return AsmEmitter::Emit(program);
53 }
54
55 /**
56 * @tc.name: codegen_test_001
57 * @tc.desc: Verify the DoLda function.
58 * @tc.type: FUNC
59 * @tc.require: issueNumber
60 */
61 HWTEST_F(CodegenTest, codegen_test_001, TestSize.Level1)
62 {
63 Register reg = 1; // 1: It's a random number
64 std::vector<Ins> result;
65 DoLda(reg, result);
66 EXPECT_EQ(result[0].regs[0], reg);
67 EXPECT_EQ(result[0].opcode, panda::pandasm::Opcode::LDA);
68 }
69
70 /**
71 * @tc.name: codegen_test_002
72 * @tc.desc: Verify the DoSta function.
73 * @tc.type: FUNC
74 * @tc.require: issueNumber
75 */
76 HWTEST_F(CodegenTest, codegen_test_002, TestSize.Level1)
77 {
78 Register reg = 1; // 1: It's a random number
79 std::vector<Ins> result;
80 DoSta(reg, result);
81 EXPECT_EQ(result[0].regs[0], reg);
82 EXPECT_EQ(result[0].opcode, panda::pandasm::Opcode::STA);
83 }
84
85 /**
86 * @tc.name: codegen_test_003
87 * @tc.desc: Verify the EmitJump function.
88 * @tc.type: FUNC
89 * @tc.require: issueNumber
90 */
91 HWTEST_F(CodegenTest, codegen_test_003, TestSize.Level1)
92 {
93 std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
94 const char *test_method_name = "func1";
95 bool status = false;
96
__anona44e78530102(Graph* graph, std::string &method_name) 97 graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
98 if (test_method_name != method_name) {
99 return;
100 }
101
102 EXPECT_NE(graph, nullptr);
103 for (auto bb : graph->GetBlocksRPO()) {
104 EXPECT_NE(bb, nullptr);
105 if (bb->IsTryBegin()) {
106 status = true;
107 Function *function = nullptr;
108 BytecodeOptIrInterface *interface = nullptr;
109 Program *prog = nullptr;
110 BytecodeGen bc_gen(graph, function, interface, prog);
111 bc_gen.EmitJump(bb->GetSuccessor(1));
112 EXPECT_FALSE(bc_gen.GetResult().empty());
113 EXPECT_EQ(bc_gen.GetResult().back().ids[0], "label_6");
114 bc_gen.EmitJump(bb->GetSuccessor(0));
115 EXPECT_EQ(bc_gen.GetResult().back().ids[0], "label_3");
116 }
117 }
118 });
119 EXPECT_TRUE(status);
120 }
121
122 /**
123 * @tc.name: codegen_test_004
124 * @tc.desc: Verify the EmitJump function.
125 * @tc.type: FUNC
126 * @tc.require: issueNumber
127 */
128 HWTEST_F(CodegenTest, codegen_test_004, TestSize.Level1)
129 {
130 std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
131 const char *test_method_name = "func2";
132 bool status = false;
133
__anona44e78530202(Graph* graph, std::string &method_name) 134 graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
135 if (test_method_name != method_name) {
136 return;
137 }
138
139 EXPECT_NE(graph, nullptr);
140 for (auto bb : graph->GetBlocksRPO()) {
141 EXPECT_NE(bb, nullptr);
142 for(auto inst : bb->AllInsts()){
143 if(inst->GetOpcode() == Opcode::IfImm){
144 status = true;
145 Function *function = nullptr;
146 BytecodeOptIrInterface *interface = nullptr;
147 Program *prog = nullptr;
148 BytecodeGen bc_gen(graph, function, interface, prog);
149 bc_gen.EmitJump(bb);
150 EXPECT_FALSE(bc_gen.GetResult().empty());
151 EXPECT_EQ(bc_gen.GetResult().back().opcode, panda::pandasm::Opcode::JMP);
152 }
153 }
154 }
155 });
156 EXPECT_TRUE(status);
157 }
158
159 /**
160 * @tc.name: codegen_test_005
161 * @tc.desc: Verify the VisitConstant function.
162 * @tc.type: FUNC
163 * @tc.require: issueNumber
164 */
165 HWTEST_F(CodegenTest, codegen_test_005, TestSize.Level1)
166 {
167 std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
168 const char *test_method_name = "func5";
169 bool status = false;
170
__anona44e78530302(Graph* graph, std::string &method_name) 171 graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
172 if (test_method_name != method_name) {
173 return;
174 }
175
176 EXPECT_NE(graph, nullptr);
177 for (auto bb : graph->GetBlocksRPO()) {
178 for(auto inst : bb->AllInsts()) {
179 if (inst->GetOpcode() != Opcode::Constant) {
180 continue;
181 }
182 status = true;
183 Function *function = nullptr;
184 BytecodeOptIrInterface *interface = nullptr;
185 Program *prog = nullptr;
186
187 BytecodeGen graph_visitor(graph, function, interface, prog);
188
189 ConstantInst *const_inst = inst->CastToConstant();
190 const_inst->SetType(DataType::Type::INT64);
191 EXPECT_EQ(const_inst->GetType(), DataType::Type::INT64);
192 Register reg = INVALID_REG;
193 const_inst->SetDstReg(reg);
194 EXPECT_EQ(const_inst->GetDstReg(), reg);
195 BytecodeGen::VisitConstant(&graph_visitor, const_inst);
196 EXPECT_FALSE(graph_visitor.GetResult().empty());
197 EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::STA);
198
199 ConstantInst *const_inst1 = inst->CastToConstant();
200 const_inst1->SetType(DataType::Type::FLOAT64);
201 EXPECT_EQ(const_inst->GetType(), DataType::Type::FLOAT64);
202 const_inst1->SetDstReg(reg);
203 EXPECT_EQ(const_inst->GetDstReg(), reg);
204 BytecodeGen::VisitConstant(&graph_visitor, const_inst1);
205 EXPECT_FALSE(graph_visitor.GetResult().empty());
206 EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::STA);
207
208 ConstantInst *const_inst2 = inst->CastToConstant();
209 const_inst2->SetType(DataType::Type::INT32);
210 EXPECT_EQ(const_inst->GetType(), DataType::Type::INT32);
211 const_inst2->SetDstReg(reg);
212 EXPECT_EQ(const_inst->GetDstReg(), reg);
213 BytecodeGen::VisitConstant(&graph_visitor, const_inst2);
214 EXPECT_FALSE(graph_visitor.GetResult().empty());
215 EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::STA);
216 }
217 }
218 });
219 EXPECT_TRUE(status);
220 }
221
222 /**
223 * @tc.name: codegen_test_006
224 * @tc.desc: Verify the EncodeSta function.
225 * @tc.type: FUNC
226 * @tc.require: issueNumber
227 */
228 HWTEST_F(CodegenTest, codegen_test_006, TestSize.Level1)
229 {
230 std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
231 const char *test_method_name = "func1";
232 bool status = false;
233
__anona44e78530402(Graph* graph, std::string &method_name) 234 graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
235 if (test_method_name != method_name) {
236 return;
237 }
238
239 EXPECT_NE(graph, nullptr);
240 for (auto bb : graph->GetBlocksRPO()) {
241 EXPECT_NE(bb, nullptr);
242 if (bb->IsTryBegin()) {
243 status = true;
244 Register reg = 1; // 1: It's a random number
245 Function *function = nullptr;
246 BytecodeOptIrInterface *interface = nullptr;
247 Program *prog = nullptr;
248 BytecodeGen bc_gen(graph, function, interface, prog);
249 bc_gen.EncodeSta(reg, DataType::Type::ANY);
250 EXPECT_FALSE(bc_gen.GetResult().empty());
251 EXPECT_EQ(bc_gen.GetResult().back().opcode, panda::pandasm::Opcode::STA);
252 }
253 }
254 });
255 EXPECT_TRUE(status);
256 }
257
258 /**
259 * @tc.name: codegen_test_007
260 * @tc.desc: Verify the VisitLoadString function.
261 * @tc.type: FUNC
262 * @tc.require: issueNumber
263 */
264 HWTEST_F(CodegenTest, codegen_test_007, TestSize.Level1)
265 {
266 std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
267 const char *test_method_name = "func6";
268 bool status = false;
269
__anona44e78530502(Graph* graph, std::string &method_name) 270 graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
271 if (test_method_name != method_name) {
272 return;
273 }
274
275 EXPECT_NE(graph, nullptr);
276 for (auto bb : graph->GetVectorBlocks()) {
277 EXPECT_NE(bb, nullptr);
278 for(auto inst1 : bb->AllInsts()) {
279 if (inst1->GetOpcode() != Opcode::LoadString) {
280 continue;
281 }
282 status = true;
283 Function *function = nullptr;
284 Program *prog = nullptr;
285 AsmEmitter::PandaFileToPandaAsmMaps maps;
286 uint32_t id = 2; // 2: It's a random number
287 maps.strings.emplace(id, "i32[]");
288 BytecodeOptIrInterface interface(&maps, prog);
289
290 BytecodeGen graph_visitor(graph, function, &interface, prog);
291 auto inst = inst1->CastToLoadString();
292 inst->SetTypeId(2);
293
294 unsigned index = 5; // 5: It's a random number
295 unsigned size = 6; // 6: It's a random number
296 User user(true, index, size);
297 inst->AddUser(&user);
298
299 Register reg1 = ACC_REG_ID;
300 inst->SetDstReg(reg1);
301 BytecodeGen::VisitLoadString(&graph_visitor, inst);
302 EXPECT_FALSE(graph_visitor.GetResult().empty());
303 EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::LDA_STR);
304
305 Register reg2 = INVALID_REG;
306 inst->SetDstReg(reg2);
307 BytecodeGen::VisitLoadString(&graph_visitor, inst);
308 EXPECT_FALSE(graph_visitor.GetResult().empty());
309 EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::STA);
310 }
311 }
312 });
313 EXPECT_TRUE(status);
314 }
315
316 /**
317 * @tc.name: codegen_test_008
318 * @tc.desc: Verify the VisitDefault function.
319 * @tc.type: FUNC
320 * @tc.require: issueNumber
321 */
322 HWTEST_F(CodegenTest, codegen_test_008, TestSize.Level1)
323 {
324 std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
325 const char *test_method_name = "func1";
326 bool status = false;
327
__anona44e78530602(Graph* graph, std::string &method_name) 328 graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
329 if (test_method_name != method_name) {
330 return;
331 }
332
333 EXPECT_NE(graph, nullptr);
334 for (auto bb : graph->GetBlocksRPO()) {
335 EXPECT_NE(bb, nullptr);
336 if (bb->IsTryBegin()) {
337 status = true;
338 Function *function = nullptr;
339 BytecodeOptIrInterface *interface = nullptr;
340 Program *prog = nullptr;
341 BytecodeGen bc_gen(graph, function, interface, prog);
342 bc_gen.VisitDefault(bb->GetFirstInst());
343 EXPECT_FALSE(bc_gen.GetStatus());
344 }
345 }
346 });
347 EXPECT_TRUE(status);
348 }
349
350 /**
351 * @tc.name: codegen_test_009
352 * @tc.desc: Verify the GetLiteralArrayByOffset function.
353 * @tc.type: FUNC
354 * @tc.require: issueNumber
355 */
356 HWTEST_F(CodegenTest, codegen_test_009, TestSize.Level1)
357 {
358 AsmEmitter::PandaFileToPandaAsmMaps maps;
359 uint32_t id = 2; // 2: It's a random number
360 maps.literalarrays.emplace(id, "i32[]");
361 maps.strings.emplace(id, "i33[]");
362 Program *prog = nullptr;
363 BytecodeOptIrInterface interface(&maps, prog);
364
365 uint32_t offset = 2; // 2: It's a random number
366 EXPECT_EQ(interface.GetLiteralArrayByOffset(offset), "i32[]");
367 }
368
369 /**
370 * @tc.name: codegen_test_010
371 * @tc.desc: Verify the GetTypeIdByOffset function.
372 * @tc.type: FUNC
373 * @tc.require: issueNumber
374 */
375 HWTEST_F(CodegenTest, codegen_test_010, TestSize.Level1)
376 {
377 AsmEmitter::PandaFileToPandaAsmMaps maps;
378 uint32_t id = 2; // 2: It's a random number
379 maps.classes.emplace(id, "i32[]");
380 Program *prog = nullptr;
381 BytecodeOptIrInterface interface(&maps, prog);
382
383 uint32_t offset = 2; // 2: It's a random number
384 EXPECT_EQ(interface.GetTypeIdByOffset(offset), "i32[]");
385 }
386
387 /**
388 * @tc.name: codegen_test_011
389 * @tc.desc: Verify the GetFieldIdByOffset function.
390 * @tc.type: FUNC
391 * @tc.require: issueNumber
392 */
393 HWTEST_F(CodegenTest, codegen_test_011, TestSize.Level1)
394 {
395 AsmEmitter::PandaFileToPandaAsmMaps maps;
396 uint32_t id = 2; // 2: It's a random number
397 maps.fields.emplace(id, "i32[]");
398 Program *prog = nullptr;
399 BytecodeOptIrInterface interface(&maps, prog);
400
401 uint32_t offset = 2; // 2: It's a random number
402 interface.GetFieldIdByOffset(offset);
403 EXPECT_EQ(interface.GetFieldIdByOffset(offset), "i32[]");
404 EXPECT_TRUE(interface.IsMapsSet());
405 }
406
407
408 /**
409 * @tc.name: codegen_test_012
410 * @tc.desc: Verify the GetMethodArgumentsCount function.
411 * @tc.type: FUNC
412 * @tc.require: issueNumber
413 */
414 HWTEST_F(CodegenTest, codegen_test_012, TestSize.Level1)
415 {
416 auto source = std::string(R"(
417 .function u1 foo() {
418 sta v4
419 lda v4
420 return
421 }
422 )");
423 std::unique_ptr<const panda_file::File> pfile = ParseAndEmit(source);
424 BytecodeOptimizerRuntimeAdapter runtime_adapter(*pfile.get());
425
426 RuntimeInterface::MethodPtr caller = nullptr;
427 BytecodeOptimizerRuntimeAdapter::MethodId id = 251; // 251: It's a random number
428 EXPECT_EQ(runtime_adapter.GetMethodArgumentsCount(caller, id), 0);
429 }
430
431 /**
432 * @tc.name: codegen_test_013
433 * @tc.desc: Verify the GetMethodFullName function.
434 * @tc.type: FUNC
435 * @tc.require: issueNumber
436 */
437 HWTEST_F(CodegenTest, codegen_test_013, TestSize.Level1)
438 {
439 auto source = std::string(R"(
440 .function u1 foo() {
441 sta v4
442 lda v4
443 return
444 }
445 )");
446 std::unique_ptr<const panda_file::File> pfile = ParseAndEmit(source);
447 BytecodeOptimizerRuntimeAdapter runtime_adapter(*pfile.get());
448
449 int f = 222; // 222: It's a random number
450 RuntimeInterface::MethodPtr method;
451 method=(void*)(long)f;
452
453 EXPECT_EQ(runtime_adapter.GetMethodFullName(method, false), "L_ESSlotNumberAnnotation;::SlotNumber");
454 }
455
456 /**
457 * @tc.name: codegen_test_014
458 * @tc.desc: Verify the GetBlocksToVisit function.
459 * @tc.type: FUNC
460 * @tc.require: issueNumber
461 */
462 HWTEST_F(CodegenTest, codegen_test_014, TestSize.Level1)
463 {
464 std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
465 const char *test_method_name = "func1";
466 bool status = false;
467
__anona44e78530702(Graph* graph, std::string &method_name) 468 graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
469 if (test_method_name != method_name) {
470 return;
471 }
472 status = true;
473 EXPECT_NE(graph, nullptr);
474
475 Function *function = nullptr;
476 BytecodeOptIrInterface *interface = nullptr;
477 Program *prog = nullptr;
478 size_t size = 10; // 10: It's block size
479 BytecodeGen bc_gen(graph, function, interface, prog);
480 EXPECT_EQ(bc_gen.GetBlocksToVisit().size(), size);
481 });
482 EXPECT_TRUE(status);
483 }
484
485 /**
486 * @tc.name: codegen_test_015
487 * @tc.desc: Verify the RunImpl function.
488 * @tc.type: FUNC
489 * @tc.require: issueNumber
490 */
491 HWTEST_F(CodegenTest, codegen_test_015, TestSize.Level1)
492 {
493 const auto source = R"(
494 .function any func_main_0(any a0, any a1, any a2) <static> {
495 mov v0, a0
496 mov v1, a1
497 mov v2, a2
498 try_begin_label_0:
499 ldai 0x1
500 trystglobalbyname 0x0, "a"
501 try_end_label_0:
502 jmp handler_end_label_0_0
503 handler_begin_label_0_0:
504 sta v4
505 ldai 0x2
506 trystglobalbyname 0x1, "a"
507 handler_end_label_0_0:
508 ldundefined
509 returnundefined
510
511 .catchall try_begin_label_0, try_end_label_0, handler_begin_label_0_0, handler_end_label_0_0
512 }
513 )";
514
515 panda::pandasm::Parser parser;
516 auto res = parser.Parse(source);
517 auto &prog = res.Value();
518
519 auto &function = prog.function_table.at("func_main_0:(any,any,any)");
520
521 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
522 auto ir_interface = panda::bytecodeopt::BytecodeOptIrInterface(&maps, &prog);
523 bool status = false;
524
525 graph_test_.TestBuildGraphFromFunc(prog, "func_main_0:(any,any,any)", maps, ir_interface, [&function,
__anona44e78530802(Graph* graph) 526 &ir_interface, &prog, &status](Graph* graph) {
527
528 EXPECT_NE(graph, nullptr);
529 int32_t pc = -1; // -1: It's a random number
530 uint8_t id1 = 2; // 2: It's a random number
531 TypeInfoIndex type = static_cast<BuiltinIndexType>(id1);
532 graph->GetRuntime()->AddPcTypePair(pc, type);
533
534 size_t id = 13; // 13: It's a random number
535 graph->GetRuntime()->FillInstIdTypePairByPc(id, pc);
536
537 for (auto bb : graph->GetBlocksRPO()) {
538 EXPECT_NE(bb, nullptr);
539 if(bb->IsTryBegin()){
540 status = true;
541 graph->AppendTryBeginBlock(bb);
542 }
543 }
544 EXPECT_TRUE(graph->RunPass<compiler::Cleanup>());
545 LiteralArray lit;
546 const auto &key = *(graph->GetRuntime()->GetTypeLiteralArrayKey());
547 prog.literalarray_table[key] = lit;
548
549 EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
550 EXPECT_FALSE(graph->RunPass<panda::compiler::ValNum>());
551 EXPECT_TRUE(graph->RunPass<panda::compiler::Lowering>());
552 EXPECT_TRUE(graph->RunPass<panda::compiler::MoveConstants>());
553 EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
554 EXPECT_TRUE(graph->RunPass<RegAccAlloc>());
555 EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
556 EXPECT_TRUE(RegAlloc(graph));
557 EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
558 EXPECT_TRUE(graph->RunPass<RegEncoder>());
559
560 EXPECT_TRUE(graph->RunPass<BytecodeGen>(&function, &ir_interface, &prog));
561 });
562 EXPECT_TRUE(status);
563 }
564 } // namespace panda::bytecodeopt
565