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