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