• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <climits>
17 
18 #include <random>
19 #include <gtest/gtest.h>
20 
21 #include "mem/code_allocator.h"
22 #include "mem/pool_manager.h"
23 #include "target/aarch64/target.h"
24 #include "mem/base_mem_stats.h"
25 
26 template <typename T>
27 const char *TypeName(void);
28 template <typename T>
TypeName(T)29 const char *TypeName(T)
30 {
31     return TypeName<T>();
32 }
33 
34 #define CLASS_NAME(type)             \
35     template <>                      \
36     const char *TypeName<type>(void) \
37     {                                \
38         return #type;                \
39     }
40 
41 CLASS_NAME(int8_t)
42 CLASS_NAME(int16_t)
43 CLASS_NAME(int32_t)
44 CLASS_NAME(int64_t)
45 CLASS_NAME(uint8_t)
46 CLASS_NAME(uint16_t)
47 CLASS_NAME(uint32_t)
48 CLASS_NAME(uint64_t)
49 CLASS_NAME(float)
50 CLASS_NAME(double)
51 
52 const uint64_t SEED = 0x1234;
53 const uint64_t ARRAY_SIZE = 10;
54 #ifndef PANDA_NIGHTLY_TEST_ON
55 const uint64_t ITERATION = 40;
56 #else
57 const uint64_t ITERATION = 4000;
58 #endif
59 static inline auto random_generator = std::mt19937_64(SEED);
60 
61 // Max and min exponent on the basus of two float and double
62 static const float MIN_EXP_BASE2_FLOAT = std::log2(FLT_MIN);
63 static const float MAX_EXP_BASE2_FLOAT = std::log2(FLT_MAX) - 1.0;
64 static const double MIN_EXP_BASE2_DOUBLE = std::log2(DBL_MIN);
65 static const double MAX_EXP_BASE2_DOUBLE = std::log2(DBL_MAX) - 1.0;
66 
67 // Masks for generete denormal float numbers
68 static const uint32_t MASK_DENORMAL_FLOAT = 0x807FFFFF;
69 static const uint64_t MASK_DENORMAL_DOUBLE = 0x800FFFFFFFFFFFFF;
70 
71 template <typename T>
random_gen()72 static T random_gen()
73 {
74     auto gen {random_generator()};
75 
76     if constexpr (std::is_integral_v<T>) {
77         return gen;
78     } else {
79         switch (gen % 20U) {
80             case (0U):
81                 return std::numeric_limits<T>::quiet_NaN();
82 
83             case (1U):
84                 return std::numeric_limits<T>::infinity();
85 
86             case (2U):
87                 return -std::numeric_limits<T>::infinity();
88 
89             case (3U): {
90                 if constexpr (std::is_same_v<T, float>) {
91                     return panda::bit_cast<float, uint32_t>(gen & MASK_DENORMAL_FLOAT);
92                 } else {
93                     return panda::bit_cast<double, uint64_t>(gen & MASK_DENORMAL_DOUBLE);
94                 }
95             }
96             default:
97                 break;
98         }
99 
100         // Uniform distribution floating value
101         std::uniform_real_distribution<T> dis_num(1.0, 2.0);
102         int8_t sign = (gen % 2) == 0 ? 1 : -1;
103         if constexpr (std::is_same_v<T, float>) {
104             std::uniform_real_distribution<float> dis(MIN_EXP_BASE2_FLOAT, MAX_EXP_BASE2_FLOAT);
105             return sign * dis_num(random_generator) * std::pow(2.0F, dis(random_generator));
106         } else if constexpr (std::is_same_v<T, double>) {
107             std::uniform_real_distribution<double> dis(MIN_EXP_BASE2_DOUBLE, MAX_EXP_BASE2_DOUBLE);
108             return sign * dis_num(random_generator) * std::pow(2.0, dis(random_generator));
109         }
110 
111         UNREACHABLE();
112     }
113 }
114 
115 template <typename T>
random_mask_gen()116 T random_mask_gen()
117 {
118     static_assert(std::is_integral_v<T>);
119     static constexpr size_t MASKS_COUNT = 4;
120     static constexpr std::array<uint64_t, MASKS_COUNT> MASKS = {0x8888888888888888ULL, 0xCCCCCCCCCCCCCCCCULL,
121                                                                 0xAAAAAAAAAAAAAAAAULL, 0xEEEEEEEEEEEEEEEEULL};
122     auto mask = MASKS[random_generator() % MASKS_COUNT];
123     auto type_size = panda::compiler::TypeInfo(T(0)).GetSize();
124     auto rot = random_generator() % type_size;
125     auto rotated_mask = (mask << rot) | (mask >> (type_size - rot));
126     return static_cast<T>(rotated_mask);
127 }
128 
129 namespace panda::compiler {
130 class Encoder64Test : public ::testing::Test {
131 public:
Encoder64Test()132     Encoder64Test()
133     {
134         panda::mem::MemConfig::Initialize(64_MB, 64_MB, 64_MB, 32_MB);
135         PoolManager::Initialize();
136         allocator_ = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER);
137         encoder_ = Encoder::Create(allocator_, Arch::AARCH64, false);
138         encoder_->InitMasm();
139         regfile_ = RegistersDescription::Create(allocator_, Arch::AARCH64);
140         callconv_ = CallingConvention::Create(allocator_, encoder_, regfile_, Arch::AARCH64);
141         encoder_->SetRegfile(regfile_);
142         mem_stats_ = new BaseMemStats();
143         code_alloc_ = new (std::nothrow) CodeAllocator(mem_stats_);
144     }
145 
~Encoder64Test()146     virtual ~Encoder64Test()
147     {
148         Logger::Destroy();
149         encoder_->~Encoder();
150         delete allocator_;
151         delete code_alloc_;
152         delete mem_stats_;
153         PoolManager::Finalize();
154         panda::mem::MemConfig::Finalize();
155     }
156 
GetCodeAllocator()157     CodeAllocator *GetCodeAllocator()
158     {
159         return code_alloc_;
160     }
161 
ResetCodeAllocator(void * ptr,size_t size)162     void ResetCodeAllocator(void *ptr, size_t size)
163     {
164         os::mem::MapRange<std::byte> mem_range(static_cast<std::byte *>(ptr), size);
165         mem_range.MakeReadWrite();
166         delete code_alloc_;
167         code_alloc_ = new (std::nothrow) CodeAllocator(mem_stats_);
168     }
169 
GetAllocator()170     ArenaAllocator *GetAllocator()
171     {
172         return allocator_;
173     }
174 
GetEncoder()175     Encoder *GetEncoder()
176     {
177         return encoder_;
178     }
179 
GetRegfile()180     RegistersDescription *GetRegfile()
181     {
182         return regfile_;
183     }
184 
GetCallconv()185     CallingConvention *GetCallconv()
186     {
187         return callconv_;
188     }
189 
GetCursor()190     size_t GetCursor()
191     {
192         return curr_cursor_;
193     }
194 
195     // Warning! Do not use multiply times with different types!
GetParameter(TypeInfo type,int id=0)196     Reg GetParameter(TypeInfo type, int id = 0)
197     {
198         ASSERT(id < 4);
199         if (type.IsFloat()) {
200             return Reg(id, type);
201         }
202 
203         return Target::Current().GetParamReg(id, type);
204     }
205 
PreWork()206     void PreWork()
207     {
208         // Curor need to encode multiply tests due one execution
209         curr_cursor_ = 0;
210         encoder_->SetCursorOffset(0);
211         callconv_->GeneratePrologue(FrameInfo::FullPrologue());
212     }
213 
PostWork()214     void PostWork()
215     {
216         callconv_->GenerateEpilogue(FrameInfo::FullPrologue(), []() {});
217         encoder_->Finalize();
218     }
219 
Dump(bool enabled)220     void Dump(bool enabled)
221     {
222         if (enabled) {
223             auto size = callconv_->GetCodeSize() - curr_cursor_;
224             for (uint32_t i = curr_cursor_; i < curr_cursor_ + size;) {
225                 i = encoder_->DisasmInstr(std::cout, i, 0);
226                 std::cout << std::endl;
227             }
228         }
229     }
230 
231     template <typename T, typename U>
CallCode(const T & param,const U & result)232     bool CallCode(const T &param, const U &result)
233     {
234         // Using max size type: type result "U" or 32bit to check result,
235         // because in our ISA min type is 32bit.
236         // Only integers less thаn 32bit.
237         typedef typename std::conditional<(sizeof(U) * BYTE_SIZE) >= WORD_SIZE, U, uint32_t>::type U_exp;
238         typedef typename std::conditional<(sizeof(T) * BYTE_SIZE) >= WORD_SIZE, T, uint32_t>::type T_exp;
239         using funct_ptr = U_exp (*)(T_exp data);
240         auto size = callconv_->GetCodeSize() - curr_cursor_;
241         void *offset = (static_cast<uint8_t *>(callconv_->GetCodeEntry()));
242         void *ptr = code_alloc_->AllocateCode(size, offset);
243         auto func = reinterpret_cast<funct_ptr>(ptr);
244         // We must make caste to transfer to function a correctly expanded number
245         const U_exp curr_result = func(static_cast<T_exp>(param));
246         ResetCodeAllocator(ptr, size);
247         bool ret = false;
248         if constexpr (std::is_floating_point_v<T> || std::is_floating_point_v<U>) {
249             ret = (curr_result == result && std::signbit(curr_result) == std::signbit(result)) ||
250                   (std::isnan(curr_result) && std::isnan(result));
251         } else {
252             ret = (curr_result - result == 0);
253         }
254         if (!ret) {
255             std::cerr << std::hex << "Failed CallCode for param=" << param << " and result=" << result
256                       << " current_reslt=" << curr_result << "\n";
257             if constexpr (std::is_floating_point_v<T> || std::is_floating_point_v<U>) {
258                 std::cerr << "In binary :";
259                 if constexpr (std::is_same<double, T>::value) {
260                     std::cerr << " param=" << bit_cast<uint64_t>(param);
261                 } else if constexpr (std::is_same<float, T>::value) {
262                     std::cerr << " param=" << bit_cast<uint32_t>(param);
263                 }
264                 if constexpr (std::is_same<double, U>::value) {
265                     std::cerr << " reslt=" << bit_cast<uint64_t>(result);
266                     std::cerr << " current_reslt=" << bit_cast<uint64_t>(curr_result);
267                 } else if constexpr (std::is_same<float, U>::value) {
268                     std::cerr << " result=" << bit_cast<uint32_t>(result);
269                     std::cerr << " current_reslt=" << bit_cast<uint32_t>(curr_result);
270                 }
271                 std::cerr << "\n";
272             }
273             Dump(true);
274         }
275         return ret;
276     }
277 
278     template <typename T, typename U>
CallCode(const T & param1,const T & param2,const U & result)279     bool CallCode(const T &param1, const T &param2, const U &result)
280     {
281         typedef typename std::conditional<(sizeof(U) * BYTE_SIZE) >= WORD_SIZE, U, uint32_t>::type U_exp;
282         typedef typename std::conditional<(sizeof(T) * BYTE_SIZE) >= WORD_SIZE, T, uint32_t>::type T_exp;
283         using funct_ptr = U_exp (*)(T_exp param1, T_exp param2);
284         auto size = callconv_->GetCodeSize() - curr_cursor_;
285         void *offset = (static_cast<uint8_t *>(callconv_->GetCodeEntry()));
286         void *ptr = code_alloc_->AllocateCode(size, offset);
287         auto func = reinterpret_cast<funct_ptr>(ptr);
288         const U_exp curr_result = func(static_cast<T_exp>(param1), static_cast<T_exp>(param2));
289         ResetCodeAllocator(ptr, size);
290         bool ret = false;
291         if constexpr (std::is_same<float, T>::value || std::is_same<double, T>::value) {
292             ret = (curr_result == result && std::signbit(curr_result) == std::signbit(result)) ||
293                   (std::isnan(curr_result) && std::isnan(result));
294         } else {
295             ret = (curr_result - result == 0);
296         }
297         if (!ret) {
298             std::cerr << "Failed CallCode for param1=" << param1 << " param2=" << param2 << " and result=" << result
299                       << " current_result=" << curr_result << "\n";
300             if constexpr (std::is_floating_point_v<T> || std::is_floating_point_v<U>) {
301                 std::cerr << "In binary :";
302                 if constexpr (std::is_same<double, T>::value) {
303                     std::cerr << " param1=" << bit_cast<uint64_t>(param1) << " param2=" << bit_cast<uint64_t>(param2);
304                 } else if constexpr (std::is_same<float, T>::value) {
305                     std::cerr << " param1=" << bit_cast<uint32_t>(param1) << " param2=" << bit_cast<uint32_t>(param2);
306                 }
307                 if constexpr (std::is_same<double, U>::value) {
308                     std::cerr << " reslt=" << bit_cast<uint64_t>(result);
309                     std::cerr << " current_reslt=" << bit_cast<uint64_t>(curr_result);
310 
311                 } else if constexpr (std::is_same<float, U>::value) {
312                     std::cerr << " result=" << bit_cast<uint32_t>(result);
313                     std::cerr << " current_result=" << bit_cast<uint32_t>(curr_result);
314                 }
315                 std::cerr << "\n";
316             }
317             Dump(true);
318         }
319         return ret;
320     }
321 
322     template <typename T>
CallCode(const T & param,const T & result)323     bool CallCode(const T &param, const T &result)
324     {
325         typedef typename std::conditional<(sizeof(T) * BYTE_SIZE) >= WORD_SIZE, T, uint32_t>::type T_exp;
326         using funct_ptr = T_exp (*)(T_exp data);
327         auto size = callconv_->GetCodeSize() - curr_cursor_;
328         void *offset = (static_cast<uint8_t *>(callconv_->GetCodeEntry()));
329         void *ptr = code_alloc_->AllocateCode(size, offset);
330         auto func = reinterpret_cast<funct_ptr>(ptr);
331         const T_exp curr_result = func(static_cast<T_exp>(param));
332         ResetCodeAllocator(ptr, size);
333         bool ret = false;
334         if constexpr (std::is_same<float, T>::value || std::is_same<double, T>::value) {
335             ret = (curr_result == result && std::signbit(curr_result) == std::signbit(result)) ||
336                   (std::isnan(curr_result) && std::isnan(result));
337         } else {
338             ret = (curr_result - result == 0);
339         }
340         if (!ret) {
341             std::cerr << std::hex << "Failed CallCode for param=" << param << " and result=" << result
342                       << " current_result=" << curr_result << "\n";
343             if constexpr (std::is_floating_point_v<T>) {
344                 std::cerr << "In binary :";
345                 if constexpr (std::is_same<double, T>::value) {
346                     std::cerr << " param=" << bit_cast<uint64_t>(param);
347                     std::cerr << " reslt=" << bit_cast<uint64_t>(result);
348                     std::cerr << " curr_reslt=" << bit_cast<uint64_t>(curr_result);
349                 } else if constexpr (std::is_same<float, T>::value) {
350                     std::cerr << " param=" << bit_cast<uint32_t>(param);
351                     std::cerr << " curr_result=" << bit_cast<uint32_t>(curr_result);
352                 }
353                 std::cerr << "\n";
354             }
355             Dump(true);
356         }
357         return ret;
358     }
359 
360     template <typename T>
CallCode(const T & param1,const T & param2,const T & result)361     bool CallCode(const T &param1, const T &param2, const T &result)
362     {
363         typedef typename std::conditional<(sizeof(T) * BYTE_SIZE) >= WORD_SIZE, T, uint32_t>::type T_exp;
364         using funct_ptr = T_exp (*)(T_exp param1, T_exp param2);
365         auto size = callconv_->GetCodeSize() - curr_cursor_;
366         void *offset = (static_cast<uint8_t *>(callconv_->GetCodeEntry()));
367         void *ptr = code_alloc_->AllocateCode(size, offset);
368         auto func = reinterpret_cast<funct_ptr>(ptr);
369         const T_exp curr_result = func(static_cast<T_exp>(param1), static_cast<T_exp>(param2));
370         ResetCodeAllocator(ptr, size);
371         bool ret = false;
372         if constexpr (std::is_same<float, T>::value || std::is_same<double, T>::value) {
373             ret = (curr_result == result && std::signbit(curr_result) == std::signbit(result)) ||
374                   (std::isnan(curr_result) && std::isnan(result));
375         } else {
376             ret = (curr_result - result == 0);
377         }
378         if (!ret) {
379             std::cerr << "Failed CallCode for param1=" << param1 << " param2=" << param2 << " and result=" << result
380                       << " curr_result=" << curr_result << "\n";
381             if constexpr (std::is_floating_point_v<T>) {
382                 std::cerr << "In binary :";
383                 if constexpr (std::is_same<double, T>::value) {
384                     std::cerr << " param1=" << bit_cast<uint64_t>(param1) << " param2=" << bit_cast<uint64_t>(param2);
385                     std::cerr << " reslt=" << bit_cast<uint64_t>(result)
386                               << " curr_result=" << bit_cast<uint64_t>(curr_result);
387                 } else if constexpr (std::is_same<float, T>::value) {
388                     std::cerr << " param1=" << bit_cast<uint32_t>(param1) << " param2=" << bit_cast<uint32_t>(param2);
389                     std::cerr << " result=" << bit_cast<uint32_t>(result)
390                               << " curr_result=" << bit_cast<uint32_t>(curr_result);
391                 }
392                 std::cerr << "\n";
393             }
394             Dump(true);
395         }
396         return ret;
397     }
398 
399     template <typename T>
CallCodeStore(uint64_t address,T param)400     T CallCodeStore(uint64_t address, T param)
401     {
402         using funct_ptr = T (*)(uint64_t param1, T param2);
403         auto size = callconv_->GetCodeSize() - curr_cursor_;
404         void *offset = (static_cast<uint8_t *>(callconv_->GetCodeEntry()));
405         void *ptr = code_alloc_->AllocateCode(size, offset);
406         auto func = reinterpret_cast<funct_ptr>(ptr);
407         const T curr_result = func(address, param);
408         ResetCodeAllocator(ptr, size);
409         return curr_result;
410     }
411 
412     template <typename T, typename U>
CallCodeCall(T param1,T param2)413     U CallCodeCall(T param1, T param2)
414     {
415         using funct_ptr = U (*)(T param1, T param2);
416         auto size = callconv_->GetCodeSize() - curr_cursor_;
417         void *offset = (static_cast<uint8_t *>(callconv_->GetCodeEntry()));
418         void *ptr = code_alloc_->AllocateCode(size, offset);
419         auto func = reinterpret_cast<funct_ptr>(ptr);
420         const U curr_result = func(param1, param2);
421         ResetCodeAllocator(ptr, size);
422         return curr_result;
423     }
424 
425 private:
426     ArenaAllocator *allocator_ {nullptr};
427     Encoder *encoder_ {nullptr};
428     RegistersDescription *regfile_ {nullptr};
429     CallingConvention *callconv_ {nullptr};
430     CodeAllocator *code_alloc_ {nullptr};
431     BaseMemStats *mem_stats_ {nullptr};
432     size_t curr_cursor_ {0};
433 };
434 
435 template <typename T>
TestNeg(Encoder64Test * test)436 bool TestNeg(Encoder64Test *test)
437 {
438     // Initialize
439     test->PreWork();
440     // First type-dependency
441     auto param = test->GetParameter(TypeInfo(T(0)));
442     // Main test call
443     test->GetEncoder()->EncodeNeg(param, param);
444     // Finalize
445     test->PostWork();
446 
447     // If encode unsupported - now print error
448     if (!test->GetEncoder()->GetResult()) {
449         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
450         return false;
451     }
452     // Change this for enable print disasm
453     test->Dump(false);
454 
455     // Main test loop:
456     for (uint64_t i = 0; i < ITERATION; ++i) {
457         // Second type-dependency
458         T tmp = random_gen<T>();
459         // Deduced conflicting types for parameter
460 
461         // Main check - compare parameter and
462         // return value
463         if (!test->CallCode<T>(tmp, -tmp)) {
464             return false;
465         }
466     }
467 
468     if constexpr (std::is_floating_point_v<T>) {
469         T nan = std::numeric_limits<T>::quiet_NaN();
470 
471         if (!test->CallCode<T>(nan, nan)) {
472             return false;
473         }
474     }
475 
476     return true;
477 }
478 
TEST_F(Encoder64Test,NegTest)479 TEST_F(Encoder64Test, NegTest)
480 {
481     EXPECT_TRUE(TestNeg<int32_t>(this));
482     EXPECT_TRUE(TestNeg<int64_t>(this));
483     EXPECT_TRUE(TestNeg<float>(this));
484     EXPECT_TRUE(TestNeg<double>(this));
485 }
486 
487 template <typename T>
TestNot(Encoder64Test * test)488 bool TestNot(Encoder64Test *test)
489 {
490     // Initialize
491     test->PreWork();
492     // First type-dependency
493     auto param = test->GetParameter(TypeInfo(T(0)));
494     // Main test call
495     test->GetEncoder()->EncodeNot(param, param);
496     // Finalize
497     test->PostWork();
498 
499     // If encode unsupported - now print error
500     if (!test->GetEncoder()->GetResult()) {
501         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
502         return false;
503     }
504     // Change this for enable print disasm
505     test->Dump(false);
506 
507     // Main test loop:
508     for (uint64_t i = 0; i < ITERATION; ++i) {
509         // Second type-dependency
510         T tmp = random_gen<T>();
511 
512         // Deduced conflicting types for parameter
513 
514         // Main check - compare parameter and
515         // return value
516         if (!test->CallCode<T>(tmp, ~tmp)) {
517             return false;
518         }
519     }
520     return true;
521 }
522 
TEST_F(Encoder64Test,NotTest)523 TEST_F(Encoder64Test, NotTest)
524 {
525     EXPECT_TRUE(TestNot<int32_t>(this));
526     EXPECT_TRUE(TestNot<int64_t>(this));
527     EXPECT_TRUE(TestNot<uint32_t>(this));
528     EXPECT_TRUE(TestNot<uint64_t>(this));
529 }
530 
531 template <typename T>
TestMov(Encoder64Test * test)532 bool TestMov(Encoder64Test *test)
533 {
534     // Initialize
535     test->PreWork();
536     // First type-dependency
537     auto param = test->GetParameter(TypeInfo(T(0)));
538     // Main test call
539     test->GetEncoder()->EncodeMov(param, param);
540     // Finalize
541     test->PostWork();
542 
543     // If encode unsupported - now print error
544     if (!test->GetEncoder()->GetResult()) {
545         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
546         return false;
547     }
548     // Change this for enable print disasm
549     test->Dump(false);
550 
551     // Main test loop:
552     for (uint64_t i = 0; i < ITERATION; ++i) {
553         // Second type-dependency
554         T tmp = random_gen<T>();
555         // Deduced conflicting types for parameter
556 
557         // Main check - compare parameter and
558         // return value
559         if (!test->CallCode<T>(tmp, tmp)) {
560             return false;
561         }
562     }
563 
564     if constexpr (std::is_floating_point_v<T>) {
565         T nan = std::numeric_limits<T>::quiet_NaN();
566 
567         if (!test->CallCode<T>(nan, nan)) {
568             return false;
569         }
570     }
571 
572     return true;
573 }
574 
575 template <typename Src, typename Dst>
TestMov2(Encoder64Test * test)576 bool TestMov2(Encoder64Test *test)
577 {
578     static_assert(sizeof(Src) == sizeof(Dst));
579     // Initialize
580     test->PreWork();
581     // First type-dependency
582     auto input = test->GetParameter(TypeInfo(Src(0)), 0);
583     auto output = test->GetParameter(TypeInfo(Dst(0)), 0);
584     // Main test call
585     test->GetEncoder()->EncodeMov(output, input);
586     // Finalize
587     test->PostWork();
588 
589     // If encode unsupported - now print error
590     if (!test->GetEncoder()->GetResult()) {
591         std::cerr << "Unsupported for " << TypeName<Src>() << ", " << TypeName<Dst>() << "\n";
592         return false;
593     }
594     // Change this for enable print disasm
595     test->Dump(false);
596 
597     // Main test loop:
598     for (uint64_t i = 0; i < ITERATION; ++i) {
599         // Second type-dependency
600         Src src = random_gen<Src>();
601         Dst dst = bit_cast<Dst>(src);
602         // Deduced conflicting types for parameter
603 
604         // Main check - compare parameter and
605         // return value
606         if (!test->CallCode<Src, Dst>(src, dst)) {
607             return false;
608         }
609     }
610 
611     if constexpr (std::is_floating_point_v<Src>) {
612         Src nan = std::numeric_limits<Src>::quiet_NaN();
613         Dst dst_nan = bit_cast<Dst>(nan);
614 
615         if (!test->CallCode<Src, Dst>(nan, dst_nan)) {
616             return false;
617         }
618     }
619 
620     return true;
621 }
622 
TEST_F(Encoder64Test,MovTest)623 TEST_F(Encoder64Test, MovTest)
624 {
625     EXPECT_TRUE(TestMov<int32_t>(this));
626     EXPECT_TRUE(TestMov<int64_t>(this));
627     EXPECT_TRUE(TestMov<float>(this));
628     EXPECT_TRUE(TestMov<double>(this));
629 
630     EXPECT_TRUE((TestMov2<float, int32_t>(this)));
631     EXPECT_TRUE((TestMov2<double, int64_t>(this)));
632     EXPECT_TRUE((TestMov2<int32_t, float>(this)));
633     EXPECT_TRUE((TestMov2<int64_t, double>(this)));
634 
635     // TODO (igorban) : add MOVI instructions
636     // & support uint64_t mov
637 }
638 
639 // Jump w/o cc
TEST_F(Encoder64Test,JumpTest)640 TEST_F(Encoder64Test, JumpTest)
641 {
642     // Test for
643     // EncodeJump(LabelHolder::LabelId label)
644     PreWork();
645 
646     auto param = Target::Current().GetParamReg(0);
647 
648     auto t1 = GetEncoder()->CreateLabel();
649     auto t2 = GetEncoder()->CreateLabel();
650     auto t3 = GetEncoder()->CreateLabel();
651     auto t4 = GetEncoder()->CreateLabel();
652     auto t5 = GetEncoder()->CreateLabel();
653 
654     GetEncoder()->EncodeAdd(param, param, Imm(0x1));
655     GetEncoder()->EncodeJump(t1);
656     GetEncoder()->EncodeMov(param, Imm(0x0));
657     GetEncoder()->EncodeReturn();
658     // T4
659     GetEncoder()->BindLabel(t4);
660     GetEncoder()->EncodeAdd(param, param, Imm(0x1));
661     GetEncoder()->EncodeJump(t5);
662     // Fail value
663     GetEncoder()->EncodeMov(param, Imm(0x0));
664     GetEncoder()->EncodeReturn();
665 
666     // T2
667     GetEncoder()->BindLabel(t2);
668     GetEncoder()->EncodeAdd(param, param, Imm(0x1));
669     GetEncoder()->EncodeJump(t3);
670     // Fail value
671     GetEncoder()->EncodeMov(param, Imm(0x0));
672     GetEncoder()->EncodeReturn();
673     // T3
674     GetEncoder()->BindLabel(t3);
675     GetEncoder()->EncodeAdd(param, param, Imm(0x1));
676     GetEncoder()->EncodeJump(t4);
677     // Fail value
678     GetEncoder()->EncodeMov(param, Imm(0x0));
679     GetEncoder()->EncodeReturn();
680     // T1
681     GetEncoder()->BindLabel(t1);
682     GetEncoder()->EncodeAdd(param, param, Imm(0x1));
683     GetEncoder()->EncodeJump(t2);
684     // Fail value
685     GetEncoder()->EncodeMov(param, Imm(0x0));
686     GetEncoder()->EncodeReturn();
687     // Sucess exit
688     GetEncoder()->BindLabel(t5);
689     PostWork();
690 
691     if (!GetEncoder()->GetResult()) {
692         std::cerr << "Unsupported \n";
693         return;
694     }
695     Dump(false);
696     for (uint64_t i = 0; i < ITERATION; ++i) {
697         // Second type-dependency
698         auto tmp = random_gen<int32_t>();
699         // Deduced conflicting types for parameter
700         EXPECT_TRUE(CallCode<int32_t>(tmp, tmp + 5));
701     }
702 }
703 
704 template <typename T, bool NotZero = false>
TestBitTestAndBranch(Encoder64Test * test,T value,int pos,uint32_t expected)705 bool TestBitTestAndBranch(Encoder64Test *test, T value, int pos, uint32_t expected)
706 {
707     test->PreWork();
708     auto param = test->GetParameter(TypeInfo(T(0)));
709     auto ret_val = Target::Current().GetReturnReg();
710     auto label = test->GetEncoder()->CreateLabel();
711 
712     if (NotZero) {
713         test->GetEncoder()->EncodeBitTestAndBranch(label, param, pos, true);
714     } else {
715         test->GetEncoder()->EncodeBitTestAndBranch(label, param, pos, false);
716     }
717     test->GetEncoder()->EncodeMov(ret_val, Imm(1));
718     test->GetCallconv()->GenerateEpilogue(FrameInfo::FullPrologue(), []() {});
719 
720     test->GetEncoder()->BindLabel(label);
721     test->GetEncoder()->EncodeMov(ret_val, Imm(0));
722 
723     test->PostWork();
724 
725     if (!test->GetEncoder()->GetResult()) {
726         std::cerr << "Unsupported for " << TypeName<T>() << std::endl;
727         return false;
728     }
729     // Change this for enable print disasm
730     test->Dump(false);
731 
732     if (!test->CallCode<T>(value, expected)) {
733         std::cerr << "Bit " << pos << " of 0x" << std::hex << value << " is not equal to " << std::dec << expected
734                   << std::endl;
735         return false;
736     }
737 
738     return true;
739 }
740 
741 template <typename T, bool NotZero = false>
TestBitTestAndBranch(Encoder64Test * test)742 bool TestBitTestAndBranch(Encoder64Test *test)
743 {
744     size_t max_pos = std::is_same<uint64_t, T>::value ? 64 : 32;
745     for (size_t i = 0; i < max_pos; i++) {
746         T value = static_cast<T>(1UL << i);
747         if (!TestBitTestAndBranch<T, NotZero>(test, value, i, NotZero ? 0 : 1)) {
748             return false;
749         }
750         if (!TestBitTestAndBranch<T, NotZero>(test, ~value, i, NotZero ? 1 : 0)) {
751             return false;
752         }
753     }
754     return true;
755 }
756 
757 template <typename T, bool is_equal = true>
TestAddOverflow(Encoder64Test * test,T value1,T value2,T expected)758 bool TestAddOverflow(Encoder64Test *test, T value1, T value2, T expected)
759 {
760     test->PreWork();
761     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
762     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
763     auto ret_val = Target::Current().GetReturnReg(TypeInfo(T(0)));
764     auto label = test->GetEncoder()->CreateLabel();
765     auto end = test->GetEncoder()->CreateLabel();
766 
767     if (is_equal) {
768         test->GetEncoder()->EncodeAddOverflow(label, ret_val, param1, param2, Condition::VS);
769         test->GetEncoder()->EncodeJump(end);
770         test->GetEncoder()->BindLabel(label);
771         test->GetEncoder()->EncodeMov(ret_val, Imm(0));
772     } else {
773         test->GetEncoder()->EncodeAddOverflow(end, ret_val, param1, param2, Condition::VC);
774         test->GetEncoder()->EncodeMov(ret_val, Imm(0));
775     }
776 
777     test->GetEncoder()->BindLabel(end);
778 
779     test->PostWork();
780 
781     if (!test->GetEncoder()->GetResult()) {
782         std::cerr << "Unsupported for " << TypeName<T>() << std::endl;
783         return false;
784     }
785     // Change this for enable print disasm
786     test->Dump(false);
787 
788     if (!test->CallCode<T>(value1, value2, expected)) {
789         std::cerr << "AddOverflow "
790                   << " of 0x" << std::hex << value1 << " and 0x" << std::hex << value2 << " is not equal to "
791                   << std::dec << expected << std::endl;
792         return false;
793     }
794 
795     return true;
796 }
797 
798 template <typename T>
TestAddOverflow(Encoder64Test * test)799 bool TestAddOverflow(Encoder64Test *test)
800 {
801     T min = std::numeric_limits<T>::min();
802     T max = std::numeric_limits<T>::max();
803     std::array<T, 7> values = {0, 2, 5, -7, -10, max, min};
804     for (uint32_t i = 0; i < values.size(); ++i) {
805         for (uint32_t j = 0; j < values.size(); ++j) {
806             T a0 = values[i];
807             T a1 = values[j];
808             T expected;
809             if ((a0 > 0 && a1 > max - a0) || (a0 < 0 && a1 < min - a0)) {
810                 expected = 0;
811             } else {
812                 expected = a0 + a1;
813             }
814             if (!TestAddOverflow<T, true>(test, a0, a1, expected) ||
815                 !TestAddOverflow<T, false>(test, a0, a1, expected)) {
816                 return false;
817             }
818         }
819     }
820     return true;
821 }
822 
823 template <typename T, bool is_equal = true>
TestSubOverflow(Encoder64Test * test,T value1,T value2,T expected)824 bool TestSubOverflow(Encoder64Test *test, T value1, T value2, T expected)
825 {
826     test->PreWork();
827     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
828     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
829     auto ret_val = Target::Current().GetReturnReg(TypeInfo(T(0)));
830     auto label = test->GetEncoder()->CreateLabel();
831     auto end = test->GetEncoder()->CreateLabel();
832 
833     if (is_equal) {
834         test->GetEncoder()->EncodeSubOverflow(label, ret_val, param1, param2, Condition::VS);
835         test->GetEncoder()->EncodeJump(end);
836         test->GetEncoder()->BindLabel(label);
837         test->GetEncoder()->EncodeMov(ret_val, Imm(0));
838     } else {
839         test->GetEncoder()->EncodeSubOverflow(end, ret_val, param1, param2, Condition::VC);
840         test->GetEncoder()->EncodeMov(ret_val, Imm(0));
841     }
842 
843     test->GetEncoder()->BindLabel(end);
844 
845     test->PostWork();
846 
847     if (!test->GetEncoder()->GetResult()) {
848         std::cerr << "Unsupported for " << TypeName<T>() << std::endl;
849         return false;
850     }
851     // Change this for enable print disasm
852     test->Dump(false);
853 
854     if (!test->CallCode<T>(value1, value2, expected)) {
855         std::cerr << "SubOverflow "
856                   << " of 0x" << std::hex << value1 << " and 0x" << std::hex << value2 << " is not equal to "
857                   << std::dec << expected << std::endl;
858         return false;
859     }
860 
861     return true;
862 }
863 
864 template <typename T>
TestSubOverflow(Encoder64Test * test)865 bool TestSubOverflow(Encoder64Test *test)
866 {
867     T min = std::numeric_limits<T>::min();
868     T max = std::numeric_limits<T>::max();
869     std::array<T, 7> values = {0, 2, 5, -7, -10, max, min};
870     for (uint32_t i = 0; i < values.size(); ++i) {
871         for (uint32_t j = 0; j < values.size(); ++j) {
872             T a0 = values[i];
873             T a1 = values[j];
874             T expected;
875             if ((a1 > 0 && a0 < min + a1) || (a1 < 0 && a0 > max + a1)) {
876                 expected = 0;
877             } else {
878                 expected = a0 - a1;
879             }
880             if (!TestSubOverflow<T, true>(test, a0, a1, expected) ||
881                 !TestSubOverflow<T, false>(test, a0, a1, expected)) {
882                 return false;
883             }
884         }
885     }
886     return true;
887 }
888 
889 template <typename T, Condition cc>
TestJumpCC(Encoder64Test * test)890 bool TestJumpCC(Encoder64Test *test)
891 {
892     bool is_signed = std::is_signed<T>::value;
893     // Initialize
894     test->PreWork();
895     // First type-dependency
896     auto param = test->GetParameter(TypeInfo(T(0)));
897     // Main test call
898     auto ret_val = Target::Current().GetReturnReg();
899 
900     auto tsucc = test->GetEncoder()->CreateLabel();
901 
902     test->GetEncoder()->EncodeJump(tsucc, param, cc);
903     test->GetEncoder()->EncodeMov(param, Imm(0x0));
904     test->GetEncoder()->EncodeMov(ret_val, Imm(0x1));
905     test->GetCallconv()->GenerateEpilogue(FrameInfo::FullPrologue(), []() {});
906 
907     test->GetEncoder()->BindLabel(tsucc);
908     test->GetEncoder()->EncodeMov(param, Imm(0x0));
909     test->GetEncoder()->EncodeMov(ret_val, Imm(0x0));
910     // test->GetEncoder()->EncodeReturn(); < encoded in PostWork
911 
912     // Finalize
913     test->PostWork();
914 
915     // If encode unsupported - now print error
916     if (!test->GetEncoder()->GetResult()) {
917         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
918         return false;
919     }
920     // Change this for enable print disasm
921     test->Dump(false);
922 
923     if constexpr (cc == Condition::EQ) {
924         if (!test->CallCode<T>(0, 0)) {
925             std::cerr << "zero EQ test fail \n";
926             return false;
927         }
928     }
929     if constexpr (cc == Condition::NE) {
930         if (!test->CallCode<T>(0, 1)) {
931             std::cerr << "zero EQ test fail \n";
932             return false;
933         }
934     }
935 
936     // Main test loop:
937     for (uint64_t i = 0; i < ITERATION; ++i) {
938         // Second type-dependency
939         T tmp = random_gen<T>();
940         if (tmp == 0) {  // Only non-zero values
941             tmp += 1;
942         }
943         // Deduced conflicting types for parameter
944 
945         if constexpr (cc == Condition::EQ) {
946             if (!test->CallCode<T>(tmp, 1)) {
947                 std::cerr << "non-zero EQ test fail " << tmp << " \n";
948                 return false;
949             }
950         }
951         if constexpr (cc == Condition::NE) {
952             if (!test->CallCode<T>(tmp, 0)) {
953                 std::cerr << "non-zero EQ test fail " << tmp << " \n";
954                 return false;
955             }
956         }
957         // Main check - compare parameter and
958         // return value
959     }
960     return true;
961 }
962 
963 // Jump with cc
TEST_F(Encoder64Test,JumpCCTest)964 TEST_F(Encoder64Test, JumpCCTest)
965 {
966     EXPECT_TRUE((TestJumpCC<int32_t, Condition::EQ>(this)));
967     EXPECT_TRUE((TestJumpCC<int32_t, Condition::NE>(this)));
968     EXPECT_TRUE((TestJumpCC<int64_t, Condition::NE>(this)));
969     EXPECT_TRUE((TestJumpCC<int64_t, Condition::EQ>(this)));
970     EXPECT_TRUE((TestJumpCC<uint32_t, Condition::EQ>(this)));
971     EXPECT_TRUE((TestJumpCC<uint32_t, Condition::NE>(this)));
972     EXPECT_TRUE((TestJumpCC<uint64_t, Condition::EQ>(this)));
973     EXPECT_TRUE((TestJumpCC<uint64_t, Condition::NE>(this)));
974     // TestJumpCC<float, Condition::EQ>
975     // TestJumpCC<float, Condition::NE>
976     // TestJumpCC<double, Condition::EQ>
977     // TestJumpCC<double, Condition::NE>
978 }
979 
TEST_F(Encoder64Test,BitTestAndBranchZero)980 TEST_F(Encoder64Test, BitTestAndBranchZero)
981 {
982     EXPECT_TRUE(TestBitTestAndBranch<uint32_t>(this));
983     EXPECT_TRUE(TestBitTestAndBranch<uint64_t>(this));
984 }
985 
TEST_F(Encoder64Test,BitTestAndBranchNotZero)986 TEST_F(Encoder64Test, BitTestAndBranchNotZero)
987 {
988     constexpr bool notZero = true;
989     EXPECT_TRUE((TestBitTestAndBranch<uint32_t, notZero>(this)));
990     EXPECT_TRUE((TestBitTestAndBranch<uint64_t, notZero>(this)));
991 }
992 
TEST_F(Encoder64Test,AddOverflow)993 TEST_F(Encoder64Test, AddOverflow)
994 {
995     EXPECT_TRUE((TestAddOverflow<int32_t>(this)));
996     EXPECT_TRUE((TestAddOverflow<int64_t>(this)));
997 }
998 
TEST_F(Encoder64Test,SubOverflow)999 TEST_F(Encoder64Test, SubOverflow)
1000 {
1001     EXPECT_TRUE((TestSubOverflow<int32_t>(this)));
1002     EXPECT_TRUE((TestSubOverflow<int64_t>(this)));
1003 }
1004 
1005 template <typename T>
TestLdr(Encoder64Test * test)1006 bool TestLdr(Encoder64Test *test)
1007 {
1008     bool is_signed = std::is_signed<T>::value;
1009     // Initialize
1010     test->PreWork();
1011     // First type-dependency
1012     // Some strange code - default parameter is addres (32 bit)
1013 
1014     auto param = Target::Current().GetReturnReg();
1015     // But return value is cutted by loaded value
1016     auto ret_val = test->GetParameter(TypeInfo(T(0)));
1017 
1018     auto mem = MemRef(param);
1019     test->GetEncoder()->EncodeLdr(ret_val, is_signed, mem);
1020 
1021     // Finalize
1022     test->PostWork();
1023 
1024     // If encode unsupported - now print error
1025     if (!test->GetEncoder()->GetResult()) {
1026         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1027         return false;
1028     }
1029     // Change this for enable print disasm
1030     test->Dump(false);
1031 
1032     // Main test loop:
1033     for (uint64_t i = 0; i < ITERATION; ++i) {
1034         // Second type-dependency
1035         T tmp = random_gen<T>();
1036         T *ptr = &tmp;
1037         // Test : param - Pointer to value
1038         //        return - value (loaded by ptr)
1039         // Value is resulting type, but call is ptr_type
1040         if (!test->CallCode<int64_t, T>(reinterpret_cast<int64_t>(ptr), tmp)) {
1041             std::cerr << "Ldr test fail " << tmp << " \n";
1042             return false;
1043         }
1044     }
1045     return true;
1046 }
1047 
1048 // Load test
TEST_F(Encoder64Test,LoadTest)1049 TEST_F(Encoder64Test, LoadTest)
1050 {
1051     EXPECT_TRUE((TestLdr<int32_t>(this)));
1052     EXPECT_TRUE((TestLdr<int64_t>(this)));
1053     EXPECT_TRUE((TestLdr<uint32_t>(this)));
1054     EXPECT_TRUE((TestLdr<uint64_t>(this)));
1055     EXPECT_TRUE((TestLdr<float>(this)));
1056     EXPECT_TRUE((TestLdr<double>(this)));
1057     // TODO(igorban) : additional test for full memory model:
1058     //                 + mem(base + index<<scale + disp)
1059 }
1060 
1061 template <typename T>
TestStr(Encoder64Test * test)1062 bool TestStr(Encoder64Test *test)
1063 {
1064     // Initialize
1065     test->PreWork();
1066     // First type-dependency
1067     auto param = test->GetParameter(TypeInfo(int64_t(0)), 0);
1068     // Data to be stored:
1069     auto stored_value = test->GetParameter(TypeInfo(T(0)), 1);
1070     if constexpr ((std::is_same<float, T>::value) || std::is_same<double, T>::value) {
1071         stored_value = test->GetParameter(TypeInfo(T(0)), 0);
1072     }
1073 
1074     auto mem = MemRef(param);
1075     test->GetEncoder()->EncodeStr(stored_value, mem);
1076     // Finalize
1077     test->PostWork();
1078 
1079     // If encode unsupported - now print error
1080     if (!test->GetEncoder()->GetResult()) {
1081         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1082         return false;
1083     }
1084     // Change this for enable print disasm
1085     test->Dump(false);
1086 
1087     // Main test loop:
1088     for (uint64_t i = 0; i < ITERATION; ++i) {
1089         // Second type-dependency
1090         T tmp = random_gen<T>();
1091         T ret_data = 0;
1092         T *ptr = &ret_data;
1093 
1094         // Test : param - Pointer to value
1095         //        return - value (loaded by ptr)
1096         // Value is resulting type, but call is ptr_type
1097         auto result = test->CallCodeStore<T>(reinterpret_cast<int64_t>(ptr), tmp);
1098         // Store must change ret_data value
1099         if (!(ret_data == tmp || (std::is_floating_point_v<T> && std::isnan(ret_data) && std::isnan(tmp)))) {
1100             std::cerr << std::hex << "Str test fail " << tmp << " ret_data = " << ret_data << "\n";
1101             return false;
1102         }
1103     }
1104     return true;
1105 }
1106 
1107 // Simple store test
TEST_F(Encoder64Test,StrTest)1108 TEST_F(Encoder64Test, StrTest)
1109 {
1110     //  EncodeStr(Reg src, MemRef mem)
1111     EXPECT_TRUE((TestStr<int32_t>(this)));
1112     EXPECT_TRUE((TestStr<int64_t>(this)));
1113     EXPECT_TRUE((TestStr<uint32_t>(this)));
1114     EXPECT_TRUE((TestStr<uint64_t>(this)));
1115     EXPECT_TRUE((TestStr<float>(this)));
1116     EXPECT_TRUE((TestStr<double>(this)));
1117 
1118     // TODO(igorban) : additional test for full memory model:
1119     //                 + mem(base + index<<scale + disp)
1120 }
1121 
1122 // Store immediate test
1123 // TEST_F(Encoder64Test, StiTest) {
1124 //  EncodeSti(Imm src, MemRef mem)
1125 
1126 template <typename T>
TestStrz(Encoder64Test * test)1127 bool TestStrz(Encoder64Test *test)
1128 {
1129     // Initialize
1130     test->PreWork();
1131     // First type-dependency
1132     auto param = test->GetParameter(TypeInfo(int64_t(0)), 0);
1133     // Data to be stored:
1134     auto stored_value = test->GetParameter(TypeInfo(T(0)), 1);
1135     if constexpr (std::is_floating_point_v<T>) {
1136         stored_value = test->GetParameter(TypeInfo(T(0)), 0);
1137     }
1138 
1139     auto mem = MemRef(param);
1140     test->GetEncoder()->EncodeStrz(stored_value, mem);
1141     // Finalize
1142     test->PostWork();
1143 
1144     // If encode unsupported - now print error
1145     if (!test->GetEncoder()->GetResult()) {
1146         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1147         return false;
1148     }
1149     // Change this for enable print disasm
1150     test->Dump(false);
1151 
1152     // Main test loop:
1153     for (uint64_t i = 0; i < ITERATION; ++i) {
1154         // Test : param - Pointer to value
1155         //        return - value (loaded by ptr)
1156         // Value is resulting type, but call is ptr_type
1157         if constexpr (std::is_floating_point_v<T>) {
1158             // Second type-dependency
1159             T tmp = random_gen<T>();
1160             T ret_data[ARRAY_SIZE];
1161             T *ptr = ret_data;
1162             for (uint64_t j = 0; j < ARRAY_SIZE; ++j) {
1163                 ret_data[j] = random_gen<T>();
1164             }
1165 
1166             auto result = test->CallCodeStore<T>(reinterpret_cast<int64_t>(ptr), tmp);
1167             // Store must change ret_data value
1168             bool ret = (ret_data[0] == tmp && std::signbit(ret_data[0]) == std::signbit(tmp)) ||
1169                        (std::isnan(ret_data[0]) && std::isnan(tmp)) || (std::isinf(ret_data[0]) && std::isinf(tmp));
1170 
1171             if (!ret) {
1172                 if constexpr (std::is_same<float, T>::value) {
1173                     std::cerr << std::hex << "Strz test fail " << bit_cast<uint32_t>(tmp)
1174                               << " ret_data = " << bit_cast<uint32_t>(ret_data[0]) << "\n";
1175                 }
1176                 if constexpr (std::is_same<double, T>::value) {
1177                     std::cerr << std::hex << "Strz test fail " << bit_cast<uint64_t>(tmp)
1178                               << " ret_data = " << bit_cast<uint64_t>(ret_data[0]) << "\n";
1179                 }
1180                 std::cerr << std::hex << "Strz test fail " << tmp << " ret_data = " << ret_data[0] << "\n";
1181                 return false;
1182             }
1183         } else {
1184             // Second type-dependency
1185             T tmp = random_gen<T>();
1186             uint64_t ret_data = 0xffffffffffffffff;
1187             T *ptr = reinterpret_cast<T *>(&ret_data);
1188 
1189             uint64_t result = test->CallCodeStore<T>(reinterpret_cast<int64_t>(ptr), tmp);
1190             // Store must change ret_data value
1191             if (ret_data != tmp) {
1192                 std::cerr << std::hex << "Strz test fail " << (uint64_t)tmp << " ret_data = " << (uint64_t)ret_data
1193                           << "\n";
1194                 return false;
1195             }
1196         }
1197     }
1198     return true;
1199 }
1200 
1201 // Store zero upper test
TEST_F(Encoder64Test,StrzTest)1202 TEST_F(Encoder64Test, StrzTest)
1203 {
1204     EXPECT_TRUE((TestStrz<uint8_t>(this)));
1205     EXPECT_TRUE((TestStrz<uint16_t>(this)));
1206     EXPECT_TRUE((TestStrz<uint32_t>(this)));
1207     EXPECT_TRUE((TestStrz<uint64_t>(this)));
1208 
1209     EXPECT_TRUE((TestStrz<float>(this)));
1210     EXPECT_TRUE((TestStrz<double>(this)));
1211 }
1212 
1213 // Return test ???? What here may be tested
1214 // TEST_F(Encoder64Test, ReturnTest) {
1215 //  EncodeReturn()
1216 
foo(uint32_t param1,uint32_t param2)1217 bool foo(uint32_t param1, uint32_t param2)
1218 {
1219     // TODO(igorban): use variables
1220     return (param1 == param2);
1221 }
1222 
1223 using funct_ptr = bool (*)(uint32_t param1, uint32_t param2);
1224 
1225 funct_ptr foo_ptr = &foo;
1226 
1227 // Call Test
TEST_F(Encoder64Test,CallTest)1228 TEST_F(Encoder64Test, CallTest)
1229 {
1230     // Initialize
1231     auto link_reg = Target::Current().GetLinkReg();
1232 
1233     PreWork();
1234     static_cast<aarch64::Aarch64Encoder *>(GetEncoder())
1235         ->GetMasm()
1236         ->Push(vixl::aarch64::xzr, aarch64::VixlReg(link_reg));
1237 
1238     // Call foo
1239     GetEncoder()->MakeCall(reinterpret_cast<void *>(foo_ptr));
1240 
1241     static_cast<aarch64::Aarch64Encoder *>(GetEncoder())
1242         ->GetMasm()
1243         ->Pop(aarch64::VixlReg(link_reg), vixl::aarch64::xzr);
1244     // return value - moved to return value
1245     PostWork();
1246 
1247     // If encode unsupported - now print error
1248     if (!GetEncoder()->GetResult()) {
1249         std::cerr << "Unsupported Call-instruction \n";
1250         return;
1251     }
1252     // Change this for enable print disasm
1253     Dump(false);
1254     // Equality test
1255     auto tmp1 = random_gen<uint32_t>();
1256     uint32_t tmp2 = tmp1;
1257     // first template arg - parameter type, second - return type
1258     auto result = CallCodeCall<uint32_t, bool>(tmp1, tmp2);
1259     // Store must change ret_data value
1260     if (!result) {
1261         std::cerr << std::hex << "Call test fail tmp1=" << tmp1 << " tmp2=" << tmp2 << " result =" << result << "\n";
1262     }
1263     EXPECT_TRUE(result);
1264 
1265     // Main test loop:
1266     for (uint64_t i = 0; i < ITERATION; ++i) {
1267         // Second type-dependency
1268         auto tmp1 = random_gen<uint32_t>();
1269         auto tmp2 = random_gen<uint32_t>();
1270 
1271         // first template arg - parameter type, second - return type
1272         auto result = CallCodeCall<uint32_t, bool>(tmp1, tmp2);
1273         auto ret_data = (tmp1 == tmp2);
1274 
1275         // Store must change ret_data value
1276         if (result != ret_data) {
1277             std::cerr << std::hex << "Call test fail tmp1=" << tmp1 << " tmp2=" << tmp2 << " ret_data = " << ret_data
1278                       << " result =" << result << "\n";
1279         }
1280         EXPECT_EQ(result, ret_data);
1281     }
1282 }
1283 
1284 template <typename T>
TestAbs(Encoder64Test * test)1285 bool TestAbs(Encoder64Test *test)
1286 {
1287     // Initialize
1288     test->PreWork();
1289 
1290     // First type-dependency
1291     auto param = test->GetParameter(TypeInfo(T(0)));
1292 
1293     // Main test call
1294     test->GetEncoder()->EncodeAbs(param, param);
1295 
1296     // Finalize
1297     test->PostWork();
1298 
1299     // If encode unsupported - now print error
1300     if (!test->GetEncoder()->GetResult()) {
1301         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1302         return false;
1303     }
1304     // Change this for enable print disasm
1305     test->Dump(false);
1306 
1307     // Main test loop:
1308     for (uint64_t i = 0; i < ITERATION; ++i) {
1309         // Second type-dependency
1310         T tmp = random_gen<T>();
1311         // Main check - compare parameter and
1312         // return value
1313         if (!test->CallCode(tmp, std::abs(tmp))) {
1314             return false;
1315         }
1316     }
1317 
1318     if constexpr (std::is_floating_point_v<T>) {
1319         T nan = std::numeric_limits<T>::quiet_NaN();
1320 
1321         if (!test->CallCode<T>(nan, nan)) {
1322             return false;
1323         }
1324     }
1325 
1326     return true;
1327 }
1328 
TEST_F(Encoder64Test,AbsTest)1329 TEST_F(Encoder64Test, AbsTest)
1330 {
1331     EXPECT_TRUE(TestAbs<int32_t>(this));
1332     EXPECT_TRUE(TestAbs<int64_t>(this));
1333     EXPECT_TRUE(TestAbs<float>(this));
1334     EXPECT_TRUE(TestAbs<double>(this));
1335 }
1336 
1337 template <typename T>
TestSqrt(Encoder64Test * test)1338 bool TestSqrt(Encoder64Test *test)
1339 {
1340     // Initialize
1341     test->PreWork();
1342 
1343     // First type-dependency
1344     auto param = test->GetParameter(TypeInfo(T(0)));
1345 
1346     // Main test call
1347     test->GetEncoder()->EncodeSqrt(param, param);
1348 
1349     // Finalize
1350     test->PostWork();
1351 
1352     // If encode unsupported - now print error
1353     if (!test->GetEncoder()->GetResult()) {
1354         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1355         return false;
1356     }
1357     // Change this for enable print disasm
1358     test->Dump(false);
1359 
1360     // Main test loop:
1361     for (uint64_t i = 0; i < ITERATION; ++i) {
1362         // Second type-dependency
1363         T tmp = random_gen<T>();
1364         // Main check - compare parameter and
1365         // return value
1366         if (!test->CallCode(tmp, std::sqrt(tmp))) {
1367             return false;
1368         }
1369     }
1370 
1371     if constexpr (std::is_floating_point_v<T>) {
1372         T nan = std::numeric_limits<T>::quiet_NaN();
1373 
1374         if (!test->CallCode<T>(nan, nan)) {
1375             return false;
1376         }
1377     }
1378 
1379     return true;
1380 }
1381 
TEST_F(Encoder64Test,SqrtTest)1382 TEST_F(Encoder64Test, SqrtTest)
1383 {
1384     EXPECT_TRUE(TestSqrt<float>(this));
1385     EXPECT_TRUE(TestSqrt<double>(this));
1386 }
1387 
1388 template <typename T>
TestAdd(Encoder64Test * test)1389 bool TestAdd(Encoder64Test *test)
1390 {
1391     // Initialize
1392     test->PreWork();
1393 
1394     // First type-dependency
1395     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1396     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1397 
1398     // Main test call
1399     test->GetEncoder()->EncodeAdd(param1, param1, param2);
1400 
1401     // Finalize
1402     test->PostWork();
1403 
1404     // If encode unsupported - now print error
1405     if (!test->GetEncoder()->GetResult()) {
1406         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1407         return false;
1408     }
1409     // Change this for enable print disasm
1410     test->Dump(false);
1411 
1412     // Main test loop:
1413     for (uint64_t i = 0; i < ITERATION; ++i) {
1414         // Second type-dependency
1415         auto tmp1 = random_gen<T>();
1416         auto tmp2 = random_gen<T>();
1417         // Deduced conflicting types for parameter
1418 
1419         // Main check - compare parameter and
1420         // return value
1421         if (!test->CallCode<T>(tmp1, tmp2, tmp1 + tmp2)) {
1422             return false;
1423         }
1424     }
1425 
1426     if constexpr (std::is_floating_point_v<T>) {
1427         T nan = std::numeric_limits<T>::quiet_NaN();
1428 
1429         if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1430             return false;
1431         }
1432         if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1433             return false;
1434         }
1435         if (!test->CallCode<T>(-std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
1436             return false;
1437         }
1438         if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), nan)) {
1439             return false;
1440         }
1441     }
1442 
1443     return true;
1444 }
1445 
TEST_F(Encoder64Test,AddTest)1446 TEST_F(Encoder64Test, AddTest)
1447 {
1448     EXPECT_TRUE(TestAdd<int32_t>(this));
1449     EXPECT_TRUE(TestAdd<int64_t>(this));
1450     EXPECT_TRUE(TestAdd<float>(this));
1451     EXPECT_TRUE(TestAdd<double>(this));
1452 }
1453 
1454 template <typename T>
TestAddImm(Encoder64Test * test)1455 bool TestAddImm(Encoder64Test *test)
1456 {
1457     // Initialize
1458     test->PreWork();
1459 
1460     // First type-dependency
1461     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1462     T param2 = random_gen<T>();
1463 
1464     // Main test call
1465     test->GetEncoder()->EncodeAdd(param1, param1, Imm(param2));
1466 
1467     // Finalize
1468     test->PostWork();
1469 
1470     // If encode unsupported - now print error
1471     if (!test->GetEncoder()->GetResult()) {
1472         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1473         return false;
1474     }
1475     // Change this for enable print disasm
1476     test->Dump(false);
1477 
1478     // Main test loop:
1479     for (uint64_t i = 0; i < ITERATION; ++i) {
1480         // Second type-dependency
1481         T tmp1 = random_gen<T>();
1482         // Deduced conflicting types for parameter
1483 
1484         // Main check - compare parameter and
1485         // return value
1486         if (!test->CallCode<T>(tmp1, tmp1 + param2)) {
1487             return false;
1488         }
1489     }
1490     return true;
1491 }
1492 
TEST_F(Encoder64Test,AddImmTest)1493 TEST_F(Encoder64Test, AddImmTest)
1494 {
1495     EXPECT_TRUE(TestAddImm<int32_t>(this));
1496     EXPECT_TRUE(TestAddImm<int64_t>(this));
1497     // TestAddImm<float>
1498     // TestAddImm<double>
1499 }
1500 
1501 template <typename T>
TestSub(Encoder64Test * test)1502 bool TestSub(Encoder64Test *test)
1503 {
1504     // Initialize
1505     test->PreWork();
1506 
1507     // First type-dependency
1508     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1509     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1510 
1511     // Main test call
1512     test->GetEncoder()->EncodeSub(param1, param1, param2);
1513 
1514     // Finalize
1515     test->PostWork();
1516 
1517     // If encode unsupported - now print error
1518     if (!test->GetEncoder()->GetResult()) {
1519         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1520         return false;
1521     }
1522     // Change this for enable print disasm
1523     test->Dump(false);
1524 
1525     // Main test loop:
1526     for (uint64_t i = 0; i < ITERATION; ++i) {
1527         // Second type-dependency
1528         T tmp1 = random_gen<T>();
1529         T tmp2 = random_gen<T>();
1530         // Deduced conflicting types for parameter
1531 
1532         // Main check - compare parameter and
1533         // return value
1534         if (!test->CallCode<T>(tmp1, tmp2, tmp1 - tmp2)) {
1535             return false;
1536         }
1537     }
1538 
1539     if constexpr (std::is_floating_point_v<T>) {
1540         T nan = std::numeric_limits<T>::quiet_NaN();
1541 
1542         if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1543             return false;
1544         }
1545         if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1546             return false;
1547         }
1548         if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
1549             return false;
1550         }
1551         if (!test->CallCode<T>(-std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), nan)) {
1552             return false;
1553         }
1554     }
1555 
1556     return true;
1557 }
1558 
TEST_F(Encoder64Test,SubTest)1559 TEST_F(Encoder64Test, SubTest)
1560 {
1561     EXPECT_TRUE(TestSub<int32_t>(this));
1562     EXPECT_TRUE(TestSub<int64_t>(this));
1563     EXPECT_TRUE(TestSub<float>(this));
1564     EXPECT_TRUE(TestSub<double>(this));
1565 }
1566 
1567 template <typename T>
TestSubImm(Encoder64Test * test)1568 bool TestSubImm(Encoder64Test *test)
1569 {
1570     // Initialize
1571     test->PreWork();
1572 
1573     // First type-dependency
1574     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1575     T param2 = random_gen<T>();
1576 
1577     // Main test call
1578     test->GetEncoder()->EncodeSub(param1, param1, Imm(param2));
1579 
1580     // Finalize
1581     test->PostWork();
1582 
1583     // If encode unsupported - now print error
1584     if (!test->GetEncoder()->GetResult()) {
1585         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1586         return false;
1587     }
1588     // Change this for enable print disasm
1589     test->Dump(false);
1590 
1591     // Main test loop:
1592     for (uint64_t i = 0; i < ITERATION; ++i) {
1593         // Second type-dependency
1594         T tmp1 = random_gen<T>();
1595         // Deduced conflicting types for parameter
1596 
1597         // Main check - compare parameter and
1598         // return value
1599         if (!test->CallCode<T>(tmp1, tmp1 - param2)) {
1600             return false;
1601         }
1602     }
1603     return true;
1604 }
1605 
TEST_F(Encoder64Test,SubImmTest)1606 TEST_F(Encoder64Test, SubImmTest)
1607 {
1608     EXPECT_TRUE(TestSubImm<int32_t>(this));
1609     EXPECT_TRUE(TestSubImm<int64_t>(this));
1610     // TestSubImm<float>
1611     // TestSubImm<double>
1612 }
1613 
1614 template <typename T>
TestMul(Encoder64Test * test)1615 bool TestMul(Encoder64Test *test)
1616 {
1617     // Initialize
1618     test->PreWork();
1619 
1620     // First type-dependency
1621     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1622     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1623 
1624     // Main test call
1625     test->GetEncoder()->EncodeMul(param1, param1, param2);
1626 
1627     // Finalize
1628     test->PostWork();
1629 
1630     // If encode unsupported - now print error
1631     if (!test->GetEncoder()->GetResult()) {
1632         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1633         return false;
1634     }
1635     // Change this for enable print disasm
1636     test->Dump(false);
1637 
1638     // Main test loop:
1639     for (uint64_t i = 0; i < ITERATION; ++i) {
1640         // Second type-dependency
1641         T tmp1 = random_gen<T>();
1642         T tmp2 = random_gen<T>();
1643         // Deduced conflicting types for parameter
1644 
1645         // Main check - compare parameter and
1646         // return value
1647         if (!test->CallCode<T>(tmp1, tmp2, tmp1 * tmp2)) {
1648             return false;
1649         }
1650     }
1651 
1652     if constexpr (std::is_floating_point_v<T>) {
1653         T nan = std::numeric_limits<T>::quiet_NaN();
1654 
1655         if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1656             return false;
1657         }
1658         if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1659             return false;
1660         }
1661         if (!test->CallCode<T>(0.0, std::numeric_limits<T>::infinity(), nan)) {
1662             return false;
1663         }
1664         if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), 0.0, nan)) {
1665             return false;
1666         }
1667     }
1668 
1669     return true;
1670 }
1671 
TEST_F(Encoder64Test,MulTest)1672 TEST_F(Encoder64Test, MulTest)
1673 {
1674     EXPECT_TRUE(TestMul<int32_t>(this));
1675     EXPECT_TRUE(TestMul<int64_t>(this));
1676     EXPECT_TRUE(TestMul<float>(this));
1677     EXPECT_TRUE(TestMul<double>(this));
1678 }
1679 
1680 template <typename T>
TestMin(Encoder64Test * test)1681 bool TestMin(Encoder64Test *test)
1682 {
1683     // Initialize
1684     test->PreWork();
1685 
1686     // First type-dependency
1687     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1688     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1689 
1690     // Main test call
1691     test->GetEncoder()->EncodeMin(param1, std::is_signed_v<T>, param1, param2);
1692 
1693     // Finalize
1694     test->PostWork();
1695 
1696     // If encode unsupported - now print error
1697     if (!test->GetEncoder()->GetResult()) {
1698         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1699         return false;
1700     }
1701     // Change this for enable print disasm
1702     test->Dump(false);
1703 
1704     // Main test loop:
1705     for (uint64_t i = 0; i < ITERATION; ++i) {
1706         // Second type-dependency
1707         T tmp1 = random_gen<T>();
1708         T tmp2 = random_gen<T>();
1709         // Deduced conflicting types for parameter
1710 
1711         T result {0};
1712         if (std::is_floating_point_v<T> && (std::isnan(tmp1) || std::isnan(tmp2))) {
1713             result = std::numeric_limits<T>::quiet_NaN();
1714         } else {
1715             // We do that, because auto check -0.0 and +0.0 std::max give incorrect result
1716             if (std::fabs(tmp1) < 1e-300 && std::fabs(tmp2) < 1e-300) {
1717                 continue;
1718             }
1719             result = std::min(tmp1, tmp2);
1720         }
1721 
1722         // Main check - compare parameter and
1723         // return value
1724         if (!test->CallCode<T>(tmp1, tmp2, result)) {
1725             return false;
1726         }
1727     }
1728 
1729     if constexpr (std::is_floating_point_v<T>) {
1730         T nan = std::numeric_limits<T>::quiet_NaN();
1731 
1732         if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1733             return false;
1734         }
1735         if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1736             return false;
1737         }
1738         // use static_cast to make sure correct float/double type is applied
1739         if (!test->CallCode<T>(static_cast<T>(-0.0), static_cast<T>(+0.0), static_cast<T>(-0.0))) {
1740             return false;
1741         }
1742         if (!test->CallCode<T>(static_cast<T>(+0.0), static_cast<T>(-0.0), static_cast<T>(-0.0))) {
1743             return false;
1744         }
1745     }
1746 
1747     return true;
1748 }
1749 
TEST_F(Encoder64Test,MinTest)1750 TEST_F(Encoder64Test, MinTest)
1751 {
1752     EXPECT_TRUE(TestMin<int32_t>(this));
1753     EXPECT_TRUE(TestMin<int64_t>(this));
1754     EXPECT_TRUE(TestMin<uint32_t>(this));
1755     EXPECT_TRUE(TestMin<uint64_t>(this));
1756     EXPECT_TRUE(TestMin<float>(this));
1757     EXPECT_TRUE(TestMin<double>(this));
1758 }
1759 
1760 template <typename T>
TestMax(Encoder64Test * test)1761 bool TestMax(Encoder64Test *test)
1762 {
1763     // Initialize
1764     test->PreWork();
1765 
1766     // First type-dependency
1767     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1768     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1769 
1770     // Main test call
1771     test->GetEncoder()->EncodeMax(param1, std::is_signed_v<T>, param1, param2);
1772 
1773     // Finalize
1774     test->PostWork();
1775 
1776     // If encode unsupported - now print error
1777     if (!test->GetEncoder()->GetResult()) {
1778         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1779         return false;
1780     }
1781     // Change this for enable print disasm
1782     test->Dump(false);
1783 
1784     // Main test loop:
1785     for (uint64_t i = 0; i < ITERATION; ++i) {
1786         // Second type-dependency
1787         T tmp1 = random_gen<T>();
1788         T tmp2 = random_gen<T>();
1789         // Deduced conflicting types for parameter
1790         T result {0};
1791         if (std::is_floating_point_v<T> && (std::isnan(tmp1) || std::isnan(tmp2))) {
1792             result = std::numeric_limits<T>::quiet_NaN();
1793         } else {
1794             // We do that, because auto check -0.0 and +0.0 std::max give incorrect result
1795             if (std::fabs(tmp1) < 1e-300 && std::fabs(tmp2) < 1e-300) {
1796                 continue;
1797             }
1798             result = std::max(tmp1, tmp2);
1799         }
1800 
1801         // Main check - compare parameter and
1802         // return value
1803         if (!test->CallCode<T>(tmp1, tmp2, result)) {
1804             return false;
1805         }
1806     }
1807 
1808     if constexpr (std::is_floating_point_v<T>) {
1809         T nan = std::numeric_limits<T>::quiet_NaN();
1810 
1811         if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1812             return false;
1813         }
1814         if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1815             return false;
1816         }
1817         // use static_cast to make sure correct float/double type is applied
1818         if (!test->CallCode<T>(static_cast<T>(-0.0), static_cast<T>(+0.0), static_cast<T>(+0.0))) {
1819             return false;
1820         }
1821         if (!test->CallCode<T>(static_cast<T>(+0.0), static_cast<T>(-0.0), static_cast<T>(+0.0))) {
1822             return false;
1823         }
1824     }
1825 
1826     return true;
1827 }
1828 
TEST_F(Encoder64Test,MaxTest)1829 TEST_F(Encoder64Test, MaxTest)
1830 {
1831     EXPECT_TRUE(TestMax<int32_t>(this));
1832     EXPECT_TRUE(TestMax<int64_t>(this));
1833     EXPECT_TRUE(TestMax<uint32_t>(this));
1834     EXPECT_TRUE(TestMax<uint64_t>(this));
1835     EXPECT_TRUE(TestMax<float>(this));
1836     EXPECT_TRUE(TestMax<double>(this));
1837 }
1838 
1839 template <typename T>
TestShl(Encoder64Test * test)1840 bool TestShl(Encoder64Test *test)
1841 {
1842     // Initialize
1843     test->PreWork();
1844 
1845     // First type-dependency
1846     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1847     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1848 
1849     // Main test call
1850     test->GetEncoder()->EncodeShl(param1, param1, param2);
1851 
1852     // Finalize
1853     test->PostWork();
1854 
1855     // If encode unsupported - now print error
1856     if (!test->GetEncoder()->GetResult()) {
1857         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1858         return false;
1859     }
1860     // Change this for enable print disasm
1861     test->Dump(false);
1862 
1863     // Main test loop:
1864     for (uint64_t i = 0; i < ITERATION; ++i) {
1865         // Second type-dependency
1866         T tmp1 = random_gen<T>();
1867         T tmp2 {0};
1868         if constexpr (std::is_same_v<T, int64_t>) {
1869             tmp2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
1870         } else {
1871             tmp2 = random_gen<uint8_t>() % WORD_SIZE;
1872         }
1873         // Deduced conflicting types for parameter
1874 
1875         // Main check - compare parameter and
1876         // return value
1877         bool result {false};
1878 
1879         if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>) {
1880             result = test->CallCode<T>(tmp1, tmp2, tmp1 << (tmp2 & (CHAR_BIT * sizeof(T) - 1)));
1881         } else {
1882             result = test->CallCode<T>(tmp1, tmp2, tmp1 << tmp2);
1883         }
1884 
1885         if (!result) {
1886             return false;
1887         }
1888     }
1889     return true;
1890 }
1891 
TEST_F(Encoder64Test,ShlTest)1892 TEST_F(Encoder64Test, ShlTest)
1893 {
1894     EXPECT_TRUE(TestShl<int32_t>(this));
1895     EXPECT_TRUE(TestShl<int64_t>(this));
1896 }
1897 
1898 template <typename T>
TestShr(Encoder64Test * test)1899 bool TestShr(Encoder64Test *test)
1900 {
1901     // Initialize
1902     test->PreWork();
1903 
1904     // First type-dependency
1905     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1906     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1907 
1908     // Main test call
1909     test->GetEncoder()->EncodeShr(param1, param1, param2);
1910 
1911     // Finalize
1912     test->PostWork();
1913 
1914     // If encode unsupported - now print error
1915     if (!test->GetEncoder()->GetResult()) {
1916         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1917         return false;
1918     }
1919     // Change this for enable print disasm
1920     test->Dump(false);
1921 
1922     // Main test loop:
1923     for (uint64_t i = 0; i < ITERATION; ++i) {
1924         // Second type-dependency
1925         T tmp1 = random_gen<T>();
1926         T tmp2 {0};
1927         if constexpr (sizeof(T) == sizeof(int64_t)) {
1928             tmp2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
1929         } else {
1930             tmp2 = random_gen<uint8_t>() % WORD_SIZE;
1931         }
1932         // Deduced conflicting types for parameter
1933 
1934         // Main check - compare parameter and
1935         // return value
1936         bool result {false};
1937 
1938         if constexpr (sizeof(T) == sizeof(int64_t)) {
1939             result = test->CallCode<T>(tmp1, tmp2, (static_cast<uint64_t>(tmp1)) >> tmp2);
1940         } else {
1941             result =
1942                 test->CallCode<T>(tmp1, tmp2, (static_cast<uint32_t>(tmp1)) >> (tmp2 & (CHAR_BIT * sizeof(T) - 1)));
1943         }
1944 
1945         if (!result) {
1946             return false;
1947         }
1948     }
1949     return true;
1950 }
1951 
TEST_F(Encoder64Test,ShrTest)1952 TEST_F(Encoder64Test, ShrTest)
1953 {
1954     EXPECT_TRUE(TestShr<int32_t>(this));
1955     EXPECT_TRUE(TestShr<int64_t>(this));
1956     EXPECT_TRUE(TestShr<uint32_t>(this));
1957     EXPECT_TRUE(TestShr<uint64_t>(this));
1958 }
1959 
1960 template <typename T>
TestAShr(Encoder64Test * test)1961 bool TestAShr(Encoder64Test *test)
1962 {
1963     // Initialize
1964     test->PreWork();
1965 
1966     // First type-dependency
1967     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1968     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1969 
1970     // Main test call
1971     test->GetEncoder()->EncodeAShr(param1, param1, param2);
1972 
1973     // Finalize
1974     test->PostWork();
1975 
1976     // If encode unsupported - now print error
1977     if (!test->GetEncoder()->GetResult()) {
1978         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1979         return false;
1980     }
1981     // Change this for enable print disasm
1982     test->Dump(false);
1983 
1984     // Main test loop:
1985     for (uint64_t i = 0; i < ITERATION; ++i) {
1986         // Second type-dependency
1987         T tmp1 = random_gen<T>();
1988         T tmp2 {0};
1989         if constexpr (std::is_same_v<T, int64_t>) {
1990             tmp2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
1991         } else {
1992             tmp2 = random_gen<uint8_t>() % WORD_SIZE;
1993         }
1994         // Deduced conflicting types for parameter
1995 
1996         // Main check - compare parameter and
1997         // return value
1998         bool result {false};
1999 
2000         if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>) {
2001             result = test->CallCode<T>(tmp1, tmp2, tmp1 >> (tmp2 & (CHAR_BIT * sizeof(T) - 1)));
2002         } else {
2003             result = test->CallCode<T>(tmp1, tmp2, tmp1 >> tmp2);
2004         }
2005 
2006         if (!result) {
2007             return false;
2008         }
2009     }
2010     return true;
2011 }
2012 
TEST_F(Encoder64Test,AShrTest)2013 TEST_F(Encoder64Test, AShrTest)
2014 {
2015     EXPECT_TRUE(TestAShr<int32_t>(this));
2016     EXPECT_TRUE(TestAShr<int64_t>(this));
2017 }
2018 
2019 template <typename T>
TestAnd(Encoder64Test * test)2020 bool TestAnd(Encoder64Test *test)
2021 {
2022     // Initialize
2023     test->PreWork();
2024 
2025     // First type-dependency
2026     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2027     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2028 
2029     // Main test call
2030     test->GetEncoder()->EncodeAnd(param1, param1, param2);
2031 
2032     // Finalize
2033     test->PostWork();
2034 
2035     // If encode unsupported - now print error
2036     if (!test->GetEncoder()->GetResult()) {
2037         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2038         return false;
2039     }
2040     // Change this for enable print disasm
2041     test->Dump(false);
2042 
2043     // Main test loop:
2044     for (uint64_t i = 0; i < ITERATION; ++i) {
2045         // Second type-dependency
2046         T tmp1 = random_gen<T>();
2047         T tmp2 = random_gen<T>();
2048         // Deduced conflicting types for parameter
2049 
2050         // Main check - compare parameter and
2051         // return value
2052         if (!test->CallCode<T>(tmp1, tmp2, tmp1 & tmp2)) {
2053             return false;
2054         }
2055     }
2056     return true;
2057 }
2058 
TEST_F(Encoder64Test,AndTest)2059 TEST_F(Encoder64Test, AndTest)
2060 {
2061     EXPECT_TRUE(TestAnd<int32_t>(this));
2062     EXPECT_TRUE(TestAnd<int64_t>(this));
2063 }
2064 
2065 template <typename T>
TestOr(Encoder64Test * test)2066 bool TestOr(Encoder64Test *test)
2067 {
2068     // Initialize
2069     test->PreWork();
2070 
2071     // First type-dependency
2072     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2073     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2074 
2075     // Main test call
2076     test->GetEncoder()->EncodeOr(param1, param1, param2);
2077 
2078     // Finalize
2079     test->PostWork();
2080 
2081     // If encode unsupported - now print error
2082     if (!test->GetEncoder()->GetResult()) {
2083         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2084         return false;
2085     }
2086     // Change this for enable print disasm
2087     test->Dump(false);
2088 
2089     // Main test loop:
2090     for (uint64_t i = 0; i < ITERATION; ++i) {
2091         // Second type-dependency
2092         T tmp1 = random_gen<T>();
2093         T tmp2 = random_gen<T>();
2094         // Deduced conflicting types for parameter
2095 
2096         // Main check - compare parameter and
2097         // return value
2098         if (!test->CallCode<T>(tmp1, tmp2, tmp1 | tmp2)) {
2099             return false;
2100         }
2101     }
2102     return true;
2103 }
2104 
TEST_F(Encoder64Test,OrTest)2105 TEST_F(Encoder64Test, OrTest)
2106 {
2107     EXPECT_TRUE(TestOr<int32_t>(this));
2108     EXPECT_TRUE(TestOr<int64_t>(this));
2109 }
2110 
2111 template <typename T>
TestXor(Encoder64Test * test)2112 bool TestXor(Encoder64Test *test)
2113 {
2114     // Initialize
2115     test->PreWork();
2116 
2117     // First type-dependency
2118     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2119     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2120 
2121     // Main test call
2122     test->GetEncoder()->EncodeXor(param1, param1, param2);
2123 
2124     // Finalize
2125     test->PostWork();
2126 
2127     // If encode unsupported - now print error
2128     if (!test->GetEncoder()->GetResult()) {
2129         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2130         return false;
2131     }
2132     // Change this for enable print disasm
2133     test->Dump(false);
2134 
2135     // Main test loop:
2136     for (uint64_t i = 0; i < ITERATION; ++i) {
2137         // Second type-dependency
2138         T tmp1 = random_gen<T>();
2139         T tmp2 = random_gen<T>();
2140         // Deduced conflicting types for parameter
2141 
2142         // Main check - compare parameter and
2143         // return value
2144         if (!test->CallCode<T>(tmp1, tmp2, tmp1 ^ tmp2)) {
2145             return false;
2146         }
2147     }
2148     return true;
2149 }
2150 
TEST_F(Encoder64Test,XorTest)2151 TEST_F(Encoder64Test, XorTest)
2152 {
2153     EXPECT_TRUE(TestXor<int32_t>(this));
2154     EXPECT_TRUE(TestXor<int64_t>(this));
2155 }
2156 
2157 template <typename T>
TestShlImm(Encoder64Test * test)2158 bool TestShlImm(Encoder64Test *test)
2159 {
2160     // Initialize
2161     test->PreWork();
2162 
2163     // First type-dependency
2164     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2165     int64_t param2 {0};
2166     if constexpr (std::is_same_v<T, int64_t>) {
2167         param2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
2168     } else {
2169         param2 = random_gen<uint8_t>() % WORD_SIZE;
2170     }
2171 
2172     // Main test call
2173     test->GetEncoder()->EncodeShl(param1, param1, Imm(param2));
2174 
2175     // Finalize
2176     test->PostWork();
2177 
2178     // If encode unsupported - now print error
2179     if (!test->GetEncoder()->GetResult()) {
2180         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2181         return false;
2182     }
2183     // Change this for enable print disasm
2184     test->Dump(false);
2185 
2186     // Main test loop:
2187     for (uint64_t i = 0; i < ITERATION; ++i) {
2188         // Second type-dependency
2189         T tmp1 = random_gen<T>();
2190 
2191         // Deduced conflicting types for parameter
2192 
2193         // Main check - compare parameter and
2194         // return value
2195         bool result {false};
2196 
2197         if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>) {
2198             result = test->CallCode<T>(tmp1, tmp1 << (param2 & (CHAR_BIT * sizeof(T) - 1)));
2199         } else {
2200             result = test->CallCode<T>(tmp1, tmp1 << param2);
2201         }
2202 
2203         if (!result) {
2204             return false;
2205         }
2206     }
2207     return true;
2208 }
2209 
TEST_F(Encoder64Test,ShlImmTest)2210 TEST_F(Encoder64Test, ShlImmTest)
2211 {
2212     EXPECT_TRUE(TestShlImm<int32_t>(this));
2213     EXPECT_TRUE(TestShlImm<int64_t>(this));
2214 }
2215 
2216 template <typename T>
TestShrImm(Encoder64Test * test)2217 bool TestShrImm(Encoder64Test *test)
2218 {
2219     // Initialize
2220     test->PreWork();
2221 
2222     // First type-dependency
2223     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2224     int64_t param2 {0};
2225     if constexpr (sizeof(T) == sizeof(int64_t)) {
2226         param2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
2227     } else {
2228         param2 = random_gen<uint8_t>() % WORD_SIZE;
2229     }
2230 
2231     // Main test call
2232     test->GetEncoder()->EncodeShr(param1, param1, Imm(param2));
2233 
2234     // Finalize
2235     test->PostWork();
2236 
2237     // If encode unsupported - now print error
2238     if (!test->GetEncoder()->GetResult()) {
2239         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2240         return false;
2241     }
2242     // Change this for enable print disasm
2243     test->Dump(false);
2244 
2245     // Main test loop:
2246     for (uint64_t i = 0; i < ITERATION; ++i) {
2247         // Second type-dependency
2248         T tmp1 = random_gen<T>();
2249 
2250         // Deduced conflicting types for parameter
2251 
2252         // Main check - compare parameter and
2253         // return value
2254         bool result {false};
2255 
2256         if constexpr (sizeof(T) == sizeof(int64_t)) {
2257             result = test->CallCode<T>(tmp1, (static_cast<uint64_t>(tmp1)) >> (param2 & (CHAR_BIT * sizeof(T) - 1)));
2258         } else {
2259             result = test->CallCode<T>(tmp1, (static_cast<uint32_t>(tmp1)) >> param2);
2260         }
2261 
2262         if (!result) {
2263             return false;
2264         }
2265     }
2266     return true;
2267 }
2268 
TEST_F(Encoder64Test,ShrImmTest)2269 TEST_F(Encoder64Test, ShrImmTest)
2270 {
2271     EXPECT_TRUE(TestShrImm<int32_t>(this));
2272     EXPECT_TRUE(TestShrImm<int64_t>(this));
2273     EXPECT_TRUE(TestShrImm<uint32_t>(this));
2274     EXPECT_TRUE(TestShrImm<uint64_t>(this));
2275 }
2276 
2277 template <typename T>
TestCmp(Encoder64Test * test)2278 bool TestCmp(Encoder64Test *test)
2279 {
2280     static_assert(std::is_integral_v<T>);
2281     // Initialize
2282     test->PreWork();
2283 
2284     // First type-dependency
2285     auto output = test->GetParameter(TypeInfo(int32_t(0)), 0);
2286     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2287     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2288 
2289     // Main test call
2290     test->GetEncoder()->EncodeCmp(output, param1, param2, std::is_signed_v<T> ? Condition::LT : Condition::LO);
2291 
2292     // Finalize
2293     test->PostWork();
2294 
2295     // If encode unsupported - now print error
2296     if (!test->GetEncoder()->GetResult()) {
2297         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2298         return false;
2299     }
2300     // Change this for enable print disasm
2301     test->Dump(false);
2302 
2303     // Main test loop:
2304     for (uint64_t i = 0; i < ITERATION; ++i) {
2305         // Second type-dependency
2306         T tmp1 = random_gen<T>();
2307         T tmp2 = random_gen<T>();
2308         // Deduced conflicting types for parameter
2309 
2310         auto compare = [](T a, T b) -> int32_t { return a < b ? -1 : a > b ? 1 : 0; };
2311         int32_t result {compare(tmp1, tmp2)};
2312 
2313         // Main check - compare parameter and
2314         // return value
2315         if (!test->CallCode<T, int32_t>(tmp1, tmp2, result)) {
2316             return false;
2317         }
2318     }
2319 
2320     return true;
2321 }
2322 
2323 template <typename T>
TestFcmp(Encoder64Test * test,bool is_fcmpg)2324 bool TestFcmp(Encoder64Test *test, bool is_fcmpg)
2325 {
2326     static_assert(std::is_floating_point_v<T>);
2327     // Initialize
2328     test->PreWork();
2329 
2330     // First type-dependency
2331     auto output = test->GetParameter(TypeInfo(int32_t(0)), 0);
2332     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2333     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2334 
2335     // Main test call
2336     test->GetEncoder()->EncodeCmp(output, param1, param2, is_fcmpg ? Condition::MI : Condition::LT);
2337 
2338     // Finalize
2339     test->PostWork();
2340 
2341     // If encode unsupported - now print error
2342     if (!test->GetEncoder()->GetResult()) {
2343         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2344         return false;
2345     }
2346     // Change this for enable print disasm
2347     test->Dump(false);
2348 
2349     // Main test loop:
2350     for (uint64_t i = 0; i < ITERATION; ++i) {
2351         // Second type-dependency
2352         T tmp1 = random_gen<T>();
2353         T tmp2 = random_gen<T>();
2354         // Deduced conflicting types for parameter
2355 
2356         auto compare = [](T a, T b) -> int32_t { return a < b ? -1 : a > b ? 1 : 0; };
2357 
2358         int32_t result {0};
2359         if (std::isnan(tmp1) || std::isnan(tmp2)) {
2360             result = is_fcmpg ? 1 : -1;
2361         } else {
2362             result = compare(tmp1, tmp2);
2363         }
2364 
2365         // Main check - compare parameter and
2366         // return value
2367         if (!test->CallCode<T, int32_t>(tmp1, tmp2, result)) {
2368             return false;
2369         }
2370     }
2371 
2372     if constexpr (std::is_floating_point_v<T>) {
2373         T nan = std::numeric_limits<T>::quiet_NaN();
2374 
2375         if (!test->CallCode<T, int32_t>(nan, 5.0, is_fcmpg ? 1 : -1)) {
2376             return false;
2377         }
2378         if (!test->CallCode<T, int32_t>(5.0, nan, is_fcmpg ? 1 : -1)) {
2379             return false;
2380         }
2381         if (!test->CallCode<T, int32_t>(nan, nan, is_fcmpg ? 1 : -1)) {
2382             return false;
2383         }
2384     }
2385 
2386     return true;
2387 }
2388 
TEST_F(Encoder64Test,CmpTest)2389 TEST_F(Encoder64Test, CmpTest)
2390 {
2391     EXPECT_TRUE(TestCmp<int32_t>(this));
2392     EXPECT_TRUE(TestCmp<int64_t>(this));
2393     EXPECT_TRUE(TestCmp<uint32_t>(this));
2394     EXPECT_TRUE(TestCmp<uint64_t>(this));
2395     EXPECT_TRUE(TestFcmp<float>(this, false));
2396     EXPECT_TRUE(TestFcmp<double>(this, false));
2397     EXPECT_TRUE(TestFcmp<float>(this, true));
2398     EXPECT_TRUE(TestFcmp<double>(this, true));
2399 }
2400 
2401 template <typename T>
TestCmp64(Encoder64Test * test)2402 bool TestCmp64(Encoder64Test *test)
2403 {
2404     static_assert(sizeof(T) == sizeof(int64_t));
2405     // Initialize
2406     test->PreWork();
2407 
2408     // First type-dependency
2409     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2410     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2411 
2412     // Main test call
2413     test->GetEncoder()->EncodeCmp(param1, param1, param2, std::is_signed_v<T> ? Condition::LT : Condition::LO);
2414 
2415     // Finalize
2416     test->PostWork();
2417 
2418     // If encode unsupported - now print error
2419     if (!test->GetEncoder()->GetResult()) {
2420         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2421         return false;
2422     }
2423     // Change this for enable print disasm
2424     test->Dump(false);
2425 
2426     uint64_t hi = static_cast<uint64_t>(0xABCDEFU) << (BITS_PER_BYTE * sizeof(uint32_t));
2427 
2428     // Main test loop:
2429     for (uint64_t i = 0; i < ITERATION; ++i) {
2430         uint32_t lo = random_gen<T>();
2431 
2432         // Second type-dependency
2433         T tmp1 = hi | (lo + 1U);
2434         T tmp2 = hi | lo;
2435         // Deduced conflicting types for parameter
2436 
2437         auto compare = [](T a, T b) -> int32_t { return a < b ? -1 : a > b ? 1 : 0; };
2438 
2439         // Main check - compare parameter and
2440         // return value
2441         if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
2442             return false;
2443         }
2444     }
2445     return true;
2446 }
2447 
TEST_F(Encoder64Test,Cmp64Test)2448 TEST_F(Encoder64Test, Cmp64Test)
2449 {
2450     EXPECT_TRUE(TestCmp64<int64_t>(this));
2451     EXPECT_TRUE(TestCmp64<uint64_t>(this));
2452 }
2453 
2454 template <typename T>
TestCompare(Encoder64Test * test)2455 bool TestCompare(Encoder64Test *test)
2456 {
2457     // Initialize
2458     test->PreWork();
2459 
2460     // First type-dependency
2461     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2462     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2463 
2464     // Main test call
2465     test->GetEncoder()->EncodeCompare(param1, param1, param2, std::is_signed_v<T> ? Condition::GE : Condition::HS);
2466 
2467     // Finalize
2468     test->PostWork();
2469 
2470     // If encode unsupported - now print error
2471     if (!test->GetEncoder()->GetResult()) {
2472         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2473         return false;
2474     }
2475     // Change this for enable print disasm
2476     test->Dump(false);
2477 
2478     // Main test loop:
2479     for (uint64_t i = 0; i < ITERATION; ++i) {
2480         // Second type-dependency
2481         T tmp1 = random_gen<T>();
2482         T tmp2 = random_gen<T>();
2483         // Deduced conflicting types for parameter
2484 
2485         auto compare = [](T a, T b) -> int32_t { return a >= b; };
2486 
2487         // Main check - compare parameter and
2488         // return value
2489         if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
2490             return false;
2491         }
2492     }
2493     return true;
2494 }
2495 
TEST_F(Encoder64Test,CompareTest)2496 TEST_F(Encoder64Test, CompareTest)
2497 {
2498     EXPECT_TRUE(TestCompare<int32_t>(this));
2499     EXPECT_TRUE(TestCompare<int64_t>(this));
2500     EXPECT_TRUE(TestCompare<uint32_t>(this));
2501     EXPECT_TRUE(TestCompare<uint64_t>(this));
2502 }
2503 
2504 template <typename T>
TestCompare64(Encoder64Test * test)2505 bool TestCompare64(Encoder64Test *test)
2506 {
2507     static_assert(sizeof(T) == sizeof(int64_t));
2508     // Initialize
2509     test->PreWork();
2510 
2511     // First type-dependency
2512     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2513     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2514 
2515     // Main test call
2516     test->GetEncoder()->EncodeCompare(param1, param1, param2, std::is_signed_v<T> ? Condition::LT : Condition::LO);
2517 
2518     // Finalize
2519     test->PostWork();
2520 
2521     // If encode unsupported - now print error
2522     if (!test->GetEncoder()->GetResult()) {
2523         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2524         return false;
2525     }
2526     // Change this for enable print disasm
2527     test->Dump(false);
2528 
2529     uint64_t hi = static_cast<uint64_t>(0xABCDEFU) << (BITS_PER_BYTE * sizeof(uint32_t));
2530 
2531     // Main test loop:
2532     for (uint64_t i = 0; i < ITERATION; ++i) {
2533         uint32_t lo = random_gen<T>();
2534 
2535         // Second type-dependency
2536         T tmp1 = hi | (lo + 1U);
2537         T tmp2 = hi | lo;
2538         // Deduced conflicting types for parameter
2539 
2540         auto compare = [](T a, T b) -> int32_t { return a < b; };
2541 
2542         // Main check - compare parameter and
2543         // return value
2544         if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
2545             return false;
2546         }
2547     }
2548     return true;
2549 }
2550 
TEST_F(Encoder64Test,Compare64Test)2551 TEST_F(Encoder64Test, Compare64Test)
2552 {
2553     EXPECT_TRUE(TestCompare64<int64_t>(this));
2554     EXPECT_TRUE(TestCompare64<uint64_t>(this));
2555 }
2556 
2557 template <typename Src, typename Dst>
TestCast(Encoder64Test * test)2558 bool TestCast(Encoder64Test *test)
2559 {
2560     // Initialize
2561     test->PreWork();
2562     // First type-dependency
2563     auto input = test->GetParameter(TypeInfo(Src(0)), 0);
2564     auto output = test->GetParameter(TypeInfo(Dst(0)), 0);
2565     // Main test call
2566     test->GetEncoder()->EncodeCast(output, std::is_signed_v<Dst>, input, std::is_signed_v<Src>);
2567 
2568     // Finalize
2569     test->PostWork();
2570 
2571     // If encode unsupported - now print error
2572     if (!test->GetEncoder()->GetResult()) {
2573         std::cerr << "Unsupported for " << TypeName<Src>() << ", " << TypeName<Dst>() << "\n";
2574         return false;
2575     }
2576     // Change this for enable print disasm
2577     test->Dump(false);
2578 
2579     // Main test loop:
2580     for (uint64_t i = 0; i < ITERATION; ++i) {
2581         // Using max size type: type result "Dst" or 32bit to check result,
2582         // because in our ISA min type is 32bit.
2583         // Only integers less thаn 32bit.
2584         typedef typename std::conditional<(sizeof(Dst) * BYTE_SIZE) >= WORD_SIZE, Dst, uint32_t>::type DstExt;
2585 
2586         // Second type-dependency
2587         auto src = random_gen<Src>();
2588         DstExt dst = static_cast<DstExt>(static_cast<Dst>(src));
2589 
2590         // Other cast for float->int
2591         if (std::is_floating_point<Src>() && !std::is_floating_point<Dst>()) {
2592             auto MIN_INT = std::numeric_limits<Dst>::min();
2593             auto MAX_INT = std::numeric_limits<Dst>::max();
2594             auto FLOAT_MIN_INT = static_cast<Src>(MIN_INT);
2595             auto FLOAT_MAX_INT = static_cast<Src>(MAX_INT);
2596 
2597             if (src > FLOAT_MIN_INT) {
2598                 if (src < FLOAT_MAX_INT) {
2599                     dst = static_cast<Dst>(src);
2600                 } else {
2601                     dst = MAX_INT;
2602                 }
2603             } else if (std::isnan(src)) {
2604                 dst = 0;
2605             } else {
2606                 dst = MIN_INT;
2607             }
2608         }
2609 
2610         // Deduced conflicting types for parameter
2611 
2612         // Main check - compare parameter and
2613         // return value
2614         if (!test->CallCode<Src, DstExt>(src, dst)) {
2615             return false;
2616         }
2617     }
2618 
2619     if constexpr (std::is_floating_point_v<Src> && std::is_integral_v<Dst>) {
2620         Src nan = std::numeric_limits<Src>::quiet_NaN();
2621         typedef typename std::conditional<(sizeof(Dst) * BYTE_SIZE) >= WORD_SIZE, Dst, uint32_t>::type DstExt;
2622 
2623         if (!test->CallCode<Src, DstExt>(nan, static_cast<DstExt>((Dst(0))))) {
2624             return false;
2625         }
2626     }
2627 
2628     return true;
2629 }
2630 
TEST_F(Encoder64Test,CastTest)2631 TEST_F(Encoder64Test, CastTest)
2632 {
2633     // Test int8
2634     EXPECT_TRUE((TestCast<int8_t, int8_t>(this)));
2635     EXPECT_TRUE((TestCast<int8_t, int16_t>(this)));
2636     EXPECT_TRUE((TestCast<int8_t, int32_t>(this)));
2637     EXPECT_TRUE((TestCast<int8_t, int64_t>(this)));
2638 
2639     EXPECT_TRUE((TestCast<int8_t, uint8_t>(this)));
2640     EXPECT_TRUE((TestCast<int8_t, uint16_t>(this)));
2641     EXPECT_TRUE((TestCast<int8_t, uint32_t>(this)));
2642     EXPECT_TRUE((TestCast<int8_t, uint64_t>(this)));
2643     EXPECT_TRUE((TestCast<int8_t, float>(this)));
2644     EXPECT_TRUE((TestCast<int8_t, double>(this)));
2645 
2646     EXPECT_TRUE((TestCast<uint8_t, int8_t>(this)));
2647     EXPECT_TRUE((TestCast<uint8_t, int16_t>(this)));
2648     EXPECT_TRUE((TestCast<uint8_t, int32_t>(this)));
2649     EXPECT_TRUE((TestCast<uint8_t, int64_t>(this)));
2650 
2651     EXPECT_TRUE((TestCast<uint8_t, uint8_t>(this)));
2652     EXPECT_TRUE((TestCast<uint8_t, uint16_t>(this)));
2653     EXPECT_TRUE((TestCast<uint8_t, uint32_t>(this)));
2654     EXPECT_TRUE((TestCast<uint8_t, uint64_t>(this)));
2655     EXPECT_TRUE((TestCast<uint8_t, float>(this)));
2656     EXPECT_TRUE((TestCast<uint8_t, double>(this)));
2657 
2658     // Test int16
2659     EXPECT_TRUE((TestCast<int16_t, int8_t>(this)));
2660     EXPECT_TRUE((TestCast<int16_t, int16_t>(this)));
2661     EXPECT_TRUE((TestCast<int16_t, int32_t>(this)));
2662     EXPECT_TRUE((TestCast<int16_t, int64_t>(this)));
2663 
2664     EXPECT_TRUE((TestCast<int16_t, uint8_t>(this)));
2665     EXPECT_TRUE((TestCast<int16_t, uint16_t>(this)));
2666     EXPECT_TRUE((TestCast<int16_t, uint32_t>(this)));
2667     EXPECT_TRUE((TestCast<int16_t, uint64_t>(this)));
2668     EXPECT_TRUE((TestCast<int16_t, float>(this)));
2669     EXPECT_TRUE((TestCast<int16_t, double>(this)));
2670 
2671     EXPECT_TRUE((TestCast<uint16_t, int8_t>(this)));
2672     EXPECT_TRUE((TestCast<uint16_t, int16_t>(this)));
2673     EXPECT_TRUE((TestCast<uint16_t, int32_t>(this)));
2674     EXPECT_TRUE((TestCast<uint16_t, int64_t>(this)));
2675 
2676     EXPECT_TRUE((TestCast<uint16_t, uint8_t>(this)));
2677     EXPECT_TRUE((TestCast<uint16_t, uint16_t>(this)));
2678     EXPECT_TRUE((TestCast<uint16_t, uint32_t>(this)));
2679     EXPECT_TRUE((TestCast<uint16_t, uint64_t>(this)));
2680     EXPECT_TRUE((TestCast<uint16_t, float>(this)));
2681     EXPECT_TRUE((TestCast<uint16_t, double>(this)));
2682 
2683     // Test int32
2684     EXPECT_TRUE((TestCast<int32_t, int8_t>(this)));
2685     EXPECT_TRUE((TestCast<int32_t, int16_t>(this)));
2686     EXPECT_TRUE((TestCast<int32_t, int32_t>(this)));
2687     EXPECT_TRUE((TestCast<int32_t, int64_t>(this)));
2688 
2689     EXPECT_TRUE((TestCast<int32_t, uint8_t>(this)));
2690     EXPECT_TRUE((TestCast<int32_t, uint16_t>(this)));
2691     EXPECT_TRUE((TestCast<int32_t, uint32_t>(this)));
2692     EXPECT_TRUE((TestCast<int32_t, uint64_t>(this)));
2693     EXPECT_TRUE((TestCast<int32_t, float>(this)));
2694     EXPECT_TRUE((TestCast<int32_t, double>(this)));
2695 
2696     EXPECT_TRUE((TestCast<uint32_t, int8_t>(this)));
2697     EXPECT_TRUE((TestCast<uint32_t, int16_t>(this)));
2698     EXPECT_TRUE((TestCast<uint32_t, int32_t>(this)));
2699     EXPECT_TRUE((TestCast<uint32_t, int64_t>(this)));
2700 
2701     EXPECT_TRUE((TestCast<uint32_t, uint8_t>(this)));
2702     EXPECT_TRUE((TestCast<uint32_t, uint16_t>(this)));
2703     EXPECT_TRUE((TestCast<uint32_t, uint32_t>(this)));
2704     EXPECT_TRUE((TestCast<uint32_t, uint64_t>(this)));
2705     EXPECT_TRUE((TestCast<uint32_t, float>(this)));
2706     EXPECT_TRUE((TestCast<uint32_t, double>(this)));
2707 
2708     // Test int64
2709     EXPECT_TRUE((TestCast<int64_t, int8_t>(this)));
2710     EXPECT_TRUE((TestCast<int64_t, int16_t>(this)));
2711     EXPECT_TRUE((TestCast<int64_t, int32_t>(this)));
2712     EXPECT_TRUE((TestCast<int64_t, int64_t>(this)));
2713 
2714     EXPECT_TRUE((TestCast<int64_t, uint8_t>(this)));
2715     EXPECT_TRUE((TestCast<int64_t, uint16_t>(this)));
2716     EXPECT_TRUE((TestCast<int64_t, uint32_t>(this)));
2717     EXPECT_TRUE((TestCast<int64_t, uint64_t>(this)));
2718     EXPECT_TRUE((TestCast<int64_t, float>(this)));
2719     EXPECT_TRUE((TestCast<int64_t, double>(this)));
2720 
2721     EXPECT_TRUE((TestCast<uint64_t, int8_t>(this)));
2722     EXPECT_TRUE((TestCast<uint64_t, int16_t>(this)));
2723     EXPECT_TRUE((TestCast<uint64_t, int32_t>(this)));
2724     EXPECT_TRUE((TestCast<uint64_t, int64_t>(this)));
2725 
2726     EXPECT_TRUE((TestCast<uint64_t, uint8_t>(this)));
2727     EXPECT_TRUE((TestCast<uint64_t, uint16_t>(this)));
2728     EXPECT_TRUE((TestCast<uint64_t, uint32_t>(this)));
2729     EXPECT_TRUE((TestCast<uint64_t, uint64_t>(this)));
2730     EXPECT_TRUE((TestCast<uint64_t, float>(this)));
2731     EXPECT_TRUE((TestCast<uint64_t, double>(this)));
2732 
2733     // Test float/double
2734     EXPECT_TRUE((TestCast<float, float>(this)));
2735     EXPECT_TRUE((TestCast<double, double>(this)));
2736     EXPECT_TRUE((TestCast<float, double>(this)));
2737     EXPECT_TRUE((TestCast<double, float>(this)));
2738 
2739     // We DON'T support cast from float32/64 to int8/16.
2740 
2741     EXPECT_TRUE((TestCast<float, int32_t>(this)));
2742     EXPECT_TRUE((TestCast<float, int64_t>(this)));
2743     EXPECT_TRUE((TestCast<double, int32_t>(this)));
2744     EXPECT_TRUE((TestCast<double, int64_t>(this)));
2745 
2746     EXPECT_TRUE((TestCast<float, uint32_t>(this)));
2747     EXPECT_TRUE((TestCast<float, uint64_t>(this)));
2748     EXPECT_TRUE((TestCast<double, uint32_t>(this)));
2749     EXPECT_TRUE((TestCast<double, uint64_t>(this)));
2750 }
2751 
2752 template <typename T>
TestDiv(Encoder64Test * test)2753 bool TestDiv(Encoder64Test *test)
2754 {
2755     bool is_signed = std::is_signed<T>::value;
2756 
2757     test->PreWork();
2758 
2759     // First type-dependency
2760     auto param_1 = test->GetParameter(TypeInfo(T(0)), 0);
2761     auto param_2 = test->GetParameter(TypeInfo(T(0)), 1);
2762 
2763     // Main test call
2764     test->GetEncoder()->EncodeDiv(param_1, is_signed, param_1, param_2);
2765 
2766     // Finalize
2767     test->PostWork();
2768 
2769     // If encode unsupported - now print error
2770     if (!test->GetEncoder()->GetResult()) {
2771         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2772         return false;
2773     }
2774     // Change this for enable print disasm
2775     test->Dump(false);
2776 
2777     // Main test loop:
2778     for (uint64_t i = 0; i < ITERATION; ++i) {
2779         // Second type-dependency
2780         T tmp1 = random_gen<T>();
2781         T tmp2 = random_gen<T>();
2782         if (tmp2 == 0) {
2783             tmp2 += 1;
2784         }
2785         // Main check - compare parameter and
2786         // return value
2787         if (!test->CallCode<T>(tmp1, tmp2, (tmp1 / tmp2))) {
2788             return false;
2789         }
2790     }
2791 
2792     if constexpr (std::is_floating_point_v<T>) {
2793         T nan = std::numeric_limits<T>::quiet_NaN();
2794 
2795         if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
2796             return false;
2797         }
2798         if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
2799             return false;
2800         }
2801         if (!test->CallCode<T>(0.0, 0.0, nan)) {
2802             return false;
2803         }
2804         if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
2805             return false;
2806         }
2807         if (!test->CallCode<T>(-std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
2808             return false;
2809         }
2810     }
2811 
2812     return true;
2813 }
2814 
TEST_F(Encoder64Test,DivTest)2815 TEST_F(Encoder64Test, DivTest)
2816 {
2817     EXPECT_TRUE(TestDiv<int32_t>(this));
2818     EXPECT_TRUE(TestDiv<int64_t>(this));
2819     EXPECT_TRUE(TestDiv<uint32_t>(this));
2820     EXPECT_TRUE(TestDiv<uint64_t>(this));
2821     EXPECT_TRUE(TestDiv<float>(this));
2822     EXPECT_TRUE(TestDiv<double>(this));
2823 }
2824 
2825 template <typename T>
TestMod(Encoder64Test * test)2826 bool TestMod(Encoder64Test *test)
2827 {
2828     bool is_signed = std::is_signed<T>::value;
2829 
2830     auto link_reg = Target::Current().GetLinkReg();
2831 
2832     test->PreWork();
2833     static_cast<aarch64::Aarch64Encoder *>(test->GetEncoder())
2834         ->GetMasm()
2835         ->Push(vixl::aarch64::xzr, aarch64::VixlReg(link_reg));
2836 
2837     // First type-dependency
2838     auto param_1 = test->GetParameter(TypeInfo(T(0)), 0);
2839     auto param_2 = test->GetParameter(TypeInfo(T(0)), 1);
2840 
2841     // Main test call
2842     test->GetEncoder()->EncodeMod(param_1, is_signed, param_1, param_2);
2843 
2844     // Finalize
2845     static_cast<aarch64::Aarch64Encoder *>(test->GetEncoder())
2846         ->GetMasm()
2847         ->Pop(aarch64::VixlReg(link_reg), vixl::aarch64::xzr);
2848     test->PostWork();
2849 
2850     // If encode unsupported - now print error
2851     if (!test->GetEncoder()->GetResult()) {
2852         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2853         return false;
2854     }
2855     // Change this for enable print disasm
2856     test->Dump(false);
2857 
2858     // Main test loop:
2859     for (uint64_t i = 0; i < ITERATION; ++i) {
2860         // Second type-dependency
2861         T tmp1 = random_gen<T>();
2862         T tmp2 = random_gen<T>();
2863         if (tmp2 == 0) {
2864             tmp2 += 1;
2865         }
2866         // Main check - compare parameter and
2867         // return value
2868         if constexpr (std::is_same<float, T>::value) {
2869             if (!test->CallCode<T>(tmp1, tmp2, fmodf(tmp1, tmp2))) {
2870                 return false;
2871             }
2872         } else if constexpr (std::is_same<double, T>::value) {
2873             if (!test->CallCode<T>(tmp1, tmp2, fmod(tmp1, tmp2))) {
2874                 return false;
2875             }
2876         } else {
2877             if (!test->CallCode<T>(tmp1, tmp2, static_cast<T>(tmp1 % tmp2))) {
2878                 return false;
2879             }
2880         }
2881     }
2882 
2883     if constexpr (std::is_floating_point_v<T>) {
2884         T nan = std::numeric_limits<T>::quiet_NaN();
2885 
2886         if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
2887             return false;
2888         }
2889         if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
2890             return false;
2891         }
2892         if (!test->CallCode<T>(0.0, 0.0, nan)) {
2893             return false;
2894         }
2895         if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
2896             return false;
2897         }
2898         if (!test->CallCode<T>(-std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
2899             return false;
2900         }
2901     }
2902 
2903     return true;
2904 }
2905 
TEST_F(Encoder64Test,ModTest)2906 TEST_F(Encoder64Test, ModTest)
2907 {
2908     EXPECT_TRUE(TestMod<int32_t>(this));
2909     EXPECT_TRUE(TestMod<int64_t>(this));
2910     EXPECT_TRUE(TestMod<uint32_t>(this));
2911     EXPECT_TRUE(TestMod<uint64_t>(this));
2912     EXPECT_TRUE(TestMod<float>(this));
2913     EXPECT_TRUE(TestMod<double>(this));
2914 }
2915 
2916 // MemCopy Test
2917 // TEST_F(Encoder64Test, MemCopyTest) {
2918 //  EncodeMemCopy(MemRef mem_from, MemRef mem_to, size_t size)
2919 
2920 // MemCopyz Test
2921 // TEST_F(Encoder64Test, MemCopyzTest) {
2922 //  EncodeMemCopyz(MemRef mem_from, MemRef mem_to, size_t size)
2923 
2924 template <int ID, typename T>
TestParam(Encoder64Test * test)2925 bool TestParam(Encoder64Test *test)
2926 {
2927     // int32_t uint64_t int32_t  int64_t         int32_t int32_t
2928     //   r0    r2+r3   stack0  stack2(align)   stack4
2929     using funct_ptr = uint64_t (*)(uint32_t, uint64_t, int32_t, int64_t, int32_t, int32_t);
2930 
2931     bool is_signed = std::is_signed<T>::value;
2932 
2933     constexpr TypeInfo params[6] = {INT32_TYPE, INT64_TYPE, INT32_TYPE, INT64_TYPE, INT32_TYPE, INT32_TYPE};
2934     TypeInfo curr_param = params[ID];
2935 
2936     auto param_info = test->GetCallconv()->GetParameterInfo(0);
2937     auto par = param_info->GetNativeParam(params[0]);
2938     // First ret value geted
2939     for (int i = 1; i <= ID; ++i) {
2940         par = param_info->GetNativeParam(params[i]);
2941     }
2942 
2943     auto link_reg = Target::Current().GetLinkReg();
2944     ArenaVector<Reg> used_regs(test->GetAllocator()->Adapter());
2945     used_regs.emplace_back(link_reg);
2946     test->PreWork();
2947 
2948     auto ret_reg = test->GetParameter(curr_param, 0);
2949 
2950     // Main test call
2951     if (std::holds_alternative<Reg>(par)) {
2952         test->GetEncoder()->EncodeMov(ret_reg, std::get<Reg>(par));
2953     } else {
2954         auto mem = MemRef(Target::Current().GetStackReg(), std::get<uint8_t>(par) * sizeof(uint32_t));
2955         test->GetEncoder()->EncodeLdr(ret_reg, is_signed, mem);
2956     }
2957 
2958     // If encode unsupported - now print error
2959     if (!test->GetEncoder()->GetResult()) {
2960         std::cerr << "Unsupported parameter with " << ID << "\n";
2961         return false;
2962     }
2963 
2964     // Finalize
2965     test->PostWork();
2966 
2967     // Change this for enable print disasm
2968     test->Dump(false);
2969 
2970     auto size = test->GetCallconv()->GetCodeSize() - test->GetCursor();
2971     void *offset = (static_cast<uint8_t *>(test->GetCallconv()->GetCodeEntry()));
2972     void *ptr = test->GetCodeAllocator()->AllocateCode(size, offset);
2973     auto func = reinterpret_cast<funct_ptr>(ptr);
2974 
2975     // Main test loop:
2976     for (uint64_t i = 0; i < ITERATION; ++i) {
2977         // Second type-dependency
2978         int32_t param_0 = random_gen<uint32_t>();
2979         uint64_t param_1 = random_gen<uint64_t>();
2980         int32_t param_2 = random_gen<int32_t>();
2981         int64_t param_3 = random_gen<int64_t>();
2982         int32_t param_4 = random_gen<int32_t>();
2983         int32_t param_5 = random_gen<int32_t>();
2984 
2985         // Main check - compare parameter and
2986         // return value
2987         const T curr_result = func(param_0, param_1, param_2, param_3, param_4, param_5);
2988         T result;
2989         if constexpr (ID == 0) {
2990             result = param_0;
2991         }
2992         if constexpr (ID == 1) {
2993             result = param_1;
2994         }
2995         if constexpr (ID == 2) {
2996             result = param_2;
2997         }
2998         if constexpr (ID == 3) {
2999             result = param_3;
3000         }
3001         if constexpr (ID == 4) {
3002             result = param_4;
3003         }
3004         if constexpr (ID == 5) {
3005             result = param_5;
3006         }
3007         if (curr_result != result) {
3008             return false;
3009         };
3010     }
3011     return true;
3012 }
3013 
TEST_F(Encoder64Test,ReadParams)3014 TEST_F(Encoder64Test, ReadParams)
3015 {
3016     EXPECT_TRUE((TestParam<0, int32_t>(this)));
3017     EXPECT_TRUE((TestParam<1, uint64_t>(this)));
3018     EXPECT_TRUE((TestParam<2, int32_t>(this)));
3019     EXPECT_TRUE((TestParam<3, int64_t>(this)));
3020     EXPECT_TRUE((TestParam<4, int32_t>(this)));
3021     EXPECT_TRUE((TestParam<5, int32_t>(this)));
3022 }
3023 
3024 template <typename T, Condition cc>
TestSelect(Encoder64Test * test)3025 bool TestSelect(Encoder64Test *test)
3026 {
3027     // Initialize
3028     test->PreWork();
3029 
3030     // First type-dependency
3031     auto param0 = test->GetParameter(TypeInfo(T(0)), 0);
3032     auto param1 = test->GetParameter(TypeInfo(T(0)), 1);
3033     auto param2 = test->GetParameter(TypeInfo(uint32_t(0)), 2);
3034     auto param3 = test->GetParameter(TypeInfo(uint32_t(0)), 3);
3035 
3036     // Main test call
3037     test->GetEncoder()->EncodeMov(param2, Imm(1));
3038     test->GetEncoder()->EncodeMov(param3, Imm(0));
3039     test->GetEncoder()->EncodeSelect(Reg(param0.GetId(), TypeInfo(uint32_t(0))), param2, param3, param0, param1, cc);
3040 
3041     // Finalize
3042     test->PostWork();
3043 
3044     // If encode unsupported - now print error
3045     if (!test->GetEncoder()->GetResult()) {
3046         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3047         return false;
3048     }
3049     // Change this for enable print disasm
3050     test->Dump(false);
3051 
3052     // Main test loop:
3053     for (uint64_t i = 0; i < ITERATION; ++i) {
3054         // Second type-dependency
3055         T tmp0 = random_gen<T>();
3056         T tmp1 = random_gen<T>();
3057 
3058         bool res {false};
3059         switch (cc) {
3060             case Condition::LT:
3061             case Condition::LO:
3062                 res = tmp0 < tmp1;
3063                 break;
3064             case Condition::EQ:
3065                 res = tmp0 == tmp1;
3066                 break;
3067             case Condition::NE:
3068                 res = tmp0 != tmp1;
3069                 break;
3070             case Condition::GT:
3071             case Condition::HI:
3072                 res = tmp0 > tmp1;
3073                 break;
3074             default:
3075                 UNREACHABLE();
3076         }
3077 
3078         // Main check - compare parameter and
3079         // return value
3080         if (!test->CallCode<T, bool>(tmp0, tmp1, res)) {
3081             return false;
3082         }
3083     }
3084     return true;
3085 }
3086 
TEST_F(Encoder64Test,SelectTest)3087 TEST_F(Encoder64Test, SelectTest)
3088 {
3089     EXPECT_TRUE((TestSelect<uint32_t, Condition::LO>(this)));
3090     EXPECT_TRUE((TestSelect<uint32_t, Condition::EQ>(this)));
3091     EXPECT_TRUE((TestSelect<uint32_t, Condition::NE>(this)));
3092     EXPECT_TRUE((TestSelect<uint32_t, Condition::HI>(this)));
3093 
3094     EXPECT_TRUE((TestSelect<uint64_t, Condition::LO>(this)));
3095     EXPECT_TRUE((TestSelect<uint64_t, Condition::EQ>(this)));
3096     EXPECT_TRUE((TestSelect<uint64_t, Condition::NE>(this)));
3097     EXPECT_TRUE((TestSelect<uint64_t, Condition::HI>(this)));
3098 
3099     EXPECT_TRUE((TestSelect<int32_t, Condition::LT>(this)));
3100     EXPECT_TRUE((TestSelect<int32_t, Condition::EQ>(this)));
3101     EXPECT_TRUE((TestSelect<int32_t, Condition::NE>(this)));
3102     EXPECT_TRUE((TestSelect<int32_t, Condition::GT>(this)));
3103 
3104     EXPECT_TRUE((TestSelect<int64_t, Condition::LT>(this)));
3105     EXPECT_TRUE((TestSelect<int64_t, Condition::EQ>(this)));
3106     EXPECT_TRUE((TestSelect<int64_t, Condition::NE>(this)));
3107     EXPECT_TRUE((TestSelect<int64_t, Condition::GT>(this)));
3108 }
3109 
3110 template <typename T, Condition cc, bool is_imm>
TestSelectTest(Encoder64Test * test)3111 bool TestSelectTest(Encoder64Test *test)
3112 {
3113     // Initialize
3114     test->PreWork();
3115 
3116     auto param0 = test->GetParameter(TypeInfo(T(0)), 0);
3117     auto param1 = test->GetParameter(TypeInfo(T(0)), 1);
3118     auto param2 = test->GetParameter(TypeInfo(uint32_t(0)), 2);
3119     auto param3 = test->GetParameter(TypeInfo(uint32_t(0)), 3);
3120     // truncate immediate value to max imm size
3121     [[maybe_unused]] T imm_value = random_mask_gen<T>();
3122 
3123     // Main test call
3124     test->GetEncoder()->EncodeMov(param2, Imm(1));
3125     test->GetEncoder()->EncodeMov(param3, Imm(0));
3126 
3127     if constexpr (is_imm) {
3128         test->GetEncoder()->EncodeSelectTest(Reg(param0.GetId(), TypeInfo(uint32_t(0))), param2, param3, param0,
3129                                              Imm(imm_value), cc);
3130     } else {
3131         test->GetEncoder()->EncodeSelectTest(Reg(param0.GetId(), TypeInfo(uint32_t(0))), param2, param3, param0, param1,
3132                                              cc);
3133     }
3134 
3135     // Finalize
3136     test->PostWork();
3137 
3138     // If encode unsupported - now print error
3139     if (!test->GetEncoder()->GetResult()) {
3140         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3141         return false;
3142     }
3143     // Change this for enable print disasm
3144     test->Dump(false);
3145 
3146     // Main test loop:
3147     for (uint64_t i = 0; i < ITERATION; ++i) {
3148         T tmp0 = random_gen<T>();
3149         T tmp1;
3150 
3151         if constexpr (is_imm) {
3152             tmp1 = imm_value;
3153         } else {
3154             tmp1 = random_gen<T>();
3155         }
3156 
3157         T and_res = tmp0 & tmp1;
3158         bool res = cc == Condition::TST_EQ ? and_res == 0 : and_res != 0;
3159 
3160         // Main check - compare parameter and return value
3161         if (!test->CallCode<T, bool>(tmp0, tmp1, res)) {
3162             return false;
3163         }
3164     }
3165     return true;
3166 }
3167 
TEST_F(Encoder64Test,SelectTestTest)3168 TEST_F(Encoder64Test, SelectTestTest)
3169 {
3170     EXPECT_TRUE((TestSelectTest<uint32_t, Condition::TST_EQ, false>(this)));
3171     EXPECT_TRUE((TestSelectTest<uint32_t, Condition::TST_NE, false>(this)));
3172     EXPECT_TRUE((TestSelectTest<uint32_t, Condition::TST_EQ, true>(this)));
3173     EXPECT_TRUE((TestSelectTest<uint32_t, Condition::TST_NE, true>(this)));
3174 
3175     EXPECT_TRUE((TestSelectTest<int32_t, Condition::TST_EQ, false>(this)));
3176     EXPECT_TRUE((TestSelectTest<int32_t, Condition::TST_NE, false>(this)));
3177     EXPECT_TRUE((TestSelectTest<int32_t, Condition::TST_EQ, true>(this)));
3178     EXPECT_TRUE((TestSelectTest<int32_t, Condition::TST_NE, true>(this)));
3179 
3180     EXPECT_TRUE((TestSelectTest<uint64_t, Condition::TST_EQ, false>(this)));
3181     EXPECT_TRUE((TestSelectTest<uint64_t, Condition::TST_NE, false>(this)));
3182     EXPECT_TRUE((TestSelectTest<uint64_t, Condition::TST_EQ, true>(this)));
3183     EXPECT_TRUE((TestSelectTest<uint64_t, Condition::TST_NE, true>(this)));
3184 
3185     EXPECT_TRUE((TestSelectTest<int64_t, Condition::TST_EQ, false>(this)));
3186     EXPECT_TRUE((TestSelectTest<int64_t, Condition::TST_NE, false>(this)));
3187     EXPECT_TRUE((TestSelectTest<int64_t, Condition::TST_EQ, true>(this)));
3188     EXPECT_TRUE((TestSelectTest<int64_t, Condition::TST_NE, true>(this)));
3189 }
3190 
3191 template <typename T, Condition cc>
TestCompareTest(Encoder64Test * test)3192 bool TestCompareTest(Encoder64Test *test)
3193 {
3194     // Initialize
3195     test->PreWork();
3196 
3197     // First type-dependency
3198     auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
3199     auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
3200 
3201     // Main test call
3202     test->GetEncoder()->EncodeCompareTest(param1, param1, param2, cc);
3203 
3204     // Finalize
3205     test->PostWork();
3206 
3207     // If encode unsupported - now print error
3208     if (!test->GetEncoder()->GetResult()) {
3209         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3210         return false;
3211     }
3212     // Change this for enable print disasm
3213     test->Dump(false);
3214 
3215     // Main test loop:
3216     for (uint64_t i = 0; i < ITERATION; ++i) {
3217         // Second type-dependency
3218         T tmp1 = random_gen<T>();
3219         T tmp2 = random_gen<T>();
3220         // Deduced conflicting types for parameter
3221 
3222         auto compare = [](T a, T b) -> int32_t { return cc == Condition::TST_EQ ? (a & b) == 0 : (a & b) != 0; };
3223 
3224         // Main check - compare parameter and
3225         // return value
3226         if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
3227             return false;
3228         }
3229     }
3230     return true;
3231 }
3232 
TEST_F(Encoder64Test,CompareTestTest)3233 TEST_F(Encoder64Test, CompareTestTest)
3234 {
3235     EXPECT_TRUE((TestCompareTest<int32_t, Condition::TST_EQ>(this)));
3236     EXPECT_TRUE((TestCompareTest<int32_t, Condition::TST_NE>(this)));
3237     EXPECT_TRUE((TestCompareTest<int64_t, Condition::TST_EQ>(this)));
3238     EXPECT_TRUE((TestCompareTest<int64_t, Condition::TST_NE>(this)));
3239     EXPECT_TRUE((TestCompareTest<uint32_t, Condition::TST_EQ>(this)));
3240     EXPECT_TRUE((TestCompareTest<uint32_t, Condition::TST_NE>(this)));
3241     EXPECT_TRUE((TestCompareTest<uint64_t, Condition::TST_EQ>(this)));
3242     EXPECT_TRUE((TestCompareTest<uint64_t, Condition::TST_NE>(this)));
3243 }
3244 
3245 template <typename T, Condition cc, bool is_imm>
TestJumpTest(Encoder64Test * test)3246 bool TestJumpTest(Encoder64Test *test)
3247 {
3248     // Initialize
3249     test->PreWork();
3250 
3251     // First type-dependency
3252     auto param0 = test->GetParameter(TypeInfo(T(0)), 0);
3253     auto param1 = test->GetParameter(TypeInfo(T(0)), 1);
3254     auto ret_val = Target::Current().GetParamReg(0);
3255 
3256     auto true_branch = test->GetEncoder()->CreateLabel();
3257     auto end = test->GetEncoder()->CreateLabel();
3258     [[maybe_unused]] T imm_value = random_mask_gen<T>();
3259 
3260     // Main test call
3261     if constexpr (is_imm) {
3262         test->GetEncoder()->EncodeJumpTest(true_branch, param0, Imm(imm_value), cc);
3263     } else {
3264         test->GetEncoder()->EncodeJumpTest(true_branch, param0, param1, cc);
3265     }
3266     test->GetEncoder()->EncodeMov(ret_val, Imm(0));
3267     test->GetEncoder()->EncodeJump(end);
3268 
3269     test->GetEncoder()->BindLabel(true_branch);
3270     test->GetEncoder()->EncodeMov(ret_val, Imm(1));
3271 
3272     test->GetEncoder()->BindLabel(end);
3273     // Finalize
3274     test->PostWork();
3275 
3276     // If encode unsupported - now print error
3277     if (!test->GetEncoder()->GetResult()) {
3278         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3279         return false;
3280     }
3281     // Change this for enable print disasm
3282     test->Dump(false);
3283 
3284     // Main test loop:
3285     for (uint64_t i = 0; i < ITERATION; ++i) {
3286         // Second type-dependency
3287         T tmp1 = random_gen<T>();
3288         T tmp2;
3289         if constexpr (is_imm) {
3290             tmp2 = imm_value;
3291         } else {
3292             tmp2 = random_gen<T>();
3293         }
3294         // Deduced conflicting types for parameter
3295 
3296         auto compare = [](T a, T b) -> int32_t { return cc == Condition::TST_EQ ? (a & b) == 0 : (a & b) != 0; };
3297 
3298         // Main check - compare parameter and
3299         // return value
3300         if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
3301             return false;
3302         }
3303     }
3304     return true;
3305 }
3306 
TEST_F(Encoder64Test,JumpTestTest)3307 TEST_F(Encoder64Test, JumpTestTest)
3308 {
3309     EXPECT_TRUE((TestJumpTest<int32_t, Condition::TST_EQ, false>(this)));
3310     EXPECT_TRUE((TestJumpTest<int32_t, Condition::TST_NE, false>(this)));
3311     EXPECT_TRUE((TestJumpTest<int64_t, Condition::TST_EQ, false>(this)));
3312     EXPECT_TRUE((TestJumpTest<int64_t, Condition::TST_NE, false>(this)));
3313     EXPECT_TRUE((TestJumpTest<uint32_t, Condition::TST_EQ, false>(this)));
3314     EXPECT_TRUE((TestJumpTest<uint32_t, Condition::TST_NE, false>(this)));
3315     EXPECT_TRUE((TestJumpTest<uint64_t, Condition::TST_EQ, false>(this)));
3316     EXPECT_TRUE((TestJumpTest<uint64_t, Condition::TST_NE, false>(this)));
3317 
3318     EXPECT_TRUE((TestJumpTest<int32_t, Condition::TST_EQ, true>(this)));
3319     EXPECT_TRUE((TestJumpTest<int32_t, Condition::TST_NE, true>(this)));
3320     EXPECT_TRUE((TestJumpTest<int64_t, Condition::TST_EQ, true>(this)));
3321     EXPECT_TRUE((TestJumpTest<int64_t, Condition::TST_NE, true>(this)));
3322     EXPECT_TRUE((TestJumpTest<uint32_t, Condition::TST_EQ, true>(this)));
3323     EXPECT_TRUE((TestJumpTest<uint32_t, Condition::TST_NE, true>(this)));
3324     EXPECT_TRUE((TestJumpTest<uint64_t, Condition::TST_EQ, true>(this)));
3325     EXPECT_TRUE((TestJumpTest<uint64_t, Condition::TST_NE, true>(this)));
3326 }
3327 
3328 template <typename T, bool is_acquire>
TestLoadExclusive(Encoder64Test * test,uint64_t input_word,T expected_result)3329 bool TestLoadExclusive(Encoder64Test *test, uint64_t input_word, T expected_result)
3330 {
3331     uint64_t buffer[3] = {0xFFFFFFFFFFFFFFFFULL, input_word, 0xFFFFFFFFFFFFFFFFULL};
3332     test->PreWork();
3333     auto param_0 = test->GetParameter(TypeInfo(uintptr_t(0)), 0);
3334     auto result = test->GetParameter(TypeInfo(T(0)), 0);
3335     test->GetEncoder()->EncodeLdrExclusive(result, param_0, is_acquire);
3336     test->PostWork();
3337 
3338     if (!test->GetEncoder()->GetResult()) {
3339         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3340         return false;
3341     }
3342     // Change this for enable print disasm
3343     test->Dump(false);
3344     auto word_addr = reinterpret_cast<uintptr_t>(&buffer[1]);
3345     return test->CallCode<uintptr_t, T>(word_addr, expected_result);
3346 }
3347 
3348 template <typename T, bool is_release>
TestStoreExclusiveFailed(Encoder64Test * test)3349 bool TestStoreExclusiveFailed(Encoder64Test *test)
3350 {
3351     uint64_t buffer = 0xFFFFFFFFFFFFFFFFULL;
3352     test->PreWork();
3353     auto param_0 = test->GetParameter(TypeInfo(uintptr_t(0)), 0);
3354     auto tmp_reg = test->GetParameter(TypeInfo(T(0)), 1);
3355     auto result = test->GetParameter(TypeInfo(T(0)), 0);
3356 
3357     // perform store without load - should fail as there are no exlusive monitor
3358     test->GetEncoder()->EncodeStrExclusive(result, tmp_reg, param_0, is_release);
3359     test->PostWork();
3360 
3361     if (!test->GetEncoder()->GetResult()) {
3362         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3363         return false;
3364     }
3365     // Change this for enable print disasm
3366     test->Dump(false);
3367     auto word_addr = reinterpret_cast<uintptr_t>(&buffer);
3368     return test->CallCode<uintptr_t, T>(word_addr, static_cast<T>(buffer), 1);
3369 }
3370 
3371 template <typename T, bool is_release>
TestStoreExclusive(Encoder64Test * test,T value,uint64_t expected_result)3372 bool TestStoreExclusive(Encoder64Test *test, T value, uint64_t expected_result)
3373 {
3374     // test writes value into buffer[1]
3375     uint64_t buffer[3] = {0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL};
3376     test->PreWork();
3377     auto param_0 = test->GetParameter(TypeInfo(uintptr_t(0)), 0);
3378     auto param_1 = test->GetParameter(TypeInfo(T(0)), 1);
3379     auto result = test->GetParameter(TypeInfo(T(0)), 0);
3380     auto retry_label = test->GetEncoder()->CreateLabel();
3381     Reg tmp_reg(test->GetRegfile()->GetZeroReg().GetId(), TypeInfo(T(0)));
3382 
3383     test->GetEncoder()->BindLabel(retry_label);
3384     test->GetEncoder()->EncodeLdrExclusive(tmp_reg, param_0, false);
3385     test->GetEncoder()->EncodeStrExclusive(result, param_1, param_0, is_release);
3386     // retry if store exclusive returned non zero value
3387     test->GetEncoder()->EncodeJump(retry_label, result, Condition::NE);
3388 
3389     test->PostWork();
3390 
3391     if (!test->GetEncoder()->GetResult()) {
3392         std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3393         return false;
3394     }
3395     // Change this for enable print disasm
3396     test->Dump(false);
3397     auto word_addr = reinterpret_cast<uintptr_t>(&buffer[1]);
3398     if (!test->CallCode<uintptr_t, T>(word_addr, value, 0)) {
3399         return false;
3400     }
3401     if (buffer[1] != expected_result) {
3402         std::cerr << "Failed: expected value " << std::hex << expected_result << " differs from actual result "
3403                   << buffer[1] << std::dec << std::endl;
3404         return false;
3405     }
3406     return true;
3407 }
3408 
TEST_F(Encoder64Test,LoadExclusiveTest)3409 TEST_F(Encoder64Test, LoadExclusiveTest)
3410 {
3411     const uint64_t SOURCE_WORD = 0x1122334455667788ULL;
3412     // aarch64 is little-endian, so bytes are actually stored in following order:
3413     // 0x 88 77 66 55 44 33 22 11
3414     EXPECT_TRUE((TestLoadExclusive<uint8_t, false>(this, SOURCE_WORD, 0x88U)));
3415     EXPECT_TRUE((TestLoadExclusive<uint16_t, false>(this, SOURCE_WORD, 0x7788U)));
3416     EXPECT_TRUE((TestLoadExclusive<uint32_t, false>(this, SOURCE_WORD, 0x55667788UL)));
3417     EXPECT_TRUE((TestLoadExclusive<uint64_t, false>(this, SOURCE_WORD, SOURCE_WORD)));
3418 
3419     EXPECT_TRUE((TestLoadExclusive<uint8_t, true>(this, SOURCE_WORD, 0x88U)));
3420     EXPECT_TRUE((TestLoadExclusive<uint16_t, true>(this, SOURCE_WORD, 0x7788U)));
3421     EXPECT_TRUE((TestLoadExclusive<uint32_t, true>(this, SOURCE_WORD, 0x55667788UL)));
3422     EXPECT_TRUE((TestLoadExclusive<uint64_t, true>(this, SOURCE_WORD, SOURCE_WORD)));
3423 }
3424 
TEST_F(Encoder64Test,StoreExclusiveTest)3425 TEST_F(Encoder64Test, StoreExclusiveTest)
3426 {
3427     EXPECT_TRUE((TestStoreExclusiveFailed<uint8_t, false>(this)));
3428     EXPECT_TRUE((TestStoreExclusiveFailed<uint16_t, false>(this)));
3429     EXPECT_TRUE((TestStoreExclusiveFailed<uint32_t, false>(this)));
3430     EXPECT_TRUE((TestStoreExclusiveFailed<uint64_t, false>(this)));
3431 
3432     EXPECT_TRUE((TestStoreExclusiveFailed<uint8_t, true>(this)));
3433     EXPECT_TRUE((TestStoreExclusiveFailed<uint16_t, true>(this)));
3434     EXPECT_TRUE((TestStoreExclusiveFailed<uint32_t, true>(this)));
3435     EXPECT_TRUE((TestStoreExclusiveFailed<uint64_t, true>(this)));
3436 
3437     EXPECT_TRUE((TestStoreExclusive<uint8_t, false>(this, 0x11U, 0xFFFFFFFFFFFFFF11ULL)));
3438     EXPECT_TRUE((TestStoreExclusive<uint16_t, false>(this, 0x1122U, 0xFFFFFFFFFFFF1122ULL)));
3439     EXPECT_TRUE((TestStoreExclusive<uint32_t, false>(this, 0x11223344UL, 0xFFFFFFFF11223344ULL)));
3440     EXPECT_TRUE((TestStoreExclusive<uint64_t, false>(this, 0xAABBCCDD11335577ULL, 0xAABBCCDD11335577ULL)));
3441 }
3442 
3443 class Encoder64ApiTest : public Encoder64Test {
3444 public:
Encoder64ApiTest()3445     Encoder64ApiTest() : decoder_(GetAllocator()) {}
3446 
GetOutput(const aarch64::Aarch64Encoder & encoder)3447     std::string &GetOutput(const aarch64::Aarch64Encoder &encoder)
3448     {
3449         output_.resize(0);
3450         char buf[64];
3451         vixl::aarch64::Disassembler disasm(buf, sizeof(buf));
3452         vixl::aarch64::Decoder::ScopedVisitors sv(decoder_, {&disasm});
3453         auto begin = encoder.GetMasm()->GetBuffer()->GetOffsetAddress<uint8_t *>(0);
3454         auto end = begin + encoder.GetMasm()->GetSizeOfCodeGenerated();
3455         for (auto instr = reinterpret_cast<const vixl::aarch64::Instruction *>(begin);
3456              instr < reinterpret_cast<const vixl::aarch64::Instruction *>(end); instr = instr->GetNextInstruction()) {
3457             decoder_.Decode(instr);
3458             if (!output_.empty()) {
3459                 output_ += '\n';
3460             }
3461             output_ += disasm.GetOutput();
3462         }
3463         return output_;
3464     }
3465 
3466 protected:
3467     std::string output_;
3468     vixl::aarch64::Decoder decoder_;
3469 };
3470 
TEST_F(Encoder64ApiTest,TestEncodeMov)3471 TEST_F(Encoder64ApiTest, TestEncodeMov)
3472 {
3473     {
3474         aarch64::Aarch64Encoder encoder(GetAllocator());
3475         encoder.InitMasm();
3476         encoder.SetRegfile(GetRegfile());
3477         encoder.EncodeMov(Reg(0, INT32_TYPE), Reg(1, INT32_TYPE));
3478         encoder.Finalize();
3479         EXPECT_TRUE(encoder.GetResult());
3480         EXPECT_STREQ("mov w0, w1", GetOutput(encoder).c_str());
3481     }
3482     {
3483         aarch64::Aarch64Encoder encoder(GetAllocator());
3484         encoder.InitMasm();
3485         encoder.SetRegfile(GetRegfile());
3486         encoder.EncodeMov(Reg(0, INT32_TYPE), Reg(1, INT64_TYPE));
3487         encoder.Finalize();
3488         EXPECT_TRUE(encoder.GetResult());
3489         EXPECT_STREQ("mov w0, w1", GetOutput(encoder).c_str());
3490     }
3491     {
3492         aarch64::Aarch64Encoder encoder(GetAllocator());
3493         encoder.InitMasm();
3494         encoder.SetRegfile(GetRegfile());
3495         encoder.EncodeMov(Reg(0, INT64_TYPE), Reg(1, INT32_TYPE));
3496         encoder.Finalize();
3497         EXPECT_TRUE(encoder.GetResult());
3498         EXPECT_STREQ("mov x0, x1", GetOutput(encoder).c_str());
3499     }
3500     {
3501         aarch64::Aarch64Encoder encoder(GetAllocator());
3502         encoder.InitMasm();
3503         encoder.SetRegfile(GetRegfile());
3504         encoder.EncodeMov(Reg(0, INT32_TYPE), Reg(0, INT32_TYPE));
3505         encoder.Finalize();
3506         EXPECT_TRUE(encoder.GetResult());
3507         EXPECT_STREQ("", GetOutput(encoder).c_str());
3508     }
3509     {
3510         aarch64::Aarch64Encoder encoder(GetAllocator());
3511         encoder.InitMasm();
3512         encoder.SetRegfile(GetRegfile());
3513         encoder.EncodeMov(Reg(0, FLOAT64_TYPE), Reg(1, FLOAT64_TYPE));
3514         encoder.Finalize();
3515         EXPECT_TRUE(encoder.GetResult());
3516         EXPECT_STREQ("fmov d0, d1", GetOutput(encoder).c_str());
3517     }
3518     {
3519         aarch64::Aarch64Encoder encoder(GetAllocator());
3520         encoder.InitMasm();
3521         encoder.SetRegfile(GetRegfile());
3522         encoder.EncodeMov(Reg(0, FLOAT64_TYPE), Reg(1, FLOAT32_TYPE));
3523         encoder.Finalize();
3524         EXPECT_TRUE(encoder.GetResult());
3525         EXPECT_STREQ("fcvt d0, s1", GetOutput(encoder).c_str());
3526     }
3527     {
3528         aarch64::Aarch64Encoder encoder(GetAllocator());
3529         encoder.InitMasm();
3530         encoder.SetRegfile(GetRegfile());
3531         encoder.EncodeMov(Reg(0, INT32_TYPE), Reg(1, FLOAT32_TYPE));
3532         encoder.Finalize();
3533         EXPECT_TRUE(encoder.GetResult());
3534         EXPECT_STREQ("fmov w0, s1", GetOutput(encoder).c_str());
3535     }
3536     {
3537         aarch64::Aarch64Encoder encoder(GetAllocator());
3538         encoder.InitMasm();
3539         encoder.SetRegfile(GetRegfile());
3540         encoder.EncodeMov(Reg(0, FLOAT32_TYPE), Reg(1, INT32_TYPE));
3541         encoder.Finalize();
3542         EXPECT_TRUE(encoder.GetResult());
3543         EXPECT_STREQ("fmov s0, w1", GetOutput(encoder).c_str());
3544     }
3545 }
3546 
TEST_F(Encoder64ApiTest,TestEncodeLdr)3547 TEST_F(Encoder64ApiTest, TestEncodeLdr)
3548 {
3549     {
3550         aarch64::Aarch64Encoder encoder(GetAllocator());
3551         encoder.InitMasm();
3552         encoder.SetRegfile(GetRegfile());
3553         encoder.EncodeLdr(Reg(0, FLOAT64_TYPE), true, MemRef(Reg(0, INT64_TYPE)));
3554         encoder.Finalize();
3555         EXPECT_TRUE(encoder.GetResult());
3556         EXPECT_STREQ("ldr d0, [x0]", GetOutput(encoder).c_str());
3557     }
3558     {
3559         aarch64::Aarch64Encoder encoder(GetAllocator());
3560         encoder.InitMasm();
3561         encoder.SetRegfile(GetRegfile());
3562         encoder.EncodeLdr(Reg(0, INT8_TYPE), true, MemRef(Reg(0, INT64_TYPE)));
3563         encoder.Finalize();
3564         EXPECT_TRUE(encoder.GetResult());
3565         EXPECT_STREQ("ldrsb x0, [x0]", GetOutput(encoder).c_str());
3566     }
3567     {
3568         aarch64::Aarch64Encoder encoder(GetAllocator());
3569         encoder.InitMasm();
3570         encoder.SetRegfile(GetRegfile());
3571         encoder.EncodeLdr(Reg(0, INT16_TYPE), true, MemRef(Reg(0, INT64_TYPE)));
3572         encoder.Finalize();
3573         EXPECT_TRUE(encoder.GetResult());
3574         EXPECT_STREQ("ldrsh w0, [x0]", GetOutput(encoder).c_str());
3575     }
3576     {
3577         aarch64::Aarch64Encoder encoder(GetAllocator());
3578         encoder.InitMasm();
3579         encoder.SetRegfile(GetRegfile());
3580         encoder.EncodeLdr(Reg(0, INT32_TYPE), true, MemRef(Reg(0, INT64_TYPE)));
3581         encoder.Finalize();
3582         EXPECT_TRUE(encoder.GetResult());
3583         EXPECT_STREQ("ldr w0, [x0]", GetOutput(encoder).c_str());
3584     }
3585     {
3586         aarch64::Aarch64Encoder encoder(GetAllocator());
3587         encoder.InitMasm();
3588         encoder.SetRegfile(GetRegfile());
3589         encoder.EncodeLdr(Reg(0, INT8_TYPE), false, MemRef(Reg(0, INT64_TYPE)));
3590         encoder.Finalize();
3591         EXPECT_TRUE(encoder.GetResult());
3592         EXPECT_STREQ("ldrb w0, [x0]", GetOutput(encoder).c_str());
3593     }
3594     {
3595         aarch64::Aarch64Encoder encoder(GetAllocator());
3596         encoder.InitMasm();
3597         encoder.SetRegfile(GetRegfile());
3598         encoder.EncodeLdr(Reg(0, INT16_TYPE), false, MemRef(Reg(0, INT64_TYPE)));
3599         encoder.Finalize();
3600         EXPECT_TRUE(encoder.GetResult());
3601         EXPECT_STREQ("ldrh w0, [x0]", GetOutput(encoder).c_str());
3602     }
3603     {
3604         aarch64::Aarch64Encoder encoder(GetAllocator());
3605         encoder.InitMasm();
3606         encoder.SetRegfile(GetRegfile());
3607         encoder.EncodeLdr(Reg(0, INT32_TYPE), false, MemRef(Reg(0, INT64_TYPE)));
3608         encoder.Finalize();
3609         EXPECT_TRUE(encoder.GetResult());
3610         EXPECT_STREQ("ldr w0, [x0]", GetOutput(encoder).c_str());
3611     }
3612     {
3613         aarch64::Aarch64Encoder encoder(GetAllocator());
3614         encoder.InitMasm();
3615         encoder.SetRegfile(GetRegfile());
3616         encoder.EncodeLdr(Reg(0, INT64_TYPE), false, MemRef(Reg(0, INT64_TYPE)));
3617         encoder.Finalize();
3618         EXPECT_TRUE(encoder.GetResult());
3619         EXPECT_STREQ("ldr x0, [x0]", GetOutput(encoder).c_str());
3620     }
3621 }
3622 
TEST_F(Encoder64ApiTest,TestEncodeStr)3623 TEST_F(Encoder64ApiTest, TestEncodeStr)
3624 {
3625     {
3626         aarch64::Aarch64Encoder encoder(GetAllocator());
3627         encoder.InitMasm();
3628         encoder.SetRegfile(GetRegfile());
3629         encoder.EncodeStr(Reg(0, FLOAT64_TYPE), MemRef(Reg(0, INT64_TYPE)));
3630         encoder.Finalize();
3631         EXPECT_TRUE(encoder.GetResult());
3632         EXPECT_STREQ("str d0, [x0]", GetOutput(encoder).c_str());
3633     }
3634     {
3635         aarch64::Aarch64Encoder encoder(GetAllocator());
3636         encoder.InitMasm();
3637         encoder.SetRegfile(GetRegfile());
3638         encoder.EncodeStr(Reg(0, INT8_TYPE), MemRef(Reg(0, INT64_TYPE)));
3639         encoder.Finalize();
3640         EXPECT_TRUE(encoder.GetResult());
3641         EXPECT_STREQ("strb w0, [x0]", GetOutput(encoder).c_str());
3642     }
3643     {
3644         aarch64::Aarch64Encoder encoder(GetAllocator());
3645         encoder.InitMasm();
3646         encoder.SetRegfile(GetRegfile());
3647         encoder.EncodeStr(Reg(0, INT16_TYPE), MemRef(Reg(0, INT64_TYPE)));
3648         encoder.Finalize();
3649         EXPECT_TRUE(encoder.GetResult());
3650         EXPECT_STREQ("strh w0, [x0]", GetOutput(encoder).c_str());
3651     }
3652     {
3653         aarch64::Aarch64Encoder encoder(GetAllocator());
3654         encoder.InitMasm();
3655         encoder.SetRegfile(GetRegfile());
3656         encoder.EncodeStr(Reg(0, INT32_TYPE), MemRef(Reg(0, INT64_TYPE)));
3657         encoder.Finalize();
3658         EXPECT_TRUE(encoder.GetResult());
3659         EXPECT_STREQ("str w0, [x0]", GetOutput(encoder).c_str());
3660     }
3661     {
3662         aarch64::Aarch64Encoder encoder(GetAllocator());
3663         encoder.InitMasm();
3664         encoder.SetRegfile(GetRegfile());
3665         encoder.EncodeStr(Reg(0, INT64_TYPE), MemRef(Reg(0, INT64_TYPE)));
3666         encoder.Finalize();
3667         EXPECT_TRUE(encoder.GetResult());
3668         EXPECT_STREQ("str x0, [x0]", GetOutput(encoder).c_str());
3669     }
3670 }
3671 
TEST_F(Encoder64ApiTest,TestEncodeMemCopy)3672 TEST_F(Encoder64ApiTest, TestEncodeMemCopy)
3673 {
3674     {
3675         aarch64::Aarch64Encoder encoder(GetAllocator());
3676         encoder.InitMasm();
3677         encoder.SetRegfile(GetRegfile());
3678         encoder.EncodeMemCopy(MemRef(Reg(0, INT64_TYPE)), MemRef(Reg(1, INT64_TYPE)), BYTE_SIZE);
3679         encoder.Finalize();
3680         EXPECT_TRUE(encoder.GetResult());
3681         EXPECT_STREQ("ldrb w16, [x0]\nstrb w16, [x1]", GetOutput(encoder).c_str());
3682     }
3683     {
3684         aarch64::Aarch64Encoder encoder(GetAllocator());
3685         encoder.InitMasm();
3686         encoder.SetRegfile(GetRegfile());
3687         encoder.EncodeMemCopy(MemRef(Reg(0, INT64_TYPE)), MemRef(Reg(1, INT64_TYPE)), HALF_SIZE);
3688         encoder.Finalize();
3689         EXPECT_TRUE(encoder.GetResult());
3690         EXPECT_STREQ("ldrh w16, [x0]\nstrh w16, [x1]", GetOutput(encoder).c_str());
3691     }
3692     {
3693         aarch64::Aarch64Encoder encoder(GetAllocator());
3694         encoder.InitMasm();
3695         encoder.SetRegfile(GetRegfile());
3696         encoder.EncodeMemCopy(MemRef(Reg(0, INT64_TYPE)), MemRef(Reg(1, INT64_TYPE)), WORD_SIZE);
3697         encoder.Finalize();
3698         EXPECT_TRUE(encoder.GetResult());
3699         EXPECT_STREQ("ldr w16, [x0]\nstr w16, [x1]", GetOutput(encoder).c_str());
3700     }
3701     {
3702         aarch64::Aarch64Encoder encoder(GetAllocator());
3703         encoder.InitMasm();
3704         encoder.SetRegfile(GetRegfile());
3705         encoder.EncodeMemCopy(MemRef(Reg(0, INT64_TYPE)), MemRef(Reg(1, INT64_TYPE)), DOUBLE_WORD_SIZE);
3706         encoder.Finalize();
3707         EXPECT_TRUE(encoder.GetResult());
3708         EXPECT_STREQ("ldr x16, [x0]\nstr x16, [x1]", GetOutput(encoder).c_str());
3709     }
3710 }
3711 
TEST_F(Encoder64Test,Registers)3712 TEST_F(Encoder64Test, Registers)
3713 {
3714     auto target = GetEncoder()->GetTarget();
3715     {
3716         {
3717             ScopedTmpReg tmp1(GetEncoder(), true);
3718             ASSERT_EQ(tmp1.GetReg(), target.GetLinkReg());
3719             ScopedTmpReg tmp2(GetEncoder(), true);
3720             ASSERT_NE(tmp2.GetReg(), target.GetLinkReg());
3721         }
3722         ScopedTmpReg tmp3(GetEncoder(), true);
3723         ASSERT_EQ(tmp3.GetReg(), target.GetLinkReg());
3724     }
3725     {
3726         ScopedTmpReg tmp1(GetEncoder(), false);
3727         ASSERT_NE(tmp1.GetReg(), target.GetLinkReg());
3728     }
3729 }
3730 }  // namespace panda::compiler
3731