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 ¶m, 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 ¶m1, const T ¶m2, 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 ¶m, 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 ¶m1, const T ¶m2, 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