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