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 if (!ret) {
1171 if constexpr (std::is_same<float, T>::value) {
1172 std::cerr << std::hex << "Strz test fail " << bit_cast<uint32_t>(tmp)
1173 << " ret_data = " << bit_cast<uint32_t>(ret_data[0]) << "\n";
1174 }
1175 if constexpr (std::is_same<double, T>::value) {
1176 std::cerr << std::hex << "Strz test fail " << bit_cast<uint64_t>(tmp)
1177 << " ret_data = " << bit_cast<uint64_t>(ret_data[0]) << "\n";
1178 }
1179 std::cerr << std::hex << "Strz test fail " << tmp << " ret_data = " << ret_data[0] << "\n";
1180 return false;
1181 }
1182 } else {
1183 // Second type-dependency
1184 T tmp = random_gen<T>();
1185 uint64_t ret_data = 0xffffffffffffffff;
1186 T *ptr = reinterpret_cast<T *>(&ret_data);
1187
1188 uint64_t result = test->CallCodeStore<T>(reinterpret_cast<int64_t>(ptr), tmp);
1189 // Store must change ret_data value
1190 if (ret_data != tmp) {
1191 std::cerr << std::hex << "Strz test fail " << (uint64_t)tmp << " ret_data = " << (uint64_t)ret_data
1192 << "\n";
1193 return false;
1194 }
1195 }
1196 }
1197 return true;
1198 }
1199
1200 // Store zero upper test
TEST_F(Encoder64Test,StrzTest)1201 TEST_F(Encoder64Test, StrzTest)
1202 {
1203 EXPECT_TRUE((TestStrz<uint8_t>(this)));
1204 EXPECT_TRUE((TestStrz<uint16_t>(this)));
1205 EXPECT_TRUE((TestStrz<uint32_t>(this)));
1206 EXPECT_TRUE((TestStrz<uint64_t>(this)));
1207
1208 EXPECT_TRUE((TestStrz<float>(this)));
1209 EXPECT_TRUE((TestStrz<double>(this)));
1210 }
1211
1212 // Return test ???? What here may be tested
1213 // TEST_F(Encoder64Test, ReturnTest) {
1214 // EncodeReturn()
1215
foo(uint32_t param1,uint32_t param2)1216 bool foo(uint32_t param1, uint32_t param2)
1217 {
1218 // TODO(igorban): use variables
1219 return (param1 == param2);
1220 }
1221
1222 using funct_ptr = bool (*)(uint32_t param1, uint32_t param2);
1223
1224 funct_ptr foo_ptr = &foo;
1225
1226 // Call Test
TEST_F(Encoder64Test,CallTest)1227 TEST_F(Encoder64Test, CallTest)
1228 {
1229 // Initialize
1230 auto link_reg = Target::Current().GetLinkReg();
1231
1232 PreWork();
1233 static_cast<aarch64::Aarch64Encoder *>(GetEncoder())
1234 ->GetMasm()
1235 ->Push(vixl::aarch64::xzr, aarch64::VixlReg(link_reg));
1236
1237 // Call foo
1238 GetEncoder()->MakeCall(reinterpret_cast<void *>(foo_ptr));
1239
1240 static_cast<aarch64::Aarch64Encoder *>(GetEncoder())
1241 ->GetMasm()
1242 ->Pop(aarch64::VixlReg(link_reg), vixl::aarch64::xzr);
1243 // return value - moved to return value
1244 PostWork();
1245
1246 // If encode unsupported - now print error
1247 if (!GetEncoder()->GetResult()) {
1248 std::cerr << "Unsupported Call-instruction \n";
1249 return;
1250 }
1251 // Change this for enable print disasm
1252 Dump(false);
1253 // Equality test
1254 auto tmp1 = random_gen<uint32_t>();
1255 uint32_t tmp2 = tmp1;
1256 // first template arg - parameter type, second - return type
1257 auto result = CallCodeCall<uint32_t, bool>(tmp1, tmp2);
1258 // Store must change ret_data value
1259 if (!result) {
1260 std::cerr << std::hex << "Call test fail tmp1=" << tmp1 << " tmp2=" << tmp2 << " result =" << result << "\n";
1261 }
1262 EXPECT_TRUE(result);
1263
1264 // Main test loop:
1265 for (uint64_t i = 0; i < ITERATION; ++i) {
1266 // Second type-dependency
1267 auto tmp1 = random_gen<uint32_t>();
1268 auto tmp2 = random_gen<uint32_t>();
1269
1270 // first template arg - parameter type, second - return type
1271 auto result = CallCodeCall<uint32_t, bool>(tmp1, tmp2);
1272 auto ret_data = (tmp1 == tmp2);
1273
1274 // Store must change ret_data value
1275 if (result != ret_data) {
1276 std::cerr << std::hex << "Call test fail tmp1=" << tmp1 << " tmp2=" << tmp2 << " ret_data = " << ret_data
1277 << " result =" << result << "\n";
1278 }
1279 EXPECT_EQ(result, ret_data);
1280 }
1281 }
1282
1283 template <typename T>
TestAbs(Encoder64Test * test)1284 bool TestAbs(Encoder64Test *test)
1285 {
1286 // Initialize
1287 test->PreWork();
1288
1289 // First type-dependency
1290 auto param = test->GetParameter(TypeInfo(T(0)));
1291
1292 // Main test call
1293 test->GetEncoder()->EncodeAbs(param, param);
1294
1295 // Finalize
1296 test->PostWork();
1297
1298 // If encode unsupported - now print error
1299 if (!test->GetEncoder()->GetResult()) {
1300 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1301 return false;
1302 }
1303 // Change this for enable print disasm
1304 test->Dump(false);
1305
1306 // Main test loop:
1307 for (uint64_t i = 0; i < ITERATION; ++i) {
1308 // Second type-dependency
1309 T tmp = random_gen<T>();
1310 // Main check - compare parameter and
1311 // return value
1312 if (!test->CallCode(tmp, std::abs(tmp))) {
1313 return false;
1314 }
1315 }
1316
1317 if constexpr (std::is_floating_point_v<T>) {
1318 T nan = std::numeric_limits<T>::quiet_NaN();
1319
1320 if (!test->CallCode<T>(nan, nan)) {
1321 return false;
1322 }
1323 }
1324
1325 return true;
1326 }
1327
TEST_F(Encoder64Test,AbsTest)1328 TEST_F(Encoder64Test, AbsTest)
1329 {
1330 EXPECT_TRUE(TestAbs<int32_t>(this));
1331 EXPECT_TRUE(TestAbs<int64_t>(this));
1332 EXPECT_TRUE(TestAbs<float>(this));
1333 EXPECT_TRUE(TestAbs<double>(this));
1334 }
1335
1336 template <typename T>
TestSqrt(Encoder64Test * test)1337 bool TestSqrt(Encoder64Test *test)
1338 {
1339 // Initialize
1340 test->PreWork();
1341
1342 // First type-dependency
1343 auto param = test->GetParameter(TypeInfo(T(0)));
1344
1345 // Main test call
1346 test->GetEncoder()->EncodeSqrt(param, param);
1347
1348 // Finalize
1349 test->PostWork();
1350
1351 // If encode unsupported - now print error
1352 if (!test->GetEncoder()->GetResult()) {
1353 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1354 return false;
1355 }
1356 // Change this for enable print disasm
1357 test->Dump(false);
1358
1359 // Main test loop:
1360 for (uint64_t i = 0; i < ITERATION; ++i) {
1361 // Second type-dependency
1362 T tmp = random_gen<T>();
1363 // Main check - compare parameter and
1364 // return value
1365 if (!test->CallCode(tmp, std::sqrt(tmp))) {
1366 return false;
1367 }
1368 }
1369
1370 if constexpr (std::is_floating_point_v<T>) {
1371 T nan = std::numeric_limits<T>::quiet_NaN();
1372 if (!test->CallCode<T>(nan, nan)) {
1373 return false;
1374 }
1375 }
1376
1377 return true;
1378 }
1379
TEST_F(Encoder64Test,SqrtTest)1380 TEST_F(Encoder64Test, SqrtTest)
1381 {
1382 EXPECT_TRUE(TestSqrt<float>(this));
1383 EXPECT_TRUE(TestSqrt<double>(this));
1384 }
1385
1386 template <typename T>
TestAdd(Encoder64Test * test)1387 bool TestAdd(Encoder64Test *test)
1388 {
1389 // Initialize
1390 test->PreWork();
1391
1392 // First type-dependency
1393 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1394 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1395
1396 // Main test call
1397 test->GetEncoder()->EncodeAdd(param1, param1, param2);
1398
1399 // Finalize
1400 test->PostWork();
1401
1402 // If encode unsupported - now print error
1403 if (!test->GetEncoder()->GetResult()) {
1404 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1405 return false;
1406 }
1407 // Change this for enable print disasm
1408 test->Dump(false);
1409
1410 // Main test loop:
1411 for (uint64_t i = 0; i < ITERATION; ++i) {
1412 // Second type-dependency
1413 auto tmp1 = random_gen<T>();
1414 auto tmp2 = random_gen<T>();
1415 // Deduced conflicting types for parameter
1416
1417 // Main check - compare parameter and
1418 // return value
1419 if (!test->CallCode<T>(tmp1, tmp2, tmp1 + tmp2)) {
1420 return false;
1421 }
1422 }
1423
1424 if constexpr (std::is_floating_point_v<T>) {
1425 T nan = std::numeric_limits<T>::quiet_NaN();
1426
1427 if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1428 return false;
1429 }
1430 if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1431 return false;
1432 }
1433 if (!test->CallCode<T>(-std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
1434 return false;
1435 }
1436 if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), nan)) {
1437 return false;
1438 }
1439 }
1440
1441 return true;
1442 }
1443
TEST_F(Encoder64Test,AddTest)1444 TEST_F(Encoder64Test, AddTest)
1445 {
1446 EXPECT_TRUE(TestAdd<int32_t>(this));
1447 EXPECT_TRUE(TestAdd<int64_t>(this));
1448 EXPECT_TRUE(TestAdd<float>(this));
1449 EXPECT_TRUE(TestAdd<double>(this));
1450 }
1451
1452 template <typename T>
TestAddImm(Encoder64Test * test)1453 bool TestAddImm(Encoder64Test *test)
1454 {
1455 // Initialize
1456 test->PreWork();
1457
1458 // First type-dependency
1459 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1460 T param2 = random_gen<T>();
1461
1462 // Main test call
1463 test->GetEncoder()->EncodeAdd(param1, param1, Imm(param2));
1464
1465 // Finalize
1466 test->PostWork();
1467
1468 // If encode unsupported - now print error
1469 if (!test->GetEncoder()->GetResult()) {
1470 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1471 return false;
1472 }
1473 // Change this for enable print disasm
1474 test->Dump(false);
1475
1476 // Main test loop:
1477 for (uint64_t i = 0; i < ITERATION; ++i) {
1478 // Second type-dependency
1479 T tmp1 = random_gen<T>();
1480 // Deduced conflicting types for parameter
1481 // Main check - compare parameter and
1482 // return value
1483 if (!test->CallCode<T>(tmp1, tmp1 + param2)) {
1484 return false;
1485 }
1486 }
1487 return true;
1488 }
1489
TEST_F(Encoder64Test,AddImmTest)1490 TEST_F(Encoder64Test, AddImmTest)
1491 {
1492 EXPECT_TRUE(TestAddImm<int32_t>(this));
1493 EXPECT_TRUE(TestAddImm<int64_t>(this));
1494 // TestAddImm<float>
1495 // TestAddImm<double>
1496 }
1497
1498 template <typename T>
TestSub(Encoder64Test * test)1499 bool TestSub(Encoder64Test *test)
1500 {
1501 // Initialize
1502 test->PreWork();
1503
1504 // First type-dependency
1505 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1506 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1507
1508 // Main test call
1509 test->GetEncoder()->EncodeSub(param1, param1, param2);
1510
1511 // Finalize
1512 test->PostWork();
1513
1514 // If encode unsupported - now print error
1515 if (!test->GetEncoder()->GetResult()) {
1516 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1517 return false;
1518 }
1519 // Change this for enable print disasm
1520 test->Dump(false);
1521
1522 // Main test loop:
1523 for (uint64_t i = 0; i < ITERATION; ++i) {
1524 // Second type-dependency
1525 T tmp1 = random_gen<T>();
1526 T tmp2 = random_gen<T>();
1527 // Deduced conflicting types for parameter
1528
1529 // Main check - compare parameter and
1530 // return value
1531 if (!test->CallCode<T>(tmp1, tmp2, tmp1 - tmp2)) {
1532 return false;
1533 }
1534 }
1535
1536 if constexpr (std::is_floating_point_v<T>) {
1537 T nan = std::numeric_limits<T>::quiet_NaN();
1538
1539 if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1540 return false;
1541 }
1542 if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1543 return false;
1544 }
1545 if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), 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 }
1552
1553 return true;
1554 }
1555
TEST_F(Encoder64Test,SubTest)1556 TEST_F(Encoder64Test, SubTest)
1557 {
1558 EXPECT_TRUE(TestSub<int32_t>(this));
1559 EXPECT_TRUE(TestSub<int64_t>(this));
1560 EXPECT_TRUE(TestSub<float>(this));
1561 EXPECT_TRUE(TestSub<double>(this));
1562 }
1563
1564 template <typename T>
TestSubImm(Encoder64Test * test)1565 bool TestSubImm(Encoder64Test *test)
1566 {
1567 // Initialize
1568 test->PreWork();
1569
1570 // First type-dependency
1571 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1572 T param2 = random_gen<T>();
1573
1574 // Main test call
1575 test->GetEncoder()->EncodeSub(param1, param1, Imm(param2));
1576
1577 // Finalize
1578 test->PostWork();
1579
1580 // If encode unsupported - now print error
1581 if (!test->GetEncoder()->GetResult()) {
1582 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1583 return false;
1584 }
1585 // Change this for enable print disasm
1586 test->Dump(false);
1587
1588 // Main test loop:
1589 for (uint64_t i = 0; i < ITERATION; ++i) {
1590 // Second type-dependency
1591 T tmp1 = random_gen<T>();
1592 // Deduced conflicting types for parameter
1593 // Main check - compare parameter and
1594 // return value
1595 if (!test->CallCode<T>(tmp1, tmp1 - param2)) {
1596 return false;
1597 }
1598 }
1599 return true;
1600 }
1601
TEST_F(Encoder64Test,SubImmTest)1602 TEST_F(Encoder64Test, SubImmTest)
1603 {
1604 EXPECT_TRUE(TestSubImm<int32_t>(this));
1605 EXPECT_TRUE(TestSubImm<int64_t>(this));
1606 // TestSubImm<float>
1607 // TestSubImm<double>
1608 }
1609
1610 template <typename T>
TestMul(Encoder64Test * test)1611 bool TestMul(Encoder64Test *test)
1612 {
1613 // Initialize
1614 test->PreWork();
1615
1616 // First type-dependency
1617 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1618 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1619
1620 // Main test call
1621 test->GetEncoder()->EncodeMul(param1, param1, param2);
1622
1623 // Finalize
1624 test->PostWork();
1625
1626 // If encode unsupported - now print error
1627 if (!test->GetEncoder()->GetResult()) {
1628 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1629 return false;
1630 }
1631 // Change this for enable print disasm
1632 test->Dump(false);
1633
1634 // Main test loop:
1635 for (uint64_t i = 0; i < ITERATION; ++i) {
1636 // Second type-dependency
1637 T tmp1 = random_gen<T>();
1638 T tmp2 = random_gen<T>();
1639 // Deduced conflicting types for parameter
1640
1641 // Main check - compare parameter and
1642 // return value
1643 if (!test->CallCode<T>(tmp1, tmp2, tmp1 * tmp2)) {
1644 return false;
1645 }
1646 }
1647
1648 if constexpr (std::is_floating_point_v<T>) {
1649 T nan = std::numeric_limits<T>::quiet_NaN();
1650
1651 if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1652 return false;
1653 }
1654 if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1655 return false;
1656 }
1657 if (!test->CallCode<T>(0.0, std::numeric_limits<T>::infinity(), nan)) {
1658 return false;
1659 }
1660 if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), 0.0, nan)) {
1661 return false;
1662 }
1663 }
1664
1665 return true;
1666 }
1667
TEST_F(Encoder64Test,MulTest)1668 TEST_F(Encoder64Test, MulTest)
1669 {
1670 EXPECT_TRUE(TestMul<int32_t>(this));
1671 EXPECT_TRUE(TestMul<int64_t>(this));
1672 EXPECT_TRUE(TestMul<float>(this));
1673 EXPECT_TRUE(TestMul<double>(this));
1674 }
1675
1676 template <typename T>
TestMin(Encoder64Test * test)1677 bool TestMin(Encoder64Test *test)
1678 {
1679 // Initialize
1680 test->PreWork();
1681
1682 // First type-dependency
1683 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1684 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1685
1686 // Main test call
1687 test->GetEncoder()->EncodeMin(param1, std::is_signed_v<T>, param1, param2);
1688
1689 // Finalize
1690 test->PostWork();
1691
1692 // If encode unsupported - now print error
1693 if (!test->GetEncoder()->GetResult()) {
1694 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1695 return false;
1696 }
1697 // Change this for enable print disasm
1698 test->Dump(false);
1699
1700 // Main test loop:
1701 for (uint64_t i = 0; i < ITERATION; ++i) {
1702 // Second type-dependency
1703 T tmp1 = random_gen<T>();
1704 T tmp2 = random_gen<T>();
1705 // Deduced conflicting types for parameter
1706
1707 T result {0};
1708 if (std::is_floating_point_v<T> && (std::isnan(tmp1) || std::isnan(tmp2))) {
1709 result = std::numeric_limits<T>::quiet_NaN();
1710 } else {
1711 // We do that, because auto check -0.0 and +0.0 std::max give incorrect result
1712 if (std::fabs(tmp1) < 1e-300 && std::fabs(tmp2) < 1e-300) {
1713 continue;
1714 }
1715 result = std::min(tmp1, tmp2);
1716 }
1717
1718 // Main check - compare parameter and
1719 // return value
1720 if (!test->CallCode<T>(tmp1, tmp2, result)) {
1721 return false;
1722 }
1723 }
1724
1725 if constexpr (std::is_floating_point_v<T>) {
1726 T nan = std::numeric_limits<T>::quiet_NaN();
1727
1728 if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1729 return false;
1730 }
1731 if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1732 return false;
1733 }
1734 // use static_cast to make sure correct float/double type is applied
1735 if (!test->CallCode<T>(static_cast<T>(-0.0), static_cast<T>(+0.0), static_cast<T>(-0.0))) {
1736 return false;
1737 }
1738 if (!test->CallCode<T>(static_cast<T>(+0.0), static_cast<T>(-0.0), static_cast<T>(-0.0))) {
1739 return false;
1740 }
1741 }
1742
1743 return true;
1744 }
1745
TEST_F(Encoder64Test,MinTest)1746 TEST_F(Encoder64Test, MinTest)
1747 {
1748 EXPECT_TRUE(TestMin<int32_t>(this));
1749 EXPECT_TRUE(TestMin<int64_t>(this));
1750 EXPECT_TRUE(TestMin<uint32_t>(this));
1751 EXPECT_TRUE(TestMin<uint64_t>(this));
1752 EXPECT_TRUE(TestMin<float>(this));
1753 EXPECT_TRUE(TestMin<double>(this));
1754 }
1755
1756 template <typename T>
TestMax(Encoder64Test * test)1757 bool TestMax(Encoder64Test *test)
1758 {
1759 // Initialize
1760 test->PreWork();
1761
1762 // First type-dependency
1763 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1764 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1765
1766 // Main test call
1767 test->GetEncoder()->EncodeMax(param1, std::is_signed_v<T>, param1, param2);
1768
1769 // Finalize
1770 test->PostWork();
1771
1772 // If encode unsupported - now print error
1773 if (!test->GetEncoder()->GetResult()) {
1774 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1775 return false;
1776 }
1777 // Change this for enable print disasm
1778 test->Dump(false);
1779
1780 // Main test loop:
1781 for (uint64_t i = 0; i < ITERATION; ++i) {
1782 // Second type-dependency
1783 T tmp1 = random_gen<T>();
1784 T tmp2 = random_gen<T>();
1785 // Deduced conflicting types for parameter
1786 T result {0};
1787 if (std::is_floating_point_v<T> && (std::isnan(tmp1) || std::isnan(tmp2))) {
1788 result = std::numeric_limits<T>::quiet_NaN();
1789 } else {
1790 // We do that, because auto check -0.0 and +0.0 std::max give incorrect result
1791 if (std::fabs(tmp1) < 1e-300 && std::fabs(tmp2) < 1e-300) {
1792 continue;
1793 }
1794 result = std::max(tmp1, tmp2);
1795 }
1796
1797 // Main check - compare parameter and
1798 // return value
1799 if (!test->CallCode<T>(tmp1, tmp2, result)) {
1800 return false;
1801 }
1802 }
1803
1804 if constexpr (std::is_floating_point_v<T>) {
1805 T nan = std::numeric_limits<T>::quiet_NaN();
1806
1807 if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
1808 return false;
1809 }
1810 if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
1811 return false;
1812 }
1813 // use static_cast to make sure correct float/double type is applied
1814 if (!test->CallCode<T>(static_cast<T>(-0.0), static_cast<T>(+0.0), static_cast<T>(+0.0))) {
1815 return false;
1816 }
1817 if (!test->CallCode<T>(static_cast<T>(+0.0), static_cast<T>(-0.0), static_cast<T>(+0.0))) {
1818 return false;
1819 }
1820 }
1821
1822 return true;
1823 }
1824
TEST_F(Encoder64Test,MaxTest)1825 TEST_F(Encoder64Test, MaxTest)
1826 {
1827 EXPECT_TRUE(TestMax<int32_t>(this));
1828 EXPECT_TRUE(TestMax<int64_t>(this));
1829 EXPECT_TRUE(TestMax<uint32_t>(this));
1830 EXPECT_TRUE(TestMax<uint64_t>(this));
1831 EXPECT_TRUE(TestMax<float>(this));
1832 EXPECT_TRUE(TestMax<double>(this));
1833 }
1834
1835 template <typename T>
TestShl(Encoder64Test * test)1836 bool TestShl(Encoder64Test *test)
1837 {
1838 // Initialize
1839 test->PreWork();
1840
1841 // First type-dependency
1842 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1843 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1844
1845 // Main test call
1846 test->GetEncoder()->EncodeShl(param1, param1, param2);
1847
1848 // Finalize
1849 test->PostWork();
1850
1851 // If encode unsupported - now print error
1852 if (!test->GetEncoder()->GetResult()) {
1853 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1854 return false;
1855 }
1856 // Change this for enable print disasm
1857 test->Dump(false);
1858
1859 // Main test loop:
1860 for (uint64_t i = 0; i < ITERATION; ++i) {
1861 // Second type-dependency
1862 T tmp1 = random_gen<T>();
1863 T tmp2 {0};
1864 if constexpr (std::is_same_v<T, int64_t>) {
1865 tmp2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
1866 } else {
1867 tmp2 = random_gen<uint8_t>() % WORD_SIZE;
1868 }
1869 // Deduced conflicting types for parameter
1870
1871 // Main check - compare parameter and
1872 // return value
1873 bool result {false};
1874
1875 if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>) {
1876 result = test->CallCode<T>(tmp1, tmp2, tmp1 << (tmp2 & (CHAR_BIT * sizeof(T) - 1)));
1877 } else {
1878 result = test->CallCode<T>(tmp1, tmp2, tmp1 << tmp2);
1879 }
1880
1881 if (!result) {
1882 return false;
1883 }
1884 }
1885 return true;
1886 }
1887
TEST_F(Encoder64Test,ShlTest)1888 TEST_F(Encoder64Test, ShlTest)
1889 {
1890 EXPECT_TRUE(TestShl<int32_t>(this));
1891 EXPECT_TRUE(TestShl<int64_t>(this));
1892 }
1893
1894 template <typename T>
TestShr(Encoder64Test * test)1895 bool TestShr(Encoder64Test *test)
1896 {
1897 // Initialize
1898 test->PreWork();
1899
1900 // First type-dependency
1901 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1902 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1903
1904 // Main test call
1905 test->GetEncoder()->EncodeShr(param1, param1, param2);
1906
1907 // Finalize
1908 test->PostWork();
1909
1910 // If encode unsupported - now print error
1911 if (!test->GetEncoder()->GetResult()) {
1912 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1913 return false;
1914 }
1915 // Change this for enable print disasm
1916 test->Dump(false);
1917
1918 // Main test loop:
1919 for (uint64_t i = 0; i < ITERATION; ++i) {
1920 // Second type-dependency
1921 T tmp1 = random_gen<T>();
1922 T tmp2 {0};
1923 if constexpr (sizeof(T) == sizeof(int64_t)) {
1924 tmp2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
1925 } else {
1926 tmp2 = random_gen<uint8_t>() % WORD_SIZE;
1927 }
1928 // Deduced conflicting types for parameter
1929
1930 // Main check - compare parameter and
1931 // return value
1932 bool result {false};
1933
1934 if constexpr (sizeof(T) == sizeof(int64_t)) {
1935 result = test->CallCode<T>(tmp1, tmp2, (static_cast<uint64_t>(tmp1)) >> tmp2);
1936 } else {
1937 result =
1938 test->CallCode<T>(tmp1, tmp2, (static_cast<uint32_t>(tmp1)) >> (tmp2 & (CHAR_BIT * sizeof(T) - 1)));
1939 }
1940
1941 if (!result) {
1942 return false;
1943 }
1944 }
1945 return true;
1946 }
1947
TEST_F(Encoder64Test,ShrTest)1948 TEST_F(Encoder64Test, ShrTest)
1949 {
1950 EXPECT_TRUE(TestShr<int32_t>(this));
1951 EXPECT_TRUE(TestShr<int64_t>(this));
1952 EXPECT_TRUE(TestShr<uint32_t>(this));
1953 EXPECT_TRUE(TestShr<uint64_t>(this));
1954 }
1955
1956 template <typename T>
TestAShr(Encoder64Test * test)1957 bool TestAShr(Encoder64Test *test)
1958 {
1959 // Initialize
1960 test->PreWork();
1961
1962 // First type-dependency
1963 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
1964 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
1965
1966 // Main test call
1967 test->GetEncoder()->EncodeAShr(param1, param1, param2);
1968
1969 // Finalize
1970 test->PostWork();
1971
1972 // If encode unsupported - now print error
1973 if (!test->GetEncoder()->GetResult()) {
1974 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
1975 return false;
1976 }
1977 // Change this for enable print disasm
1978 test->Dump(false);
1979
1980 // Main test loop:
1981 for (uint64_t i = 0; i < ITERATION; ++i) {
1982 // Second type-dependency
1983 T tmp1 = random_gen<T>();
1984 T tmp2 {0};
1985 if constexpr (std::is_same_v<T, int64_t>) {
1986 tmp2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
1987 } else {
1988 tmp2 = random_gen<uint8_t>() % WORD_SIZE;
1989 }
1990 // Deduced conflicting types for parameter
1991
1992 // Main check - compare parameter and
1993 // return value
1994 bool result {false};
1995
1996 if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>) {
1997 result = test->CallCode<T>(tmp1, tmp2, tmp1 >> (tmp2 & (CHAR_BIT * sizeof(T) - 1)));
1998 } else {
1999 result = test->CallCode<T>(tmp1, tmp2, tmp1 >> tmp2);
2000 }
2001
2002 if (!result) {
2003 return false;
2004 }
2005 }
2006 return true;
2007 }
2008
TEST_F(Encoder64Test,AShrTest)2009 TEST_F(Encoder64Test, AShrTest)
2010 {
2011 EXPECT_TRUE(TestAShr<int32_t>(this));
2012 EXPECT_TRUE(TestAShr<int64_t>(this));
2013 }
2014
2015 template <typename T>
TestAnd(Encoder64Test * test)2016 bool TestAnd(Encoder64Test *test)
2017 {
2018 // Initialize
2019 test->PreWork();
2020
2021 // First type-dependency
2022 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2023 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2024
2025 // Main test call
2026 test->GetEncoder()->EncodeAnd(param1, param1, param2);
2027
2028 // Finalize
2029 test->PostWork();
2030
2031 // If encode unsupported - now print error
2032 if (!test->GetEncoder()->GetResult()) {
2033 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2034 return false;
2035 }
2036 // Change this for enable print disasm
2037 test->Dump(false);
2038
2039 // Main test loop:
2040 for (uint64_t i = 0; i < ITERATION; ++i) {
2041 // Second type-dependency
2042 T tmp1 = random_gen<T>();
2043 T tmp2 = random_gen<T>();
2044 // Deduced conflicting types for parameter
2045
2046 // Main check - compare parameter and
2047 // return value
2048 if (!test->CallCode<T>(tmp1, tmp2, tmp1 & tmp2)) {
2049 return false;
2050 }
2051 }
2052 return true;
2053 }
2054
TEST_F(Encoder64Test,AndTest)2055 TEST_F(Encoder64Test, AndTest)
2056 {
2057 EXPECT_TRUE(TestAnd<int32_t>(this));
2058 EXPECT_TRUE(TestAnd<int64_t>(this));
2059 }
2060
2061 template <typename T>
TestOr(Encoder64Test * test)2062 bool TestOr(Encoder64Test *test)
2063 {
2064 // Initialize
2065 test->PreWork();
2066
2067 // First type-dependency
2068 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2069 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2070
2071 // Main test call
2072 test->GetEncoder()->EncodeOr(param1, param1, param2);
2073
2074 // Finalize
2075 test->PostWork();
2076
2077 // If encode unsupported - now print error
2078 if (!test->GetEncoder()->GetResult()) {
2079 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2080 return false;
2081 }
2082 // Change this for enable print disasm
2083 test->Dump(false);
2084
2085 // Main test loop:
2086 for (uint64_t i = 0; i < ITERATION; ++i) {
2087 // Second type-dependency
2088 T tmp1 = random_gen<T>();
2089 T tmp2 = random_gen<T>();
2090 // Deduced conflicting types for parameter
2091
2092 // Main check - compare parameter and
2093 // return value
2094 if (!test->CallCode<T>(tmp1, tmp2, tmp1 | tmp2)) {
2095 return false;
2096 }
2097 }
2098 return true;
2099 }
2100
TEST_F(Encoder64Test,OrTest)2101 TEST_F(Encoder64Test, OrTest)
2102 {
2103 EXPECT_TRUE(TestOr<int32_t>(this));
2104 EXPECT_TRUE(TestOr<int64_t>(this));
2105 }
2106
2107 template <typename T>
TestXor(Encoder64Test * test)2108 bool TestXor(Encoder64Test *test)
2109 {
2110 // Initialize
2111 test->PreWork();
2112
2113 // First type-dependency
2114 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2115 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2116
2117 // Main test call
2118 test->GetEncoder()->EncodeXor(param1, param1, param2);
2119
2120 // Finalize
2121 test->PostWork();
2122
2123 // If encode unsupported - now print error
2124 if (!test->GetEncoder()->GetResult()) {
2125 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2126 return false;
2127 }
2128 // Change this for enable print disasm
2129 test->Dump(false);
2130
2131 // Main test loop:
2132 for (uint64_t i = 0; i < ITERATION; ++i) {
2133 // Second type-dependency
2134 T tmp1 = random_gen<T>();
2135 T tmp2 = random_gen<T>();
2136 // Deduced conflicting types for parameter
2137
2138 // Main check - compare parameter and
2139 // return value
2140 if (!test->CallCode<T>(tmp1, tmp2, tmp1 ^ tmp2)) {
2141 return false;
2142 }
2143 }
2144 return true;
2145 }
2146
TEST_F(Encoder64Test,XorTest)2147 TEST_F(Encoder64Test, XorTest)
2148 {
2149 EXPECT_TRUE(TestXor<int32_t>(this));
2150 EXPECT_TRUE(TestXor<int64_t>(this));
2151 }
2152
2153 template <typename T>
TestShlImm(Encoder64Test * test)2154 bool TestShlImm(Encoder64Test *test)
2155 {
2156 // Initialize
2157 test->PreWork();
2158
2159 // First type-dependency
2160 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2161 int64_t param2 {0};
2162 if constexpr (std::is_same_v<T, int64_t>) {
2163 param2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
2164 } else {
2165 param2 = random_gen<uint8_t>() % WORD_SIZE;
2166 }
2167
2168 // Main test call
2169 test->GetEncoder()->EncodeShl(param1, param1, Imm(param2));
2170
2171 // Finalize
2172 test->PostWork();
2173
2174 // If encode unsupported - now print error
2175 if (!test->GetEncoder()->GetResult()) {
2176 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2177 return false;
2178 }
2179 // Change this for enable print disasm
2180 test->Dump(false);
2181
2182 // Main test loop:
2183 for (uint64_t i = 0; i < ITERATION; ++i) {
2184 // Second type-dependency
2185 T tmp1 = random_gen<T>();
2186
2187 // Deduced conflicting types for parameter
2188
2189 // Main check - compare parameter and
2190 // return value
2191 bool result {false};
2192
2193 if constexpr (std::is_same_v<T, int8_t> || std::is_same_v<T, int16_t>) {
2194 result = test->CallCode<T>(tmp1, tmp1 << (param2 & (CHAR_BIT * sizeof(T) - 1)));
2195 } else {
2196 result = test->CallCode<T>(tmp1, tmp1 << param2);
2197 }
2198
2199 if (!result) {
2200 return false;
2201 }
2202 }
2203 return true;
2204 }
2205
TEST_F(Encoder64Test,ShlImmTest)2206 TEST_F(Encoder64Test, ShlImmTest)
2207 {
2208 EXPECT_TRUE(TestShlImm<int32_t>(this));
2209 EXPECT_TRUE(TestShlImm<int64_t>(this));
2210 }
2211
2212 template <typename T>
TestShrImm(Encoder64Test * test)2213 bool TestShrImm(Encoder64Test *test)
2214 {
2215 // Initialize
2216 test->PreWork();
2217
2218 // First type-dependency
2219 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2220 int64_t param2 {0};
2221 if constexpr (sizeof(T) == sizeof(int64_t)) {
2222 param2 = random_gen<uint8_t>() % DOUBLE_WORD_SIZE;
2223 } else {
2224 param2 = random_gen<uint8_t>() % WORD_SIZE;
2225 }
2226
2227 // Main test call
2228 test->GetEncoder()->EncodeShr(param1, param1, Imm(param2));
2229
2230 // Finalize
2231 test->PostWork();
2232
2233 // If encode unsupported - now print error
2234 if (!test->GetEncoder()->GetResult()) {
2235 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2236 return false;
2237 }
2238 // Change this for enable print disasm
2239 test->Dump(false);
2240
2241 // Main test loop:
2242 for (uint64_t i = 0; i < ITERATION; ++i) {
2243 // Second type-dependency
2244 T tmp1 = random_gen<T>();
2245
2246 // Deduced conflicting types for parameter
2247
2248 // Main check - compare parameter and
2249 // return value
2250 bool result {false};
2251
2252 if constexpr (sizeof(T) == sizeof(int64_t)) {
2253 result = test->CallCode<T>(tmp1, (static_cast<uint64_t>(tmp1)) >> (param2 & (CHAR_BIT * sizeof(T) - 1)));
2254 } else {
2255 result = test->CallCode<T>(tmp1, (static_cast<uint32_t>(tmp1)) >> param2);
2256 }
2257
2258 if (!result) {
2259 return false;
2260 }
2261 }
2262 return true;
2263 }
2264
TEST_F(Encoder64Test,ShrImmTest)2265 TEST_F(Encoder64Test, ShrImmTest)
2266 {
2267 EXPECT_TRUE(TestShrImm<int32_t>(this));
2268 EXPECT_TRUE(TestShrImm<int64_t>(this));
2269 EXPECT_TRUE(TestShrImm<uint32_t>(this));
2270 EXPECT_TRUE(TestShrImm<uint64_t>(this));
2271 }
2272
2273 template <typename T>
TestCmp(Encoder64Test * test)2274 bool TestCmp(Encoder64Test *test)
2275 {
2276 static_assert(std::is_integral_v<T>);
2277 // Initialize
2278 test->PreWork();
2279
2280 // First type-dependency
2281 auto output = test->GetParameter(TypeInfo(int32_t(0)), 0);
2282 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2283 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2284
2285 // Main test call
2286 test->GetEncoder()->EncodeCmp(output, param1, param2, std::is_signed_v<T> ? Condition::LT : Condition::LO);
2287
2288 // Finalize
2289 test->PostWork();
2290
2291 // If encode unsupported - now print error
2292 if (!test->GetEncoder()->GetResult()) {
2293 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2294 return false;
2295 }
2296 // Change this for enable print disasm
2297 test->Dump(false);
2298
2299 // Main test loop:
2300 for (uint64_t i = 0; i < ITERATION; ++i) {
2301 // Second type-dependency
2302 T tmp1 = random_gen<T>();
2303 T tmp2 = random_gen<T>();
2304 // Deduced conflicting types for parameter
2305
2306 auto compare = [](T a, T b) -> int32_t { return a < b ? -1 : a > b ? 1 : 0; };
2307 int32_t result {compare(tmp1, tmp2)};
2308
2309 // Main check - compare parameter and
2310 // return value
2311 if (!test->CallCode<T, int32_t>(tmp1, tmp2, result)) {
2312 return false;
2313 }
2314 }
2315
2316 return true;
2317 }
2318
2319 template <typename T>
TestFcmp(Encoder64Test * test,bool is_fcmpg)2320 bool TestFcmp(Encoder64Test *test, bool is_fcmpg)
2321 {
2322 static_assert(std::is_floating_point_v<T>);
2323 // Initialize
2324 test->PreWork();
2325
2326 // First type-dependency
2327 auto output = test->GetParameter(TypeInfo(int32_t(0)), 0);
2328 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2329 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2330
2331 // Main test call
2332 test->GetEncoder()->EncodeCmp(output, param1, param2, is_fcmpg ? Condition::MI : Condition::LT);
2333
2334 // Finalize
2335 test->PostWork();
2336
2337 // If encode unsupported - now print error
2338 if (!test->GetEncoder()->GetResult()) {
2339 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2340 return false;
2341 }
2342 // Change this for enable print disasm
2343 test->Dump(false);
2344
2345 // Main test loop:
2346 for (uint64_t i = 0; i < ITERATION; ++i) {
2347 // Second type-dependency
2348 T tmp1 = random_gen<T>();
2349 T tmp2 = random_gen<T>();
2350 // Deduced conflicting types for parameter
2351
2352 auto compare = [](T a, T b) -> int32_t { return a < b ? -1 : a > b ? 1 : 0; };
2353
2354 int32_t result {0};
2355 if (std::isnan(tmp1) || std::isnan(tmp2)) {
2356 result = is_fcmpg ? 1 : -1;
2357 } else {
2358 result = compare(tmp1, tmp2);
2359 }
2360
2361 // Main check - compare parameter and
2362 // return value
2363 if (!test->CallCode<T, int32_t>(tmp1, tmp2, result)) {
2364 return false;
2365 }
2366 }
2367
2368 if constexpr (std::is_floating_point_v<T>) {
2369 T nan = std::numeric_limits<T>::quiet_NaN();
2370
2371 if (!test->CallCode<T, int32_t>(nan, 5.0, is_fcmpg ? 1 : -1)) {
2372 return false;
2373 }
2374 if (!test->CallCode<T, int32_t>(5.0, nan, is_fcmpg ? 1 : -1)) {
2375 return false;
2376 }
2377 if (!test->CallCode<T, int32_t>(nan, nan, is_fcmpg ? 1 : -1)) {
2378 return false;
2379 }
2380 }
2381
2382 return true;
2383 }
2384
TEST_F(Encoder64Test,CmpTest)2385 TEST_F(Encoder64Test, CmpTest)
2386 {
2387 EXPECT_TRUE(TestCmp<int32_t>(this));
2388 EXPECT_TRUE(TestCmp<int64_t>(this));
2389 EXPECT_TRUE(TestCmp<uint32_t>(this));
2390 EXPECT_TRUE(TestCmp<uint64_t>(this));
2391 EXPECT_TRUE(TestFcmp<float>(this, false));
2392 EXPECT_TRUE(TestFcmp<double>(this, false));
2393 EXPECT_TRUE(TestFcmp<float>(this, true));
2394 EXPECT_TRUE(TestFcmp<double>(this, true));
2395 }
2396
2397 template <typename T>
TestCmp64(Encoder64Test * test)2398 bool TestCmp64(Encoder64Test *test)
2399 {
2400 static_assert(sizeof(T) == sizeof(int64_t));
2401 // Initialize
2402 test->PreWork();
2403
2404 // First type-dependency
2405 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2406 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2407
2408 // Main test call
2409 test->GetEncoder()->EncodeCmp(param1, param1, param2, std::is_signed_v<T> ? Condition::LT : Condition::LO);
2410
2411 // Finalize
2412 test->PostWork();
2413
2414 // If encode unsupported - now print error
2415 if (!test->GetEncoder()->GetResult()) {
2416 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2417 return false;
2418 }
2419 // Change this for enable print disasm
2420 test->Dump(false);
2421
2422 uint64_t hi = static_cast<uint64_t>(0xABCDEFU) << (BITS_PER_BYTE * sizeof(uint32_t));
2423
2424 // Main test loop:
2425 for (uint64_t i = 0; i < ITERATION; ++i) {
2426 uint32_t lo = random_gen<T>();
2427
2428 // Second type-dependency
2429 T tmp1 = hi | (lo + 1U);
2430 T tmp2 = hi | lo;
2431 // Deduced conflicting types for parameter
2432
2433 auto compare = [](T a, T b) -> int32_t { return a < b ? -1 : a > b ? 1 : 0; };
2434
2435 // Main check - compare parameter and
2436 // return value
2437 if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
2438 return false;
2439 }
2440 }
2441 return true;
2442 }
2443
TEST_F(Encoder64Test,Cmp64Test)2444 TEST_F(Encoder64Test, Cmp64Test)
2445 {
2446 EXPECT_TRUE(TestCmp64<int64_t>(this));
2447 EXPECT_TRUE(TestCmp64<uint64_t>(this));
2448 }
2449
2450 template <typename T>
TestCompare(Encoder64Test * test)2451 bool TestCompare(Encoder64Test *test)
2452 {
2453 // Initialize
2454 test->PreWork();
2455
2456 // First type-dependency
2457 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2458 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2459
2460 // Main test call
2461 test->GetEncoder()->EncodeCompare(param1, param1, param2, std::is_signed_v<T> ? Condition::GE : Condition::HS);
2462
2463 // Finalize
2464 test->PostWork();
2465
2466 // If encode unsupported - now print error
2467 if (!test->GetEncoder()->GetResult()) {
2468 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2469 return false;
2470 }
2471 // Change this for enable print disasm
2472 test->Dump(false);
2473
2474 // Main test loop:
2475 for (uint64_t i = 0; i < ITERATION; ++i) {
2476 // Second type-dependency
2477 T tmp1 = random_gen<T>();
2478 T tmp2 = random_gen<T>();
2479 // Deduced conflicting types for parameter
2480
2481 auto compare = [](T a, T b) -> int32_t { return a >= b; };
2482
2483 // Main check - compare parameter and
2484 // return value
2485 if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
2486 return false;
2487 }
2488 }
2489 return true;
2490 }
2491
TEST_F(Encoder64Test,CompareTest)2492 TEST_F(Encoder64Test, CompareTest)
2493 {
2494 EXPECT_TRUE(TestCompare<int32_t>(this));
2495 EXPECT_TRUE(TestCompare<int64_t>(this));
2496 EXPECT_TRUE(TestCompare<uint32_t>(this));
2497 EXPECT_TRUE(TestCompare<uint64_t>(this));
2498 }
2499
2500 template <typename T>
TestCompare64(Encoder64Test * test)2501 bool TestCompare64(Encoder64Test *test)
2502 {
2503 static_assert(sizeof(T) == sizeof(int64_t));
2504 // Initialize
2505 test->PreWork();
2506
2507 // First type-dependency
2508 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
2509 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
2510
2511 // Main test call
2512 test->GetEncoder()->EncodeCompare(param1, param1, param2, std::is_signed_v<T> ? Condition::LT : Condition::LO);
2513
2514 // Finalize
2515 test->PostWork();
2516
2517 // If encode unsupported - now print error
2518 if (!test->GetEncoder()->GetResult()) {
2519 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2520 return false;
2521 }
2522 // Change this for enable print disasm
2523 test->Dump(false);
2524
2525 uint64_t hi = static_cast<uint64_t>(0xABCDEFU) << (BITS_PER_BYTE * sizeof(uint32_t));
2526
2527 // Main test loop:
2528 for (uint64_t i = 0; i < ITERATION; ++i) {
2529 uint32_t lo = random_gen<T>();
2530
2531 // Second type-dependency
2532 T tmp1 = hi | (lo + 1U);
2533 T tmp2 = hi | lo;
2534 // Deduced conflicting types for parameter
2535
2536 auto compare = [](T a, T b) -> int32_t { return a < b; };
2537
2538 // Main check - compare parameter and
2539 // return value
2540 if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
2541 return false;
2542 }
2543 }
2544 return true;
2545 }
2546
TEST_F(Encoder64Test,Compare64Test)2547 TEST_F(Encoder64Test, Compare64Test)
2548 {
2549 EXPECT_TRUE(TestCompare64<int64_t>(this));
2550 EXPECT_TRUE(TestCompare64<uint64_t>(this));
2551 }
2552
2553 template <typename Src, typename Dst>
TestCast(Encoder64Test * test)2554 bool TestCast(Encoder64Test *test)
2555 {
2556 // Initialize
2557 test->PreWork();
2558 // First type-dependency
2559 auto input = test->GetParameter(TypeInfo(Src(0)), 0);
2560 auto output = test->GetParameter(TypeInfo(Dst(0)), 0);
2561 // Main test call
2562 test->GetEncoder()->EncodeCast(output, std::is_signed_v<Dst>, input, std::is_signed_v<Src>);
2563
2564 // Finalize
2565 test->PostWork();
2566
2567 // If encode unsupported - now print error
2568 if (!test->GetEncoder()->GetResult()) {
2569 std::cerr << "Unsupported for " << TypeName<Src>() << ", " << TypeName<Dst>() << "\n";
2570 return false;
2571 }
2572 // Change this for enable print disasm
2573 test->Dump(false);
2574
2575 // Main test loop:
2576 for (uint64_t i = 0; i < ITERATION; ++i) {
2577 // Using max size type: type result "Dst" or 32bit to check result,
2578 // because in our ISA min type is 32bit.
2579 // Only integers less thаn 32bit.
2580 typedef typename std::conditional<(sizeof(Dst) * BYTE_SIZE) >= WORD_SIZE, Dst, uint32_t>::type DstExt;
2581
2582 // Second type-dependency
2583 auto src = random_gen<Src>();
2584 DstExt dst = static_cast<DstExt>(static_cast<Dst>(src));
2585
2586 // Other cast for float->int
2587 if (std::is_floating_point<Src>() && !std::is_floating_point<Dst>()) {
2588 auto MIN_INT = std::numeric_limits<Dst>::min();
2589 auto MAX_INT = std::numeric_limits<Dst>::max();
2590 auto FLOAT_MIN_INT = static_cast<Src>(MIN_INT);
2591 auto FLOAT_MAX_INT = static_cast<Src>(MAX_INT);
2592
2593 if (src > FLOAT_MIN_INT) {
2594 if (src < FLOAT_MAX_INT) {
2595 dst = static_cast<Dst>(src);
2596 } else {
2597 dst = MAX_INT;
2598 }
2599 } else if (std::isnan(src)) {
2600 dst = 0;
2601 } else {
2602 dst = MIN_INT;
2603 }
2604 }
2605
2606 // Deduced conflicting types for parameter
2607
2608 // Main check - compare parameter and
2609 // return value
2610 if (!test->CallCode<Src, DstExt>(src, dst)) {
2611 return false;
2612 }
2613 }
2614
2615 if constexpr (std::is_floating_point_v<Src> && std::is_integral_v<Dst>) {
2616 Src nan = std::numeric_limits<Src>::quiet_NaN();
2617 typedef typename std::conditional<(sizeof(Dst) * BYTE_SIZE) >= WORD_SIZE, Dst, uint32_t>::type DstExt;
2618
2619 if (!test->CallCode<Src, DstExt>(nan, static_cast<DstExt>((Dst(0))))) {
2620 return false;
2621 }
2622 }
2623
2624 return true;
2625 }
2626
TEST_F(Encoder64Test,CastTest)2627 TEST_F(Encoder64Test, CastTest)
2628 {
2629 // Test int8
2630 EXPECT_TRUE((TestCast<int8_t, int8_t>(this)));
2631 EXPECT_TRUE((TestCast<int8_t, int16_t>(this)));
2632 EXPECT_TRUE((TestCast<int8_t, int32_t>(this)));
2633 EXPECT_TRUE((TestCast<int8_t, int64_t>(this)));
2634
2635 EXPECT_TRUE((TestCast<int8_t, uint8_t>(this)));
2636 EXPECT_TRUE((TestCast<int8_t, uint16_t>(this)));
2637 EXPECT_TRUE((TestCast<int8_t, uint32_t>(this)));
2638 EXPECT_TRUE((TestCast<int8_t, uint64_t>(this)));
2639 EXPECT_TRUE((TestCast<int8_t, float>(this)));
2640 EXPECT_TRUE((TestCast<int8_t, double>(this)));
2641
2642 EXPECT_TRUE((TestCast<uint8_t, int8_t>(this)));
2643 EXPECT_TRUE((TestCast<uint8_t, int16_t>(this)));
2644 EXPECT_TRUE((TestCast<uint8_t, int32_t>(this)));
2645 EXPECT_TRUE((TestCast<uint8_t, int64_t>(this)));
2646
2647 EXPECT_TRUE((TestCast<uint8_t, uint8_t>(this)));
2648 EXPECT_TRUE((TestCast<uint8_t, uint16_t>(this)));
2649 EXPECT_TRUE((TestCast<uint8_t, uint32_t>(this)));
2650 EXPECT_TRUE((TestCast<uint8_t, uint64_t>(this)));
2651 EXPECT_TRUE((TestCast<uint8_t, float>(this)));
2652 EXPECT_TRUE((TestCast<uint8_t, double>(this)));
2653
2654 // Test int16
2655 EXPECT_TRUE((TestCast<int16_t, int8_t>(this)));
2656 EXPECT_TRUE((TestCast<int16_t, int16_t>(this)));
2657 EXPECT_TRUE((TestCast<int16_t, int32_t>(this)));
2658 EXPECT_TRUE((TestCast<int16_t, int64_t>(this)));
2659
2660 EXPECT_TRUE((TestCast<int16_t, uint8_t>(this)));
2661 EXPECT_TRUE((TestCast<int16_t, uint16_t>(this)));
2662 EXPECT_TRUE((TestCast<int16_t, uint32_t>(this)));
2663 EXPECT_TRUE((TestCast<int16_t, uint64_t>(this)));
2664 EXPECT_TRUE((TestCast<int16_t, float>(this)));
2665 EXPECT_TRUE((TestCast<int16_t, double>(this)));
2666
2667 EXPECT_TRUE((TestCast<uint16_t, int8_t>(this)));
2668 EXPECT_TRUE((TestCast<uint16_t, int16_t>(this)));
2669 EXPECT_TRUE((TestCast<uint16_t, int32_t>(this)));
2670 EXPECT_TRUE((TestCast<uint16_t, int64_t>(this)));
2671
2672 EXPECT_TRUE((TestCast<uint16_t, uint8_t>(this)));
2673 EXPECT_TRUE((TestCast<uint16_t, uint16_t>(this)));
2674 EXPECT_TRUE((TestCast<uint16_t, uint32_t>(this)));
2675 EXPECT_TRUE((TestCast<uint16_t, uint64_t>(this)));
2676 EXPECT_TRUE((TestCast<uint16_t, float>(this)));
2677 EXPECT_TRUE((TestCast<uint16_t, double>(this)));
2678
2679 // Test int32
2680 EXPECT_TRUE((TestCast<int32_t, int8_t>(this)));
2681 EXPECT_TRUE((TestCast<int32_t, int16_t>(this)));
2682 EXPECT_TRUE((TestCast<int32_t, int32_t>(this)));
2683 EXPECT_TRUE((TestCast<int32_t, int64_t>(this)));
2684
2685 EXPECT_TRUE((TestCast<int32_t, uint8_t>(this)));
2686 EXPECT_TRUE((TestCast<int32_t, uint16_t>(this)));
2687 EXPECT_TRUE((TestCast<int32_t, uint32_t>(this)));
2688 EXPECT_TRUE((TestCast<int32_t, uint64_t>(this)));
2689 EXPECT_TRUE((TestCast<int32_t, float>(this)));
2690 EXPECT_TRUE((TestCast<int32_t, double>(this)));
2691
2692 EXPECT_TRUE((TestCast<uint32_t, int8_t>(this)));
2693 EXPECT_TRUE((TestCast<uint32_t, int16_t>(this)));
2694 EXPECT_TRUE((TestCast<uint32_t, int32_t>(this)));
2695 EXPECT_TRUE((TestCast<uint32_t, int64_t>(this)));
2696
2697 EXPECT_TRUE((TestCast<uint32_t, uint8_t>(this)));
2698 EXPECT_TRUE((TestCast<uint32_t, uint16_t>(this)));
2699 EXPECT_TRUE((TestCast<uint32_t, uint32_t>(this)));
2700 EXPECT_TRUE((TestCast<uint32_t, uint64_t>(this)));
2701 EXPECT_TRUE((TestCast<uint32_t, float>(this)));
2702 EXPECT_TRUE((TestCast<uint32_t, double>(this)));
2703
2704 // Test int64
2705 EXPECT_TRUE((TestCast<int64_t, int8_t>(this)));
2706 EXPECT_TRUE((TestCast<int64_t, int16_t>(this)));
2707 EXPECT_TRUE((TestCast<int64_t, int32_t>(this)));
2708 EXPECT_TRUE((TestCast<int64_t, int64_t>(this)));
2709
2710 EXPECT_TRUE((TestCast<int64_t, uint8_t>(this)));
2711 EXPECT_TRUE((TestCast<int64_t, uint16_t>(this)));
2712 EXPECT_TRUE((TestCast<int64_t, uint32_t>(this)));
2713 EXPECT_TRUE((TestCast<int64_t, uint64_t>(this)));
2714 EXPECT_TRUE((TestCast<int64_t, float>(this)));
2715 EXPECT_TRUE((TestCast<int64_t, double>(this)));
2716
2717 EXPECT_TRUE((TestCast<uint64_t, int8_t>(this)));
2718 EXPECT_TRUE((TestCast<uint64_t, int16_t>(this)));
2719 EXPECT_TRUE((TestCast<uint64_t, int32_t>(this)));
2720 EXPECT_TRUE((TestCast<uint64_t, int64_t>(this)));
2721
2722 EXPECT_TRUE((TestCast<uint64_t, uint8_t>(this)));
2723 EXPECT_TRUE((TestCast<uint64_t, uint16_t>(this)));
2724 EXPECT_TRUE((TestCast<uint64_t, uint32_t>(this)));
2725 EXPECT_TRUE((TestCast<uint64_t, uint64_t>(this)));
2726 EXPECT_TRUE((TestCast<uint64_t, float>(this)));
2727 EXPECT_TRUE((TestCast<uint64_t, double>(this)));
2728
2729 // Test float/double
2730 EXPECT_TRUE((TestCast<float, float>(this)));
2731 EXPECT_TRUE((TestCast<double, double>(this)));
2732 EXPECT_TRUE((TestCast<float, double>(this)));
2733 EXPECT_TRUE((TestCast<double, float>(this)));
2734
2735 // We DON'T support cast from float32/64 to int8/16.
2736
2737 EXPECT_TRUE((TestCast<float, int32_t>(this)));
2738 EXPECT_TRUE((TestCast<float, int64_t>(this)));
2739 EXPECT_TRUE((TestCast<double, int32_t>(this)));
2740 EXPECT_TRUE((TestCast<double, int64_t>(this)));
2741
2742 EXPECT_TRUE((TestCast<float, uint32_t>(this)));
2743 EXPECT_TRUE((TestCast<float, uint64_t>(this)));
2744 EXPECT_TRUE((TestCast<double, uint32_t>(this)));
2745 EXPECT_TRUE((TestCast<double, uint64_t>(this)));
2746 }
2747
2748 template <typename T>
TestDiv(Encoder64Test * test)2749 bool TestDiv(Encoder64Test *test)
2750 {
2751 bool is_signed = std::is_signed<T>::value;
2752
2753 test->PreWork();
2754
2755 // First type-dependency
2756 auto param_1 = test->GetParameter(TypeInfo(T(0)), 0);
2757 auto param_2 = test->GetParameter(TypeInfo(T(0)), 1);
2758
2759 // Main test call
2760 test->GetEncoder()->EncodeDiv(param_1, is_signed, param_1, param_2);
2761
2762 // Finalize
2763 test->PostWork();
2764
2765 // If encode unsupported - now print error
2766 if (!test->GetEncoder()->GetResult()) {
2767 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2768 return false;
2769 }
2770 // Change this for enable print disasm
2771 test->Dump(false);
2772
2773 // Main test loop:
2774 for (uint64_t i = 0; i < ITERATION; ++i) {
2775 // Second type-dependency
2776 T tmp1 = random_gen<T>();
2777 T tmp2 = random_gen<T>();
2778 if (tmp2 == 0) {
2779 tmp2 += 1;
2780 }
2781 // Main check - compare parameter and
2782 // return value
2783 if (!test->CallCode<T>(tmp1, tmp2, (tmp1 / tmp2))) {
2784 return false;
2785 }
2786 }
2787
2788 if constexpr (std::is_floating_point_v<T>) {
2789 T nan = std::numeric_limits<T>::quiet_NaN();
2790
2791 if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
2792 return false;
2793 }
2794 if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
2795 return false;
2796 }
2797 if (!test->CallCode<T>(0.0, 0.0, nan)) {
2798 return false;
2799 }
2800 if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
2801 return false;
2802 }
2803 if (!test->CallCode<T>(-std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
2804 return false;
2805 }
2806 }
2807
2808 return true;
2809 }
2810
TEST_F(Encoder64Test,DivTest)2811 TEST_F(Encoder64Test, DivTest)
2812 {
2813 EXPECT_TRUE(TestDiv<int32_t>(this));
2814 EXPECT_TRUE(TestDiv<int64_t>(this));
2815 EXPECT_TRUE(TestDiv<uint32_t>(this));
2816 EXPECT_TRUE(TestDiv<uint64_t>(this));
2817 EXPECT_TRUE(TestDiv<float>(this));
2818 EXPECT_TRUE(TestDiv<double>(this));
2819 }
2820
2821 template <typename T>
TestMod(Encoder64Test * test)2822 bool TestMod(Encoder64Test *test)
2823 {
2824 bool is_signed = std::is_signed<T>::value;
2825
2826 auto link_reg = Target::Current().GetLinkReg();
2827
2828 test->PreWork();
2829 static_cast<aarch64::Aarch64Encoder *>(test->GetEncoder())
2830 ->GetMasm()
2831 ->Push(vixl::aarch64::xzr, aarch64::VixlReg(link_reg));
2832
2833 // First type-dependency
2834 auto param_1 = test->GetParameter(TypeInfo(T(0)), 0);
2835 auto param_2 = test->GetParameter(TypeInfo(T(0)), 1);
2836
2837 // Main test call
2838 test->GetEncoder()->EncodeMod(param_1, is_signed, param_1, param_2);
2839
2840 // Finalize
2841 static_cast<aarch64::Aarch64Encoder *>(test->GetEncoder())
2842 ->GetMasm()
2843 ->Pop(aarch64::VixlReg(link_reg), vixl::aarch64::xzr);
2844 test->PostWork();
2845
2846 // If encode unsupported - now print error
2847 if (!test->GetEncoder()->GetResult()) {
2848 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
2849 return false;
2850 }
2851 // Change this for enable print disasm
2852 test->Dump(false);
2853
2854 // Main test loop:
2855 for (uint64_t i = 0; i < ITERATION; ++i) {
2856 // Second type-dependency
2857 T tmp1 = random_gen<T>();
2858 T tmp2 = random_gen<T>();
2859 if (tmp2 == 0) {
2860 tmp2 += 1;
2861 }
2862 // Main check - compare parameter and
2863 // return value
2864 if constexpr (std::is_same<float, T>::value) {
2865 if (!test->CallCode<T>(tmp1, tmp2, fmodf(tmp1, tmp2))) {
2866 return false;
2867 }
2868 } else if constexpr (std::is_same<double, T>::value) {
2869 if (!test->CallCode<T>(tmp1, tmp2, fmod(tmp1, tmp2))) {
2870 return false;
2871 }
2872 } else {
2873 if (!test->CallCode<T>(tmp1, tmp2, static_cast<T>(tmp1 % tmp2))) {
2874 return false;
2875 }
2876 }
2877 }
2878
2879 if constexpr (std::is_floating_point_v<T>) {
2880 T nan = std::numeric_limits<T>::quiet_NaN();
2881
2882 if (!test->CallCode<T>(nan, random_gen<T>(), nan)) {
2883 return false;
2884 }
2885 if (!test->CallCode<T>(random_gen<T>(), nan, nan)) {
2886 return false;
2887 }
2888 if (!test->CallCode<T>(0.0, 0.0, nan)) {
2889 return false;
2890 }
2891 if (!test->CallCode<T>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
2892 return false;
2893 }
2894 if (!test->CallCode<T>(-std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), nan)) {
2895 return false;
2896 }
2897 }
2898
2899 return true;
2900 }
2901
TEST_F(Encoder64Test,ModTest)2902 TEST_F(Encoder64Test, ModTest)
2903 {
2904 EXPECT_TRUE(TestMod<int32_t>(this));
2905 EXPECT_TRUE(TestMod<int64_t>(this));
2906 EXPECT_TRUE(TestMod<uint32_t>(this));
2907 EXPECT_TRUE(TestMod<uint64_t>(this));
2908 EXPECT_TRUE(TestMod<float>(this));
2909 EXPECT_TRUE(TestMod<double>(this));
2910 }
2911
2912 // MemCopy Test
2913 // TEST_F(Encoder64Test, MemCopyTest) {
2914 // EncodeMemCopy(MemRef mem_from, MemRef mem_to, size_t size)
2915
2916 // MemCopyz Test
2917 // TEST_F(Encoder64Test, MemCopyzTest) {
2918 // EncodeMemCopyz(MemRef mem_from, MemRef mem_to, size_t size)
2919
2920 template <int ID, typename T>
TestParam(Encoder64Test * test)2921 bool TestParam(Encoder64Test *test)
2922 {
2923 // int32_t uint64_t int32_t int64_t int32_t int32_t
2924 // r0 r2+r3 stack0 stack2(align) stack4
2925 using funct_ptr = uint64_t (*)(uint32_t, uint64_t, int32_t, int64_t, int32_t, int32_t);
2926
2927 bool is_signed = std::is_signed<T>::value;
2928
2929 constexpr TypeInfo params[6] = {INT32_TYPE, INT64_TYPE, INT32_TYPE, INT64_TYPE, INT32_TYPE, INT32_TYPE};
2930 TypeInfo curr_param = params[ID];
2931
2932 auto param_info = test->GetCallconv()->GetParameterInfo(0);
2933 auto par = param_info->GetNativeParam(params[0]);
2934 // First ret value geted
2935 for (int i = 1; i <= ID; ++i) {
2936 par = param_info->GetNativeParam(params[i]);
2937 }
2938
2939 auto link_reg = Target::Current().GetLinkReg();
2940 ArenaVector<Reg> used_regs(test->GetAllocator()->Adapter());
2941 used_regs.emplace_back(link_reg);
2942 test->PreWork();
2943
2944 auto ret_reg = test->GetParameter(curr_param, 0);
2945
2946 // Main test call
2947 if (std::holds_alternative<Reg>(par)) {
2948 test->GetEncoder()->EncodeMov(ret_reg, std::get<Reg>(par));
2949 } else {
2950 auto mem = MemRef(Target::Current().GetStackReg(), std::get<uint8_t>(par) * sizeof(uint32_t));
2951 test->GetEncoder()->EncodeLdr(ret_reg, is_signed, mem);
2952 }
2953
2954 // If encode unsupported - now print error
2955 if (!test->GetEncoder()->GetResult()) {
2956 std::cerr << "Unsupported parameter with " << ID << "\n";
2957 return false;
2958 }
2959
2960 // Finalize
2961 test->PostWork();
2962
2963 // Change this for enable print disasm
2964 test->Dump(false);
2965
2966 auto size = test->GetCallconv()->GetCodeSize() - test->GetCursor();
2967 void *offset = (static_cast<uint8_t *>(test->GetCallconv()->GetCodeEntry()));
2968 void *ptr = test->GetCodeAllocator()->AllocateCode(size, offset);
2969 auto func = reinterpret_cast<funct_ptr>(ptr);
2970
2971 // Main test loop:
2972 for (uint64_t i = 0; i < ITERATION; ++i) {
2973 // Second type-dependency
2974 int32_t param_0 = random_gen<uint32_t>();
2975 uint64_t param_1 = random_gen<uint64_t>();
2976 int32_t param_2 = random_gen<int32_t>();
2977 int64_t param_3 = random_gen<int64_t>();
2978 int32_t param_4 = random_gen<int32_t>();
2979 int32_t param_5 = random_gen<int32_t>();
2980
2981 // Main check - compare parameter and
2982 // return value
2983 const T curr_result = func(param_0, param_1, param_2, param_3, param_4, param_5);
2984 T result;
2985 if constexpr (ID == 0) {
2986 result = param_0;
2987 }
2988 if constexpr (ID == 1) {
2989 result = param_1;
2990 }
2991 if constexpr (ID == 2) {
2992 result = param_2;
2993 }
2994 if constexpr (ID == 3) {
2995 result = param_3;
2996 }
2997 if constexpr (ID == 4) {
2998 result = param_4;
2999 }
3000 if constexpr (ID == 5) {
3001 result = param_5;
3002 }
3003 if (curr_result != result) {
3004 return false;
3005 };
3006 }
3007 return true;
3008 }
3009
TEST_F(Encoder64Test,ReadParams)3010 TEST_F(Encoder64Test, ReadParams)
3011 {
3012 EXPECT_TRUE((TestParam<0, int32_t>(this)));
3013 EXPECT_TRUE((TestParam<1, uint64_t>(this)));
3014 EXPECT_TRUE((TestParam<2, int32_t>(this)));
3015 EXPECT_TRUE((TestParam<3, int64_t>(this)));
3016 EXPECT_TRUE((TestParam<4, int32_t>(this)));
3017 EXPECT_TRUE((TestParam<5, int32_t>(this)));
3018 }
3019
3020 template <typename T, Condition cc>
TestSelect(Encoder64Test * test)3021 bool TestSelect(Encoder64Test *test)
3022 {
3023 // Initialize
3024 test->PreWork();
3025
3026 // First type-dependency
3027 auto param0 = test->GetParameter(TypeInfo(T(0)), 0);
3028 auto param1 = test->GetParameter(TypeInfo(T(0)), 1);
3029 auto param2 = test->GetParameter(TypeInfo(uint32_t(0)), 2);
3030 auto param3 = test->GetParameter(TypeInfo(uint32_t(0)), 3);
3031
3032 // Main test call
3033 test->GetEncoder()->EncodeMov(param2, Imm(1));
3034 test->GetEncoder()->EncodeMov(param3, Imm(0));
3035 test->GetEncoder()->EncodeSelect(Reg(param0.GetId(), TypeInfo(uint32_t(0))), param2, param3, param0, param1, cc);
3036
3037 // Finalize
3038 test->PostWork();
3039
3040 // If encode unsupported - now print error
3041 if (!test->GetEncoder()->GetResult()) {
3042 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3043 return false;
3044 }
3045 // Change this for enable print disasm
3046 test->Dump(false);
3047
3048 // Main test loop:
3049 for (uint64_t i = 0; i < ITERATION; ++i) {
3050 // Second type-dependency
3051 T tmp0 = random_gen<T>();
3052 T tmp1 = random_gen<T>();
3053
3054 bool res {false};
3055 switch (cc) {
3056 case Condition::LT:
3057 case Condition::LO:
3058 res = tmp0 < tmp1;
3059 break;
3060 case Condition::EQ:
3061 res = tmp0 == tmp1;
3062 break;
3063 case Condition::NE:
3064 res = tmp0 != tmp1;
3065 break;
3066 case Condition::GT:
3067 case Condition::HI:
3068 res = tmp0 > tmp1;
3069 break;
3070 default:
3071 UNREACHABLE();
3072 }
3073
3074 // Main check - compare parameter and
3075 // return value
3076 if (!test->CallCode<T, bool>(tmp0, tmp1, res)) {
3077 return false;
3078 }
3079 }
3080 return true;
3081 }
3082
TEST_F(Encoder64Test,SelectTest)3083 TEST_F(Encoder64Test, SelectTest)
3084 {
3085 EXPECT_TRUE((TestSelect<uint32_t, Condition::LO>(this)));
3086 EXPECT_TRUE((TestSelect<uint32_t, Condition::EQ>(this)));
3087 EXPECT_TRUE((TestSelect<uint32_t, Condition::NE>(this)));
3088 EXPECT_TRUE((TestSelect<uint32_t, Condition::HI>(this)));
3089
3090 EXPECT_TRUE((TestSelect<uint64_t, Condition::LO>(this)));
3091 EXPECT_TRUE((TestSelect<uint64_t, Condition::EQ>(this)));
3092 EXPECT_TRUE((TestSelect<uint64_t, Condition::NE>(this)));
3093 EXPECT_TRUE((TestSelect<uint64_t, Condition::HI>(this)));
3094
3095 EXPECT_TRUE((TestSelect<int32_t, Condition::LT>(this)));
3096 EXPECT_TRUE((TestSelect<int32_t, Condition::EQ>(this)));
3097 EXPECT_TRUE((TestSelect<int32_t, Condition::NE>(this)));
3098 EXPECT_TRUE((TestSelect<int32_t, Condition::GT>(this)));
3099
3100 EXPECT_TRUE((TestSelect<int64_t, Condition::LT>(this)));
3101 EXPECT_TRUE((TestSelect<int64_t, Condition::EQ>(this)));
3102 EXPECT_TRUE((TestSelect<int64_t, Condition::NE>(this)));
3103 EXPECT_TRUE((TestSelect<int64_t, Condition::GT>(this)));
3104 }
3105
3106 template <typename T, Condition cc, bool is_imm>
TestSelectTest(Encoder64Test * test)3107 bool TestSelectTest(Encoder64Test *test)
3108 {
3109 // Initialize
3110 test->PreWork();
3111
3112 auto param0 = test->GetParameter(TypeInfo(T(0)), 0);
3113 auto param1 = test->GetParameter(TypeInfo(T(0)), 1);
3114 auto param2 = test->GetParameter(TypeInfo(uint32_t(0)), 2);
3115 auto param3 = test->GetParameter(TypeInfo(uint32_t(0)), 3);
3116 // truncate immediate value to max imm size
3117 [[maybe_unused]] T imm_value = random_mask_gen<T>();
3118
3119 // Main test call
3120 test->GetEncoder()->EncodeMov(param2, Imm(1));
3121 test->GetEncoder()->EncodeMov(param3, Imm(0));
3122
3123 if constexpr (is_imm) {
3124 test->GetEncoder()->EncodeSelectTest(Reg(param0.GetId(), TypeInfo(uint32_t(0))), param2, param3, param0,
3125 Imm(imm_value), cc);
3126 } else {
3127 test->GetEncoder()->EncodeSelectTest(Reg(param0.GetId(), TypeInfo(uint32_t(0))), param2, param3, param0, param1,
3128 cc);
3129 }
3130
3131 // Finalize
3132 test->PostWork();
3133
3134 // If encode unsupported - now print error
3135 if (!test->GetEncoder()->GetResult()) {
3136 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3137 return false;
3138 }
3139 // Change this for enable print disasm
3140 test->Dump(false);
3141
3142 // Main test loop:
3143 for (uint64_t i = 0; i < ITERATION; ++i) {
3144 T tmp0 = random_gen<T>();
3145 T tmp1;
3146
3147 if constexpr (is_imm) {
3148 tmp1 = imm_value;
3149 } else {
3150 tmp1 = random_gen<T>();
3151 }
3152
3153 T and_res = tmp0 & tmp1;
3154 bool res = cc == Condition::TST_EQ ? and_res == 0 : and_res != 0;
3155
3156 // Main check - compare parameter and return value
3157 if (!test->CallCode<T, bool>(tmp0, tmp1, res)) {
3158 return false;
3159 }
3160 }
3161 return true;
3162 }
3163
TEST_F(Encoder64Test,SelectTestTest)3164 TEST_F(Encoder64Test, SelectTestTest)
3165 {
3166 EXPECT_TRUE((TestSelectTest<uint32_t, Condition::TST_EQ, false>(this)));
3167 EXPECT_TRUE((TestSelectTest<uint32_t, Condition::TST_NE, false>(this)));
3168 EXPECT_TRUE((TestSelectTest<uint32_t, Condition::TST_EQ, true>(this)));
3169 EXPECT_TRUE((TestSelectTest<uint32_t, Condition::TST_NE, true>(this)));
3170
3171 EXPECT_TRUE((TestSelectTest<int32_t, Condition::TST_EQ, false>(this)));
3172 EXPECT_TRUE((TestSelectTest<int32_t, Condition::TST_NE, false>(this)));
3173 EXPECT_TRUE((TestSelectTest<int32_t, Condition::TST_EQ, true>(this)));
3174 EXPECT_TRUE((TestSelectTest<int32_t, Condition::TST_NE, true>(this)));
3175
3176 EXPECT_TRUE((TestSelectTest<uint64_t, Condition::TST_EQ, false>(this)));
3177 EXPECT_TRUE((TestSelectTest<uint64_t, Condition::TST_NE, false>(this)));
3178 EXPECT_TRUE((TestSelectTest<uint64_t, Condition::TST_EQ, true>(this)));
3179 EXPECT_TRUE((TestSelectTest<uint64_t, Condition::TST_NE, true>(this)));
3180
3181 EXPECT_TRUE((TestSelectTest<int64_t, Condition::TST_EQ, false>(this)));
3182 EXPECT_TRUE((TestSelectTest<int64_t, Condition::TST_NE, false>(this)));
3183 EXPECT_TRUE((TestSelectTest<int64_t, Condition::TST_EQ, true>(this)));
3184 EXPECT_TRUE((TestSelectTest<int64_t, Condition::TST_NE, true>(this)));
3185 }
3186
3187 template <typename T, Condition cc>
TestCompareTest(Encoder64Test * test)3188 bool TestCompareTest(Encoder64Test *test)
3189 {
3190 // Initialize
3191 test->PreWork();
3192
3193 // First type-dependency
3194 auto param1 = test->GetParameter(TypeInfo(T(0)), 0);
3195 auto param2 = test->GetParameter(TypeInfo(T(0)), 1);
3196
3197 // Main test call
3198 test->GetEncoder()->EncodeCompareTest(param1, param1, param2, cc);
3199
3200 // Finalize
3201 test->PostWork();
3202
3203 // If encode unsupported - now print error
3204 if (!test->GetEncoder()->GetResult()) {
3205 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3206 return false;
3207 }
3208 // Change this for enable print disasm
3209 test->Dump(false);
3210
3211 // Main test loop:
3212 for (uint64_t i = 0; i < ITERATION; ++i) {
3213 // Second type-dependency
3214 T tmp1 = random_gen<T>();
3215 T tmp2 = random_gen<T>();
3216 // Deduced conflicting types for parameter
3217
3218 auto compare = [](T a, T b) -> int32_t { return cc == Condition::TST_EQ ? (a & b) == 0 : (a & b) != 0; };
3219
3220 // Main check - compare parameter and
3221 // return value
3222 if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
3223 return false;
3224 }
3225 }
3226 return true;
3227 }
3228
TEST_F(Encoder64Test,CompareTestTest)3229 TEST_F(Encoder64Test, CompareTestTest)
3230 {
3231 EXPECT_TRUE((TestCompareTest<int32_t, Condition::TST_EQ>(this)));
3232 EXPECT_TRUE((TestCompareTest<int32_t, Condition::TST_NE>(this)));
3233 EXPECT_TRUE((TestCompareTest<int64_t, Condition::TST_EQ>(this)));
3234 EXPECT_TRUE((TestCompareTest<int64_t, Condition::TST_NE>(this)));
3235 EXPECT_TRUE((TestCompareTest<uint32_t, Condition::TST_EQ>(this)));
3236 EXPECT_TRUE((TestCompareTest<uint32_t, Condition::TST_NE>(this)));
3237 EXPECT_TRUE((TestCompareTest<uint64_t, Condition::TST_EQ>(this)));
3238 EXPECT_TRUE((TestCompareTest<uint64_t, Condition::TST_NE>(this)));
3239 }
3240
3241 template <typename T, Condition cc, bool is_imm>
TestJumpTest(Encoder64Test * test)3242 bool TestJumpTest(Encoder64Test *test)
3243 {
3244 // Initialize
3245 test->PreWork();
3246
3247 // First type-dependency
3248 auto param0 = test->GetParameter(TypeInfo(T(0)), 0);
3249 auto param1 = test->GetParameter(TypeInfo(T(0)), 1);
3250 auto ret_val = Target::Current().GetParamReg(0);
3251
3252 auto true_branch = test->GetEncoder()->CreateLabel();
3253 auto end = test->GetEncoder()->CreateLabel();
3254 [[maybe_unused]] T imm_value = random_mask_gen<T>();
3255
3256 // Main test call
3257 if constexpr (is_imm) {
3258 test->GetEncoder()->EncodeJumpTest(true_branch, param0, Imm(imm_value), cc);
3259 } else {
3260 test->GetEncoder()->EncodeJumpTest(true_branch, param0, param1, cc);
3261 }
3262 test->GetEncoder()->EncodeMov(ret_val, Imm(0));
3263 test->GetEncoder()->EncodeJump(end);
3264
3265 test->GetEncoder()->BindLabel(true_branch);
3266 test->GetEncoder()->EncodeMov(ret_val, Imm(1));
3267
3268 test->GetEncoder()->BindLabel(end);
3269 // Finalize
3270 test->PostWork();
3271
3272 // If encode unsupported - now print error
3273 if (!test->GetEncoder()->GetResult()) {
3274 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3275 return false;
3276 }
3277 // Change this for enable print disasm
3278 test->Dump(false);
3279
3280 // Main test loop:
3281 for (uint64_t i = 0; i < ITERATION; ++i) {
3282 // Second type-dependency
3283 T tmp1 = random_gen<T>();
3284 T tmp2;
3285 if constexpr (is_imm) {
3286 tmp2 = imm_value;
3287 } else {
3288 tmp2 = random_gen<T>();
3289 }
3290 // Deduced conflicting types for parameter
3291
3292 auto compare = [](T a, T b) -> int32_t { return cc == Condition::TST_EQ ? (a & b) == 0 : (a & b) != 0; };
3293
3294 // Main check - compare parameter and
3295 // return value
3296 if (!test->CallCode<T, int32_t>(tmp1, tmp2, compare(tmp1, tmp2))) {
3297 return false;
3298 }
3299 }
3300 return true;
3301 }
3302
TEST_F(Encoder64Test,JumpTestTest)3303 TEST_F(Encoder64Test, JumpTestTest)
3304 {
3305 EXPECT_TRUE((TestJumpTest<int32_t, Condition::TST_EQ, false>(this)));
3306 EXPECT_TRUE((TestJumpTest<int32_t, Condition::TST_NE, false>(this)));
3307 EXPECT_TRUE((TestJumpTest<int64_t, Condition::TST_EQ, false>(this)));
3308 EXPECT_TRUE((TestJumpTest<int64_t, Condition::TST_NE, false>(this)));
3309 EXPECT_TRUE((TestJumpTest<uint32_t, Condition::TST_EQ, false>(this)));
3310 EXPECT_TRUE((TestJumpTest<uint32_t, Condition::TST_NE, false>(this)));
3311 EXPECT_TRUE((TestJumpTest<uint64_t, Condition::TST_EQ, false>(this)));
3312 EXPECT_TRUE((TestJumpTest<uint64_t, Condition::TST_NE, false>(this)));
3313
3314 EXPECT_TRUE((TestJumpTest<int32_t, Condition::TST_EQ, true>(this)));
3315 EXPECT_TRUE((TestJumpTest<int32_t, Condition::TST_NE, true>(this)));
3316 EXPECT_TRUE((TestJumpTest<int64_t, Condition::TST_EQ, true>(this)));
3317 EXPECT_TRUE((TestJumpTest<int64_t, Condition::TST_NE, true>(this)));
3318 EXPECT_TRUE((TestJumpTest<uint32_t, Condition::TST_EQ, true>(this)));
3319 EXPECT_TRUE((TestJumpTest<uint32_t, Condition::TST_NE, true>(this)));
3320 EXPECT_TRUE((TestJumpTest<uint64_t, Condition::TST_EQ, true>(this)));
3321 EXPECT_TRUE((TestJumpTest<uint64_t, Condition::TST_NE, true>(this)));
3322 }
3323
3324 template <typename T, bool is_acquire>
TestLoadExclusive(Encoder64Test * test,uint64_t input_word,T expected_result)3325 bool TestLoadExclusive(Encoder64Test *test, uint64_t input_word, T expected_result)
3326 {
3327 uint64_t buffer[3] = {0xFFFFFFFFFFFFFFFFULL, input_word, 0xFFFFFFFFFFFFFFFFULL};
3328 test->PreWork();
3329 auto param_0 = test->GetParameter(TypeInfo(uintptr_t(0)), 0);
3330 auto result = test->GetParameter(TypeInfo(T(0)), 0);
3331 test->GetEncoder()->EncodeLdrExclusive(result, param_0, is_acquire);
3332 test->PostWork();
3333
3334 if (!test->GetEncoder()->GetResult()) {
3335 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3336 return false;
3337 }
3338 // Change this for enable print disasm
3339 test->Dump(false);
3340 auto word_addr = reinterpret_cast<uintptr_t>(&buffer[1]);
3341 return test->CallCode<uintptr_t, T>(word_addr, expected_result);
3342 }
3343
3344 template <typename T, bool is_release>
TestStoreExclusiveFailed(Encoder64Test * test)3345 bool TestStoreExclusiveFailed(Encoder64Test *test)
3346 {
3347 uint64_t buffer = 0xFFFFFFFFFFFFFFFFULL;
3348 test->PreWork();
3349 auto param_0 = test->GetParameter(TypeInfo(uintptr_t(0)), 0);
3350 auto tmp_reg = test->GetParameter(TypeInfo(T(0)), 1);
3351 auto result = test->GetParameter(TypeInfo(T(0)), 0);
3352
3353 // perform store without load - should fail as there are no exlusive monitor
3354 test->GetEncoder()->EncodeStrExclusive(result, tmp_reg, param_0, is_release);
3355 test->PostWork();
3356
3357 if (!test->GetEncoder()->GetResult()) {
3358 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3359 return false;
3360 }
3361 // Change this for enable print disasm
3362 test->Dump(false);
3363 auto word_addr = reinterpret_cast<uintptr_t>(&buffer);
3364 return test->CallCode<uintptr_t, T>(word_addr, static_cast<T>(buffer), 1);
3365 }
3366
3367 template <typename T, bool is_release>
TestStoreExclusive(Encoder64Test * test,T value,uint64_t expected_result)3368 bool TestStoreExclusive(Encoder64Test *test, T value, uint64_t expected_result)
3369 {
3370 // test writes value into buffer[1]
3371 uint64_t buffer[3] = {0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL};
3372 test->PreWork();
3373 auto param_0 = test->GetParameter(TypeInfo(uintptr_t(0)), 0);
3374 auto param_1 = test->GetParameter(TypeInfo(T(0)), 1);
3375 auto result = test->GetParameter(TypeInfo(T(0)), 0);
3376 auto retry_label = test->GetEncoder()->CreateLabel();
3377 Reg tmp_reg(test->GetRegfile()->GetZeroReg().GetId(), TypeInfo(T(0)));
3378
3379 test->GetEncoder()->BindLabel(retry_label);
3380 test->GetEncoder()->EncodeLdrExclusive(tmp_reg, param_0, false);
3381 test->GetEncoder()->EncodeStrExclusive(result, param_1, param_0, is_release);
3382 // retry if store exclusive returned non zero value
3383 test->GetEncoder()->EncodeJump(retry_label, result, Condition::NE);
3384
3385 test->PostWork();
3386
3387 if (!test->GetEncoder()->GetResult()) {
3388 std::cerr << "Unsupported for " << TypeName<T>() << "\n";
3389 return false;
3390 }
3391 // Change this for enable print disasm
3392 test->Dump(false);
3393 auto word_addr = reinterpret_cast<uintptr_t>(&buffer[1]);
3394 if (!test->CallCode<uintptr_t, T>(word_addr, value, 0)) {
3395 return false;
3396 }
3397 if (buffer[1] != expected_result) {
3398 std::cerr << "Failed: expected value " << std::hex << expected_result << " differs from actual result "
3399 << buffer[1] << std::dec << std::endl;
3400 return false;
3401 }
3402 return true;
3403 }
3404
TEST_F(Encoder64Test,LoadExclusiveTest)3405 TEST_F(Encoder64Test, LoadExclusiveTest)
3406 {
3407 const uint64_t SOURCE_WORD = 0x1122334455667788ULL;
3408 // aarch64 is little-endian, so bytes are actually stored in following order:
3409 // 0x 88 77 66 55 44 33 22 11
3410 EXPECT_TRUE((TestLoadExclusive<uint8_t, false>(this, SOURCE_WORD, 0x88U)));
3411 EXPECT_TRUE((TestLoadExclusive<uint16_t, false>(this, SOURCE_WORD, 0x7788U)));
3412 EXPECT_TRUE((TestLoadExclusive<uint32_t, false>(this, SOURCE_WORD, 0x55667788UL)));
3413 EXPECT_TRUE((TestLoadExclusive<uint64_t, false>(this, SOURCE_WORD, SOURCE_WORD)));
3414
3415 EXPECT_TRUE((TestLoadExclusive<uint8_t, true>(this, SOURCE_WORD, 0x88U)));
3416 EXPECT_TRUE((TestLoadExclusive<uint16_t, true>(this, SOURCE_WORD, 0x7788U)));
3417 EXPECT_TRUE((TestLoadExclusive<uint32_t, true>(this, SOURCE_WORD, 0x55667788UL)));
3418 EXPECT_TRUE((TestLoadExclusive<uint64_t, true>(this, SOURCE_WORD, SOURCE_WORD)));
3419 }
3420
TEST_F(Encoder64Test,StoreExclusiveTest)3421 TEST_F(Encoder64Test, StoreExclusiveTest)
3422 {
3423 EXPECT_TRUE((TestStoreExclusiveFailed<uint8_t, false>(this)));
3424 EXPECT_TRUE((TestStoreExclusiveFailed<uint16_t, false>(this)));
3425 EXPECT_TRUE((TestStoreExclusiveFailed<uint32_t, false>(this)));
3426 EXPECT_TRUE((TestStoreExclusiveFailed<uint64_t, false>(this)));
3427
3428 EXPECT_TRUE((TestStoreExclusiveFailed<uint8_t, true>(this)));
3429 EXPECT_TRUE((TestStoreExclusiveFailed<uint16_t, true>(this)));
3430 EXPECT_TRUE((TestStoreExclusiveFailed<uint32_t, true>(this)));
3431 EXPECT_TRUE((TestStoreExclusiveFailed<uint64_t, true>(this)));
3432
3433 EXPECT_TRUE((TestStoreExclusive<uint8_t, false>(this, 0x11U, 0xFFFFFFFFFFFFFF11ULL)));
3434 EXPECT_TRUE((TestStoreExclusive<uint16_t, false>(this, 0x1122U, 0xFFFFFFFFFFFF1122ULL)));
3435 EXPECT_TRUE((TestStoreExclusive<uint32_t, false>(this, 0x11223344UL, 0xFFFFFFFF11223344ULL)));
3436 EXPECT_TRUE((TestStoreExclusive<uint64_t, false>(this, 0xAABBCCDD11335577ULL, 0xAABBCCDD11335577ULL)));
3437 }
3438
3439 class Encoder64ApiTest : public Encoder64Test {
3440 public:
Encoder64ApiTest()3441 Encoder64ApiTest() : decoder_(GetAllocator()) {}
3442
GetOutput(const aarch64::Aarch64Encoder & encoder)3443 std::string &GetOutput(const aarch64::Aarch64Encoder &encoder)
3444 {
3445 output_.resize(0);
3446 char buf[64];
3447 vixl::aarch64::Disassembler disasm(buf, sizeof(buf));
3448 vixl::aarch64::Decoder::ScopedVisitors sv(decoder_, {&disasm});
3449 auto begin = encoder.GetMasm()->GetBuffer()->GetOffsetAddress<uint8_t *>(0);
3450 auto end = begin + encoder.GetMasm()->GetSizeOfCodeGenerated();
3451 for (auto instr = reinterpret_cast<const vixl::aarch64::Instruction *>(begin);
3452 instr < reinterpret_cast<const vixl::aarch64::Instruction *>(end); instr = instr->GetNextInstruction()) {
3453 decoder_.Decode(instr);
3454 if (!output_.empty()) {
3455 output_ += '\n';
3456 }
3457 output_ += disasm.GetOutput();
3458 }
3459 return output_;
3460 }
3461
3462 protected:
3463 std::string output_;
3464 vixl::aarch64::Decoder decoder_;
3465 };
3466
TEST_F(Encoder64ApiTest,TestEncodeMov)3467 TEST_F(Encoder64ApiTest, TestEncodeMov)
3468 {
3469 {
3470 aarch64::Aarch64Encoder encoder(GetAllocator());
3471 encoder.InitMasm();
3472 encoder.SetRegfile(GetRegfile());
3473 encoder.EncodeMov(Reg(0, INT32_TYPE), Reg(1, INT32_TYPE));
3474 encoder.Finalize();
3475 EXPECT_TRUE(encoder.GetResult());
3476 EXPECT_STREQ("mov w0, w1", GetOutput(encoder).c_str());
3477 }
3478 {
3479 aarch64::Aarch64Encoder encoder(GetAllocator());
3480 encoder.InitMasm();
3481 encoder.SetRegfile(GetRegfile());
3482 encoder.EncodeMov(Reg(0, INT32_TYPE), Reg(1, INT64_TYPE));
3483 encoder.Finalize();
3484 EXPECT_TRUE(encoder.GetResult());
3485 EXPECT_STREQ("mov w0, w1", GetOutput(encoder).c_str());
3486 }
3487 {
3488 aarch64::Aarch64Encoder encoder(GetAllocator());
3489 encoder.InitMasm();
3490 encoder.SetRegfile(GetRegfile());
3491 encoder.EncodeMov(Reg(0, INT64_TYPE), Reg(1, INT32_TYPE));
3492 encoder.Finalize();
3493 EXPECT_TRUE(encoder.GetResult());
3494 EXPECT_STREQ("mov x0, x1", GetOutput(encoder).c_str());
3495 }
3496 {
3497 aarch64::Aarch64Encoder encoder(GetAllocator());
3498 encoder.InitMasm();
3499 encoder.SetRegfile(GetRegfile());
3500 encoder.EncodeMov(Reg(0, INT32_TYPE), Reg(0, INT32_TYPE));
3501 encoder.Finalize();
3502 EXPECT_TRUE(encoder.GetResult());
3503 EXPECT_STREQ("", GetOutput(encoder).c_str());
3504 }
3505 {
3506 aarch64::Aarch64Encoder encoder(GetAllocator());
3507 encoder.InitMasm();
3508 encoder.SetRegfile(GetRegfile());
3509 encoder.EncodeMov(Reg(0, FLOAT64_TYPE), Reg(1, FLOAT64_TYPE));
3510 encoder.Finalize();
3511 EXPECT_TRUE(encoder.GetResult());
3512 EXPECT_STREQ("fmov d0, d1", GetOutput(encoder).c_str());
3513 }
3514 {
3515 aarch64::Aarch64Encoder encoder(GetAllocator());
3516 encoder.InitMasm();
3517 encoder.SetRegfile(GetRegfile());
3518 encoder.EncodeMov(Reg(0, FLOAT64_TYPE), Reg(1, FLOAT32_TYPE));
3519 encoder.Finalize();
3520 EXPECT_TRUE(encoder.GetResult());
3521 EXPECT_STREQ("fcvt d0, s1", GetOutput(encoder).c_str());
3522 }
3523 {
3524 aarch64::Aarch64Encoder encoder(GetAllocator());
3525 encoder.InitMasm();
3526 encoder.SetRegfile(GetRegfile());
3527 encoder.EncodeMov(Reg(0, INT32_TYPE), Reg(1, FLOAT32_TYPE));
3528 encoder.Finalize();
3529 EXPECT_TRUE(encoder.GetResult());
3530 EXPECT_STREQ("fmov w0, s1", GetOutput(encoder).c_str());
3531 }
3532 {
3533 aarch64::Aarch64Encoder encoder(GetAllocator());
3534 encoder.InitMasm();
3535 encoder.SetRegfile(GetRegfile());
3536 encoder.EncodeMov(Reg(0, FLOAT32_TYPE), Reg(1, INT32_TYPE));
3537 encoder.Finalize();
3538 EXPECT_TRUE(encoder.GetResult());
3539 EXPECT_STREQ("fmov s0, w1", GetOutput(encoder).c_str());
3540 }
3541 }
3542
TEST_F(Encoder64ApiTest,TestEncodeLdr)3543 TEST_F(Encoder64ApiTest, TestEncodeLdr)
3544 {
3545 {
3546 aarch64::Aarch64Encoder encoder(GetAllocator());
3547 encoder.InitMasm();
3548 encoder.SetRegfile(GetRegfile());
3549 encoder.EncodeLdr(Reg(0, FLOAT64_TYPE), true, MemRef(Reg(0, INT64_TYPE)));
3550 encoder.Finalize();
3551 EXPECT_TRUE(encoder.GetResult());
3552 EXPECT_STREQ("ldr d0, [x0]", GetOutput(encoder).c_str());
3553 }
3554 {
3555 aarch64::Aarch64Encoder encoder(GetAllocator());
3556 encoder.InitMasm();
3557 encoder.SetRegfile(GetRegfile());
3558 encoder.EncodeLdr(Reg(0, INT8_TYPE), true, MemRef(Reg(0, INT64_TYPE)));
3559 encoder.Finalize();
3560 EXPECT_TRUE(encoder.GetResult());
3561 EXPECT_STREQ("ldrsb x0, [x0]", GetOutput(encoder).c_str());
3562 }
3563 {
3564 aarch64::Aarch64Encoder encoder(GetAllocator());
3565 encoder.InitMasm();
3566 encoder.SetRegfile(GetRegfile());
3567 encoder.EncodeLdr(Reg(0, INT16_TYPE), true, MemRef(Reg(0, INT64_TYPE)));
3568 encoder.Finalize();
3569 EXPECT_TRUE(encoder.GetResult());
3570 EXPECT_STREQ("ldrsh w0, [x0]", GetOutput(encoder).c_str());
3571 }
3572 {
3573 aarch64::Aarch64Encoder encoder(GetAllocator());
3574 encoder.InitMasm();
3575 encoder.SetRegfile(GetRegfile());
3576 encoder.EncodeLdr(Reg(0, INT32_TYPE), true, MemRef(Reg(0, INT64_TYPE)));
3577 encoder.Finalize();
3578 EXPECT_TRUE(encoder.GetResult());
3579 EXPECT_STREQ("ldr w0, [x0]", GetOutput(encoder).c_str());
3580 }
3581 {
3582 aarch64::Aarch64Encoder encoder(GetAllocator());
3583 encoder.InitMasm();
3584 encoder.SetRegfile(GetRegfile());
3585 encoder.EncodeLdr(Reg(0, INT8_TYPE), false, MemRef(Reg(0, INT64_TYPE)));
3586 encoder.Finalize();
3587 EXPECT_TRUE(encoder.GetResult());
3588 EXPECT_STREQ("ldrb w0, [x0]", GetOutput(encoder).c_str());
3589 }
3590 {
3591 aarch64::Aarch64Encoder encoder(GetAllocator());
3592 encoder.InitMasm();
3593 encoder.SetRegfile(GetRegfile());
3594 encoder.EncodeLdr(Reg(0, INT16_TYPE), false, MemRef(Reg(0, INT64_TYPE)));
3595 encoder.Finalize();
3596 EXPECT_TRUE(encoder.GetResult());
3597 EXPECT_STREQ("ldrh w0, [x0]", GetOutput(encoder).c_str());
3598 }
3599 {
3600 aarch64::Aarch64Encoder encoder(GetAllocator());
3601 encoder.InitMasm();
3602 encoder.SetRegfile(GetRegfile());
3603 encoder.EncodeLdr(Reg(0, INT32_TYPE), false, MemRef(Reg(0, INT64_TYPE)));
3604 encoder.Finalize();
3605 EXPECT_TRUE(encoder.GetResult());
3606 EXPECT_STREQ("ldr w0, [x0]", GetOutput(encoder).c_str());
3607 }
3608 {
3609 aarch64::Aarch64Encoder encoder(GetAllocator());
3610 encoder.InitMasm();
3611 encoder.SetRegfile(GetRegfile());
3612 encoder.EncodeLdr(Reg(0, INT64_TYPE), false, MemRef(Reg(0, INT64_TYPE)));
3613 encoder.Finalize();
3614 EXPECT_TRUE(encoder.GetResult());
3615 EXPECT_STREQ("ldr x0, [x0]", GetOutput(encoder).c_str());
3616 }
3617 }
3618
TEST_F(Encoder64ApiTest,TestEncodeStr)3619 TEST_F(Encoder64ApiTest, TestEncodeStr)
3620 {
3621 {
3622 aarch64::Aarch64Encoder encoder(GetAllocator());
3623 encoder.InitMasm();
3624 encoder.SetRegfile(GetRegfile());
3625 encoder.EncodeStr(Reg(0, FLOAT64_TYPE), MemRef(Reg(0, INT64_TYPE)));
3626 encoder.Finalize();
3627 EXPECT_TRUE(encoder.GetResult());
3628 EXPECT_STREQ("str d0, [x0]", GetOutput(encoder).c_str());
3629 }
3630 {
3631 aarch64::Aarch64Encoder encoder(GetAllocator());
3632 encoder.InitMasm();
3633 encoder.SetRegfile(GetRegfile());
3634 encoder.EncodeStr(Reg(0, INT8_TYPE), MemRef(Reg(0, INT64_TYPE)));
3635 encoder.Finalize();
3636 EXPECT_TRUE(encoder.GetResult());
3637 EXPECT_STREQ("strb w0, [x0]", GetOutput(encoder).c_str());
3638 }
3639 {
3640 aarch64::Aarch64Encoder encoder(GetAllocator());
3641 encoder.InitMasm();
3642 encoder.SetRegfile(GetRegfile());
3643 encoder.EncodeStr(Reg(0, INT16_TYPE), MemRef(Reg(0, INT64_TYPE)));
3644 encoder.Finalize();
3645 EXPECT_TRUE(encoder.GetResult());
3646 EXPECT_STREQ("strh w0, [x0]", GetOutput(encoder).c_str());
3647 }
3648 {
3649 aarch64::Aarch64Encoder encoder(GetAllocator());
3650 encoder.InitMasm();
3651 encoder.SetRegfile(GetRegfile());
3652 encoder.EncodeStr(Reg(0, INT32_TYPE), MemRef(Reg(0, INT64_TYPE)));
3653 encoder.Finalize();
3654 EXPECT_TRUE(encoder.GetResult());
3655 EXPECT_STREQ("str w0, [x0]", GetOutput(encoder).c_str());
3656 }
3657 {
3658 aarch64::Aarch64Encoder encoder(GetAllocator());
3659 encoder.InitMasm();
3660 encoder.SetRegfile(GetRegfile());
3661 encoder.EncodeStr(Reg(0, INT64_TYPE), MemRef(Reg(0, INT64_TYPE)));
3662 encoder.Finalize();
3663 EXPECT_TRUE(encoder.GetResult());
3664 EXPECT_STREQ("str x0, [x0]", GetOutput(encoder).c_str());
3665 }
3666 }
3667
TEST_F(Encoder64ApiTest,TestEncodeMemCopy)3668 TEST_F(Encoder64ApiTest, TestEncodeMemCopy)
3669 {
3670 {
3671 aarch64::Aarch64Encoder encoder(GetAllocator());
3672 encoder.InitMasm();
3673 encoder.SetRegfile(GetRegfile());
3674 encoder.EncodeMemCopy(MemRef(Reg(0, INT64_TYPE)), MemRef(Reg(1, INT64_TYPE)), BYTE_SIZE);
3675 encoder.Finalize();
3676 EXPECT_TRUE(encoder.GetResult());
3677 EXPECT_STREQ("ldrb w16, [x0]\nstrb w16, [x1]", GetOutput(encoder).c_str());
3678 }
3679 {
3680 aarch64::Aarch64Encoder encoder(GetAllocator());
3681 encoder.InitMasm();
3682 encoder.SetRegfile(GetRegfile());
3683 encoder.EncodeMemCopy(MemRef(Reg(0, INT64_TYPE)), MemRef(Reg(1, INT64_TYPE)), HALF_SIZE);
3684 encoder.Finalize();
3685 EXPECT_TRUE(encoder.GetResult());
3686 EXPECT_STREQ("ldrh w16, [x0]\nstrh w16, [x1]", GetOutput(encoder).c_str());
3687 }
3688 {
3689 aarch64::Aarch64Encoder encoder(GetAllocator());
3690 encoder.InitMasm();
3691 encoder.SetRegfile(GetRegfile());
3692 encoder.EncodeMemCopy(MemRef(Reg(0, INT64_TYPE)), MemRef(Reg(1, INT64_TYPE)), WORD_SIZE);
3693 encoder.Finalize();
3694 EXPECT_TRUE(encoder.GetResult());
3695 EXPECT_STREQ("ldr w16, [x0]\nstr w16, [x1]", GetOutput(encoder).c_str());
3696 }
3697 {
3698 aarch64::Aarch64Encoder encoder(GetAllocator());
3699 encoder.InitMasm();
3700 encoder.SetRegfile(GetRegfile());
3701 encoder.EncodeMemCopy(MemRef(Reg(0, INT64_TYPE)), MemRef(Reg(1, INT64_TYPE)), DOUBLE_WORD_SIZE);
3702 encoder.Finalize();
3703 EXPECT_TRUE(encoder.GetResult());
3704 EXPECT_STREQ("ldr x16, [x0]\nstr x16, [x1]", GetOutput(encoder).c_str());
3705 }
3706 }
3707
TEST_F(Encoder64Test,Registers)3708 TEST_F(Encoder64Test, Registers)
3709 {
3710 auto target = GetEncoder()->GetTarget();
3711 {
3712 {
3713 ScopedTmpReg tmp1(GetEncoder(), true);
3714 ASSERT_EQ(tmp1.GetReg(), target.GetLinkReg());
3715 ScopedTmpReg tmp2(GetEncoder(), true);
3716 ASSERT_NE(tmp2.GetReg(), target.GetLinkReg());
3717 }
3718 ScopedTmpReg tmp3(GetEncoder(), true);
3719 ASSERT_EQ(tmp3.GetReg(), target.GetLinkReg());
3720 }
3721 {
3722 ScopedTmpReg tmp1(GetEncoder(), false);
3723 ASSERT_NE(tmp1.GetReg(), target.GetLinkReg());
3724 }
3725 }
3726 } // namespace panda::compiler
3727