• 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:
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