• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 <random>
17 
18 #include "optimizer/code_generator/codegen.h"
19 #include "optimizer/ir/basicblock.h"
20 #include "optimizer/ir/inst.h"
21 #include "optimizer/optimizations/if_conversion.h"
22 #include "optimizer/optimizations/lowering.h"
23 #include "optimizer/optimizations/regalloc/reg_alloc.h"
24 #include "optimizer/optimizations/regalloc/reg_alloc_linear_scan.h"
25 #include "optimizer_run.h"
26 
27 #include "gtest/gtest.h"
28 #include "libpandabase/macros.h"
29 #include "unit_test.h"
30 #include "utils/bit_utils.h"
31 #include "vixl_exec_module.h"
32 
33 const uint64_t SEED = 0x1234;
34 #ifndef PANDA_NIGHTLY_TEST_ON
35 const uint64_t ITERATION = 40;
36 #else
37 const uint64_t ITERATION = 20000;
38 #endif
39 static inline auto random_generator = std::mt19937_64(SEED);
40 
41 namespace panda::compiler {
42 namespace {
43 template <typename T>
Compare(ConditionCode cc,T lhs,T rhs)44 bool Compare(ConditionCode cc, T lhs, T rhs)
45 {
46     using signed_t = std::make_signed_t<T>;
47     using unsigned_t = std::make_unsigned_t<T>;
48     unsigned_t lhs_u = bit_cast<unsigned_t>(lhs);
49     unsigned_t rhs_u = bit_cast<unsigned_t>(rhs);
50     signed_t lhs_s = bit_cast<signed_t>(lhs);
51     signed_t rhs_s = bit_cast<signed_t>(rhs);
52 
53     switch (cc) {
54         case ConditionCode::CC_EQ:
55             return lhs_u == rhs_u;
56         case ConditionCode::CC_NE:
57             return lhs_u != rhs_u;
58         case ConditionCode::CC_LT:
59             return lhs_s < rhs_s;
60         case ConditionCode::CC_LE:
61             return lhs_s <= rhs_s;
62         case ConditionCode::CC_GT:
63             return lhs_s > rhs_s;
64         case ConditionCode::CC_GE:
65             return lhs_s >= rhs_s;
66         case ConditionCode::CC_B:
67             return lhs_u < rhs_u;
68         case ConditionCode::CC_BE:
69             return lhs_u <= rhs_u;
70         case ConditionCode::CC_A:
71             return lhs_u > rhs_u;
72         case ConditionCode::CC_AE:
73             return lhs_u >= rhs_u;
74         case ConditionCode::CC_TST_EQ:
75             return (lhs_u & rhs_u) == 0;
76         case ConditionCode::CC_TST_NE:
77             return (lhs_u & rhs_u) != 0;
78         default:
79             UNREACHABLE();
80             return false;
81     }
82 }
83 }  // namespace
84 
85 class CodegenTest : public GraphTest {
86 public:
CodegenTest()87     CodegenTest() : exec_module_(GetAllocator(), GetGraph()->GetRuntime())
88     {
89 #ifndef NDEBUG
90         // GraphChecker hack: LowLevel instructions may appear only after Lowering pass:
91         GetGraph()->SetLowLevelInstructionsEnabled();
92 #endif
93     }
~CodegenTest()94     ~CodegenTest() override {}
95 
GetExecModule()96     VixlExecModule &GetExecModule()
97     {
98         return exec_module_;
99     }
100 
101     template <typename T>
102     void CheckStoreArray();
103 
104     template <typename T>
105     void CheckLoadArray();
106 
107     template <typename T>
108     void CheckStoreArrayPair(bool imm);
109 
110     template <typename T>
111     void CheckLoadArrayPair(bool imm);
112 
113     template <typename T>
114     void CheckCmp(bool is_fcmpg = false);
115 
116     template <typename T>
117     void CheckReturnValue(Graph *graph, T expected_value);
118 
119     template <typename T>
120     void CheckBounds(uint64_t count);
121 
122     void TestBinaryOperationWithShiftedOperand(Opcode opcode, uint32_t l, uint32_t r, ShiftType shift_type,
123                                                uint32_t shift, uint32_t erv);
124 
125 private:
126     VixlExecModule exec_module_;
127 };
128 
RunCodegen(Graph * graph)129 bool RunCodegen(Graph *graph)
130 {
131     if (!graph->RunPass<Codegen>()) {
132         return false;
133     }
134     return true;
135 }
136 
TEST_F(CodegenTest,SimpleProgramm)137 TEST_F(CodegenTest, SimpleProgramm)
138 {
139     /*
140     .function main()<main>{
141         movi.64 v0, 100000000           ##      0 -> 3      ##  bb0
142         movi.64 v1, 4294967296          ##      1 -> 4      ##  bb0
143         ldai 0                          ##      2 -> 5      ##  bb0
144     loop:                               ##                  ##
145         jeq v0, loop_exit               ##      6, 7, 8     ##  bb1
146                                         ##                  ##
147         sta.64 v2                       ##      9           ##  bb2
148         and.64 v1                       ##      10          ##  bb2
149         sta.64 v1                       ##      11          ##  bb2
150         lda.64 v2                       ##      12          ##  bb2
151         inc                             ##      13          ##  bb2
152         jmp loop                        ##      14          ##  bb2
153     loop_exit:                          ##                  ##
154         lda.64 v1                       ##      14          ##  bb3
155         return.64                       ##      15          ##  bb3
156     }
157     */
158 
159     GRAPH(GetGraph())
160     {
161         CONSTANT(0, 10UL);          // r1
162         CONSTANT(1, 4294967296UL);  // r2
163         CONSTANT(2, 0UL);           // r3 -> acc(3)
164         CONSTANT(3, 0x1UL);         // r20 -> 0x1 (for inc constant)
165 
166         BASIC_BLOCK(2, 4, 3)
167         {
168             INST(16, Opcode::Phi).Inputs(2, 13).s64();  // PHI acc
169             INST(17, Opcode::Phi).Inputs(1, 10).s64();  // PHI  v1
170             INST(20, Opcode::Phi).Inputs(2, 10).s64();  // result to return
171 
172             // TODO (igorban): support CMP instr
173             INST(18, Opcode::Compare).b().CC(CC_NE).Inputs(0, 16);
174             INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(18);
175         }
176 
177         BASIC_BLOCK(3, 2)
178         {
179             INST(10, Opcode::And).Inputs(16, 17).s64();  // -> acc
180             INST(13, Opcode::Add).Inputs(16, 3).s64();   // -> acc
181         }
182 
183         BASIC_BLOCK(4, -1)
184         {
185             INST(19, Opcode::Return).Inputs(20).s64();
186         }
187     }
188 
189     SetNumVirtRegs(0);
190     SetNumArgs(1);
191 
192     RegAlloc(GetGraph());
193 
194     // call codegen
195     EXPECT_TRUE(RunCodegen(GetGraph()));
196     auto entry = reinterpret_cast<char *>(GetGraph()->GetData().Data());
197     auto exit = entry + GetGraph()->GetData().Size();
198     ASSERT(entry != nullptr && exit != nullptr);
199     GetExecModule().SetInstructions(entry, exit);
200     GetExecModule().SetDump(false);
201 
202     GetExecModule().Execute();
203 
204     auto ret_data = GetExecModule().GetRetValue();
205     EXPECT_EQ(ret_data, 0U);
206 
207     // Clear data for next execution
208     while (auto current = GetGraph()->GetFirstConstInst()) {
209         GetGraph()->RemoveConstFromList(current);
210     }
211 }
212 
213 template <typename T>
CheckStoreArray()214 void CodegenTest::CheckStoreArray()
215 {
216     constexpr DataType::Type type = VixlExecModule::GetType<T>();
217 
218     // Create graph
219     auto graph = CreateEmptyGraph();
220     RuntimeInterfaceMock runtime;
221     graph->SetRuntime(&runtime);
222 
223     auto entry = graph->CreateStartBlock();
224     auto exit = graph->CreateEndBlock();
225     auto block = graph->CreateEmptyBlock();
226     entry->AddSucc(block);
227     block->AddSucc(exit);
228 
229     auto array = graph->AddNewParameter(0, DataType::REFERENCE);
230     auto index = graph->AddNewParameter(1, DataType::INT32);
231     auto store_value = graph->AddNewParameter(2, type);
232 
233     graph->ResetParameterInfo();
234     array->SetLocationData(graph->GetDataForNativeParam(DataType::REFERENCE));
235     index->SetLocationData(graph->GetDataForNativeParam(DataType::INT32));
236     store_value->SetLocationData(graph->GetDataForNativeParam(type));
237 
238     auto st_arr = graph->CreateInst(Opcode::StoreArray);
239     block->AppendInst(st_arr);
240     st_arr->SetType(type);
241     st_arr->SetInput(0, array);
242     st_arr->SetInput(1, index);
243     st_arr->SetInput(2, store_value);
244     auto ret = graph->CreateInst(Opcode::ReturnVoid);
245     block->AppendInst(ret);
246 
247     SetNumVirtRegs(0);
248     SetNumArgs(3);
249 
250     RegAlloc(graph);
251 
252     // call codegen
253     EXPECT_TRUE(RunCodegen(graph));
254     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
255     auto code_exit = code_entry + graph->GetData().Size();
256     ASSERT(code_entry != nullptr && code_exit != nullptr);
257     GetExecModule().SetInstructions(code_entry, code_exit);
258 
259     GetExecModule().SetDump(false);
260 
261     T array_data[4];
262     auto default_value = CutValue<T>(0, type);
263     for (auto i = 0; i < 4; i++) {
264         array_data[i] = default_value;
265     }
266     auto param_1 = GetExecModule().CreateArray(array_data, 4, GetObjectAllocator());
267     auto param_2 = CutValue<int32_t>(2, DataType::INT32);
268     auto param_3 = CutValue<T>(10, type);
269     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
270     GetExecModule().SetParameter(1U, param_2);
271     GetExecModule().SetParameter(2U, param_3);
272 
273     GetExecModule().Execute();
274 
275     GetExecModule().CopyArray(param_1, array_data);
276 
277     for (auto i = 0; i < 4; i++) {
278         if (i == 2) {
279             EXPECT_EQ(array_data[i], param_3);
280         } else {
281             EXPECT_EQ(array_data[i], default_value);
282         }
283     }
284     GetExecModule().FreeArray(param_1);
285 }
286 
287 template <typename T>
CheckLoadArray()288 void CodegenTest::CheckLoadArray()
289 {
290     constexpr DataType::Type type = VixlExecModule::GetType<T>();
291 
292     // Create graph
293     auto graph = CreateEmptyGraph();
294     RuntimeInterfaceMock runtime;
295     graph->SetRuntime(&runtime);
296 
297     auto entry = graph->CreateStartBlock();
298     auto exit = graph->CreateEndBlock();
299     auto block = graph->CreateEmptyBlock();
300     entry->AddSucc(block);
301     block->AddSucc(exit);
302 
303     auto array = graph->AddNewParameter(0, DataType::REFERENCE);
304     auto index = graph->AddNewParameter(1, DataType::INT32);
305 
306     graph->ResetParameterInfo();
307     array->SetLocationData(graph->GetDataForNativeParam(DataType::REFERENCE));
308     index->SetLocationData(graph->GetDataForNativeParam(DataType::INT32));
309 
310     auto ld_arr = graph->CreateInst(Opcode::LoadArray);
311     block->AppendInst(ld_arr);
312     ld_arr->SetType(type);
313     ld_arr->SetInput(0, array);
314     ld_arr->SetInput(1, index);
315     auto ret = graph->CreateInst(Opcode::Return);
316     ret->SetType(type);
317     ret->SetInput(0, ld_arr);
318     block->AppendInst(ret);
319 
320     SetNumVirtRegs(0);
321     SetNumArgs(2);
322 
323     RegAlloc(graph);
324 
325     EXPECT_TRUE(RunCodegen(graph));
326     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
327     auto code_exit = code_entry + graph->GetData().Size();
328     ASSERT(code_entry != nullptr && code_exit != nullptr);
329     GetExecModule().SetInstructions(code_entry, code_exit);
330 
331     GetExecModule().SetDump(false);
332 
333     T array_data[4];
334     for (auto i = 0; i < 4; i++) {
335         array_data[i] = CutValue<T>((-i), type);
336     }
337     auto param_1 = GetExecModule().CreateArray(array_data, 4, GetObjectAllocator());
338     auto param_2 = CutValue<int32_t>(2, DataType::INT32);
339     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
340     GetExecModule().SetParameter(1U, param_2);
341 
342     GetExecModule().Execute();
343 
344     GetExecModule().CopyArray(param_1, array_data);
345 
346     GetExecModule().FreeArray(param_1);
347 
348     auto ret_data = GetExecModule().GetRetValue<T>();
349     EXPECT_EQ(ret_data, CutValue<T>(-2, type));
350 }
351 
352 template <typename T>
CheckStoreArrayPair(bool imm)353 void CodegenTest::CheckStoreArrayPair(bool imm)
354 {
355     constexpr DataType::Type type = VixlExecModule::GetType<T>();
356 
357     // Create graph
358     auto graph = CreateEmptyGraph();
359     RuntimeInterfaceMock runtime;
360     graph->SetRuntime(&runtime);
361 #ifndef NDEBUG
362     // GraphChecker hack: LowLevel instructions may appear only after Lowering pass:
363     graph->SetLowLevelInstructionsEnabled();
364 #endif
365 
366     auto entry = graph->CreateStartBlock();
367     auto exit = graph->CreateEndBlock();
368     auto block = graph->CreateEmptyBlock();
369     entry->AddSucc(block);
370     block->AddSucc(exit);
371 
372     auto array = graph->AddNewParameter(0, DataType::REFERENCE);
373     [[maybe_unused]] auto index = graph->AddNewParameter(1, DataType::INT32);
374     auto val0 = graph->AddNewParameter(2, type);
375     auto val1 = graph->AddNewParameter(3, type);
376 
377     graph->ResetParameterInfo();
378     array->SetLocationData(graph->GetDataForNativeParam(DataType::REFERENCE));
379     index->SetLocationData(graph->GetDataForNativeParam(DataType::INT32));
380     val0->SetLocationData(graph->GetDataForNativeParam(type));
381     val1->SetLocationData(graph->GetDataForNativeParam(type));
382 
383     Inst *stp_arr = nullptr;
384     if (imm) {
385         stp_arr = graph->CreateInstStoreArrayPairI(2);
386         block->AppendInst(stp_arr);
387         stp_arr->SetType(type);
388         stp_arr->SetInput(0, array);
389         stp_arr->SetInput(1, val0);
390         stp_arr->SetInput(2, val1);
391     } else {
392         stp_arr = graph->CreateInstStoreArrayPair();
393         block->AppendInst(stp_arr);
394         stp_arr->SetType(type);
395         stp_arr->SetInput(0, array);
396         stp_arr->SetInput(1, index);
397         stp_arr->SetInput(2, val0);
398         stp_arr->SetInput(3, val1);
399     }
400 
401     auto ret = graph->CreateInst(Opcode::ReturnVoid);
402     block->AppendInst(ret);
403 
404     GraphChecker(graph).Check();
405 
406     SetNumVirtRegs(0);
407     SetNumArgs(4);
408 
409     RegAlloc(graph);
410 
411     EXPECT_TRUE(RunCodegen(graph));
412     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
413     auto code_exit = code_entry + graph->GetData().Size();
414     ASSERT(code_entry != nullptr && code_exit != nullptr);
415     GetExecModule().SetInstructions(code_entry, code_exit);
416 
417     GetExecModule().SetDump(false);
418 
419     T array_data[6] = {0, 0, 0, 0, 0, 0};
420     auto param_1 = GetExecModule().CreateArray(array_data, 6, GetObjectAllocator());
421     auto param_2 = CutValue<int32_t>(2, DataType::INT32);
422     auto param_3 = CutValue<T>(3, type);
423     auto param_4 = CutValue<T>(5, type);
424     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
425     GetExecModule().SetParameter(1U, param_2);
426     GetExecModule().SetParameter(2U, param_3);
427     GetExecModule().SetParameter(3U, param_4);
428 
429     GetExecModule().Execute();
430     GetExecModule().CopyArray(param_1, array_data);
431     GetExecModule().FreeArray(param_1);
432 
433     T array_expected[6] = {0, 0, 3, 5, 0, 0};
434 
435     for (auto i = 0; i < 6; ++i) {
436         EXPECT_EQ(array_data[i], array_expected[i]);
437     }
438 }
439 
440 template <typename T>
CheckLoadArrayPair(bool imm)441 void CodegenTest::CheckLoadArrayPair(bool imm)
442 {
443     constexpr DataType::Type type = VixlExecModule::GetType<T>();
444 
445     // Create graph
446     auto graph = CreateEmptyGraph();
447     RuntimeInterfaceMock runtime;
448     graph->SetRuntime(&runtime);
449 #ifndef NDEBUG
450     // GraphChecker hack: LowLevel instructions may appear only after Lowering pass:
451     graph->SetLowLevelInstructionsEnabled();
452 #endif
453 
454     auto entry = graph->CreateStartBlock();
455     auto exit = graph->CreateEndBlock();
456     auto block = graph->CreateEmptyBlock();
457     entry->AddSucc(block);
458     block->AddSucc(exit);
459 
460     auto array = graph->AddNewParameter(0, DataType::REFERENCE);
461     [[maybe_unused]] auto index = graph->AddNewParameter(1, DataType::INT32);
462 
463     graph->ResetParameterInfo();
464     array->SetLocationData(graph->GetDataForNativeParam(DataType::REFERENCE));
465     index->SetLocationData(graph->GetDataForNativeParam(DataType::INT32));
466 
467     Inst *ldp_arr = nullptr;
468     if (imm) {
469         ldp_arr = graph->CreateInstLoadArrayPairI(2);
470         block->AppendInst(ldp_arr);
471         ldp_arr->SetType(type);
472         ldp_arr->SetInput(0, array);
473     } else {
474         ldp_arr = graph->CreateInstLoadArrayPair();
475         block->AppendInst(ldp_arr);
476         ldp_arr->SetType(type);
477         ldp_arr->SetInput(0, array);
478         ldp_arr->SetInput(1, index);
479     }
480 
481     auto load_high = graph->CreateInstLoadPairPart(0);
482     block->AppendInst(load_high);
483     load_high->SetType(type);
484     load_high->SetInput(0, ldp_arr);
485 
486     auto load_low = graph->CreateInstLoadPairPart(1);
487     block->AppendInst(load_low);
488     load_low->SetType(type);
489     load_low->SetInput(0, ldp_arr);
490 
491     auto sum = graph->CreateInst(Opcode::Add);
492     block->AppendInst(sum);
493     sum->SetType(type);
494     sum->SetInput(0, load_high);
495     sum->SetInput(1, load_low);
496 
497     auto ret = graph->CreateInst(Opcode::Return);
498     ret->SetType(type);
499     ret->SetInput(0, sum);
500     block->AppendInst(ret);
501 
502     GraphChecker(graph).Check();
503 
504     SetNumVirtRegs(0);
505     SetNumArgs(2);
506 
507     RegAlloc(graph);
508 
509     EXPECT_TRUE(RunCodegen(graph));
510     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
511     auto code_exit = code_entry + graph->GetData().Size();
512     ASSERT(code_entry != nullptr && code_exit != nullptr);
513     GetExecModule().SetInstructions(code_entry, code_exit);
514 
515     GetExecModule().SetDump(false);
516 
517     T array_data[6];
518     // [ 1, 2, 3, 4, 5, 6] -> 7
519     for (auto i = 0; i < 6; i++) {
520         array_data[i] = CutValue<T>(i + 1, type);
521     }
522     auto param_1 = GetExecModule().CreateArray(array_data, 6, GetObjectAllocator());
523     auto param_2 = CutValue<int32_t>(2, DataType::INT32);
524     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
525     GetExecModule().SetParameter(1U, param_2);
526 
527     GetExecModule().Execute();
528     GetExecModule().FreeArray(param_1);
529 
530     auto ret_data = GetExecModule().GetRetValue<T>();
531     EXPECT_EQ(ret_data, CutValue<T>(7, type));
532 }
533 
534 template <typename T>
CheckBounds(uint64_t count)535 void CodegenTest::CheckBounds(uint64_t count)
536 {
537     constexpr DataType::Type type = VixlExecModule::GetType<T>();
538     // Create graph
539     auto graph = CreateEmptyGraph();
540     RuntimeInterfaceMock runtime;
541     graph->SetRuntime(&runtime);
542 
543     auto entry = graph->CreateStartBlock();
544     auto exit = graph->CreateEndBlock();
545     auto block = graph->CreateEmptyBlock();
546     entry->AddSucc(block);
547     block->AddSucc(exit);
548 
549     auto param = graph->AddNewParameter(0, type);
550 
551     graph->ResetParameterInfo();
552     param->SetLocationData(graph->GetDataForNativeParam(type));
553 
554     BinaryImmOperation *last_inst = nullptr;
555     // instruction_count + parameter + return
556     for (uint64_t i = count - 1; i > 1; --i) {
557         auto add_inst = graph->CreateInstAddI(type, 0, 1);
558         block->AppendInst(add_inst);
559         if (last_inst == nullptr) {
560             add_inst->SetInput(0, param);
561         } else {
562             add_inst->SetInput(0, last_inst);
563         }
564         last_inst = add_inst;
565     }
566     auto ret = graph->CreateInst(Opcode::Return);
567     ret->SetType(type);
568     ret->SetInput(0, last_inst);
569     block->AppendInst(ret);
570 
571 #ifndef NDEBUG
572     // GraphChecker hack: LowLevel instructions may appear only after Lowering pass:
573     graph->SetLowLevelInstructionsEnabled();
574 #endif
575     GraphChecker(graph).Check();
576 
577     SetNumVirtRegs(0);
578     SetNumArgs(2);
579 
580     RegAlloc(graph);
581 
582     auto insts_per_byte = GetGraph()->GetEncoder()->MaxArchInstPerEncoded();
583     auto max_bits_in_inst = GetInstructionSizeBits(GetGraph()->GetArch());
584     if (count * insts_per_byte * max_bits_in_inst > options.GetCompilerMaxGenCodeSize()) {
585         EXPECT_FALSE(RunCodegen(graph));
586     } else {
587         ASSERT_TRUE(RunCodegen(graph));
588         auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
589         auto code_exit = code_entry + graph->GetData().Size();
590         ASSERT(code_entry != nullptr && code_exit != nullptr);
591         GetExecModule().SetInstructions(code_entry, code_exit);
592 
593         GetExecModule().SetDump(false);
594 
595         T param = 0;
596         GetExecModule().SetParameter(0U, param);
597         GetExecModule().Execute();
598 
599         auto ret_data = GetExecModule().GetRetValue<T>();
600         EXPECT_EQ(ret_data, CutValue<T>(count - 2, type));
601     }
602 }
603 
604 template <typename T>
CheckCmp(bool is_fcmpg)605 void CodegenTest::CheckCmp(bool is_fcmpg)
606 {
607     constexpr DataType::Type type = VixlExecModule::GetType<T>();
608     bool is_float = DataType::IsFloatType(type);
609 
610     // Create graph
611     auto graph = CreateEmptyGraph();
612     RuntimeInterfaceMock runtime;
613     graph->SetRuntime(&runtime);
614 
615     auto entry = graph->CreateStartBlock();
616     auto exit = graph->CreateEndBlock();
617     auto block = graph->CreateEmptyBlock();
618     entry->AddSucc(block);
619     block->AddSucc(exit);
620 
621     auto param1 = graph->AddNewParameter(0, type);
622     auto param2 = graph->AddNewParameter(1, type);
623 
624     graph->ResetParameterInfo();
625     param1->SetLocationData(graph->GetDataForNativeParam(type));
626     param2->SetLocationData(graph->GetDataForNativeParam(type));
627 
628     auto fcmp = graph->CreateInst(Opcode::Cmp);
629     block->AppendInst(fcmp);
630     fcmp->SetType(DataType::INT32);
631     fcmp->SetInput(0, param1);
632     fcmp->SetInput(1, param2);
633     static_cast<CmpInst *>(fcmp)->SetOperandsType(type);
634     if (is_float) {
635         static_cast<CmpInst *>(fcmp)->SetFcmpg(is_fcmpg);
636     }
637     auto ret = graph->CreateInst(Opcode::Return);
638     ret->SetType(DataType::INT32);
639     ret->SetInput(0, fcmp);
640     block->AppendInst(ret);
641 
642     SetNumVirtRegs(0);
643     SetNumArgs(2);
644 
645     RegAlloc(graph);
646 
647     EXPECT_TRUE(RunCodegen(graph));
648     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
649     auto code_exit = code_entry + graph->GetData().Size();
650     ASSERT(code_entry != nullptr && code_exit != nullptr);
651     GetExecModule().SetInstructions(code_entry, code_exit);
652 
653     GetExecModule().SetDump(false);
654     T param_data[3];
655     if (type == DataType::FLOAT32) {
656         param_data[0] = std::nanf("0");
657     } else if (type == DataType::FLOAT64) {
658         param_data[0] = std::nan("0");
659     } else {
660         param_data[0] = std::numeric_limits<T>::max();
661         param_data[2] = std::numeric_limits<T>::min();
662     }
663     param_data[1] = CutValue<T>(2, type);
664     if (is_float) {
665         param_data[2] = -param_data[1];
666     }
667 
668     for (auto i = 0; i < 3; i++) {
669         for (auto j = 0; j < 3; j++) {
670             auto param_1 = param_data[i];
671             auto param_2 = param_data[j];
672             GetExecModule().SetParameter(0U, param_1);
673             GetExecModule().SetParameter(1U, param_2);
674 
675             GetExecModule().Execute();
676 
677             auto ret_data = GetExecModule().GetRetValue<int32_t>();
678             if ((i == 0 || j == 0) && is_float) {
679                 EXPECT_EQ(ret_data, is_fcmpg ? 1 : -1);
680             } else if (i == j) {
681                 EXPECT_EQ(ret_data, 0);
682             } else if (i > j) {
683                 EXPECT_EQ(ret_data, -1);
684             } else {
685                 EXPECT_EQ(ret_data, 1);
686             }
687         }
688     }
689 }
690 
691 template <typename T>
CheckReturnValue(Graph * graph,T expected_value)692 void CodegenTest::CheckReturnValue(Graph *graph, [[maybe_unused]] T expected_value)
693 {
694     SetNumVirtRegs(0);
695     RegAlloc(graph);
696     EXPECT_TRUE(RunCodegen(graph));
697 
698     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
699     auto code_exit = code_entry + graph->GetData().Size();
700 
701     ASSERT(code_entry != nullptr && code_exit != nullptr);
702 
703     GetExecModule().SetInstructions(code_entry, code_exit);
704     GetExecModule().SetDump(false);
705 
706     GetExecModule().Execute();
707     auto rv = GetExecModule().GetRetValue<T>();
708     EXPECT_EQ(rv, expected_value);
709 }
710 
TestBinaryOperationWithShiftedOperand(Opcode opcode,uint32_t l,uint32_t r,ShiftType shift_type,uint32_t shift,uint32_t erv)711 void CodegenTest::TestBinaryOperationWithShiftedOperand(Opcode opcode, uint32_t l, uint32_t r, ShiftType shift_type,
712                                                         uint32_t shift, uint32_t erv)
713 {
714     GRAPH(GetGraph())
715     {
716         CONSTANT(0, l);
717         CONSTANT(1, r);
718 
719         BASIC_BLOCK(2, -1)
720         {
721             INST(2, opcode).Shift(shift_type, shift).u32().Inputs(0, 1);
722             INST(3, Opcode::Return).u32().Inputs(2);
723         }
724     }
725 
726     CheckReturnValue(GetGraph(), erv);
727 }
728 
TEST_F(CodegenTest,Cmp)729 TEST_F(CodegenTest, Cmp)
730 {
731     CheckCmp<float>(true);
732     CheckCmp<float>(false);
733     CheckCmp<double>(true);
734     CheckCmp<double>(false);
735     CheckCmp<uint8_t>();
736     CheckCmp<int8_t>();
737     CheckCmp<uint16_t>();
738     CheckCmp<int16_t>();
739     CheckCmp<uint32_t>();
740     CheckCmp<int32_t>();
741     CheckCmp<uint64_t>();
742     CheckCmp<int64_t>();
743 }
744 
TEST_F(CodegenTest,StoreArray)745 TEST_F(CodegenTest, StoreArray)
746 {
747     CheckStoreArray<bool>();
748     CheckStoreArray<int8_t>();
749     CheckStoreArray<uint8_t>();
750     CheckStoreArray<int16_t>();
751     CheckStoreArray<uint16_t>();
752     CheckStoreArray<int32_t>();
753     CheckStoreArray<uint32_t>();
754     CheckStoreArray<int64_t>();
755     CheckStoreArray<uint64_t>();
756     CheckStoreArray<float>();
757     CheckStoreArray<double>();
758 
759     GRAPH(GetGraph())
760     {
761         PARAMETER(0, 0).ref();  // array
762         PARAMETER(1, 1).u32();  // index
763         PARAMETER(2, 2).u32();  // store value
764         BASIC_BLOCK(2, -1)
765         {
766             INST(3, Opcode::StoreArray).u32().Inputs(0, 1, 2);
767             INST(4, Opcode::ReturnVoid);
768         }
769     }
770     auto graph = GetGraph();
771     SetNumVirtRegs(0);
772     SetNumArgs(3);
773 
774     RegAlloc(graph);
775 
776     EXPECT_TRUE(RunCodegen(graph));
777     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
778     auto code_exit = code_entry + graph->GetData().Size();
779     ASSERT(code_entry != nullptr && code_exit != nullptr);
780     GetExecModule().SetInstructions(code_entry, code_exit);
781 
782     GetExecModule().SetDump(false);
783 
784     object_pointer_type array[4] = {0, 0, 0, 0};
785     auto param_1 = GetExecModule().CreateArray(array, 4, GetObjectAllocator());
786     auto param_2 = CutValue<int32_t>(2, DataType::INT32);
787     auto param_3 = CutValue<object_pointer_type>(10, DataType::UINT64);
788     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
789     GetExecModule().SetParameter(1U, param_2);
790     GetExecModule().SetParameter(2U, param_3);
791 
792     GetExecModule().Execute();
793 
794     GetExecModule().CopyArray(param_1, array);
795 
796     for (auto i = 0; i < 4; i++) {
797         if (i == 2) {
798             EXPECT_EQ(array[i], 10U) << "value of i: " << i;
799         } else {
800             EXPECT_EQ(array[i], 0U) << "value of i: " << i;
801         }
802     }
803     GetExecModule().FreeArray(param_1);
804 }
805 
TEST_F(CodegenTest,StoreArrayPair)806 TEST_F(CodegenTest, StoreArrayPair)
807 {
808     CheckStoreArrayPair<uint32_t>(true);
809     CheckStoreArrayPair<int32_t>(false);
810     CheckStoreArrayPair<uint64_t>(true);
811     CheckStoreArrayPair<int64_t>(false);
812     CheckStoreArrayPair<float>(true);
813     CheckStoreArrayPair<float>(false);
814     CheckStoreArrayPair<double>(true);
815     CheckStoreArrayPair<double>(false);
816 }
817 
TEST_F(CodegenTest,Compare)818 TEST_F(CodegenTest, Compare)
819 {
820     for (int ccint = ConditionCode::CC_FIRST; ccint != ConditionCode::CC_LAST; ccint++) {
821         ConditionCode cc = static_cast<ConditionCode>(ccint);
822         for (auto inverse : {true, false}) {
823             auto graph = CreateGraphStartEndBlocks();
824             RuntimeInterfaceMock runtime;
825             graph->SetRuntime(&runtime);
826 
827             GRAPH(graph)
828             {
829                 PARAMETER(0, 0).u64();
830                 PARAMETER(1, 1).u64();
831                 CONSTANT(2, 0);
832                 CONSTANT(3, 1);
833                 BASIC_BLOCK(2, 3, 4)
834                 {
835                     INST(4, Opcode::Compare).b().CC(cc).Inputs(0, 1);
836                     INST(5, Opcode::IfImm).SrcType(DataType::BOOL).CC(inverse ? CC_EQ : CC_NE).Imm(0).Inputs(4);
837                 }
838                 BASIC_BLOCK(3, -1)
839                 {
840                     INST(6, Opcode::Return).b().Inputs(3);
841                 }
842                 BASIC_BLOCK(4, -1)
843                 {
844                     INST(7, Opcode::Return).b().Inputs(2);
845                 }
846             }
847             SetNumVirtRegs(0);
848             SetNumArgs(2);
849 
850             RegAlloc(graph);
851 
852             EXPECT_TRUE(RunCodegen(graph));
853             auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
854             auto code_exit = code_entry + graph->GetData().Size();
855             ASSERT(code_entry != nullptr && code_exit != nullptr);
856             GetExecModule().SetInstructions(code_entry, code_exit);
857 
858             GetExecModule().SetDump(false);
859 
860             bool result;
861             auto param_1 = CutValue<uint64_t>(1, DataType::UINT64);
862             auto param_2 = CutValue<uint64_t>(-1, DataType::UINT64);
863 
864             GetExecModule().SetParameter(0U, param_1);
865             GetExecModule().SetParameter(1U, param_2);
866 
867             result = (cc == CC_NE || cc == CC_GT || cc == CC_GE || cc == CC_B || cc == CC_BE);
868             if (inverse) {
869                 result = !result;
870             }
871 
872             GetExecModule().Execute();
873 
874             auto ret_data = GetExecModule().GetRetValue();
875             EXPECT_EQ(ret_data, result);
876 
877             GetExecModule().SetParameter(0U, param_2);
878             GetExecModule().SetParameter(1U, param_1);
879 
880             GetExecModule().Execute();
881 
882             result = (cc == CC_NE || cc == CC_LT || cc == CC_LE || cc == CC_A || cc == CC_AE);
883             if (inverse) {
884                 result = !result;
885             }
886 
887             ret_data = GetExecModule().GetRetValue();
888             EXPECT_EQ(ret_data, result);
889 
890             GetExecModule().SetParameter(0U, param_1);
891             GetExecModule().SetParameter(1U, param_1);
892 
893             result = (cc == CC_EQ || cc == CC_LE || cc == CC_GE || cc == CC_AE || cc == CC_BE);
894             if (inverse) {
895                 result = !result;
896             }
897 
898             GetExecModule().Execute();
899 
900             ret_data = GetExecModule().GetRetValue();
901             EXPECT_EQ(ret_data, result);
902         }
903     }
904 }
905 
TEST_F(CodegenTest,GenIf)906 TEST_F(CodegenTest, GenIf)
907 {
908     for (int ccint = ConditionCode::CC_FIRST; ccint != ConditionCode::CC_LAST; ccint++) {
909         ConditionCode cc = static_cast<ConditionCode>(ccint);
910         auto graph = CreateGraphStartEndBlocks();
911         RuntimeInterfaceMock runtime;
912         graph->SetRuntime(&runtime);
913 
914         GRAPH(graph)
915         {
916             PARAMETER(0, 0).u64();
917             PARAMETER(1, 1).u64();
918             CONSTANT(2, 0);
919             CONSTANT(3, 1);
920             BASIC_BLOCK(2, 3, 4)
921             {
922                 INST(4, Opcode::Compare).b().CC(cc).Inputs(0, 1);
923                 INST(5, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(4);
924             }
925             BASIC_BLOCK(3, -1)
926             {
927                 INST(6, Opcode::Return).b().Inputs(3);
928             }
929             BASIC_BLOCK(4, -1)
930             {
931                 INST(7, Opcode::Return).b().Inputs(2);
932             }
933         }
934         SetNumVirtRegs(0);
935         SetNumArgs(2);
936 #ifndef NDEBUG
937         graph->SetLowLevelInstructionsEnabled();
938 #endif
939         EXPECT_TRUE(graph->RunPass<Lowering>());
940         ASSERT_EQ(INS(0).GetUsers().Front().GetInst()->GetOpcode(), Opcode::If);
941 
942         RegAlloc(graph);
943 
944         EXPECT_TRUE(RunCodegen(graph));
945         auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
946         auto code_exit = code_entry + graph->GetData().Size();
947         ASSERT(code_entry != nullptr && code_exit != nullptr);
948         GetExecModule().SetInstructions(code_entry, code_exit);
949 
950         GetExecModule().SetDump(false);
951 
952         bool result;
953         auto param_1 = CutValue<uint64_t>(1, DataType::UINT64);
954         auto param_2 = CutValue<uint64_t>(-1, DataType::UINT64);
955 
956         GetExecModule().SetParameter(0U, param_1);
957         GetExecModule().SetParameter(1U, param_2);
958         result = Compare(cc, param_1, param_2);
959         GetExecModule().Execute();
960         auto ret_data = GetExecModule().GetRetValue();
961         EXPECT_EQ(ret_data, result);
962 
963         GetExecModule().SetParameter(0U, param_2);
964         GetExecModule().SetParameter(1U, param_1);
965         GetExecModule().Execute();
966         result = Compare(cc, param_2, param_1);
967         ret_data = GetExecModule().GetRetValue();
968         EXPECT_EQ(ret_data, result);
969 
970         GetExecModule().SetParameter(0U, param_1);
971         GetExecModule().SetParameter(1U, param_1);
972         result = Compare(cc, param_1, param_1);
973         GetExecModule().Execute();
974         ret_data = GetExecModule().GetRetValue();
975         EXPECT_EQ(ret_data, result);
976     }
977 }
978 
TEST_F(CodegenTest,GenIfImm)979 TEST_F(CodegenTest, GenIfImm)
980 {
981     int32_t values[3] = {-1, 0, 1};
982     for (auto value : values) {
983         for (int ccint = ConditionCode::CC_FIRST; ccint != ConditionCode::CC_LAST; ccint++) {
984             ConditionCode cc = static_cast<ConditionCode>(ccint);
985             auto graph = CreateGraphStartEndBlocks();
986             RuntimeInterfaceMock runtime;
987             graph->SetRuntime(&runtime);
988             if ((cc == CC_TST_EQ || cc == CC_TST_NE) && !graph->GetEncoder()->CanEncodeImmLogical(value, WORD_SIZE)) {
989                 continue;
990             }
991 
992             GRAPH(graph)
993             {
994                 PARAMETER(0, 0).s32();
995                 CONSTANT(1, 0);
996                 CONSTANT(2, 1);
997                 BASIC_BLOCK(2, 3, 4)
998                 {
999                     INST(3, Opcode::IfImm).SrcType(DataType::INT32).CC(cc).Imm(value).Inputs(0);
1000                 }
1001                 BASIC_BLOCK(3, -1)
1002                 {
1003                     INST(4, Opcode::Return).b().Inputs(2);
1004                 }
1005                 BASIC_BLOCK(4, -1)
1006                 {
1007                     INST(5, Opcode::Return).b().Inputs(1);
1008                 }
1009             }
1010             SetNumVirtRegs(0);
1011             SetNumArgs(2);
1012 
1013             RegAlloc(graph);
1014 
1015             EXPECT_TRUE(RunCodegen(graph));
1016             auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1017             auto code_exit = code_entry + graph->GetData().Size();
1018             ASSERT(code_entry != nullptr && code_exit != nullptr);
1019             GetExecModule().SetInstructions(code_entry, code_exit);
1020 
1021             GetExecModule().SetDump(false);
1022 
1023             bool result;
1024             auto param_1 = CutValue<uint64_t>(value, DataType::INT32);
1025             auto param_2 = CutValue<uint64_t>(value + 5, DataType::INT32);
1026             auto param_3 = CutValue<uint64_t>(value - 5, DataType::INT32);
1027 
1028             GetExecModule().SetParameter(0U, param_1);
1029             result = Compare(cc, param_1, param_1);
1030             GetExecModule().Execute();
1031             auto ret_data = GetExecModule().GetRetValue();
1032             EXPECT_EQ(ret_data, result);
1033 
1034             GetExecModule().SetParameter(0U, param_2);
1035             GetExecModule().Execute();
1036             result = Compare(cc, param_2, param_1);
1037             ret_data = GetExecModule().GetRetValue();
1038             EXPECT_EQ(ret_data, result);
1039 
1040             GetExecModule().SetParameter(0U, param_3);
1041             result = Compare(cc, param_3, param_1);
1042             GetExecModule().Execute();
1043             ret_data = GetExecModule().GetRetValue();
1044             EXPECT_EQ(ret_data, result);
1045         }
1046     }
1047 }
1048 
TEST_F(CodegenTest,If)1049 TEST_F(CodegenTest, If)
1050 {
1051     for (int ccint = ConditionCode::CC_FIRST; ccint != ConditionCode::CC_LAST; ccint++) {
1052         ConditionCode cc = static_cast<ConditionCode>(ccint);
1053         auto graph = CreateGraphStartEndBlocks();
1054         RuntimeInterfaceMock runtime;
1055         graph->SetRuntime(&runtime);
1056 
1057         GRAPH(graph)
1058         {
1059             PARAMETER(0, 0).u64();
1060             PARAMETER(1, 1).u64();
1061             CONSTANT(2, 0);
1062             CONSTANT(3, 1);
1063             BASIC_BLOCK(2, 3, 4)
1064             {
1065                 INST(4, Opcode::If).SrcType(DataType::UINT64).CC(cc).Inputs(0, 1);
1066             }
1067             BASIC_BLOCK(3, -1)
1068             {
1069                 INST(5, Opcode::Return).b().Inputs(3);
1070             }
1071             BASIC_BLOCK(4, -1)
1072             {
1073                 INST(6, Opcode::Return).b().Inputs(2);
1074             }
1075         }
1076         SetNumVirtRegs(0);
1077         SetNumArgs(2);
1078 
1079         RegAlloc(graph);
1080 
1081         EXPECT_TRUE(RunCodegen(graph));
1082         auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1083         auto code_exit = code_entry + graph->GetData().Size();
1084         ASSERT(code_entry != nullptr && code_exit != nullptr);
1085         GetExecModule().SetInstructions(code_entry, code_exit);
1086 
1087         GetExecModule().SetDump(false);
1088 
1089         bool result;
1090         auto param_1 = CutValue<uint64_t>(1, DataType::UINT64);
1091         auto param_2 = CutValue<uint64_t>(-1, DataType::UINT64);
1092 
1093         GetExecModule().SetParameter(0U, param_1);
1094         GetExecModule().SetParameter(1U, param_2);
1095         result = Compare(cc, param_1, param_2);
1096         GetExecModule().Execute();
1097         auto ret_data = GetExecModule().GetRetValue();
1098         EXPECT_EQ(ret_data, result);
1099 
1100         GetExecModule().SetParameter(0U, param_2);
1101         GetExecModule().SetParameter(1U, param_1);
1102         GetExecModule().Execute();
1103         result = Compare(cc, param_2, param_1);
1104         ret_data = GetExecModule().GetRetValue();
1105         EXPECT_EQ(ret_data, result);
1106 
1107         GetExecModule().SetParameter(0U, param_1);
1108         GetExecModule().SetParameter(1U, param_1);
1109         result = Compare(cc, param_1, param_1);
1110         GetExecModule().Execute();
1111         ret_data = GetExecModule().GetRetValue();
1112         EXPECT_EQ(ret_data, result);
1113     }
1114 }
1115 
TEST_F(CodegenTest,AddOverflow)1116 TEST_F(CodegenTest, AddOverflow)
1117 {
1118     auto graph = CreateGraphStartEndBlocks();
1119     RuntimeInterfaceMock runtime;
1120     graph->SetRuntime(&runtime);
1121 
1122     GRAPH(graph)
1123     {
1124         PARAMETER(0, 0).i32();
1125         PARAMETER(1, 1).i32();
1126         CONSTANT(2, 0);
1127         BASIC_BLOCK(2, 3, 4)
1128         {
1129             INST(4, Opcode::AddOverflow).i32().SrcType(DataType::INT32).CC(CC_EQ).Inputs(0, 1);
1130         }
1131         BASIC_BLOCK(3, -1)
1132         {
1133             INST(5, Opcode::Return).b().Inputs(2);
1134         }
1135         BASIC_BLOCK(4, -1)
1136         {
1137             INST(6, Opcode::Return).b().Inputs(4);
1138         }
1139     }
1140     SetNumVirtRegs(0);
1141     SetNumArgs(2);
1142 
1143     EXPECT_TRUE(RunOptimizations(graph));
1144     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1145     auto code_exit = code_entry + graph->GetData().Size();
1146     ASSERT(code_entry != nullptr && code_exit != nullptr);
1147     GetExecModule().SetInstructions(code_entry, code_exit);
1148 
1149     GetExecModule().SetDump(false);
1150 
1151     int32_t min = std::numeric_limits<int32_t>::min();
1152     int32_t max = std::numeric_limits<int32_t>::max();
1153     std::array<int32_t, 7> values = {0, 2, 5, -7, -10, max, min};
1154     for (uint32_t i = 0; i < values.size(); ++i) {
1155         for (uint32_t j = 0; j < values.size(); ++j) {
1156             int32_t a0 = values[i];
1157             int32_t a1 = values[j];
1158             int32_t result;
1159             auto param_1 = CutValue<int32_t>(a0, DataType::INT32);
1160             auto param_2 = CutValue<int32_t>(a1, DataType::INT32);
1161 
1162             if ((a0 > 0 && a1 > max - a0) || (a0 < 0 && a1 < min - a0)) {
1163                 result = 0;
1164             } else {
1165                 result = a0 + a1;
1166             }
1167             GetExecModule().SetParameter(0U, param_1);
1168             GetExecModule().SetParameter(1U, param_2);
1169             GetExecModule().Execute();
1170 
1171             auto ret_data = GetExecModule().GetRetValue<int32_t>();
1172             EXPECT_EQ(ret_data, result);
1173         }
1174     }
1175 }
1176 
TEST_F(CodegenTest,SubOverflow)1177 TEST_F(CodegenTest, SubOverflow)
1178 {
1179     auto graph = CreateGraphStartEndBlocks();
1180     RuntimeInterfaceMock runtime;
1181     graph->SetRuntime(&runtime);
1182 
1183     GRAPH(graph)
1184     {
1185         PARAMETER(0, 0).i32();
1186         PARAMETER(1, 1).i32();
1187         CONSTANT(2, 0);
1188         BASIC_BLOCK(2, 3, 4)
1189         {
1190             INST(4, Opcode::SubOverflow).i32().SrcType(DataType::INT32).CC(CC_EQ).Inputs(0, 1);
1191         }
1192         BASIC_BLOCK(3, -1)
1193         {
1194             INST(5, Opcode::Return).b().Inputs(2);
1195         }
1196         BASIC_BLOCK(4, -1)
1197         {
1198             INST(6, Opcode::Return).b().Inputs(4);
1199         }
1200     }
1201     SetNumVirtRegs(0);
1202     SetNumArgs(2);
1203 
1204     EXPECT_TRUE(RunOptimizations(graph));
1205     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1206     auto code_exit = code_entry + graph->GetData().Size();
1207     ASSERT(code_entry != nullptr && code_exit != nullptr);
1208     GetExecModule().SetInstructions(code_entry, code_exit);
1209 
1210     GetExecModule().SetDump(false);
1211 
1212     int32_t min = std::numeric_limits<int32_t>::min();
1213     int32_t max = std::numeric_limits<int32_t>::max();
1214     std::array<int32_t, 7> values = {0, 2, 5, -7, -10, max, min};
1215     for (uint32_t i = 0; i < values.size(); ++i) {
1216         for (uint32_t j = 0; j < values.size(); ++j) {
1217             int32_t a0 = values[i];
1218             int32_t a1 = values[j];
1219             int32_t result;
1220             auto param_1 = CutValue<int32_t>(a0, DataType::INT32);
1221             auto param_2 = CutValue<int32_t>(a1, DataType::INT32);
1222 
1223             if ((a1 > 0 && a0 < min + a1) || (a1 < 0 && a0 > max + a1)) {
1224                 result = 0;
1225             } else {
1226                 result = a0 - a1;
1227             }
1228             GetExecModule().SetParameter(0U, param_1);
1229             GetExecModule().SetParameter(1U, param_2);
1230             GetExecModule().Execute();
1231 
1232             auto ret_data = GetExecModule().GetRetValue<int32_t>();
1233             EXPECT_EQ(ret_data, result);
1234         }
1235     }
1236 }
1237 
TEST_F(CodegenTest,GenSelect)1238 TEST_F(CodegenTest, GenSelect)
1239 {
1240     for (int ccint = ConditionCode::CC_FIRST; ccint != ConditionCode::CC_LAST; ccint++) {
1241         ConditionCode cc = static_cast<ConditionCode>(ccint);
1242         auto graph = CreateGraphStartEndBlocks();
1243         RuntimeInterfaceMock runtime;
1244         graph->SetRuntime(&runtime);
1245 
1246         GRAPH(graph)
1247         {
1248             PARAMETER(0, 0).s64();
1249             PARAMETER(1, 1).s64();
1250             CONSTANT(2, 0);
1251             CONSTANT(3, 1);
1252             BASIC_BLOCK(2, 3, 4)
1253             {
1254                 INST(4, Opcode::If).SrcType(DataType::INT64).CC(cc).Inputs(0, 1);
1255             }
1256             BASIC_BLOCK(3, 4) {}
1257             BASIC_BLOCK(4, -1)
1258             {
1259                 INST(5, Opcode::Phi).b().Inputs({{3, 3}, {2, 2}});
1260                 INST(6, Opcode::Return).b().Inputs(5);
1261             }
1262         }
1263         SetNumVirtRegs(0);
1264         SetNumArgs(2);
1265 
1266         EXPECT_TRUE(graph->RunPass<IfConversion>());
1267         ASSERT_EQ(INS(6).GetInput(0).GetInst()->GetOpcode(), Opcode::Select);
1268 
1269         RegAlloc(graph);
1270 
1271         EXPECT_TRUE(RunCodegen(graph));
1272         auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1273         auto code_exit = code_entry + graph->GetData().Size();
1274         ASSERT(code_entry != nullptr && code_exit != nullptr);
1275         GetExecModule().SetInstructions(code_entry, code_exit);
1276 
1277         GetExecModule().SetDump(false);
1278 
1279         bool result;
1280         auto param_1 = CutValue<uint64_t>(1, DataType::UINT64);
1281         auto param_2 = CutValue<uint64_t>(-1, DataType::UINT64);
1282 
1283         GetExecModule().SetParameter(0U, param_1);
1284         GetExecModule().SetParameter(1U, param_2);
1285         result = Compare(cc, param_1, param_2);
1286         GetExecModule().Execute();
1287         auto ret_data = GetExecModule().GetRetValue();
1288         EXPECT_EQ(ret_data, result);
1289 
1290         GetExecModule().SetParameter(0U, param_2);
1291         GetExecModule().SetParameter(1U, param_1);
1292         GetExecModule().Execute();
1293         result = Compare(cc, param_2, param_1);
1294         ret_data = GetExecModule().GetRetValue();
1295         EXPECT_EQ(ret_data, result);
1296 
1297         GetExecModule().SetParameter(0U, param_1);
1298         GetExecModule().SetParameter(1U, param_1);
1299         result = Compare(cc, param_1, param_1);
1300         GetExecModule().Execute();
1301         ret_data = GetExecModule().GetRetValue();
1302         EXPECT_EQ(ret_data, result);
1303     }
1304 }
1305 
TEST_F(CodegenTest,BoolSelectImm)1306 TEST_F(CodegenTest, BoolSelectImm)
1307 {
1308     for (int ccint = ConditionCode::CC_FIRST; ccint != ConditionCode::CC_LAST; ccint++) {
1309         ConditionCode cc = static_cast<ConditionCode>(ccint);
1310         auto graph = CreateGraphStartEndBlocks();
1311         RuntimeInterfaceMock runtime;
1312         graph->SetRuntime(&runtime);
1313 
1314         GRAPH(graph)
1315         {
1316             PARAMETER(0, 0).u64();
1317             PARAMETER(1, 1).u64();
1318             CONSTANT(2, 0);
1319             CONSTANT(3, 1);
1320             BASIC_BLOCK(2, -1)
1321             {
1322                 INST(4, Opcode::Compare).b().CC(cc).Inputs(0, 1);
1323                 INST(5, Opcode::SelectImm).b().SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(3, 2, 4);
1324                 INST(6, Opcode::Return).b().Inputs(5);
1325             }
1326         }
1327         SetNumVirtRegs(0);
1328         SetNumArgs(2);
1329 
1330         RegAlloc(graph);
1331 
1332         EXPECT_TRUE(RunCodegen(graph));
1333         auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1334         auto code_exit = code_entry + graph->GetData().Size();
1335         ASSERT(code_entry != nullptr && code_exit != nullptr);
1336         GetExecModule().SetInstructions(code_entry, code_exit);
1337         GetExecModule().SetDump(false);
1338 
1339         auto param_1 = CutValue<uint64_t>(1, DataType::UINT64);
1340         auto param_2 = CutValue<uint64_t>(-1, DataType::UINT64);
1341 
1342         GetExecModule().SetParameter(0U, param_1);
1343         GetExecModule().SetParameter(1U, param_2);
1344         bool result = Compare(cc, param_1, param_2);
1345         GetExecModule().Execute();
1346         auto ret_data = GetExecModule().GetRetValue();
1347         EXPECT_EQ(ret_data, result);
1348 
1349         GetExecModule().SetParameter(0U, param_2);
1350         GetExecModule().SetParameter(1U, param_1);
1351         GetExecModule().Execute();
1352         result = Compare(cc, param_2, param_1);
1353         ret_data = GetExecModule().GetRetValue();
1354         EXPECT_EQ(ret_data, result);
1355 
1356         GetExecModule().SetParameter(0U, param_1);
1357         GetExecModule().SetParameter(1U, param_1);
1358         result = Compare(cc, param_1, param_1);
1359         GetExecModule().Execute();
1360         ret_data = GetExecModule().GetRetValue();
1361         EXPECT_EQ(ret_data, result);
1362     }
1363 }
1364 
TEST_F(CodegenTest,Select)1365 TEST_F(CodegenTest, Select)
1366 {
1367     for (int ccint = ConditionCode::CC_FIRST; ccint != ConditionCode::CC_LAST; ccint++) {
1368         ConditionCode cc = static_cast<ConditionCode>(ccint);
1369         auto graph = CreateGraphStartEndBlocks();
1370         RuntimeInterfaceMock runtime;
1371         graph->SetRuntime(&runtime);
1372 
1373         GRAPH(graph)
1374         {
1375             PARAMETER(0, 0).u64();
1376             PARAMETER(1, 1).u64();
1377             CONSTANT(2, 0);
1378             CONSTANT(3, 1);
1379             BASIC_BLOCK(2, -1)
1380             {
1381                 INST(5, Opcode::Select).u64().SrcType(DataType::UINT64).CC(cc).Inputs(3, 2, 0, 1);
1382                 INST(6, Opcode::Return).u64().Inputs(5);
1383             }
1384         }
1385         SetNumVirtRegs(0);
1386         SetNumArgs(2);
1387 
1388         RegAlloc(graph);
1389 
1390         EXPECT_TRUE(RunCodegen(graph));
1391         auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1392         auto code_exit = code_entry + graph->GetData().Size();
1393         ASSERT(code_entry != nullptr && code_exit != nullptr);
1394         GetExecModule().SetInstructions(code_entry, code_exit);
1395         GetExecModule().SetDump(false);
1396 
1397         auto param_1 = CutValue<uint64_t>(1, DataType::UINT64);
1398         auto param_2 = CutValue<uint64_t>(-1, DataType::UINT64);
1399 
1400         GetExecModule().SetParameter(0U, param_1);
1401         GetExecModule().SetParameter(1U, param_2);
1402         bool result = Compare(cc, param_1, param_2);
1403         GetExecModule().Execute();
1404         auto ret_data = GetExecModule().GetRetValue();
1405         EXPECT_EQ(ret_data, result);
1406 
1407         GetExecModule().SetParameter(0U, param_2);
1408         GetExecModule().SetParameter(1U, param_1);
1409         GetExecModule().Execute();
1410         result = Compare(cc, param_2, param_1);
1411         ret_data = GetExecModule().GetRetValue();
1412         EXPECT_EQ(ret_data, result);
1413 
1414         GetExecModule().SetParameter(0U, param_1);
1415         GetExecModule().SetParameter(1U, param_1);
1416         result = (cc == CC_EQ || cc == CC_LE || cc == CC_GE || cc == CC_AE || cc == CC_BE);
1417         GetExecModule().Execute();
1418         ret_data = GetExecModule().GetRetValue();
1419         EXPECT_EQ(ret_data, result);
1420     }
1421 }
1422 
TEST_F(CodegenTest,CompareObj)1423 TEST_F(CodegenTest, CompareObj)
1424 {
1425     auto graph = CreateGraphStartEndBlocks();
1426     RuntimeInterfaceMock runtime;
1427     graph->SetRuntime(&runtime);
1428     GRAPH(graph)
1429     {
1430         PARAMETER(0, 0).ref();
1431         CONSTANT(1, 0);
1432 
1433         BASIC_BLOCK(2, -1)
1434         {
1435             INST(2, Opcode::Compare).b().SrcType(DataType::REFERENCE).CC(CC_NE).Inputs(0, 1);
1436             INST(3, Opcode::Return).b().Inputs(2);
1437         }
1438     }
1439     SetNumVirtRegs(0);
1440     SetNumArgs(1);
1441 
1442     RegAlloc(graph);
1443 
1444     EXPECT_TRUE(RunCodegen(graph));
1445     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1446     auto code_exit = code_entry + graph->GetData().Size();
1447     ASSERT(code_entry != nullptr && code_exit != nullptr);
1448     GetExecModule().SetInstructions(code_entry, code_exit);
1449 
1450     GetExecModule().SetDump(false);
1451 
1452     auto param_1 = CutValue<uint64_t>(1, DataType::UINT64);
1453     auto param_2 = CutValue<uint64_t>(0, DataType::UINT64);
1454 
1455     GetExecModule().SetParameter(0U, param_1);
1456 
1457     GetExecModule().Execute();
1458 
1459     auto ret_data = GetExecModule().GetRetValue();
1460     EXPECT_EQ(ret_data, 1);
1461 
1462     GetExecModule().SetParameter(0U, param_2);
1463 
1464     GetExecModule().Execute();
1465 
1466     ret_data = GetExecModule().GetRetValue();
1467     EXPECT_EQ(ret_data, 0);
1468 }
1469 
TEST_F(CodegenTest,LoadArray)1470 TEST_F(CodegenTest, LoadArray)
1471 {
1472     CheckLoadArray<bool>();
1473     CheckLoadArray<int8_t>();
1474     CheckLoadArray<uint8_t>();
1475     CheckLoadArray<int16_t>();
1476     CheckLoadArray<uint16_t>();
1477     CheckLoadArray<int32_t>();
1478     CheckLoadArray<uint32_t>();
1479     CheckLoadArray<int64_t>();
1480     CheckLoadArray<uint64_t>();
1481     CheckLoadArray<float>();
1482     CheckLoadArray<double>();
1483 
1484     GRAPH(GetGraph())
1485     {
1486         PARAMETER(0, 0).ref();  // array
1487         PARAMETER(1, 1).u32();  // index
1488         BASIC_BLOCK(2, -1)
1489         {
1490             INST(2, Opcode::LoadArray).u32().Inputs(0, 1);
1491             INST(3, Opcode::Return).u32().Inputs(2);
1492         }
1493     }
1494     auto graph = GetGraph();
1495     SetNumVirtRegs(0);
1496     SetNumArgs(2);
1497 
1498     RegAlloc(graph);
1499 
1500     EXPECT_TRUE(RunCodegen(graph));
1501     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1502     auto code_exit = code_entry + graph->GetData().Size();
1503     ASSERT(code_entry != nullptr && code_exit != nullptr);
1504     GetExecModule().SetInstructions(code_entry, code_exit);
1505 
1506     GetExecModule().SetDump(false);
1507 
1508     object_pointer_type array[4] = {0xffffaaaa, 0xffffbbbb, 0xffffcccc, 0xffffdddd};
1509     auto param_1 = GetExecModule().CreateArray(array, 4, GetObjectAllocator());
1510     auto param_2 = CutValue<int32_t>(2, DataType::INT32);
1511     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
1512     GetExecModule().SetParameter(1U, param_2);
1513 
1514     GetExecModule().Execute();
1515 
1516     GetExecModule().CopyArray(param_1, array);
1517 
1518     GetExecModule().FreeArray(param_1);
1519     auto ret_data = GetExecModule().GetRetValue();
1520     EXPECT_EQ(ret_data, array[2]);
1521 }
1522 
TEST_F(CodegenTest,LoadArrayPair)1523 TEST_F(CodegenTest, LoadArrayPair)
1524 {
1525     CheckLoadArrayPair<uint32_t>(true);
1526     CheckLoadArrayPair<int32_t>(false);
1527     CheckLoadArrayPair<uint64_t>(true);
1528     CheckLoadArrayPair<int64_t>(false);
1529     CheckLoadArrayPair<float>(true);
1530     CheckLoadArrayPair<float>(false);
1531     CheckLoadArrayPair<double>(true);
1532     CheckLoadArrayPair<double>(false);
1533 }
1534 
1535 #ifndef USE_ADDRESS_SANITIZER
TEST_F(CodegenTest,CheckCodegenBounds)1536 TEST_F(CodegenTest, CheckCodegenBounds)
1537 {
1538     // Do not try to encode too large graph
1539     uint64_t insts_per_byte = GetGraph()->GetEncoder()->MaxArchInstPerEncoded();
1540     uint64_t max_bits_in_inst = GetInstructionSizeBits(GetGraph()->GetArch());
1541     uint64_t inst_count = options.GetCompilerMaxGenCodeSize() / (insts_per_byte * max_bits_in_inst);
1542 
1543     CheckBounds<uint32_t>(inst_count - 1);
1544     CheckBounds<uint32_t>(inst_count + 1);
1545 
1546     CheckBounds<uint32_t>(inst_count / 2);
1547 }
1548 #endif
1549 
TEST_F(CodegenTest,LenArray)1550 TEST_F(CodegenTest, LenArray)
1551 {
1552     GRAPH(GetGraph())
1553     {
1554         PARAMETER(0, 0).ref();  // array
1555         BASIC_BLOCK(2, -1)
1556         {
1557             INST(1, Opcode::LenArray).s32().Inputs(0);
1558             INST(2, Opcode::Return).s32().Inputs(1);
1559         }
1560     }
1561     auto graph = GetGraph();
1562     SetNumVirtRegs(0);
1563     SetNumArgs(1);
1564 
1565     RegAlloc(graph);
1566 
1567     EXPECT_TRUE(RunCodegen(graph));
1568     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1569     auto code_exit = code_entry + graph->GetData().Size();
1570     ASSERT(code_entry != nullptr && code_exit != nullptr);
1571     GetExecModule().SetInstructions(code_entry, code_exit);
1572 
1573     GetExecModule().SetDump(false);
1574 
1575     uint64_t array[4] = {0, 0, 0, 0};
1576     auto param_1 = GetExecModule().CreateArray(array, 4, GetObjectAllocator());
1577     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
1578 
1579     GetExecModule().Execute();
1580     GetExecModule().FreeArray(param_1);
1581 
1582     auto ret_data = GetExecModule().GetRetValue();
1583     EXPECT_EQ(ret_data, 4U);
1584 }
1585 
TEST_F(CodegenTest,Parameter)1586 TEST_F(CodegenTest, Parameter)
1587 {
1588     GRAPH(GetGraph())
1589     {
1590         PARAMETER(0, 0).u64();
1591         PARAMETER(1, 1).s16();
1592         BASIC_BLOCK(2, -1)
1593         {
1594             INST(6, Opcode::Add).u64().Inputs(0, 0);
1595             INST(8, Opcode::Add).s16().Inputs(1, 1);
1596             INST(15, Opcode::Return).u64().Inputs(6);
1597             // Return parameter_0 + parameter_0
1598         }
1599     }
1600     SetNumVirtRegs(0);
1601     SetNumArgs(2);
1602 
1603     auto graph = GetGraph();
1604 
1605     RegAlloc(graph);
1606 
1607     EXPECT_TRUE(RunCodegen(graph));
1608     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1609     auto code_exit = code_entry + graph->GetData().Size();
1610     ASSERT(code_entry != nullptr && code_exit != nullptr);
1611     GetExecModule().SetInstructions(code_entry, code_exit);
1612 
1613     GetExecModule().SetDump(false);
1614 
1615     auto param_1 = CutValue<uint64_t>(1234, DataType::UINT64);
1616     auto param_2 = CutValue<int16_t>(-1234, DataType::INT16);
1617     GetExecModule().SetParameter(0U, param_1);
1618     GetExecModule().SetParameter(1U, param_2);
1619 
1620     GetExecModule().Execute();
1621 
1622     auto ret_data = GetExecModule().GetRetValue();
1623     EXPECT_EQ(ret_data, 1234U + 1234U);
1624 
1625     // Clear data for next execution
1626     while (auto current = GetGraph()->GetFirstConstInst()) {
1627         GetGraph()->RemoveConstFromList(current);
1628     }
1629 }
1630 
TEST_F(CodegenTest,RegallocTwoFreeRegs)1631 TEST_F(CodegenTest, RegallocTwoFreeRegs)
1632 {
1633     GRAPH(GetGraph())
1634     {
1635         CONSTANT(0, 1);   // const a = 1
1636         CONSTANT(1, 10);  // const b = 10
1637         CONSTANT(2, 20);  // const c = 20
1638 
1639         BASIC_BLOCK(2, 3, 4)
1640         {
1641             INST(3, Opcode::Phi).u64().Inputs({{0, 0}, {3, 7}});                        // var a' = a
1642             INST(4, Opcode::Phi).u64().Inputs({{0, 1}, {3, 8}});                        // var b' = b
1643             INST(5, Opcode::Compare).b().CC(CC_NE).Inputs(4, 0);                        // b' == 1 ?
1644             INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);  // if == (b' == 1) -> exit
1645         }
1646 
1647         BASIC_BLOCK(3, 2)
1648         {
1649             INST(7, Opcode::Mul).u64().Inputs(3, 4);  // a' = a' * b'
1650             INST(8, Opcode::Sub).u64().Inputs(4, 0);  // b' = b' - 1
1651         }
1652 
1653         BASIC_BLOCK(4, -1)
1654         {
1655             INST(10, Opcode::Add).u64().Inputs(2, 3);   // a' = c + a'
1656             INST(11, Opcode::Return).u64().Inputs(10);  // return a'
1657         }
1658     }
1659     // Create reg_mask with 5 available general registers,
1660     // 3 of them will be reserved by Reg Alloc.
1661     {
1662         RegAllocLinearScan ra(GetGraph());
1663         ra.SetRegMask(RegMask {0xFFFFF07F});
1664         ra.SetVRegMask(VRegMask {0});
1665         EXPECT_TRUE(ra.Run());
1666     }
1667     GraphChecker(GetGraph()).Check();
1668     EXPECT_TRUE(RunCodegen(GetGraph()));
1669     auto code_entry = reinterpret_cast<char *>(GetGraph()->GetData().Data());
1670     auto code_exit = code_entry + GetGraph()->GetData().Size();
1671     ASSERT(code_entry != nullptr && code_exit != nullptr);
1672     GetExecModule().SetInstructions(code_entry, code_exit);
1673 
1674     GetExecModule().SetDump(false);
1675 
1676     auto param_1 = CutValue<uint64_t>(0x0, DataType::UINT64);
1677     auto param_2 = CutValue<uint16_t>(0x0, DataType::INT32);
1678 
1679     GetExecModule().SetParameter(0U, param_1);
1680     GetExecModule().SetParameter(1U, param_2);
1681 
1682     GetExecModule().Execute();
1683 
1684     auto ret_data = GetExecModule().GetRetValue();
1685     EXPECT_TRUE(ret_data == 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 + 20);
1686 
1687     // Clear data for next execution
1688     while (auto current = GetGraph()->GetFirstConstInst()) {
1689         GetGraph()->RemoveConstFromList(current);
1690     }
1691 }
1692 
1693 // TODO (igorban): Update FillSaveStates() with filling SaveState from SpillFill
TEST_F(CodegenTest,DISABLED_TwoFreeRegs_SaveState)1694 TEST_F(CodegenTest, DISABLED_TwoFreeRegs_SaveState)
1695 {
1696     GRAPH(GetGraph())
1697     {
1698         PARAMETER(0, 0).u64();
1699         PARAMETER(11, 0).f64();
1700         PARAMETER(12, 0).f32();
1701         CONSTANT(1, 12);
1702         CONSTANT(2, -1);
1703         CONSTANT(3, 100000000);
1704 
1705         BASIC_BLOCK(2, -1)
1706         {
1707             INST(4, Opcode::Add).u64().Inputs(0, 1);
1708             INST(5, Opcode::Add).u64().Inputs(0, 2);
1709             INST(6, Opcode::Add).u64().Inputs(0, 3);
1710             INST(7, Opcode::Sub).u64().Inputs(0, 1);
1711             INST(8, Opcode::Sub).u64().Inputs(0, 2);
1712             INST(9, Opcode::Sub).u64().Inputs(0, 3);
1713             INST(17, Opcode::Add).u64().Inputs(0, 0);
1714             INST(18, Opcode::Sub).u64().Inputs(0, 0);
1715             INST(19, Opcode::Add).u16().Inputs(0, 1);
1716             INST(20, Opcode::Add).u16().Inputs(0, 2);
1717             INST(10, Opcode::SaveState)
1718                 .Inputs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 17, 18, 19, 20)
1719                 .SrcVregs({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14});
1720         }
1721     }
1722     // NO RETURN value - will droped down to SaveState block!
1723 
1724     SetNumVirtRegs(0);
1725     SetNumArgs(3);
1726     // Create reg_mask with 5 available general registers,
1727     // 3 of them will be reserved by Reg Alloc.
1728     {
1729         RegAllocLinearScan ra(GetGraph());
1730         ra.SetRegMask(RegMask {0xFFFFF07F});
1731         ra.SetVRegMask(VRegMask {0});
1732         EXPECT_TRUE(ra.Run());
1733     }
1734     GraphChecker(GetGraph()).Check();
1735 
1736     EXPECT_TRUE(RunCodegen(GetGraph()));
1737     auto code_entry = reinterpret_cast<char *>(GetGraph()->GetData().Data());
1738     auto code_exit = code_entry + GetGraph()->GetData().Size();
1739     ASSERT(code_entry != nullptr && code_exit != nullptr);
1740     GetExecModule().SetInstructions(code_entry, code_exit);
1741 
1742     GetExecModule().SetDump(false);
1743 
1744     auto param_1 = CutValue<uint64_t>(0x12345, DataType::UINT64);
1745     auto param_2 = CutValue<float>(0x12345, DataType::FLOAT32);
1746 
1747     GetExecModule().SetParameter(0U, param_1);
1748     GetExecModule().SetParameter(1U, param_2);
1749     GetExecModule().SetParameter(2U, param_2);
1750 
1751     GetExecModule().Execute();
1752 
1753     // Main check - return value get from SaveState return DEOPTIMIZATION
1754     EXPECT_EQ(GetExecModule().GetRetValue(), 1);
1755 
1756     // Clear data for next execution
1757     while (auto current = GetGraph()->GetFirstConstInst()) {
1758         GetGraph()->RemoveConstFromList(current);
1759     }
1760 }
1761 
TEST_F(CodegenTest,SaveState)1762 TEST_F(CodegenTest, SaveState)
1763 {
1764     GRAPH(GetGraph())
1765     {
1766         PARAMETER(0, 0).ref();  // array
1767         PARAMETER(1, 1).u64();  // index
1768         BASIC_BLOCK(2, 3)
1769         {
1770             INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});
1771             INST(3, Opcode::NullCheck).ref().Inputs(0, 2);
1772             INST(4, Opcode::LenArray).s32().Inputs(3);
1773             INST(5, Opcode::BoundsCheck).s32().Inputs(4, 1, 2);
1774             INST(6, Opcode::LoadArray).u64().Inputs(3, 5);
1775             INST(7, Opcode::Add).u64().Inputs(6, 6);
1776             INST(8, Opcode::StoreArray).u64().Inputs(3, 5, 7);
1777         }
1778         BASIC_BLOCK(3, -1)
1779         {
1780             INST(10, Opcode::Add).u64().Inputs(7, 7);  // Some return value
1781             INST(11, Opcode::Return).u64().Inputs(10);
1782         }
1783     }
1784 
1785     SetNumVirtRegs(0);
1786     SetNumArgs(2);
1787 
1788     auto graph = GetGraph();
1789 
1790     RegAlloc(graph);
1791 
1792     // Run codegen
1793     EXPECT_TRUE(RunCodegen(graph));
1794     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
1795     auto code_exit = code_entry + graph->GetData().Size();
1796     ASSERT(code_entry != nullptr && code_exit != nullptr);
1797     GetExecModule().SetInstructions(code_entry, code_exit);
1798 
1799     // Enable dumping
1800     GetExecModule().SetDump(false);
1801 
1802     uint64_t array_data[4];
1803     for (auto i = 0; i < 4; i++) {
1804         array_data[i] = i + 0x20;
1805     }
1806     auto param_1 = GetExecModule().CreateArray(array_data, 4, GetObjectAllocator());
1807     auto param_2 = CutValue<uint64_t>(1, DataType::UINT64);
1808     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
1809     GetExecModule().SetParameter(1U, param_2);
1810 
1811     GetExecModule().Execute();
1812     GetExecModule().SetDump(false);
1813     // End dump
1814 
1815     auto ret_data = GetExecModule().GetRetValue();
1816     // TODO (igorban) : really need to check array changes
1817     EXPECT_EQ(ret_data, 4U * 0x21);
1818 
1819     // Clear data for next execution
1820     while (auto current = GetGraph()->GetFirstConstInst()) {
1821         GetGraph()->RemoveConstFromList(current);
1822     }
1823     GetExecModule().FreeArray(param_1);
1824 }  // namespace panda::compiler
1825 
TEST_F(CodegenTest,DeoptimizeIf)1826 TEST_F(CodegenTest, DeoptimizeIf)
1827 {
1828     GRAPH(GetGraph())
1829     {
1830         PARAMETER(0, 0).b();
1831         BASIC_BLOCK(2, 1)
1832         {
1833             INST(2, Opcode::SaveStateDeoptimize).Inputs(0).SrcVregs({0});
1834             INST(3, Opcode::DeoptimizeIf).Inputs(0, 2);
1835             INST(4, Opcode::Return).b().Inputs(0);
1836         }
1837     }
1838     RegAlloc(GetGraph());
1839 
1840     EXPECT_TRUE(RunCodegen(GetGraph()));
1841     auto code_entry = reinterpret_cast<char *>(GetGraph()->GetData().Data());
1842     auto code_exit = code_entry + GetGraph()->GetData().Size();
1843     ASSERT(code_entry != nullptr && code_exit != nullptr);
1844     GetExecModule().SetInstructions(code_entry, code_exit);
1845 
1846     // param == false [OK]
1847     auto param = false;
1848     GetExecModule().SetParameter(0U, param);
1849     GetExecModule().Execute();
1850     EXPECT_EQ(GetExecModule().GetRetValue(), param);
1851 
1852     // param == true [INTERPRET]
1853 }
1854 
TEST_F(CodegenTest,ZeroCheck)1855 TEST_F(CodegenTest, ZeroCheck)
1856 {
1857     GRAPH(GetGraph())
1858     {
1859         PARAMETER(0, 0).s64();
1860         PARAMETER(1, 1).s64();
1861         BASIC_BLOCK(2, 3)
1862         {
1863             INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});
1864             INST(3, Opcode::ZeroCheck).s64().Inputs(0, 2);
1865             INST(4, Opcode::Div).s64().Inputs(1, 3);
1866             INST(5, Opcode::Mod).s64().Inputs(1, 3);
1867         }
1868         BASIC_BLOCK(3, -1)
1869         {
1870             INST(6, Opcode::Add).s64().Inputs(0, 1);  // Some return value
1871             INST(7, Opcode::Return).s64().Inputs(6);
1872         }
1873     }
1874     RegAlloc(GetGraph());
1875 
1876     SetNumVirtRegs(GetGraph()->GetVRegsCount());
1877 
1878     EXPECT_TRUE(RunCodegen(GetGraph()));
1879     auto code_entry = reinterpret_cast<char *>(GetGraph()->GetData().Data());
1880     auto code_exit = code_entry + GetGraph()->GetData().Size();
1881     ASSERT(code_entry != nullptr && code_exit != nullptr);
1882     GetExecModule().SetInstructions(code_entry, code_exit);
1883 
1884     // param1 < 0 [OK]
1885     auto param_1 = CutValue<uint64_t>(std::numeric_limits<int64_t>::min(), DataType::INT64);
1886     auto param_2 = CutValue<uint64_t>(std::numeric_limits<int64_t>::max(), DataType::INT64);
1887     GetExecModule().SetParameter(0U, param_1);
1888     GetExecModule().SetParameter(1U, param_2);
1889     GetExecModule().Execute();
1890     EXPECT_EQ(GetExecModule().GetRetValue(), param_1 + param_2);
1891 
1892     // param1 > 0 [OK]
1893     param_1 = CutValue<uint64_t>(std::numeric_limits<int64_t>::max(), DataType::INT64);
1894     param_2 = CutValue<uint64_t>(0, DataType::INT64);
1895     GetExecModule().SetParameter(0U, param_1);
1896     GetExecModule().SetParameter(1U, param_2);
1897     GetExecModule().Execute();
1898     EXPECT_EQ(GetExecModule().GetRetValue(), param_1 + param_2);
1899 
1900     // param1 == 0 [THROW]
1901 }
1902 
TEST_F(CodegenTest,NegativeCheck)1903 TEST_F(CodegenTest, NegativeCheck)
1904 {
1905     GRAPH(GetGraph())
1906     {
1907         PARAMETER(0, 0).s64();
1908         PARAMETER(1, 1).s64();
1909         BASIC_BLOCK(2, 3)
1910         {
1911             INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});
1912             INST(3, Opcode::NegativeCheck).s64().Inputs(0, 2);
1913         }
1914         BASIC_BLOCK(3, -1)
1915         {
1916             INST(6, Opcode::Add).s64().Inputs(0, 1);  // Some return value
1917             INST(7, Opcode::Return).s64().Inputs(6);
1918         }
1919     }
1920     RegAlloc(GetGraph());
1921 
1922     SetNumVirtRegs(GetGraph()->GetVRegsCount());
1923 
1924     EXPECT_TRUE(RunCodegen(GetGraph()));
1925     auto code_entry = reinterpret_cast<char *>(GetGraph()->GetData().Data());
1926     auto code_exit = code_entry + GetGraph()->GetData().Size();
1927     ASSERT(code_entry != nullptr && code_exit != nullptr);
1928     GetExecModule().SetInstructions(code_entry, code_exit);
1929 
1930     // param1 > 0 [OK]
1931     auto param_1 = CutValue<uint64_t>(std::numeric_limits<int64_t>::max(), DataType::INT64);
1932     auto param_2 = CutValue<uint64_t>(std::numeric_limits<int64_t>::min(), DataType::INT64);
1933     GetExecModule().SetParameter(0U, param_1);
1934     GetExecModule().SetParameter(1U, param_2);
1935     GetExecModule().Execute();
1936     EXPECT_EQ(GetExecModule().GetRetValue(), param_1 + param_2);
1937 
1938     // param1 == 0 [OK]
1939     param_1 = CutValue<uint64_t>(0, DataType::INT64);
1940     param_2 = CutValue<uint64_t>(std::numeric_limits<int64_t>::max(), DataType::INT64);
1941     GetExecModule().SetParameter(0U, param_1);
1942     GetExecModule().SetParameter(1U, param_2);
1943     GetExecModule().Execute();
1944     EXPECT_EQ(GetExecModule().GetRetValue(), param_1 + param_2);
1945 
1946     // param1 < 0 [THROW]
1947 }
1948 
TEST_F(CodegenTest,NullCheckBoundsCheck)1949 TEST_F(CodegenTest, NullCheckBoundsCheck)
1950 {
1951     static const unsigned ARRAY_LEN = 10;
1952 
1953     GRAPH(GetGraph())
1954     {
1955         PARAMETER(0, 0).ref();  // array
1956         PARAMETER(1, 1).u64();  // index
1957         BASIC_BLOCK(2, 3)
1958         {
1959             INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});
1960             INST(3, Opcode::NullCheck).ref().Inputs(0, 2);
1961             INST(4, Opcode::LenArray).s32().Inputs(3);
1962             INST(5, Opcode::BoundsCheck).s32().Inputs(4, 1, 2);
1963             INST(6, Opcode::LoadArray).u64().Inputs(3, 5);
1964             INST(7, Opcode::Add).u64().Inputs(6, 6);
1965             INST(8, Opcode::StoreArray).u64().Inputs(3, 5, 7);
1966         }
1967         BASIC_BLOCK(3, -1)
1968         {
1969             INST(10, Opcode::Add).u64().Inputs(7, 7);  // Some return value
1970             INST(11, Opcode::Return).u64().Inputs(10);
1971         }
1972     }
1973     SetNumVirtRegs(0);
1974     SetNumArgs(2);
1975     RegAlloc(GetGraph());
1976 
1977     EXPECT_TRUE(RunCodegen(GetGraph()));
1978     auto code_entry = reinterpret_cast<char *>(GetGraph()->GetData().Data());
1979     auto code_exit = code_entry + GetGraph()->GetData().Size();
1980     ASSERT(code_entry != nullptr && code_exit != nullptr);
1981     GetExecModule().SetInstructions(code_entry, code_exit);
1982 
1983     // TODO (igorban) : fill Frame array == nullptr [THROW]
1984 
1985     uint64_t array[ARRAY_LEN];
1986     for (auto i = 0U; i < ARRAY_LEN; i++) {
1987         array[i] = i + 0x20;
1988     }
1989     auto param_1 = GetExecModule().CreateArray(array, ARRAY_LEN, GetObjectAllocator());
1990     GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param_1));
1991 
1992     // 0 <= index < ARRAY_LEN [OK]
1993     auto index = CutValue<uint64_t>(1, DataType::UINT64);
1994     GetExecModule().SetParameter(1U, index);
1995     GetExecModule().Execute();
1996     EXPECT_EQ(GetExecModule().GetRetValue(), array[index] * 4);
1997 
1998     /*
1999     TODO (igorban) : fill Frame
2000     // index < 0 [THROW]
2001     */
2002     GetExecModule().FreeArray(param_1);
2003 }
2004 
TEST_F(CodegenTest,ResolveParamSequence)2005 TEST_F(CodegenTest, ResolveParamSequence)
2006 {
2007     ArenaVector<std::pair<uint8_t, uint8_t>> some_sequence(GetAllocator()->Adapter());
2008     some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(0, 3));
2009     some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(1, 0));
2010     some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(2, 3));
2011     some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(3, 2));
2012 
2013     auto result = ResoveParameterSequence(&some_sequence, 13, GetAllocator());
2014     EXPECT_TRUE(some_sequence.empty());
2015     ArenaVector<std::pair<uint8_t, uint8_t>> result_sequence(GetAllocator()->Adapter());
2016     result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(1, 0));
2017     result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(0, 3));
2018     result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(13, 2));
2019     result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(2, 3));
2020     result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(3, 13));
2021 
2022     EXPECT_EQ(result, result_sequence);
2023 
2024     {
2025         // Special loop-only case
2026         ArenaVector<std::pair<uint8_t, uint8_t>> some_sequence(GetAllocator()->Adapter());
2027         some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(2, 3));
2028         some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(1, 2));
2029         some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(4, 1));
2030         some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(0, 4));
2031         some_sequence.emplace_back(std::pair<uint8_t, uint8_t>(3, 0));
2032 
2033         auto result = ResoveParameterSequence(&some_sequence, 13, GetAllocator());
2034         EXPECT_TRUE(some_sequence.empty());
2035         ArenaVector<std::pair<uint8_t, uint8_t>> result_sequence(GetAllocator()->Adapter());
2036         result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(13, 2));
2037         result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(2, 3));
2038         result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(3, 0));
2039         result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(0, 4));
2040         result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(4, 1));
2041         result_sequence.emplace_back(std::pair<uint8_t, uint8_t>(1, 13));
2042 
2043         EXPECT_EQ(result, result_sequence);
2044     }
2045     const uint32_t REG_SIZE = 30;
2046     const uint8_t TMP_REG = REG_SIZE + 5;
2047     for (uint64_t i = 0; i < ITERATION; ++i) {
2048         EXPECT_TRUE(some_sequence.empty());
2049 
2050         std::vector<uint8_t> iters;
2051         for (uint8_t j = 0; j < REG_SIZE; ++j) {
2052             iters.push_back(j);
2053         }
2054         std::shuffle(iters.begin(), iters.end(), random_generator);
2055         std::vector<std::pair<uint8_t, uint8_t>> orig_vector;
2056         for (uint8_t j = 0; j < REG_SIZE; ++j) {
2057             auto gen {random_generator()};
2058             auto random_value = gen % REG_SIZE;
2059             orig_vector.push_back(std::pair<uint8_t, uint8_t>(iters[j], random_value));
2060         }
2061         for (auto &pair : orig_vector) {
2062             some_sequence.emplace_back(pair);
2063         }
2064         result_sequence = ResoveParameterSequence(&some_sequence, TMP_REG, GetAllocator());
2065         std::vector<std::pair<uint8_t, uint8_t>> result;
2066         for (auto &pair : result_sequence) {
2067             result.emplace_back(pair);
2068         }
2069 
2070         // First analysis - there are no dst before src
2071         for (uint8_t j = 0; j < REG_SIZE; ++j) {
2072             auto dst = result[j].first;
2073             for (uint8_t k = j + 1; k < REG_SIZE; ++k) {
2074                 if (result[k].second == dst && result[k].second != TMP_REG) {
2075                     std::cerr << " first = " << result[k].first << " tmp = " << REG_SIZE + 5 << "\n";
2076                     std::cerr << " Before:\n";
2077                     for (auto &it : orig_vector) {
2078                         std::cerr << " " << (size_t)it.first << "<-" << (size_t)it.second << "\n";
2079                     }
2080                     std::cerr << " After:\n";
2081                     for (auto &it : result) {
2082                         std::cerr << " " << (size_t)it.first << "<-" << (size_t)it.second << "\n";
2083                     }
2084                     std::cerr << " Fault on " << (size_t)j << " and " << (size_t)k << "\n";
2085                     EXPECT_NE(result[k].second, dst);
2086                 }
2087             }
2088         }
2089 
2090         // Second analysis - if remove all same moves - there will be
2091         // only " move tmp <- reg " & " mov reg <- tmp"
2092     }
2093 }
2094 
TEST_F(CodegenTest,BoundsCheckI)2095 TEST_F(CodegenTest, BoundsCheckI)
2096 {
2097     uint64_t array_data[4098];
2098     for (unsigned i = 0; i < 4098; i++) {
2099         array_data[i] = i;
2100     }
2101 
2102     for (unsigned index = 4095; index <= 4097; index++) {
2103         auto graph = CreateEmptyGraph();
2104         GRAPH(graph)
2105         {
2106             PARAMETER(0, 0).ref();  // array
2107             BASIC_BLOCK(2, -1)
2108             {
2109                 INST(1, Opcode::SaveState).Inputs(0).SrcVregs({0});
2110                 INST(2, Opcode::NullCheck).ref().Inputs(0, 1);
2111                 INST(3, Opcode::LenArray).s32().Inputs(2);
2112                 INST(4, Opcode::BoundsCheckI).s32().Inputs(3, 1).Imm(index);
2113                 INST(5, Opcode::LoadArrayI).u64().Inputs(2).Imm(index);
2114                 INST(6, Opcode::Return).u64().Inputs(5);
2115             }
2116         }
2117 
2118         SetNumVirtRegs(0);
2119         SetNumArgs(1);
2120 
2121         RegAlloc(graph);
2122 
2123         // Run codegen
2124         EXPECT_TRUE(RunCodegen(graph));
2125         auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
2126         auto code_exit = code_entry + graph->GetData().Size();
2127         ASSERT(code_entry != nullptr && code_exit != nullptr);
2128         GetExecModule().SetInstructions(code_entry, code_exit);
2129 
2130         // Enable dumping
2131         GetExecModule().SetDump(false);
2132 
2133         auto param = GetExecModule().CreateArray(array_data, index + 1, GetObjectAllocator());
2134         GetExecModule().SetParameter(0U, reinterpret_cast<uint64_t>(param));
2135 
2136         GetExecModule().Execute();
2137         GetExecModule().SetDump(false);
2138         // End dump
2139 
2140         auto ret_data = GetExecModule().GetRetValue();
2141         EXPECT_EQ(ret_data, index);
2142 
2143         GetExecModule().FreeArray(param);
2144     }
2145 }
2146 
TEST_F(CodegenTest,MultiplyAddInteger)2147 TEST_F(CodegenTest, MultiplyAddInteger)
2148 {
2149     if (GetGraph()->GetArch() != Arch::AARCH64) {
2150         GTEST_SKIP() << "multiply-add instruction is only supported on Aarch64";
2151     }
2152 
2153     GRAPH(GetGraph())
2154     {
2155         CONSTANT(0, 10);
2156         CONSTANT(1, 42);
2157         CONSTANT(2, 13);
2158 
2159         BASIC_BLOCK(2, -1)
2160         {
2161             INST(3, Opcode::MAdd).s64().Inputs(0, 1, 2);
2162             INST(4, Opcode::Return).s64().Inputs(3);
2163         }
2164     }
2165 
2166     CheckReturnValue(GetGraph(), 433);
2167 }
2168 
TEST_F(CodegenTest,MultiplyAddFloat)2169 TEST_F(CodegenTest, MultiplyAddFloat)
2170 {
2171     if (GetGraph()->GetArch() != Arch::AARCH64) {
2172         GTEST_SKIP() << "multiply-add instruction is only supported on Aarch64";
2173     }
2174 
2175     GRAPH(GetGraph())
2176     {
2177         CONSTANT(0, 10.0);
2178         CONSTANT(1, 42.0);
2179         CONSTANT(2, 13.0);
2180 
2181         BASIC_BLOCK(2, -1)
2182         {
2183             INST(3, Opcode::MAdd).f64().Inputs(0, 1, 2);
2184             INST(4, Opcode::Return).f64().Inputs(3);
2185         }
2186     }
2187 
2188     CheckReturnValue(GetGraph(), 433.0);
2189 }
2190 
TEST_F(CodegenTest,MultiplySubtractInteger)2191 TEST_F(CodegenTest, MultiplySubtractInteger)
2192 {
2193     if (GetGraph()->GetArch() != Arch::AARCH64) {
2194         GTEST_SKIP() << "multiply-subtract instruction is only supported on Aarch64";
2195     }
2196 
2197     GRAPH(GetGraph())
2198     {
2199         CONSTANT(0, 10);
2200         CONSTANT(1, 42);
2201         CONSTANT(2, 13);
2202 
2203         BASIC_BLOCK(2, -1)
2204         {
2205             INST(3, Opcode::MSub).s64().Inputs(0, 1, 2);
2206             INST(4, Opcode::Return).s64().Inputs(3);
2207         }
2208     }
2209 
2210     CheckReturnValue(GetGraph(), -407);
2211 }
2212 
TEST_F(CodegenTest,MultiplySubtractFloat)2213 TEST_F(CodegenTest, MultiplySubtractFloat)
2214 {
2215     if (GetGraph()->GetArch() != Arch::AARCH64) {
2216         GTEST_SKIP() << "multiply-subtract instruction is only supported on Aarch64";
2217     }
2218 
2219     GRAPH(GetGraph())
2220     {
2221         CONSTANT(0, 10.0);
2222         CONSTANT(1, 42.0);
2223         CONSTANT(2, 13.0);
2224 
2225         BASIC_BLOCK(2, -1)
2226         {
2227             INST(3, Opcode::MSub).f64().Inputs(0, 1, 2);
2228             INST(4, Opcode::Return).f64().Inputs(3);
2229         }
2230     }
2231 
2232     CheckReturnValue(GetGraph(), -407.0);
2233 }
2234 
TEST_F(CodegenTest,MultiplyNegateInteger)2235 TEST_F(CodegenTest, MultiplyNegateInteger)
2236 {
2237     if (GetGraph()->GetArch() != Arch::AARCH64) {
2238         GTEST_SKIP() << "multiply-negate instruction is only supported on Aarch64";
2239     }
2240 
2241     GRAPH(GetGraph())
2242     {
2243         CONSTANT(0, 5);
2244         CONSTANT(1, 5);
2245 
2246         BASIC_BLOCK(2, -1)
2247         {
2248             INST(2, Opcode::MNeg).s64().Inputs(0, 1);
2249             INST(3, Opcode::Return).s64().Inputs(2);
2250         }
2251     }
2252 
2253     CheckReturnValue(GetGraph(), -25);
2254 }
2255 
TEST_F(CodegenTest,MultiplyNegateFloat)2256 TEST_F(CodegenTest, MultiplyNegateFloat)
2257 {
2258     if (GetGraph()->GetArch() != Arch::AARCH64) {
2259         GTEST_SKIP() << "multiply-negate instruction is only supported on Aarch64";
2260     }
2261 
2262     GRAPH(GetGraph())
2263     {
2264         CONSTANT(0, 5.0);
2265         CONSTANT(1, 5.0);
2266 
2267         BASIC_BLOCK(2, -1)
2268         {
2269             INST(2, Opcode::MNeg).f64().Inputs(0, 1);
2270             INST(3, Opcode::Return).f64().Inputs(2);
2271         }
2272     }
2273 
2274     CheckReturnValue(GetGraph(), -25.0);
2275 }
2276 
TEST_F(CodegenTest,OrNot)2277 TEST_F(CodegenTest, OrNot)
2278 {
2279     if (GetGraph()->GetArch() != Arch::AARCH64) {
2280         GTEST_SKIP() << "multiply-negate instruction is only supported on Aarch64";
2281     }
2282 
2283     GRAPH(GetGraph())
2284     {
2285         CONSTANT(0, 0x0000beef);
2286         CONSTANT(1, 0x2152ffff);
2287 
2288         BASIC_BLOCK(2, -1)
2289         {
2290             INST(2, Opcode::OrNot).u32().Inputs(0, 1);
2291             INST(3, Opcode::Return).u32().Inputs(2);
2292         }
2293     }
2294 
2295     CheckReturnValue(GetGraph(), 0xdeadbeef);
2296 }
2297 
TEST_F(CodegenTest,AndNot)2298 TEST_F(CodegenTest, AndNot)
2299 {
2300     if (GetGraph()->GetArch() != Arch::AARCH64) {
2301         GTEST_SKIP() << "multiply-negate instruction is only supported on Aarch64";
2302     }
2303 
2304     GRAPH(GetGraph())
2305     {
2306         CONSTANT(0, 0xf0000003);
2307         CONSTANT(1, 0x1);
2308 
2309         BASIC_BLOCK(2, -1)
2310         {
2311             INST(2, Opcode::AndNot).u32().Inputs(0, 1);
2312             INST(3, Opcode::Return).u32().Inputs(2);
2313         }
2314     }
2315 
2316     CheckReturnValue(GetGraph(), 0xf0000002);
2317 }
2318 
TEST_F(CodegenTest,XorNot)2319 TEST_F(CodegenTest, XorNot)
2320 {
2321     if (GetGraph()->GetArch() != Arch::AARCH64) {
2322         GTEST_SKIP() << "multiply-negate instruction is only supported on Aarch64";
2323     }
2324 
2325     GRAPH(GetGraph())
2326     {
2327         CONSTANT(0, 0xf0f1ffd0);
2328         CONSTANT(1, 0xcf0fc0f1);
2329 
2330         BASIC_BLOCK(2, -1)
2331         {
2332             INST(2, Opcode::XorNot).u32().Inputs(0, 1);
2333             INST(3, Opcode::Return).u32().Inputs(2);
2334         }
2335     }
2336 
2337     CheckReturnValue(GetGraph(), 0xc001c0de);
2338 }
2339 
TEST_F(CodegenTest,AddSR)2340 TEST_F(CodegenTest, AddSR)
2341 {
2342     if (GetGraph()->GetArch() != Arch::AARCH64) {
2343         GTEST_SKIP() << "AddSR instruction is only supported on Aarch64";
2344     }
2345 
2346     TestBinaryOperationWithShiftedOperand(Opcode::AddSR, 10, 2, ShiftType::LSL, 1, 14);
2347 }
2348 
TEST_F(CodegenTest,SubSR)2349 TEST_F(CodegenTest, SubSR)
2350 {
2351     if (GetGraph()->GetArch() != Arch::AARCH64) {
2352         GTEST_SKIP() << "SubSR instruction is only supported on Aarch64";
2353     }
2354 
2355     TestBinaryOperationWithShiftedOperand(Opcode::SubSR, 10, 4, ShiftType::LSR, 2, 9);
2356 }
2357 
TEST_F(CodegenTest,AndSR)2358 TEST_F(CodegenTest, AndSR)
2359 {
2360     if (GetGraph()->GetArch() != Arch::AARCH64) {
2361         GTEST_SKIP() << "AndSR instruction is only supported on Aarch64";
2362     }
2363 
2364     TestBinaryOperationWithShiftedOperand(Opcode::AndSR, 1, 1, ShiftType::LSL, 1, 0);
2365 }
2366 
TEST_F(CodegenTest,OrSR)2367 TEST_F(CodegenTest, OrSR)
2368 {
2369     if (GetGraph()->GetArch() != Arch::AARCH64) {
2370         GTEST_SKIP() << "OrSR instruction is only supported on Aarch64";
2371     }
2372 
2373     TestBinaryOperationWithShiftedOperand(Opcode::OrSR, 1, 1, ShiftType::LSL, 1, 3);
2374 }
2375 
TEST_F(CodegenTest,XorSR)2376 TEST_F(CodegenTest, XorSR)
2377 {
2378     if (GetGraph()->GetArch() != Arch::AARCH64) {
2379         GTEST_SKIP() << "XorSR instruction is only supported on Aarch64";
2380     }
2381 
2382     TestBinaryOperationWithShiftedOperand(Opcode::XorSR, 3, 1, ShiftType::LSL, 1, 1);
2383 }
2384 
TEST_F(CodegenTest,AndNotSR)2385 TEST_F(CodegenTest, AndNotSR)
2386 {
2387     if (GetGraph()->GetArch() != Arch::AARCH64) {
2388         GTEST_SKIP() << "AndNotSR instruction is only supported on Aarch64";
2389     }
2390 
2391     TestBinaryOperationWithShiftedOperand(Opcode::AndNotSR, 6, 12, ShiftType::LSR, 2, 4);
2392 }
2393 
TEST_F(CodegenTest,OrNotSR)2394 TEST_F(CodegenTest, OrNotSR)
2395 {
2396     if (GetGraph()->GetArch() != Arch::AARCH64) {
2397         GTEST_SKIP() << "OrNotSR instruction is only supported on Aarch64";
2398     }
2399 
2400     TestBinaryOperationWithShiftedOperand(Opcode::OrNotSR, 1, 12, ShiftType::LSR, 2, 0xfffffffd);
2401 }
2402 
TEST_F(CodegenTest,XorNotSR)2403 TEST_F(CodegenTest, XorNotSR)
2404 {
2405     if (GetGraph()->GetArch() != Arch::AARCH64) {
2406         GTEST_SKIP() << "XorNotSR instruction is only supported on Aarch64";
2407     }
2408 
2409     TestBinaryOperationWithShiftedOperand(Opcode::XorNotSR, -1, 12, ShiftType::LSR, 2, 3);
2410 }
2411 
TEST_F(CodegenTest,NegSR)2412 TEST_F(CodegenTest, NegSR)
2413 {
2414     if (GetGraph()->GetArch() != Arch::AARCH64) {
2415         GTEST_SKIP() << "NegSR instruction is only supported on Aarch64";
2416     }
2417 
2418     GRAPH(GetGraph())
2419     {
2420         CONSTANT(0, 0x80000000);
2421 
2422         BASIC_BLOCK(2, -1)
2423         {
2424             INST(1, Opcode::NegSR).Shift(ShiftType::ASR, 1).u32().Inputs(0);
2425             INST(2, Opcode::Return).u32().Inputs(1);
2426         }
2427     }
2428 
2429     CheckReturnValue(GetGraph(), 0x40000000);
2430 }
2431 
TEST_F(CodegenTest,LoadArrayPairLivenessInfo)2432 TEST_F(CodegenTest, LoadArrayPairLivenessInfo)
2433 {
2434     auto graph = GetGraph();
2435 
2436     GRAPH(graph)
2437     {
2438         PARAMETER(0, 0).ref();
2439         PARAMETER(1, 1).s32();
2440 
2441         BASIC_BLOCK(2, -1)
2442         {
2443             INST(2, Opcode::LoadArrayPair).s32().Inputs(0, 1);
2444             INST(4, Opcode::LoadPairPart).s32().Inputs(2).Imm(0);
2445             INST(5, Opcode::LoadPairPart).s32().Inputs(2).Imm(1);
2446             INST(12, Opcode::SaveState).Inputs(0).SrcVregs({0});
2447             INST(10, Opcode::LoadClass)
2448                 .ref()
2449                 .Inputs(12)
2450                 .TypeId(42)
2451                 .Class(reinterpret_cast<RuntimeInterface::ClassPtr>(1));
2452             INST(3, Opcode::IsInstance).b().Inputs(0, 10, 12).TypeId(42);
2453             INST(6, Opcode::Cast).s32().SrcType(DataType::BOOL).Inputs(3);
2454             INST(7, Opcode::Add).s32().Inputs(4, 5);
2455             INST(8, Opcode::Add).s32().Inputs(7, 6);
2456             INST(9, Opcode::Return).s32().Inputs(8);
2457         }
2458     }
2459 
2460     SetNumVirtRegs(0);
2461     SetNumArgs(2);
2462     RegAlloc(graph);
2463     EXPECT_TRUE(RunCodegen(graph));
2464 
2465     RegMask ldp_regs {};
2466 
2467     auto cg = Codegen(graph);
2468     for (auto &bb : graph->GetBlocksLinearOrder()) {
2469         for (auto inst : bb->AllInsts()) {
2470             if (inst->GetOpcode() == Opcode::LoadArrayPair) {
2471                 ldp_regs.set(inst->GetDstReg(0));
2472                 ldp_regs.set(inst->GetDstReg(1));
2473             } else if (inst->GetOpcode() == Opcode::IsInstance) {
2474                 auto live_regs = cg.GetLiveRegisters(inst).first;
2475                 // Both dst registers should be alive during IsInstance call
2476                 ASSERT_EQ(ldp_regs & live_regs, ldp_regs);
2477             }
2478         }
2479     }
2480 }
2481 
TEST_F(CodegenTest,CompareAnyTypeInst)2482 TEST_F(CodegenTest, CompareAnyTypeInst)
2483 {
2484     auto graph = GetGraph();
2485     graph->SetDynamicMethod();
2486     GRAPH(graph)
2487     {
2488         PARAMETER(0, 0);
2489         INS(0).SetType(DataType::Type::ANY);
2490 
2491         BASIC_BLOCK(2, -1)
2492         {
2493             INST(2, Opcode::CompareAnyType).b().AnyType(AnyBaseType::UNDEFINED_TYPE).Inputs(0);
2494             INST(3, Opcode::Return).b().Inputs(2);
2495         }
2496     }
2497 
2498     SetNumVirtRegs(0);
2499     ASSERT_TRUE(RegAlloc(graph));
2500     ASSERT_TRUE(RunCodegen(graph));
2501 
2502     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
2503     auto code_exit = code_entry + graph->GetData().Size();
2504 
2505     ASSERT(code_entry != nullptr && code_exit != nullptr);
2506 
2507     GetExecModule().SetInstructions(code_entry, code_exit);
2508     GetExecModule().SetDump(false);
2509 
2510     GetExecModule().Execute();
2511     auto rv = GetExecModule().GetRetValue<bool>();
2512     EXPECT_EQ(rv, true);
2513 }
2514 
TEST_F(CodegenTest,CastAnyTypeValueInst)2515 TEST_F(CodegenTest, CastAnyTypeValueInst)
2516 {
2517     auto graph = GetGraph();
2518     graph->SetDynamicMethod();
2519     GRAPH(graph)
2520     {
2521         PARAMETER(0, 0);
2522         INS(0).SetType(DataType::Type::ANY);
2523 
2524         BASIC_BLOCK(2, -1)
2525         {
2526             INST(2, Opcode::CastAnyTypeValue).b().AnyType(AnyBaseType::UNDEFINED_TYPE).Inputs(0);
2527             INST(3, Opcode::Return).b().Inputs(2);
2528         }
2529     }
2530 
2531     SetNumVirtRegs(0);
2532     ASSERT_TRUE(RegAlloc(graph));
2533     ASSERT_TRUE(RunCodegen(graph));
2534 
2535     auto code_entry = reinterpret_cast<char *>(graph->GetData().Data());
2536     auto code_exit = code_entry + graph->GetData().Size();
2537 
2538     ASSERT(code_entry != nullptr && code_exit != nullptr);
2539 
2540     GetExecModule().SetInstructions(code_entry, code_exit);
2541     GetExecModule().SetDump(false);
2542 
2543     GetExecModule().Execute();
2544     auto rv = GetExecModule().GetRetValue<uint32_t>();
2545     EXPECT_EQ(rv, 0);
2546 }
2547 
2548 }  // namespace panda::compiler
2549