asmjit_test_compiler_x86.cpp (124653B)
1 // This file is part of AsmJit project <https://asmjit.com> 2 // 3 // See <asmjit/core.h> or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #include <asmjit/core.h> 7 #if !defined(ASMJIT_NO_X86) && !defined(ASMJIT_NO_COMPILER) 8 9 #include <asmjit/x86.h> 10 #include <setjmp.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #if ASMJIT_ARCH_X86 16 // Required for function tests that pass / return XMM registers. 17 #include <emmintrin.h> 18 #endif 19 20 #include "asmjit_test_misc.h" 21 #include "asmjit_test_compiler.h" 22 23 #ifdef _MSC_VER 24 // Interaction between '_setjmp' and C++ object destruction is non-portable. 25 #pragma warning(disable: 4611) 26 #endif 27 28 using namespace asmjit; 29 30 // x86::Compiler - X86TestCase 31 // =========================== 32 33 class X86TestCase : public TestCase { 34 public: 35 X86TestCase(const char* name = nullptr) 36 : TestCase(name, Arch::kHost == Arch::kX86 ? Arch::kX86 : Arch::kX64) {} 37 38 void compile(BaseCompiler& cc) override { 39 compile(static_cast<x86::Compiler&>(cc)); 40 } 41 42 virtual void compile(x86::Compiler& cc) = 0; 43 }; 44 45 // x86::Compiler - X86Test_AlignBase 46 // ================================= 47 48 class X86Test_AlignBase : public X86TestCase { 49 public: 50 X86Test_AlignBase(uint32_t arg_count, uint32_t alignment, bool preserve_fp) 51 : _arg_count(arg_count), 52 _alignment(alignment), 53 _preserve_fp(preserve_fp) { 54 _name.assign_format("AlignBase {NumArgs=%u Alignment=%u PreserveFP=%c}", arg_count, alignment, preserve_fp ? 'Y' : 'N'); 55 } 56 57 static void add(TestApp& app) { 58 for (uint32_t i = 0; i <= 16; i++) { 59 for (uint32_t a = 16; a <= 32; a += 16) { 60 app.add(new X86Test_AlignBase(i, a, true)); 61 app.add(new X86Test_AlignBase(i, a, false)); 62 } 63 } 64 } 65 66 void compile(x86::Compiler& cc) override { 67 uint32_t arg_count = _arg_count; 68 69 FuncSignature signature(CallConvId::kCDecl); 70 signature.set_ret_t<int>(); 71 for (uint32_t i = 0; i < arg_count; i++) { 72 signature.add_arg_t<int>(); 73 } 74 75 FuncNode* func_node = cc.add_func(signature); 76 if (_preserve_fp) 77 func_node->frame().set_preserved_fp(); 78 79 x86::Gp gp_var = cc.new_gp_ptr("gp_var"); 80 x86::Gp gp_sum; 81 x86::Mem stack = cc.new_stack(_alignment, _alignment); 82 83 // Do a sum of arguments to verify a possible relocation when misaligned. 84 if (arg_count) { 85 for (uint32_t i = 0; i < arg_count; i++) { 86 x86::Gp gp_arg = cc.new_gp32("gp_arg%u", i); 87 func_node->set_arg(i, gp_arg); 88 89 if (i == 0) 90 gp_sum = gp_arg; 91 else 92 cc.add(gp_sum, gp_arg); 93 } 94 } 95 96 // Check alignment of the stack (has to be 16). 97 cc.lea(gp_var, stack); 98 cc.and_(gp_var, _alignment - 1); 99 100 // Add a sum of all arguments to check if they are correct. 101 if (arg_count) 102 cc.or_(gp_var.r32(), gp_sum); 103 104 cc.ret(gp_var); 105 cc.end_func(); 106 } 107 108 bool run(void* _func, String& result, String& expect) override { 109 using U = unsigned int; 110 111 using Func0 = U (*)(); 112 using Func1 = U (*)(U); 113 using Func2 = U (*)(U, U); 114 using Func3 = U (*)(U, U, U); 115 using Func4 = U (*)(U, U, U, U); 116 using Func5 = U (*)(U, U, U, U, U); 117 using Func6 = U (*)(U, U, U, U, U, U); 118 using Func7 = U (*)(U, U, U, U, U, U, U); 119 using Func8 = U (*)(U, U, U, U, U, U, U, U); 120 using Func9 = U (*)(U, U, U, U, U, U, U, U, U); 121 using Func10 = U (*)(U, U, U, U, U, U, U, U, U, U); 122 using Func11 = U (*)(U, U, U, U, U, U, U, U, U, U, U); 123 using Func12 = U (*)(U, U, U, U, U, U, U, U, U, U, U, U); 124 using Func13 = U (*)(U, U, U, U, U, U, U, U, U, U, U, U, U); 125 using Func14 = U (*)(U, U, U, U, U, U, U, U, U, U, U, U, U, U); 126 using Func15 = U (*)(U, U, U, U, U, U, U, U, U, U, U, U, U, U, U); 127 using Func16 = U (*)(U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U); 128 129 unsigned int result_ret = 0; 130 unsigned int expect_ret = 0; 131 132 switch (_arg_count) { 133 case 0: 134 result_ret = ptr_as_func<Func0>(_func)(); 135 expect_ret = 0; 136 break; 137 case 1: 138 result_ret = ptr_as_func<Func1>(_func)(1); 139 expect_ret = 1; 140 break; 141 case 2: 142 result_ret = ptr_as_func<Func2>(_func)(1, 2); 143 expect_ret = 1 + 2; 144 break; 145 case 3: 146 result_ret = ptr_as_func<Func3>(_func)(1, 2, 3); 147 expect_ret = 1 + 2 + 3; 148 break; 149 case 4: 150 result_ret = ptr_as_func<Func4>(_func)(1, 2, 3, 4); 151 expect_ret = 1 + 2 + 3 + 4; 152 break; 153 case 5: 154 result_ret = ptr_as_func<Func5>(_func)(1, 2, 3, 4, 5); 155 expect_ret = 1 + 2 + 3 + 4 + 5; 156 break; 157 case 6: 158 result_ret = ptr_as_func<Func6>(_func)(1, 2, 3, 4, 5, 6); 159 expect_ret = 1 + 2 + 3 + 4 + 5 + 6; 160 break; 161 case 7: 162 result_ret = ptr_as_func<Func7>(_func)(1, 2, 3, 4, 5, 6, 7); 163 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7; 164 break; 165 case 8: 166 result_ret = ptr_as_func<Func8>(_func)(1, 2, 3, 4, 5, 6, 7, 8); 167 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8; 168 break; 169 case 9: 170 result_ret = ptr_as_func<Func9>(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9); 171 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9; 172 break; 173 case 10: 174 result_ret = ptr_as_func<Func10>(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 175 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10; 176 break; 177 case 11: 178 result_ret = ptr_as_func<Func11>(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); 179 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11; 180 break; 181 case 12: 182 result_ret = ptr_as_func<Func12>(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); 183 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12; 184 break; 185 case 13: 186 result_ret = ptr_as_func<Func13>(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13); 187 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13; 188 break; 189 case 14: 190 result_ret = ptr_as_func<Func14>(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14); 191 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14; 192 break; 193 case 15: 194 result_ret = ptr_as_func<Func15>(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); 195 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15; 196 break; 197 case 16: 198 result_ret = ptr_as_func<Func16>(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); 199 expect_ret = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16; 200 break; 201 } 202 203 result.assign_format("ret={%u, %u}", result_ret >> 28, result_ret & 0x0FFFFFFFu); 204 expect.assign_format("ret={%u, %u}", expect_ret >> 28, expect_ret & 0x0FFFFFFFu); 205 206 return result == expect; 207 } 208 209 uint32_t _arg_count; 210 uint32_t _alignment; 211 bool _preserve_fp; 212 }; 213 214 // x86::Compiler - X86Test_NoCode 215 // ============================== 216 217 class X86Test_NoCode : public X86TestCase { 218 public: 219 X86Test_NoCode() : X86TestCase("NoCode") {} 220 221 static void add(TestApp& app) { 222 app.add(new X86Test_NoCode()); 223 } 224 225 void compile(x86::Compiler& cc) override { 226 cc.add_func(FuncSignature::build<void>()); 227 cc.end_func(); 228 } 229 230 bool run(void* _func, String& result, String& expect) override { 231 Support::maybe_unused(result, expect); 232 233 using Func = void (*)(void); 234 Func func = ptr_as_func<Func>(_func); 235 236 func(); 237 return true; 238 } 239 }; 240 241 // x86::Compiler - X86Test_NoAlign 242 // =============================== 243 244 class X86Test_NoAlign : public X86TestCase { 245 public: 246 X86Test_NoAlign() : X86TestCase("NoAlign") {} 247 248 static void add(TestApp& app) { 249 app.add(new X86Test_NoAlign()); 250 } 251 252 void compile(x86::Compiler& cc) override { 253 cc.add_func(FuncSignature::build<void>()); 254 cc.align(AlignMode::kCode, 0); 255 cc.align(AlignMode::kCode, 1); 256 cc.end_func(); 257 } 258 259 bool run(void* _func, String& result, String& expect) override { 260 Support::maybe_unused(result, expect); 261 262 using Func = void (*)(void); 263 Func func = ptr_as_func<Func>(_func); 264 265 func(); 266 return true; 267 } 268 }; 269 270 // x86::Compiler - X86Test_IndirectBranchProtection 271 // ================================================ 272 273 class X86Test_IndirectBranchProtection : public X86TestCase { 274 public: 275 X86Test_IndirectBranchProtection() : X86TestCase("IndirectBranchProtection") {} 276 277 static void add(TestApp& app) { 278 app.add(new X86Test_IndirectBranchProtection()); 279 } 280 281 void compile(x86::Compiler& cc) override { 282 FuncNode* func = cc.add_func(FuncSignature::build<void>()); 283 func->add_attributes(FuncAttributes::kIndirectBranchProtection); 284 cc.end_func(); 285 } 286 287 bool run(void* _func, String& result, String& expect) override { 288 Support::maybe_unused(result, expect); 289 290 using Func = void (*)(void); 291 Func func = ptr_as_func<Func>(_func); 292 293 func(); 294 return true; 295 } 296 }; 297 298 299 // x86::Compiler - X86Test_JumpMerge 300 // ================================= 301 302 class X86Test_JumpMerge : public X86TestCase { 303 public: 304 X86Test_JumpMerge() : X86TestCase("JumpMerge") {} 305 306 static void add(TestApp& app) { 307 app.add(new X86Test_JumpMerge()); 308 } 309 310 void compile(x86::Compiler& cc) override { 311 Label L0 = cc.new_label(); 312 Label L1 = cc.new_label(); 313 Label L2 = cc.new_label(); 314 Label LEnd = cc.new_label(); 315 316 x86::Gp dst = cc.new_gp_ptr("dst"); 317 x86::Gp val = cc.new_gp32("val"); 318 319 FuncNode* func_node = cc.add_func(FuncSignature::build<void, int*, int>()); 320 func_node->set_arg(0, dst); 321 func_node->set_arg(1, val); 322 323 cc.cmp(val, 0); 324 cc.je(L2); 325 326 cc.cmp(val, 1); 327 cc.je(L1); 328 329 cc.cmp(val, 2); 330 cc.je(L0); 331 332 cc.mov(x86::dword_ptr(dst), val); 333 cc.jmp(LEnd); 334 335 // On purpose. This tests whether the CFG constructs a single basic-block 336 // from multiple labels next to each other. 337 cc.bind(L0); 338 cc.bind(L1); 339 cc.bind(L2); 340 cc.mov(x86::dword_ptr(dst), 0); 341 342 cc.bind(LEnd); 343 cc.end_func(); 344 } 345 346 bool run(void* _func, String& result, String& expect) override { 347 using Func = void (*)(int*, int); 348 Func func = ptr_as_func<Func>(_func); 349 350 int arr[5] = { -1, -1, -1, -1, -1 }; 351 int exp[5] = { 0, 0, 0, 3, 4 }; 352 353 for (int i = 0; i < 5; i++) 354 func(&arr[i], i); 355 356 result.assign_format("ret={%d, %d, %d, %d, %d}", arr[0], arr[1], arr[2], arr[3], arr[4]); 357 expect.assign_format("ret={%d, %d, %d, %d, %d}", exp[0], exp[1], exp[2], exp[3], exp[4]); 358 359 return result == expect; 360 } 361 }; 362 363 // x86::Compiler - X86Test_JumpCross 364 // ================================= 365 366 class X86Test_JumpCross : public X86TestCase { 367 public: 368 X86Test_JumpCross() : X86TestCase("JumpCross") {} 369 370 static void add(TestApp& app) { 371 app.add(new X86Test_JumpCross()); 372 } 373 374 void compile(x86::Compiler& cc) override { 375 cc.add_func(FuncSignature::build<void>()); 376 377 Label L1 = cc.new_label(); 378 Label L2 = cc.new_label(); 379 Label L3 = cc.new_label(); 380 381 cc.jmp(L2); 382 383 cc.bind(L1); 384 cc.jmp(L3); 385 386 cc.bind(L2); 387 cc.jmp(L1); 388 389 cc.bind(L3); 390 cc.end_func(); 391 } 392 393 bool run(void* _func, String& result, String& expect) override { 394 Support::maybe_unused(result, expect); 395 396 using Func = void (*)(void); 397 Func func = ptr_as_func<Func>(_func); 398 399 func(); 400 return true; 401 } 402 }; 403 404 // x86::Compiler - X86Test_JumpMany 405 // ================================ 406 407 class X86Test_JumpMany : public X86TestCase { 408 public: 409 X86Test_JumpMany() : X86TestCase("JumpMany") {} 410 411 static void add(TestApp& app) { 412 app.add(new X86Test_JumpMany()); 413 } 414 415 void compile(x86::Compiler& cc) override { 416 cc.add_func(FuncSignature::build<int>()); 417 for (uint32_t i = 0; i < 1000; i++) { 418 Label L = cc.new_label(); 419 cc.jmp(L); 420 cc.bind(L); 421 } 422 423 x86::Gp ret = cc.new_gp32("ret"); 424 cc.xor_(ret, ret); 425 cc.ret(ret); 426 cc.end_func(); 427 } 428 429 bool run(void* _func, String& result, String& expect) override { 430 using Func = int (*)(void); 431 432 Func func = ptr_as_func<Func>(_func); 433 434 int result_ret = func(); 435 int expect_ret = 0; 436 437 result.assign_format("ret={%d}", result_ret); 438 expect.assign_format("ret={%d}", expect_ret); 439 440 return result == expect; 441 } 442 }; 443 444 // x86::Compiler - X86Test_JumpUnreachable1 445 // ======================================== 446 447 class X86Test_JumpUnreachable1 : public X86TestCase { 448 public: 449 X86Test_JumpUnreachable1() : X86TestCase("JumpUnreachable1") {} 450 451 static void add(TestApp& app) { 452 app.add(new X86Test_JumpUnreachable1()); 453 } 454 455 void compile(x86::Compiler& cc) override { 456 cc.add_func(FuncSignature::build<void>()); 457 458 Label L_1 = cc.new_label(); 459 Label L_2 = cc.new_label(); 460 Label L_3 = cc.new_label(); 461 Label L_4 = cc.new_label(); 462 Label L_5 = cc.new_label(); 463 Label L_6 = cc.new_label(); 464 Label L_7 = cc.new_label(); 465 466 x86::Gp v0 = cc.new_gp32("v0"); 467 x86::Gp v1 = cc.new_gp32("v1"); 468 469 cc.bind(L_2); 470 cc.bind(L_3); 471 472 cc.jmp(L_1); 473 474 cc.bind(L_5); 475 cc.mov(v0, 0); 476 477 cc.bind(L_6); 478 cc.jmp(L_3); 479 cc.mov(v1, 1); 480 cc.jmp(L_1); 481 482 cc.bind(L_4); 483 cc.jmp(L_2); 484 cc.bind(L_7); 485 cc.add(v0, v1); 486 487 cc.align(AlignMode::kCode, 16); 488 cc.bind(L_1); 489 cc.ret(); 490 cc.end_func(); 491 } 492 493 bool run(void* _func, String& result, String& expect) override { 494 using Func = void (*)(void); 495 Func func = ptr_as_func<Func>(_func); 496 497 func(); 498 499 result.append("ret={}"); 500 expect.append("ret={}"); 501 502 return true; 503 } 504 }; 505 506 // x86::Compiler - X86Test_JumpUnreachable2 507 // ======================================== 508 509 class X86Test_JumpUnreachable2 : public X86TestCase { 510 public: 511 X86Test_JumpUnreachable2() : X86TestCase("JumpUnreachable2") {} 512 513 static void add(TestApp& app) { 514 app.add(new X86Test_JumpUnreachable2()); 515 } 516 517 void compile(x86::Compiler& cc) override { 518 cc.add_func(FuncSignature::build<void>()); 519 520 Label L_1 = cc.new_label(); 521 Label L_2 = cc.new_label(); 522 523 x86::Gp v0 = cc.new_gp32("v0"); 524 x86::Gp v1 = cc.new_gp32("v1"); 525 526 cc.jmp(L_1); 527 cc.bind(L_2); 528 cc.mov(v0, 1); 529 cc.mov(v1, 2); 530 cc.cmp(v0, v1); 531 cc.jz(L_2); 532 cc.jmp(L_1); 533 534 cc.bind(L_1); 535 cc.ret(); 536 cc.end_func(); 537 } 538 539 bool run(void* _func, String& result, String& expect) override { 540 using Func = void (*)(void); 541 Func func = ptr_as_func<Func>(_func); 542 543 func(); 544 545 result.append("ret={}"); 546 expect.append("ret={}"); 547 548 return true; 549 } 550 }; 551 552 // x86::Compiler - X86Test_JumpTable1 553 // ================================== 554 555 class X86Test_JumpTable1 : public X86TestCase { 556 public: 557 bool _annotated; 558 559 X86Test_JumpTable1(bool annotated) 560 : X86TestCase("X86Test_JumpTable1"), 561 _annotated(annotated) { 562 _name.assign_format("JumpTable {%s}", annotated ? "Annotated" : "Unknown Reg/Mem"); 563 } 564 565 enum Operator { 566 kOperatorAdd = 0, 567 kOperatorSub = 1, 568 kOperatorMul = 2, 569 kOperatorDiv = 3 570 }; 571 572 static void add(TestApp& app) { 573 app.add(new X86Test_JumpTable1(false)); 574 app.add(new X86Test_JumpTable1(true)); 575 } 576 577 void compile(x86::Compiler& cc) override { 578 x86::Vec a = cc.new_xmm_ss("a"); 579 x86::Vec b = cc.new_xmm_ss("b"); 580 x86::Gp op = cc.new_gp32("op"); 581 x86::Gp target = cc.new_gp_ptr("target"); 582 x86::Gp offset = cc.new_gp_ptr("offset"); 583 584 Label L_Table = cc.new_label(); 585 Label L_Add = cc.new_label(); 586 Label L_Sub = cc.new_label(); 587 Label L_Mul = cc.new_label(); 588 Label L_Div = cc.new_label(); 589 Label L_End = cc.new_label(); 590 591 FuncNode* func_node = cc.add_func(FuncSignature::build<float, float, float, uint32_t>()); 592 func_node->set_arg(0, a); 593 func_node->set_arg(1, b); 594 func_node->set_arg(2, op); 595 596 cc.lea(offset, x86::ptr(L_Table)); 597 if (cc.is_64bit()) 598 cc.movsxd(target, x86::dword_ptr(offset, op.clone_as(offset), 2)); 599 else 600 cc.mov(target, x86::dword_ptr(offset, op.clone_as(offset), 2)); 601 cc.add(target, offset); 602 603 // JumpAnnotation allows to annotate all possible jump targets of 604 // instructions where it cannot be deduced from operands. 605 if (_annotated) { 606 JumpAnnotation* annotation = cc.new_jump_annotation(); 607 annotation->add_label(L_Add); 608 annotation->add_label(L_Sub); 609 annotation->add_label(L_Mul); 610 annotation->add_label(L_Div); 611 cc.jmp(target, annotation); 612 } 613 else { 614 cc.jmp(target); 615 } 616 617 cc.bind(L_Add); 618 cc.addss(a, b); 619 cc.jmp(L_End); 620 621 cc.bind(L_Sub); 622 cc.subss(a, b); 623 cc.jmp(L_End); 624 625 cc.bind(L_Mul); 626 cc.mulss(a, b); 627 cc.jmp(L_End); 628 629 cc.bind(L_Div); 630 cc.divss(a, b); 631 632 cc.bind(L_End); 633 cc.ret(a); 634 635 cc.end_func(); 636 637 cc.bind(L_Table); 638 cc.embed_label_delta(L_Add, L_Table, 4); 639 cc.embed_label_delta(L_Sub, L_Table, 4); 640 cc.embed_label_delta(L_Mul, L_Table, 4); 641 cc.embed_label_delta(L_Div, L_Table, 4); 642 } 643 644 bool run(void* _func, String& result, String& expect) override { 645 using Func = float (*)(float, float, uint32_t); 646 Func func = ptr_as_func<Func>(_func); 647 648 float results[4]; 649 float expected[4]; 650 651 results[0] = func(33.0f, 14.0f, kOperatorAdd); 652 results[1] = func(33.0f, 14.0f, kOperatorSub); 653 results[2] = func(10.0f, 6.0f, kOperatorMul); 654 results[3] = func(80.0f, 8.0f, kOperatorDiv); 655 656 expected[0] = 47.0f; 657 expected[1] = 19.0f; 658 expected[2] = 60.0f; 659 expected[3] = 10.0f; 660 661 result.assign_format("ret={%f, %f, %f, %f}", double(results[0]), double(results[1]), double(results[2]), double(results[3])); 662 expect.assign_format("ret={%f, %f, %f, %f}", double(expected[0]), double(expected[1]), double(expected[2]), double(expected[3])); 663 664 return result == expect; 665 } 666 }; 667 668 // x86::Compiler - X86Test_JumpTable2 669 // ================================== 670 671 class X86Test_JumpTable2 : public X86TestCase { 672 public: 673 X86Test_JumpTable2() 674 : X86TestCase("JumpTable {Jumping to Begin}") {} 675 676 static void add(TestApp& app) { 677 app.add(new X86Test_JumpTable2()); 678 } 679 680 void compile(x86::Compiler& cc) override { 681 x86::Gp result = cc.new_gp32("result"); 682 x86::Gp value = cc.new_gp32("value"); 683 x86::Gp target = cc.new_gp_ptr("target"); 684 x86::Gp offset = cc.new_gp_ptr("offset"); 685 686 Label L_Table = cc.new_label(); 687 Label L_Begin = cc.new_label(); 688 Label L_Case0 = cc.new_label(); 689 Label L_Case1 = cc.new_label(); 690 Label L_End = cc.new_label(); 691 692 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int>()); 693 func_node->set_arg(0, value); 694 695 cc.bind(L_Begin); 696 cc.lea(offset, x86::ptr(L_Table)); 697 if (cc.is_64bit()) 698 cc.movsxd(target, x86::dword_ptr(offset, value.clone_as(offset), 2)); 699 else 700 cc.mov(target, x86::dword_ptr(offset, value.clone_as(offset), 2)); 701 cc.add(target, offset); 702 703 { 704 JumpAnnotation* annotation = cc.new_jump_annotation(); 705 annotation->add_label(L_Case0); 706 annotation->add_label(L_Case1); 707 annotation->add_label(L_Begin); // Never used, just for the purpose of the test. 708 cc.jmp(target, annotation); 709 710 cc.bind(L_Case0); 711 cc.mov(result, 0); 712 cc.jmp(L_End); 713 714 cc.bind(L_Case1); 715 cc.mov(result, 1); 716 cc.jmp(L_End); 717 } 718 719 cc.bind(L_End); 720 cc.ret(result); 721 722 cc.end_func(); 723 724 cc.bind(L_Table); 725 cc.embed_label_delta(L_Case0, L_Table, 4); 726 cc.embed_label_delta(L_Case1, L_Table, 4); 727 } 728 729 bool run(void* _func, String& result, String& expect) override { 730 using Func = int (*)(int); 731 Func func = ptr_as_func<Func>(_func); 732 733 int results[2]; 734 int expected[2]; 735 736 results[0] = func(0); 737 results[1] = func(1); 738 739 expected[0] = 0; 740 expected[1] = 1; 741 742 result.assign_format("ret={%d, %d}", results[0], results[1]); 743 expect.assign_format("ret={%d, %d}", expected[0], expected[1]); 744 745 return result == expect; 746 } 747 }; 748 749 // x86::Compiler - X86Test_JumpTable3 750 // ================================== 751 752 class X86Test_JumpTable3 : public X86TestCase { 753 public: 754 X86Test_JumpTable3() 755 : X86TestCase("JumpTable {Jumping to a single label}") {} 756 757 static void add(TestApp& app) { 758 app.add(new X86Test_JumpTable3()); 759 } 760 761 void compile(x86::Compiler& cc) override { 762 cc.add_func(FuncSignature::build<int>()); 763 764 Label L_Target = cc.new_label(); 765 x86::Gp target = cc.new_gp_ptr("target"); 766 x86::Gp result = cc.new_gp32("result"); 767 768 JumpAnnotation* annotation = cc.new_jump_annotation(); 769 annotation->add_label(L_Target); 770 771 cc.lea(target, x86::ptr(L_Target)); 772 cc.jmp(target, annotation); 773 774 cc.bind(L_Target); 775 cc.mov(result, 1234); 776 cc.ret(result); 777 cc.end_func(); 778 } 779 780 bool run(void* _func, String& result, String& expect) override { 781 using Func = int (*)(void); 782 Func func = ptr_as_func<Func>(_func); 783 784 int out = func(); 785 int expected = 1234; 786 787 result.assign_format("ret=%d", out); 788 expect.assign_format("ret=%d", expected); 789 790 return result == expect; 791 } 792 }; 793 794 // x86::Compiler - X86Test_JumpTable4 795 // ================================== 796 797 class X86Test_JumpTable4 : public X86TestCase { 798 public: 799 X86Test_JumpTable4() 800 : X86TestCase("JumpTable {Jumping to a single label and multiple labels}") {} 801 802 static void add(TestApp& app) { 803 app.add(new X86Test_JumpTable4()); 804 } 805 806 void compile(x86::Compiler& cc) override { 807 x86::Gp result = cc.new_gp32("result"); 808 x86::Gp condition = cc.new_gp32("condition"); 809 810 FuncNode* func = cc.add_func(FuncSignature::build<int, int>()); 811 func->set_arg(0, condition); 812 813 Label L_NonZero = cc.new_label(); 814 cc.test(condition, condition); 815 cc.jnz(L_NonZero); 816 817 { 818 JumpAnnotation* annotation = cc.new_jump_annotation(); 819 Label L_Target = cc.new_label(); 820 annotation->add_label(L_Target); 821 822 x86::Gp target = cc.new_gp_ptr("target"); 823 cc.lea(target, x86::ptr(L_Target)); 824 cc.jmp(target, annotation); 825 cc.bind(L_Target); 826 cc.mov(result, 1234); 827 cc.ret(result); 828 } 829 830 { 831 JumpAnnotation* annotation = cc.new_jump_annotation(); 832 Label L_Target1 = cc.new_label(); 833 Label L_Target2 = cc.new_label(); 834 annotation->add_label(L_Target1); 835 annotation->add_label(L_Target2); 836 837 cc.bind(L_NonZero); 838 x86::Gp target = cc.new_gp_ptr("target"); 839 cc.lea(target, x86::ptr(L_Target1)); 840 cc.jmp(target, annotation); 841 842 cc.bind(L_Target1); 843 cc.mov(result, 4321); 844 cc.ret(result); 845 846 // Never executed. 847 cc.bind(L_Target2); 848 cc.mov(result, 0); 849 cc.ret(result); 850 } 851 852 cc.end_func(); 853 } 854 855 bool run(void* _func, String& result, String& expect) override { 856 using Func = int (*)(int); 857 Func func = ptr_as_func<Func>(_func); 858 859 int results[2] = { func(0), func(1) }; 860 int expected[2] = { 1234, 4321 }; 861 862 result.assign_format("ret={%d, %d}", results[0], results[1]); 863 expect.assign_format("ret={%d, %d}", expected[0], expected[1]); 864 865 return result == expect; 866 } 867 }; 868 869 // x86::Compiler - X86Test_AllocBase 870 // ================================= 871 872 class X86Test_AllocBase : public X86TestCase { 873 public: 874 X86Test_AllocBase() : X86TestCase("AllocBase") {} 875 876 static void add(TestApp& app) { 877 app.add(new X86Test_AllocBase()); 878 } 879 880 void compile(x86::Compiler& cc) override { 881 cc.add_func(FuncSignature::build<int>()); 882 883 x86::Gp v0 = cc.new_gp32("v0"); 884 x86::Gp v1 = cc.new_gp32("v1"); 885 x86::Gp v2 = cc.new_gp32("v2"); 886 x86::Gp v3 = cc.new_gp32("v3"); 887 x86::Gp v4 = cc.new_gp32("v4"); 888 889 cc.xor_(v0, v0); 890 891 cc.mov(v1, 1); 892 cc.mov(v2, 2); 893 cc.mov(v3, 3); 894 cc.mov(v4, 4); 895 896 cc.add(v0, v1); 897 cc.add(v0, v2); 898 cc.add(v0, v3); 899 cc.add(v0, v4); 900 901 cc.ret(v0); 902 cc.end_func(); 903 } 904 905 bool run(void* _func, String& result, String& expect) override { 906 using Func = int (*)(void); 907 Func func = ptr_as_func<Func>(_func); 908 909 int result_ret = func(); 910 int expect_ret = 1 + 2 + 3 + 4; 911 912 result.assign_format("ret=%d", result_ret); 913 expect.assign_format("ret=%d", expect_ret); 914 915 return result == expect; 916 } 917 }; 918 919 // x86::Compiler - X86Test_AllocMany1 920 // ================================== 921 922 class X86Test_AllocMany1 : public X86TestCase { 923 public: 924 X86Test_AllocMany1() : X86TestCase("AllocMany1") {} 925 926 static inline constexpr uint32_t kCount = 8; 927 928 static void add(TestApp& app) { 929 app.add(new X86Test_AllocMany1()); 930 } 931 932 void compile(x86::Compiler& cc) override { 933 x86::Gp a0 = cc.new_gp_ptr("a0"); 934 x86::Gp a1 = cc.new_gp_ptr("a1"); 935 936 FuncNode* func_node = cc.add_func(FuncSignature::build<void, int*, int*>()); 937 func_node->set_arg(0, a0); 938 func_node->set_arg(1, a1); 939 940 // Create some variables. 941 x86::Gp t = cc.new_gp32("t"); 942 x86::Gp x[kCount]; 943 944 uint32_t i; 945 946 // Setup variables (use mov with reg/imm to se if register allocator works). 947 for (i = 0; i < kCount; i++) x[i] = cc.new_gp32("x%u", i); 948 for (i = 0; i < kCount; i++) cc.mov(x[i], int(i + 1)); 949 950 // Make sum (addition). 951 cc.xor_(t, t); 952 for (i = 0; i < kCount; i++) cc.add(t, x[i]); 953 954 // Store result to a given pointer in first argument. 955 cc.mov(x86::dword_ptr(a0), t); 956 957 // Clear t. 958 cc.xor_(t, t); 959 960 // Make sum (subtraction). 961 for (i = 0; i < kCount; i++) cc.sub(t, x[i]); 962 963 // Store result to a given pointer in second argument. 964 cc.mov(x86::dword_ptr(a1), t); 965 966 // End of function. 967 cc.end_func(); 968 } 969 970 bool run(void* _func, String& result, String& expect) override { 971 using Func = void (*)(int*, int*); 972 Func func = ptr_as_func<Func>(_func); 973 974 int result_x = 0; 975 int result_y = 0; 976 977 int expect_x = 36; 978 int expect_y = -36; 979 980 func(&result_x, &result_y); 981 982 result.assign_format("ret={x=%d, y=%d}", result_x, result_y); 983 expect.assign_format("ret={x=%d, y=%d}", expect_x, expect_y); 984 985 return result_x == expect_x && result_y == expect_y; 986 } 987 }; 988 989 // x86::Compiler - X86Test_AllocMany2 990 // ================================== 991 992 class X86Test_AllocMany2 : public X86TestCase { 993 public: 994 X86Test_AllocMany2() : X86TestCase("AllocMany2") {} 995 996 static void add(TestApp& app) { 997 app.add(new X86Test_AllocMany2()); 998 } 999 1000 void compile(x86::Compiler& cc) override { 1001 x86::Gp a = cc.new_gp_ptr("a"); 1002 x86::Gp v[32]; 1003 1004 FuncNode* func_node = cc.add_func(FuncSignature::build<void, uint32_t*>()); 1005 func_node->set_arg(0, a); 1006 1007 for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(v); i++) v[i] = cc.new_gp32("v%d", i); 1008 for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(v); i++) cc.xor_(v[i], v[i]); 1009 1010 x86::Gp x = cc.new_gp32("x"); 1011 Label L = cc.new_label(); 1012 1013 cc.mov(x, 32); 1014 cc.bind(L); 1015 for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(v); i++) cc.add(v[i], i); 1016 1017 cc.dec(x); 1018 cc.jnz(L); 1019 for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(v); i++) cc.mov(x86::dword_ptr(a, int(i * 4)), v[i]); 1020 1021 cc.end_func(); 1022 } 1023 1024 bool run(void* _func, String& result, String& expect) override { 1025 using Func = void (*)(uint32_t*); 1026 Func func = ptr_as_func<Func>(_func); 1027 1028 uint32_t i; 1029 uint32_t result_buf[32] {}; 1030 uint32_t expect_buf[32] {}; 1031 1032 for (i = 0; i < ASMJIT_ARRAY_SIZE(result_buf); i++) 1033 expect_buf[i] = i * 32; 1034 func(result_buf); 1035 1036 for (i = 0; i < ASMJIT_ARRAY_SIZE(result_buf); i++) { 1037 if (i != 0) { 1038 result.append(','); 1039 expect.append(','); 1040 } 1041 1042 result.append_format("%u", result_buf[i]); 1043 expect.append_format("%u", expect_buf[i]); 1044 } 1045 1046 return result == expect; 1047 } 1048 }; 1049 1050 // x86::Compiler - X86Test_AllocInt8 1051 // ================================= 1052 1053 class X86Test_AllocInt8 : public X86TestCase { 1054 public: 1055 X86Test_AllocInt8() : X86TestCase("AllocInt8") {} 1056 1057 static void add(TestApp& app) { 1058 app.add(new X86Test_AllocInt8()); 1059 } 1060 1061 void compile(x86::Compiler& cc) override { 1062 x86::Gp x = cc.new_gp8("x"); 1063 x86::Gp y = cc.new_gp32("y"); 1064 1065 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int8_t>()); 1066 func_node->set_arg(0, x); 1067 1068 cc.movsx(y, x); 1069 1070 cc.ret(y); 1071 cc.end_func(); 1072 } 1073 1074 bool run(void* _func, String& result, String& expect) override { 1075 using Func = int (*)(int8_t); 1076 Func func = ptr_as_func<Func>(_func); 1077 1078 int result_ret = func(int8_t(-13)); 1079 int expect_ret = -13; 1080 1081 result.assign_format("ret=%d", result_ret); 1082 expect.assign_format("ret=%d", expect_ret); 1083 1084 return result == expect; 1085 } 1086 }; 1087 1088 // x86::Compiler - X86Test_AllocUnhandledArg 1089 // ========================================= 1090 1091 class X86Test_AllocUnhandledArg : public X86TestCase { 1092 public: 1093 X86Test_AllocUnhandledArg() : X86TestCase("AllocUnhandledArg") {} 1094 1095 static void add(TestApp& app) { 1096 app.add(new X86Test_AllocUnhandledArg()); 1097 } 1098 1099 void compile(x86::Compiler& cc) override { 1100 x86::Gp x = cc.new_gp32("x"); 1101 1102 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int, int>()); 1103 func_node->set_arg(2, x); 1104 1105 cc.ret(x); 1106 cc.end_func(); 1107 } 1108 1109 bool run(void* _func, String& result, String& expect) override { 1110 using Func = int (*)(int, int, int); 1111 Func func = ptr_as_func<Func>(_func); 1112 1113 int result_ret = func(42, 155, 199); 1114 int expect_ret = 199; 1115 1116 result.assign_format("ret={%d}", result_ret); 1117 expect.assign_format("ret={%d}", expect_ret); 1118 1119 return result == expect; 1120 } 1121 }; 1122 1123 // x86::Compiler - X86Test_AllocArgsIntPtr 1124 // ======================================= 1125 1126 class X86Test_AllocArgsIntPtr : public X86TestCase { 1127 public: 1128 X86Test_AllocArgsIntPtr() : X86TestCase("AllocArgsIntPtr") {} 1129 1130 static void add(TestApp& app) { 1131 app.add(new X86Test_AllocArgsIntPtr()); 1132 } 1133 1134 void compile(x86::Compiler& cc) override { 1135 FuncNode* func_node = cc.add_func(FuncSignature::build<void, void*, void*, void*, void*, void*, void*, void*, void*>()); 1136 x86::Gp var[8]; 1137 1138 for (uint32_t i = 0; i < 8; i++) { 1139 var[i] = cc.new_gp_ptr("var%u", i); 1140 func_node->set_arg(i, var[i]); 1141 } 1142 1143 for (uint32_t i = 0; i < 8; i++) { 1144 cc.add(var[i], int(i + 1)); 1145 } 1146 1147 // Move some data into buffer provided by arguments so we can verify if it 1148 // really works without looking into assembler output. 1149 for (uint32_t i = 0; i < 8; i++) { 1150 cc.add(x86::byte_ptr(var[i]), int(i + 1)); 1151 } 1152 1153 cc.end_func(); 1154 } 1155 1156 bool run(void* _func, String& result, String& expect) override { 1157 using Func = void (*)(void*, void*, void*, void*, void*, void*, void*, void*); 1158 Func func = ptr_as_func<Func>(_func); 1159 1160 uint8_t result_buf[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1161 uint8_t expect_buf[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; 1162 1163 func(result_buf, result_buf, result_buf, result_buf, 1164 result_buf, result_buf, result_buf, result_buf); 1165 1166 result.assign_format("buf={%d, %d, %d, %d, %d, %d, %d, %d, %d}", 1167 result_buf[0], result_buf[1], result_buf[2], result_buf[3], 1168 result_buf[4], result_buf[5], result_buf[6], result_buf[7], 1169 result_buf[8]); 1170 1171 expect.assign_format("buf={%d, %d, %d, %d, %d, %d, %d, %d, %d}", 1172 expect_buf[0], expect_buf[1], expect_buf[2], expect_buf[3], 1173 expect_buf[4], expect_buf[5], expect_buf[6], expect_buf[7], 1174 expect_buf[8]); 1175 1176 return result == expect; 1177 } 1178 }; 1179 1180 // x86::Compiler - X86Test_AllocArgsFloat 1181 // ====================================== 1182 1183 class X86Test_AllocArgsFloat : public X86TestCase { 1184 public: 1185 X86Test_AllocArgsFloat() : X86TestCase("AllocArgsFloat") {} 1186 1187 static void add(TestApp& app) { 1188 app.add(new X86Test_AllocArgsFloat()); 1189 } 1190 1191 void compile(x86::Compiler& cc) override { 1192 FuncNode* func_node = cc.add_func(FuncSignature::build<void, float, float, float, float, float, float, float, void*>()); 1193 1194 x86::Gp p = cc.new_gp_ptr("p"); 1195 x86::Vec xv[7]; 1196 1197 for (uint32_t i = 0; i < 7; i++) { 1198 xv[i] = cc.new_xmm_ss("xv%u", i); 1199 func_node->set_arg(i, xv[i]); 1200 } 1201 1202 func_node->set_arg(7, p); 1203 1204 cc.addss(xv[0], xv[1]); 1205 cc.addss(xv[0], xv[2]); 1206 cc.addss(xv[0], xv[3]); 1207 cc.addss(xv[0], xv[4]); 1208 cc.addss(xv[0], xv[5]); 1209 cc.addss(xv[0], xv[6]); 1210 1211 cc.movss(x86::ptr(p), xv[0]); 1212 cc.end_func(); 1213 } 1214 1215 bool run(void* _func, String& result, String& expect) override { 1216 using Func = void (*)(float, float, float, float, float, float, float, float*); 1217 Func func = ptr_as_func<Func>(_func); 1218 1219 float result_ret = 0; 1220 float expect_ret = 1.0f + 2.0f + 3.0f + 4.0f + 5.0f + 6.0f + 7.0f; 1221 1222 func(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, &result_ret); 1223 1224 result.assign_format("ret={%g}", double(result_ret)); 1225 expect.assign_format("ret={%g}", double(expect_ret)); 1226 1227 return result == expect; 1228 } 1229 }; 1230 1231 // x86::Compiler - X86Test_AllocArgsDouble 1232 // ======================================= 1233 1234 class X86Test_AllocArgsDouble : public X86TestCase { 1235 public: 1236 X86Test_AllocArgsDouble() : X86TestCase("AllocArgsDouble") {} 1237 1238 static void add(TestApp& app) { 1239 app.add(new X86Test_AllocArgsDouble()); 1240 } 1241 1242 void compile(x86::Compiler& cc) override { 1243 FuncNode* func_node = cc.add_func(FuncSignature::build<void, double, double, double, double, double, double, double, void*>()); 1244 1245 x86::Gp p = cc.new_gp_ptr("p"); 1246 x86::Vec xv[7]; 1247 1248 for (uint32_t i = 0; i < 7; i++) { 1249 xv[i] = cc.new_xmm_sd("xv%u", i); 1250 func_node->set_arg(i, xv[i]); 1251 } 1252 1253 func_node->set_arg(7, p); 1254 1255 cc.addsd(xv[0], xv[1]); 1256 cc.addsd(xv[0], xv[2]); 1257 cc.addsd(xv[0], xv[3]); 1258 cc.addsd(xv[0], xv[4]); 1259 cc.addsd(xv[0], xv[5]); 1260 cc.addsd(xv[0], xv[6]); 1261 1262 cc.movsd(x86::ptr(p), xv[0]); 1263 cc.end_func(); 1264 } 1265 1266 bool run(void* _func, String& result, String& expect) override { 1267 using Func = void (*)(double, double, double, double, double, double, double, double*); 1268 Func func = ptr_as_func<Func>(_func); 1269 1270 double result_ret = 0; 1271 double expect_ret = 1.0 + 2.0 + 3.0 + 4.0 + 5.0 + 6.0 + 7.0; 1272 1273 func(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, &result_ret); 1274 1275 result.assign_format("ret={%g}", result_ret); 1276 expect.assign_format("ret={%g}", expect_ret); 1277 1278 return result == expect; 1279 } 1280 }; 1281 1282 // x86::Compiler - X86Test_AllocArgsVec 1283 // ==================================== 1284 1285 #if ASMJIT_ARCH_X86 1286 class X86Test_AllocArgsVec : public X86TestCase { 1287 public: 1288 X86Test_AllocArgsVec() : X86TestCase("AllocArgsVec") {} 1289 1290 static void add(TestApp& app) { 1291 // Not supported on Windows. 1292 #ifndef _WIN32 1293 app.add(new X86Test_AllocArgsVec()); 1294 #else 1295 Support::maybe_unused(app); 1296 #endif 1297 } 1298 1299 void compile(x86::Compiler& cc) override { 1300 x86::Vec a = cc.new_xmm("xmm_a"); 1301 x86::Vec b = cc.new_xmm("xmm_b"); 1302 1303 FuncNode* func_node = cc.add_func(FuncSignature::build<Type::Vec128, Type::Vec128, Type::Vec128>()); 1304 func_node->set_arg(0, a); 1305 func_node->set_arg(1, b); 1306 1307 cc.paddb(a, b); 1308 cc.ret(a); 1309 1310 cc.end_func(); 1311 } 1312 1313 bool run(void* _func, String& result, String& expect) override { 1314 using Func = __m128i (*)(__m128i, __m128i); 1315 Func func = ptr_as_func<Func>(_func); 1316 1317 uint8_t a_data[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; 1318 uint8_t b_data[16] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; 1319 1320 uint8_t r_data[16] {}; 1321 uint8_t e_data[16] = { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; 1322 1323 __m128i a_vec = _mm_loadu_si128(reinterpret_cast<const __m128i*>(a_data)); 1324 __m128i b_vec = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b_data)); 1325 1326 __m128i r_vec = func(a_vec, b_vec); 1327 _mm_storeu_si128(reinterpret_cast<__m128i*>(r_data), r_vec); 1328 1329 result.append_hex(r_data, 16); 1330 expect.append_hex(e_data, 16); 1331 1332 return result == expect; 1333 } 1334 }; 1335 #endif // ASMJIT_ARCH_X86 1336 1337 // x86::Compiler - X86Test_AllocRetFloat1 1338 // ====================================== 1339 1340 class X86Test_AllocRetFloat1 : public X86TestCase { 1341 public: 1342 X86Test_AllocRetFloat1() : X86TestCase("AllocRetFloat1") {} 1343 1344 static void add(TestApp& app) { 1345 app.add(new X86Test_AllocRetFloat1()); 1346 } 1347 1348 void compile(x86::Compiler& cc) override { 1349 x86::Vec x = cc.new_xmm_ss("x"); 1350 1351 FuncNode* func_node = cc.add_func(FuncSignature::build<float, float>()); 1352 func_node->set_arg(0, x); 1353 1354 cc.ret(x); 1355 cc.end_func(); 1356 } 1357 1358 bool run(void* _func, String& result, String& expect) override { 1359 using Func = float (*)(float); 1360 Func func = ptr_as_func<Func>(_func); 1361 1362 float result_ret = func(42.0f); 1363 float expect_ret = 42.0f; 1364 1365 result.assign_format("ret={%g}", double(result_ret)); 1366 expect.assign_format("ret={%g}", double(expect_ret)); 1367 1368 return result == expect; 1369 } 1370 }; 1371 1372 // x86::Compiler - X86Test_AllocRetFloat2 1373 // ====================================== 1374 1375 class X86Test_AllocRetFloat2 : public X86TestCase { 1376 public: 1377 X86Test_AllocRetFloat2() : X86TestCase("AllocRetFloat2") {} 1378 1379 static void add(TestApp& app) { 1380 app.add(new X86Test_AllocRetFloat2()); 1381 } 1382 1383 void compile(x86::Compiler& cc) override { 1384 x86::Vec x = cc.new_xmm_ss("x"); 1385 x86::Vec y = cc.new_xmm_ss("y"); 1386 1387 FuncNode* func_node = cc.add_func(FuncSignature::build<float, float, float>()); 1388 func_node->set_arg(0, x); 1389 func_node->set_arg(1, y); 1390 1391 cc.addss(x, y); 1392 cc.ret(x); 1393 1394 cc.end_func(); 1395 } 1396 1397 bool run(void* _func, String& result, String& expect) override { 1398 using Func = float (*)(float, float); 1399 Func func = ptr_as_func<Func>(_func); 1400 1401 float result_ret = func(1.0f, 2.0f); 1402 float expect_ret = 1.0f + 2.0f; 1403 1404 result.assign_format("ret={%g}", double(result_ret)); 1405 expect.assign_format("ret={%g}", double(expect_ret)); 1406 1407 return result == expect; 1408 } 1409 }; 1410 1411 // x86::Compiler - X86Test_AllocRetDouble1 1412 // ======================================= 1413 1414 class X86Test_AllocRetDouble1 : public X86TestCase { 1415 public: 1416 X86Test_AllocRetDouble1() : X86TestCase("AllocRetDouble1") {} 1417 1418 static void add(TestApp& app) { 1419 app.add(new X86Test_AllocRetDouble1()); 1420 } 1421 1422 void compile(x86::Compiler& cc) override { 1423 x86::Vec x = cc.new_xmm_sd("x"); 1424 1425 FuncNode* func_node = cc.add_func(FuncSignature::build<double, double>()); 1426 func_node->set_arg(0, x); 1427 1428 cc.ret(x); 1429 cc.end_func(); 1430 } 1431 1432 bool run(void* _func, String& result, String& expect) override { 1433 using Func = double (*)(double); 1434 Func func = ptr_as_func<Func>(_func); 1435 1436 double result_ret = func(42.0); 1437 double expect_ret = 42.0; 1438 1439 result.assign_format("ret={%g}", result_ret); 1440 expect.assign_format("ret={%g}", expect_ret); 1441 1442 return result == expect; 1443 } 1444 }; 1445 1446 // x86::Compiler - X86Test_AllocRetDouble2 1447 // ======================================= 1448 1449 class X86Test_AllocRetDouble2 : public X86TestCase { 1450 public: 1451 X86Test_AllocRetDouble2() : X86TestCase("AllocRetDouble2") {} 1452 1453 static void add(TestApp& app) { 1454 app.add(new X86Test_AllocRetDouble2()); 1455 } 1456 1457 void compile(x86::Compiler& cc) override { 1458 x86::Vec x = cc.new_xmm_sd("x"); 1459 x86::Vec y = cc.new_xmm_sd("y"); 1460 1461 FuncNode* func_node = cc.add_func(FuncSignature::build<double, double, double>()); 1462 func_node->set_arg(0, x); 1463 func_node->set_arg(1, y); 1464 1465 cc.addsd(x, y); 1466 cc.ret(x); 1467 1468 cc.end_func(); 1469 } 1470 1471 bool run(void* _func, String& result, String& expect) override { 1472 using Func = double (*)(double, double); 1473 Func func = ptr_as_func<Func>(_func); 1474 1475 double result_ret = func(1.0, 2.0); 1476 double expect_ret = 1.0 + 2.0; 1477 1478 result.assign_format("ret={%g}", result_ret); 1479 expect.assign_format("ret={%g}", expect_ret); 1480 1481 return result == expect; 1482 } 1483 }; 1484 1485 // x86::Compiler - X86Test_AllocStack 1486 // ================================== 1487 1488 class X86Test_AllocStack : public X86TestCase { 1489 public: 1490 X86Test_AllocStack() : X86TestCase("AllocStack") {} 1491 1492 static inline constexpr uint32_t kSize = 256u; 1493 1494 static void add(TestApp& app) { 1495 app.add(new X86Test_AllocStack()); 1496 } 1497 1498 void compile(x86::Compiler& cc) override { 1499 cc.add_func(FuncSignature::build<int>()); 1500 1501 x86::Mem stack = cc.new_stack(kSize, 1); 1502 stack.set_size(1); 1503 1504 x86::Gp i = cc.new_gp_ptr("i"); 1505 x86::Gp a = cc.new_gp32("a"); 1506 x86::Gp b = cc.new_gp32("b"); 1507 1508 Label L_1 = cc.new_label(); 1509 Label L_2 = cc.new_label(); 1510 1511 // Fill stack by sequence [0, 1, 2, 3 ... 255]. 1512 cc.xor_(i, i); 1513 1514 x86::Mem stack_with_index = stack.clone(); 1515 stack_with_index.set_index(i, 0); 1516 1517 cc.bind(L_1); 1518 cc.mov(stack_with_index, i.r8()); 1519 cc.inc(i); 1520 cc.cmp(i, 255); 1521 cc.jle(L_1); 1522 1523 // Sum sequence in stack. 1524 cc.xor_(i, i); 1525 cc.xor_(a, a); 1526 1527 cc.bind(L_2); 1528 cc.movzx(b, stack_with_index); 1529 cc.add(a, b); 1530 cc.inc(i); 1531 cc.cmp(i, 255); 1532 cc.jle(L_2); 1533 1534 cc.ret(a); 1535 cc.end_func(); 1536 } 1537 1538 bool run(void* _func, String& result, String& expect) override { 1539 using Func = int (*)(void); 1540 Func func = ptr_as_func<Func>(_func); 1541 1542 int result_ret = func(); 1543 int expect_ret = 32640; 1544 1545 result.assign_int(result_ret); 1546 expect.assign_int(expect_ret); 1547 1548 return result == expect; 1549 } 1550 }; 1551 1552 // x86::Compiler - X86Test_Imul1 1553 // ============================= 1554 1555 class X86Test_Imul1 : public X86TestCase { 1556 public: 1557 X86Test_Imul1() : X86TestCase("Imul1") {} 1558 1559 static void add(TestApp& app) { 1560 app.add(new X86Test_Imul1()); 1561 } 1562 1563 void compile(x86::Compiler& cc) override { 1564 x86::Gp dst_hi = cc.new_gp_ptr("dst_hi"); 1565 x86::Gp dst_lo = cc.new_gp_ptr("dst_lo"); 1566 1567 x86::Gp v_hi = cc.new_gp32("v_hi"); 1568 x86::Gp v_lo = cc.new_gp32("v_lo"); 1569 x86::Gp src = cc.new_gp32("src"); 1570 1571 FuncNode* func_node = cc.add_func(FuncSignature::build<void, int*, int*, int, int>()); 1572 func_node->set_arg(0, dst_hi); 1573 func_node->set_arg(1, dst_lo); 1574 func_node->set_arg(2, v_lo); 1575 func_node->set_arg(3, src); 1576 1577 cc.imul(v_hi, v_lo, src); 1578 cc.mov(x86::dword_ptr(dst_hi), v_hi); 1579 cc.mov(x86::dword_ptr(dst_lo), v_lo); 1580 cc.end_func(); 1581 } 1582 1583 bool run(void* _func, String& result, String& expect) override { 1584 using Func = void (*)(int*, int*, int, int); 1585 Func func = ptr_as_func<Func>(_func); 1586 1587 int v0 = 4; 1588 int v1 = 4; 1589 1590 int result_hi = 0; 1591 int result_lo = 0; 1592 1593 int expect_hi = 0; 1594 int expect_lo = v0 * v1; 1595 1596 func(&result_hi, &result_lo, v0, v1); 1597 1598 result.assign_format("hi=%d, lo=%d", result_hi, result_lo); 1599 expect.assign_format("hi=%d, lo=%d", expect_hi, expect_lo); 1600 1601 return result_hi == expect_hi && result_lo == expect_lo; 1602 } 1603 }; 1604 1605 // x86::Compiler - X86Test_Imul2 1606 // ============================= 1607 1608 class X86Test_Imul2 : public X86TestCase { 1609 public: 1610 X86Test_Imul2() : X86TestCase("Imul2") {} 1611 1612 static void add(TestApp& app) { 1613 app.add(new X86Test_Imul2()); 1614 } 1615 1616 void compile(x86::Compiler& cc) override { 1617 x86::Gp dst = cc.new_gp_ptr("dst"); 1618 x86::Gp src = cc.new_gp_ptr("src"); 1619 1620 FuncNode* func_node = cc.add_func(FuncSignature::build<void, int*, const int*>()); 1621 func_node->set_arg(0, dst); 1622 func_node->set_arg(1, src); 1623 1624 for (unsigned int i = 0; i < 4; i++) { 1625 x86::Gp x = cc.new_gp32("x"); 1626 x86::Gp y = cc.new_gp32("y"); 1627 x86::Gp hi = cc.new_gp32("hi"); 1628 1629 cc.mov(x, x86::dword_ptr(src, 0)); 1630 cc.mov(y, x86::dword_ptr(src, 4)); 1631 1632 cc.imul(hi, x, y); 1633 cc.add(x86::dword_ptr(dst, 0), hi); 1634 cc.add(x86::dword_ptr(dst, 4), x); 1635 } 1636 1637 cc.end_func(); 1638 } 1639 1640 bool run(void* _func, String& result, String& expect) override { 1641 using Func = void (*)(int*, const int*); 1642 Func func = ptr_as_func<Func>(_func); 1643 1644 int src[2] = { 4, 9 }; 1645 int result_ret[2] = { 0, 0 }; 1646 int expect_ret[2] = { 0, (4 * 9) * 4 }; 1647 1648 func(result_ret, src); 1649 1650 result.assign_format("ret={%d, %d}", result_ret[0], result_ret[1]); 1651 expect.assign_format("ret={%d, %d}", expect_ret[0], expect_ret[1]); 1652 1653 return result_ret[0] == expect_ret[0] && result_ret[1] == expect_ret[1]; 1654 } 1655 }; 1656 1657 // x86::Compiler - X86Test_Idiv1 1658 // ============================= 1659 1660 class X86Test_Idiv1 : public X86TestCase { 1661 public: 1662 X86Test_Idiv1() : X86TestCase("Idiv1") {} 1663 1664 static void add(TestApp& app) { 1665 app.add(new X86Test_Idiv1()); 1666 } 1667 1668 void compile(x86::Compiler& cc) override { 1669 x86::Gp a = cc.new_gp32("a"); 1670 x86::Gp b = cc.new_gp32("b"); 1671 x86::Gp dummy = cc.new_gp32("dummy"); 1672 1673 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int>()); 1674 func_node->set_arg(0, a); 1675 func_node->set_arg(1, b); 1676 1677 cc.xor_(dummy, dummy); 1678 cc.idiv(dummy, a, b); 1679 1680 cc.ret(a); 1681 cc.end_func(); 1682 } 1683 1684 bool run(void* _func, String& result, String& expect) override { 1685 using Func = int (*)(int, int); 1686 Func func = ptr_as_func<Func>(_func); 1687 1688 int v0 = 2999; 1689 int v1 = 245; 1690 1691 int result_ret = func(v0, v1); 1692 int expect_ret = 2999 / 245; 1693 1694 result.assign_format("result=%d", result_ret); 1695 expect.assign_format("result=%d", expect_ret); 1696 1697 return result == expect; 1698 } 1699 }; 1700 1701 // x86::Compiler - X86Test_Setz 1702 // ============================ 1703 1704 class X86Test_Setz : public X86TestCase { 1705 public: 1706 X86Test_Setz() : X86TestCase("Setz") {} 1707 1708 static void add(TestApp& app) { 1709 app.add(new X86Test_Setz()); 1710 } 1711 1712 void compile(x86::Compiler& cc) override { 1713 x86::Gp src0 = cc.new_gp32("src0"); 1714 x86::Gp src1 = cc.new_gp32("src1"); 1715 x86::Gp dst0 = cc.new_gp_ptr("dst0"); 1716 1717 FuncNode* func_node = cc.add_func(FuncSignature::build<void, int, int, char*>()); 1718 func_node->set_arg(0, src0); 1719 func_node->set_arg(1, src1); 1720 func_node->set_arg(2, dst0); 1721 1722 cc.cmp(src0, src1); 1723 cc.setz(x86::byte_ptr(dst0)); 1724 1725 cc.end_func(); 1726 } 1727 1728 bool run(void* _func, String& result, String& expect) override { 1729 using Func = void (*)(int, int, char*); 1730 Func func = ptr_as_func<Func>(_func); 1731 1732 char result_buf[4] {}; 1733 char expect_buf[4] = { 1, 0, 0, 1 }; 1734 1735 func(0, 0, &result_buf[0]); // We are expecting 1 (0 == 0). 1736 func(0, 1, &result_buf[1]); // We are expecting 0 (0 != 1). 1737 func(1, 0, &result_buf[2]); // We are expecting 0 (1 != 0). 1738 func(1, 1, &result_buf[3]); // We are expecting 1 (1 == 1). 1739 1740 result.assign_format("out={%d, %d, %d, %d}", result_buf[0], result_buf[1], result_buf[2], result_buf[3]); 1741 expect.assign_format("out={%d, %d, %d, %d}", expect_buf[0], expect_buf[1], expect_buf[2], expect_buf[3]); 1742 1743 return result_buf[0] == expect_buf[0] && 1744 result_buf[1] == expect_buf[1] && 1745 result_buf[2] == expect_buf[2] && 1746 result_buf[3] == expect_buf[3] ; 1747 } 1748 }; 1749 1750 // x86::Compiler - X86Test_ShlRor 1751 // ============================== 1752 1753 class X86Test_ShlRor : public X86TestCase { 1754 public: 1755 X86Test_ShlRor() : X86TestCase("ShlRor") {} 1756 1757 static void add(TestApp& app) { 1758 app.add(new X86Test_ShlRor()); 1759 } 1760 1761 void compile(x86::Compiler& cc) override { 1762 x86::Gp dst = cc.new_gp_ptr("dst"); 1763 x86::Gp var = cc.new_gp32("var"); 1764 x86::Gp v_shl_param = cc.new_gp32("v_shl_param"); 1765 x86::Gp v_ror_param = cc.new_gp32("v_ror_param"); 1766 1767 FuncNode* func_node = cc.add_func(FuncSignature::build<void, int*, int, int, int>()); 1768 func_node->set_arg(0, dst); 1769 func_node->set_arg(1, var); 1770 func_node->set_arg(2, v_shl_param); 1771 func_node->set_arg(3, v_ror_param); 1772 1773 cc.shl(var, v_shl_param); 1774 cc.ror(var, v_ror_param); 1775 cc.mov(x86::dword_ptr(dst), var); 1776 cc.end_func(); 1777 } 1778 1779 bool run(void* _func, String& result, String& expect) override { 1780 using Func = void (*)(int*, int, int, int); 1781 Func func = ptr_as_func<Func>(_func); 1782 1783 int v0 = 0x000000FF; 1784 1785 int result_ret = 0; 1786 int expect_ret = 0x0000FF00; 1787 1788 func(&result_ret, v0, 16, 8); 1789 1790 result.assign_format("ret=%d", result_ret); 1791 expect.assign_format("ret=%d", expect_ret); 1792 1793 return result == expect; 1794 } 1795 }; 1796 1797 // x86::Compiler - X86Test_GpbLo 1798 // ============================= 1799 1800 class X86Test_GpbLo1 : public X86TestCase { 1801 public: 1802 X86Test_GpbLo1() : X86TestCase("GpbLo1") {} 1803 1804 static inline constexpr uint32_t kCount = 32u; 1805 1806 static void add(TestApp& app) { 1807 app.add(new X86Test_GpbLo1()); 1808 } 1809 1810 void compile(x86::Compiler& cc) override { 1811 x86::Gp reg_Ptr = cc.new_gp_ptr("reg_Ptr"); 1812 x86::Gp sum = cc.new_gp32("sum"); 1813 x86::Gp x[kCount]; 1814 1815 FuncNode* func_node = cc.add_func(FuncSignature::build<uint32_t, uint32_t*>()); 1816 func_node->set_arg(0, reg_Ptr); 1817 1818 for (uint32_t i = 0; i < kCount; i++) { 1819 x[i] = cc.new_gp32("x%u", i); 1820 } 1821 1822 // Init pseudo-regs with values from our array. 1823 for (uint32_t i = 0; i < kCount; i++) { 1824 cc.mov(x[i], x86::dword_ptr(reg_Ptr, int(i * 4))); 1825 } 1826 1827 for (uint32_t i = 2; i < kCount; i++) { 1828 // Add and truncate to 8 bit; no purpose, just mess with jit. 1829 cc.add (x[i ], x[i-1]); 1830 cc.movzx(x[i ], x[i ].r8()); 1831 cc.movzx(x[i-2], x[i-1].r8()); 1832 cc.movzx(x[i-1], x[i-2].r8()); 1833 } 1834 1835 // Sum up all computed values. 1836 cc.mov(sum, 0); 1837 for (uint32_t i = 0; i < kCount; i++) { 1838 cc.add(sum, x[i]); 1839 } 1840 1841 // Return the sum. 1842 cc.ret(sum); 1843 cc.end_func(); 1844 } 1845 1846 bool run(void* _func, String& result, String& expect) override { 1847 using Func = uint32_t (*)(uint32_t*); 1848 Func func = ptr_as_func<Func>(_func); 1849 1850 uint32_t i; 1851 uint32_t buf[kCount]; 1852 uint32_t result_ret = 0; 1853 uint32_t expect_ret = 0; 1854 1855 for (i = 0; i < kCount; i++) { 1856 buf[i] = 1; 1857 } 1858 1859 for (i = 2; i < kCount; i++) { 1860 buf[i ]+= buf[i-1]; 1861 buf[i ] = buf[i ] & 0xFF; 1862 buf[i-2] = buf[i-1] & 0xFF; 1863 buf[i-1] = buf[i-2] & 0xFF; 1864 } 1865 1866 for (i = 0; i < kCount; i++) { 1867 expect_ret += buf[i]; 1868 } 1869 1870 for (i = 0; i < kCount; i++) { 1871 buf[i] = 1; 1872 } 1873 result_ret = func(buf); 1874 1875 result.assign_format("ret=%d", result_ret); 1876 expect.assign_format("ret=%d", expect_ret); 1877 1878 return result == expect; 1879 } 1880 }; 1881 1882 // x86::Compiler - X86Test_GpbLo2 1883 // ============================== 1884 1885 class X86Test_GpbLo2 : public X86TestCase { 1886 public: 1887 X86Test_GpbLo2() : X86TestCase("GpbLo2") {} 1888 1889 static void add(TestApp& app) { 1890 app.add(new X86Test_GpbLo2()); 1891 } 1892 1893 void compile(x86::Compiler& cc) override { 1894 x86::Gp v = cc.new_gp32("v"); 1895 1896 FuncNode* func_node = cc.add_func(FuncSignature::build<uint32_t, uint32_t>()); 1897 func_node->set_arg(0, v); 1898 1899 cc.mov(v.r8(), 0xFF); 1900 cc.ret(v); 1901 cc.end_func(); 1902 } 1903 1904 bool run(void* _func, String& result, String& expect) override { 1905 using Func = uint32_t (*)(uint32_t); 1906 Func func = ptr_as_func<Func>(_func); 1907 1908 uint32_t result_ret = func(0x12345678u); 1909 uint32_t expect_ret = 0x123456FFu; 1910 1911 result.assign_format("ret=%d", result_ret); 1912 expect.assign_format("ret=%d", expect_ret); 1913 1914 return result == expect; 1915 } 1916 }; 1917 1918 // x86::Compiler - X86Test_RepMovsb 1919 // ================================ 1920 1921 class X86Test_RepMovsb : public X86TestCase { 1922 public: 1923 X86Test_RepMovsb() : X86TestCase("RepMovsb") {} 1924 1925 static void add(TestApp& app) { 1926 app.add(new X86Test_RepMovsb()); 1927 } 1928 1929 void compile(x86::Compiler& cc) override { 1930 x86::Gp dst = cc.new_gp_ptr("dst"); 1931 x86::Gp src = cc.new_gp_ptr("src"); 1932 x86::Gp cnt = cc.new_gp_ptr("cnt"); 1933 1934 FuncNode* func_node = cc.add_func(FuncSignature::build<void, void*, void*, size_t>()); 1935 func_node->set_arg(0, dst); 1936 func_node->set_arg(1, src); 1937 func_node->set_arg(2, cnt); 1938 1939 cc.rep(cnt).movs(x86::byte_ptr(dst), x86::byte_ptr(src)); 1940 cc.end_func(); 1941 } 1942 1943 bool run(void* _func, String& result, String& expect) override { 1944 using Func = void (*)(void*, void*, size_t); 1945 Func func = ptr_as_func<Func>(_func); 1946 1947 char dst[20] = { 0 }; 1948 char src[20] = "Hello AsmJit!"; 1949 func(dst, src, strlen(src) + 1); 1950 1951 result.assign_format("ret=\"%s\"", dst); 1952 expect.assign_format("ret=\"%s\"", src); 1953 1954 return result == expect; 1955 } 1956 }; 1957 1958 // x86::Compiler - X86Test_IfElse1 1959 // =============================== 1960 1961 class X86Test_IfElse1 : public X86TestCase { 1962 public: 1963 X86Test_IfElse1() : X86TestCase("IfElse1") {} 1964 1965 static void add(TestApp& app) { 1966 app.add(new X86Test_IfElse1()); 1967 } 1968 1969 void compile(x86::Compiler& cc) override { 1970 x86::Gp v1 = cc.new_gp32("v1"); 1971 x86::Gp v2 = cc.new_gp32("v2"); 1972 1973 Label L_1 = cc.new_label(); 1974 Label L_2 = cc.new_label(); 1975 1976 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int>()); 1977 func_node->set_arg(0, v1); 1978 func_node->set_arg(1, v2); 1979 1980 cc.cmp(v1, v2); 1981 cc.jg(L_1); 1982 1983 cc.mov(v1, 1); 1984 cc.jmp(L_2); 1985 1986 cc.bind(L_1); 1987 cc.mov(v1, 2); 1988 1989 cc.bind(L_2); 1990 cc.ret(v1); 1991 cc.end_func(); 1992 } 1993 1994 bool run(void* _func, String& result, String& expect) override { 1995 using Func = int (*)(int, int); 1996 Func func = ptr_as_func<Func>(_func); 1997 1998 int a = func(0, 1); 1999 int b = func(1, 0); 2000 2001 result.append_format("ret={%d, %d}", a, b); 2002 expect.append_format("ret={%d, %d}", 1, 2); 2003 2004 return result == expect; 2005 } 2006 }; 2007 2008 // x86::Compiler - X86Test_IfElse2 2009 // =============================== 2010 2011 class X86Test_IfElse2 : public X86TestCase { 2012 public: 2013 X86Test_IfElse2() : X86TestCase("IfElse2") {} 2014 2015 static void add(TestApp& app) { 2016 app.add(new X86Test_IfElse2()); 2017 } 2018 2019 void compile(x86::Compiler& cc) override { 2020 x86::Gp v1 = cc.new_gp32("v1"); 2021 x86::Gp v2 = cc.new_gp32("v2"); 2022 2023 Label L_1 = cc.new_label(); 2024 Label L_2 = cc.new_label(); 2025 Label L_3 = cc.new_label(); 2026 Label L_4 = cc.new_label(); 2027 2028 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int>()); 2029 func_node->set_arg(0, v1); 2030 func_node->set_arg(1, v2); 2031 2032 cc.jmp(L_1); 2033 cc.bind(L_2); 2034 cc.jmp(L_4); 2035 cc.bind(L_1); 2036 2037 cc.cmp(v1, v2); 2038 cc.jg(L_3); 2039 2040 cc.mov(v1, 1); 2041 cc.jmp(L_2); 2042 2043 cc.bind(L_3); 2044 cc.mov(v1, 2); 2045 cc.jmp(L_2); 2046 2047 cc.bind(L_4); 2048 2049 cc.ret(v1); 2050 cc.end_func(); 2051 } 2052 2053 bool run(void* _func, String& result, String& expect) override { 2054 using Func = int (*)(int, int); 2055 Func func = ptr_as_func<Func>(_func); 2056 2057 int a = func(0, 1); 2058 int b = func(1, 0); 2059 2060 result.append_format("ret={%d, %d}", a, b); 2061 expect.append_format("ret={%d, %d}", 1, 2); 2062 2063 return result == expect; 2064 } 2065 }; 2066 2067 // x86::Compiler - X86Test_IfElse3 2068 // =============================== 2069 2070 class X86Test_IfElse3 : public X86TestCase { 2071 public: 2072 X86Test_IfElse3() : X86TestCase("IfElse3") {} 2073 2074 static void add(TestApp& app) { 2075 app.add(new X86Test_IfElse3()); 2076 } 2077 2078 void compile(x86::Compiler& cc) override { 2079 x86::Gp v1 = cc.new_gp32("v1"); 2080 x86::Gp v2 = cc.new_gp32("v2"); 2081 x86::Gp counter = cc.new_gp32("counter"); 2082 2083 Label L_1 = cc.new_label(); 2084 Label L_Loop = cc.new_label(); 2085 Label L_Exit = cc.new_label(); 2086 2087 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int>()); 2088 func_node->set_arg(0, v1); 2089 func_node->set_arg(1, v2); 2090 2091 cc.cmp(v1, v2); 2092 cc.jg(L_1); 2093 2094 cc.mov(counter, 0); 2095 2096 cc.bind(L_Loop); 2097 cc.mov(v1, counter); 2098 2099 cc.inc(counter); 2100 cc.cmp(counter, 1); 2101 cc.jle(L_Loop); 2102 cc.jmp(L_Exit); 2103 2104 cc.bind(L_1); 2105 cc.mov(v1, 2); 2106 2107 cc.bind(L_Exit); 2108 cc.ret(v1); 2109 cc.end_func(); 2110 } 2111 2112 bool run(void* _func, String& result, String& expect) override { 2113 using Func = int (*)(int, int); 2114 Func func = ptr_as_func<Func>(_func); 2115 2116 int a = func(0, 1); 2117 int b = func(1, 0); 2118 2119 result.append_format("ret={%d, %d}", a, b); 2120 expect.append_format("ret={%d, %d}", 1, 2); 2121 2122 return result == expect; 2123 } 2124 }; 2125 2126 // x86::Compiler - X86Test_IfElse4 2127 // =============================== 2128 2129 class X86Test_IfElse4 : public X86TestCase { 2130 public: 2131 X86Test_IfElse4() : X86TestCase("IfElse4") {} 2132 2133 static void add(TestApp& app) { 2134 app.add(new X86Test_IfElse4()); 2135 } 2136 2137 void compile(x86::Compiler& cc) override { 2138 x86::Gp v1 = cc.new_gp32("v1"); 2139 x86::Gp v2 = cc.new_gp32("v2"); 2140 x86::Gp counter = cc.new_gp32("counter"); 2141 2142 Label L_1 = cc.new_label(); 2143 Label L_Loop1 = cc.new_label(); 2144 Label L_Loop2 = cc.new_label(); 2145 Label L_Exit = cc.new_label(); 2146 2147 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int>()); 2148 func_node->set_arg(0, v1); 2149 func_node->set_arg(1, v2); 2150 2151 cc.mov(counter, 0); 2152 cc.cmp(v1, v2); 2153 cc.jg(L_1); 2154 2155 cc.bind(L_Loop1); 2156 cc.mov(v1, counter); 2157 2158 cc.inc(counter); 2159 cc.cmp(counter, 1); 2160 cc.jle(L_Loop1); 2161 cc.jmp(L_Exit); 2162 2163 cc.bind(L_1); 2164 cc.bind(L_Loop2); 2165 cc.mov(v1, counter); 2166 cc.inc(counter); 2167 cc.cmp(counter, 2); 2168 cc.jle(L_Loop2); 2169 2170 cc.bind(L_Exit); 2171 cc.ret(v1); 2172 cc.end_func(); 2173 } 2174 2175 bool run(void* _func, String& result, String& expect) override { 2176 using Func = int (*)(int, int); 2177 Func func = ptr_as_func<Func>(_func); 2178 2179 int a = func(0, 1); 2180 int b = func(1, 0); 2181 2182 result.append_format("ret={%d, %d}", a, b); 2183 expect.append_format("ret={%d, %d}", 1, 2); 2184 2185 return result == expect; 2186 } 2187 }; 2188 2189 // x86::Compiler - X86Test_Memcpy 2190 // ============================== 2191 2192 class X86Test_Memcpy : public X86TestCase { 2193 public: 2194 X86Test_Memcpy() : X86TestCase("Memcpy") {} 2195 2196 static inline constexpr uint32_t kCount = 32u; 2197 2198 static void add(TestApp& app) { 2199 app.add(new X86Test_Memcpy()); 2200 } 2201 2202 void compile(x86::Compiler& cc) override { 2203 x86::Gp dst = cc.new_gp_ptr("dst"); 2204 x86::Gp src = cc.new_gp_ptr("src"); 2205 x86::Gp cnt = cc.new_gp_ptr("cnt"); 2206 2207 Label L_Loop = cc.new_label(); // Create base labels we use 2208 Label L_Exit = cc.new_label(); // in our function. 2209 2210 FuncNode* func_node = cc.add_func(FuncSignature::build<void, uint32_t*, const uint32_t*, size_t>()); 2211 func_node->set_arg(0, dst); 2212 func_node->set_arg(1, src); 2213 func_node->set_arg(2, cnt); 2214 2215 cc.test(cnt, cnt); // Exit if the size is zero. 2216 cc.jz(L_Exit); 2217 2218 cc.bind(L_Loop); // Bind the loop label here. 2219 2220 x86::Gp tmp = cc.new_gp32("tmp"); // Copy a single dword (4 bytes). 2221 cc.mov(tmp, x86::dword_ptr(src)); 2222 cc.mov(x86::dword_ptr(dst), tmp); 2223 2224 cc.add(src, 4); // Increment dst/src pointers. 2225 cc.add(dst, 4); 2226 2227 cc.dec(cnt); // Loop until cnt isn't zero. 2228 cc.jnz(L_Loop); 2229 2230 cc.bind(L_Exit); // Bind the exit label here. 2231 cc.end_func(); // End of function. 2232 } 2233 2234 bool run(void* _func, String& result, String& expect) override { 2235 using Func = void (*)(uint32_t*, const uint32_t*, size_t); 2236 Func func = ptr_as_func<Func>(_func); 2237 2238 uint32_t i; 2239 2240 uint32_t dst_buffer[kCount]; 2241 uint32_t src_buffer[kCount]; 2242 2243 for (i = 0; i < kCount; i++) { 2244 dst_buffer[i] = 0; 2245 src_buffer[i] = i; 2246 } 2247 2248 func(dst_buffer, src_buffer, kCount); 2249 2250 result.assign("buf={"); 2251 expect.assign("buf={"); 2252 2253 for (i = 0; i < kCount; i++) { 2254 if (i != 0) { 2255 result.append(", "); 2256 expect.append(", "); 2257 } 2258 2259 result.append_format("%u", unsigned(dst_buffer[i])); 2260 expect.append_format("%u", unsigned(src_buffer[i])); 2261 } 2262 2263 result.append("}"); 2264 expect.append("}"); 2265 2266 return result == expect; 2267 } 2268 }; 2269 2270 // x86::Compiler - X86Test_ExtraBlock 2271 // ================================== 2272 2273 class X86Test_ExtraBlock : public X86TestCase { 2274 public: 2275 X86Test_ExtraBlock() : X86TestCase("ExtraBlock") {} 2276 2277 static void add(TestApp& app) { 2278 app.add(new X86Test_ExtraBlock()); 2279 } 2280 2281 void compile(x86::Compiler& cc) override { 2282 x86::Gp cond = cc.new_gp32("cond"); 2283 x86::Gp ret = cc.new_gp32("ret"); 2284 x86::Gp a = cc.new_gp32("a"); 2285 x86::Gp b = cc.new_gp32("b"); 2286 2287 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int, int>()); 2288 func_node->set_arg(0, cond); 2289 func_node->set_arg(1, a); 2290 func_node->set_arg(2, b); 2291 2292 Label L_Ret = cc.new_label(); 2293 Label L_Extra = cc.new_label(); 2294 2295 cc.test(cond, cond); 2296 cc.jnz(L_Extra); 2297 2298 cc.mov(ret, a); 2299 cc.add(ret, b); 2300 2301 cc.bind(L_Ret); 2302 cc.ret(ret); 2303 2304 // Emit code sequence at the end of the function. 2305 BaseNode* prev_cursor = cc.set_cursor(func_node->end_node()->prev()); 2306 cc.bind(L_Extra); 2307 cc.mov(ret, a); 2308 cc.sub(ret, b); 2309 cc.jmp(L_Ret); 2310 cc.set_cursor(prev_cursor); 2311 2312 cc.end_func(); 2313 } 2314 2315 bool run(void* _func, String& result, String& expect) override { 2316 using Func = int (*)(int, int, int); 2317 Func func = ptr_as_func<Func>(_func); 2318 2319 int ret1 = func(0, 4, 5); 2320 int ret2 = func(1, 4, 5); 2321 2322 int exp1 = 4 + 5; 2323 int exp2 = 4 - 5; 2324 2325 result.assign_format("ret={%d, %d}", ret1, ret2); 2326 expect.assign_format("ret={%d, %d}", exp1, exp2); 2327 2328 return result == expect; 2329 } 2330 }; 2331 2332 // x86::Compiler - X86Test_AlphaBlend 2333 // ================================== 2334 2335 class X86Test_AlphaBlend : public X86TestCase { 2336 public: 2337 X86Test_AlphaBlend() : X86TestCase("AlphaBlend") {} 2338 2339 static inline constexpr uint32_t kCount = 17u; 2340 2341 static void add(TestApp& app) { 2342 app.add(new X86Test_AlphaBlend()); 2343 } 2344 2345 static uint32_t blend_src_over(uint32_t d, uint32_t s) { 2346 uint32_t sa_inv = ~s >> 24; 2347 2348 uint32_t d_20 = (d ) & 0x00FF00FF; 2349 uint32_t d_31 = (d >> 8) & 0x00FF00FF; 2350 2351 d_20 *= sa_inv; 2352 d_31 *= sa_inv; 2353 2354 d_20 = ((d_20 + ((d_20 >> 8) & 0x00FF00FFu) + 0x00800080u) & 0xFF00FF00u) >> 8; 2355 d_31 = ((d_31 + ((d_31 >> 8) & 0x00FF00FFu) + 0x00800080u) & 0xFF00FF00u); 2356 2357 return d_20 + d_31 + s; 2358 } 2359 2360 void compile(x86::Compiler& cc) override { 2361 asmtest::generate_sse_alpha_blend(cc, true); 2362 } 2363 2364 bool run(void* _func, String& result, String& expect) override { 2365 using Func = void (*)(void*, const void*, size_t); 2366 Func func = ptr_as_func<Func>(_func); 2367 2368 static const uint32_t dst_const_data[] = { 0x00000000, 0x10101010, 0x20100804, 0x30200003, 0x40204040, 0x5000004D, 0x60302E2C, 0x706F6E6D, 0x807F4F2F, 0x90349001, 0xA0010203, 0xB03204AB, 0xC023AFBD, 0xD0D0D0C0, 0xE0AABBCC, 0xFFFFFFFF, 0xF8F4F2F1 }; 2369 static const uint32_t src_const_data[] = { 0xE0E0E0E0, 0xA0008080, 0x341F1E1A, 0xFEFEFEFE, 0x80302010, 0x49490A0B, 0x998F7798, 0x00000000, 0x01010101, 0xA0264733, 0xBAB0B1B9, 0xFF000000, 0xDAB0A0C1, 0xE0BACFDA, 0x99887766, 0xFFFFFF80, 0xEE0A5FEC }; 2370 2371 uint32_t dst_buffer_storage[kCount + 3]; 2372 uint32_t src_buffer_storage[kCount + 3]; 2373 2374 // Has to be aligned. 2375 uint32_t* dst_buffer = (uint32_t*)Support::align_up<intptr_t>((intptr_t)dst_buffer_storage, 16); 2376 uint32_t* src_buffer = (uint32_t*)Support::align_up<intptr_t>((intptr_t)src_buffer_storage, 16); 2377 2378 memcpy(dst_buffer, dst_const_data, sizeof(dst_const_data)); 2379 memcpy(src_buffer, src_const_data, sizeof(src_const_data)); 2380 2381 uint32_t i; 2382 uint32_t exp_buffer[kCount]; 2383 2384 for (i = 0; i < kCount; i++) { 2385 exp_buffer[i] = blend_src_over(dst_buffer[i], src_buffer[i]); 2386 } 2387 2388 func(dst_buffer, src_buffer, kCount); 2389 2390 result.assign("buf={"); 2391 expect.assign("buf={"); 2392 2393 for (i = 0; i < kCount; i++) { 2394 if (i != 0) { 2395 result.append(", "); 2396 expect.append(", "); 2397 } 2398 2399 result.append_format("%08X", unsigned(dst_buffer[i])); 2400 expect.append_format("%08X", unsigned(exp_buffer[i])); 2401 } 2402 2403 result.append("}"); 2404 expect.append("}"); 2405 2406 return result == expect; 2407 } 2408 }; 2409 2410 // x86::Compiler - X86Test_AVX512_KK 2411 // ================================= 2412 2413 class X86Test_AVX512_KK : public X86TestCase { 2414 public: 2415 X86Test_AVX512_KK() : X86TestCase("AVX512_KK") {} 2416 2417 static void add(TestApp& app) { 2418 const CpuInfo& cpu_info = CpuInfo::host(); 2419 2420 if (cpu_info.features().x86().has_avx512_f()) { 2421 app.add(new X86Test_AVX512_KK()); 2422 } 2423 } 2424 2425 void compile(x86::Compiler& cc) override { 2426 FuncNode* func_node = cc.add_func(FuncSignature::build<uint32_t, const void*, const void*, uint32_t>()); 2427 2428 x86::Gp a = cc.new_gp_ptr("a"); 2429 x86::Gp b = cc.new_gp_ptr("b"); 2430 x86::Gp pred = cc.new_gp32("pred"); 2431 x86::Gp result = cc.new_gp32("result"); 2432 2433 x86::Vec va = cc.new_zmm("va"); 2434 x86::Vec vb = cc.new_zmm("vb"); 2435 x86::KReg k_in = cc.new_kd("k_in"); 2436 x86::KReg k_out = cc.new_kd("k_out"); 2437 2438 func_node->set_arg(0, a); 2439 func_node->set_arg(1, b); 2440 func_node->set_arg(2, pred); 2441 2442 cc.vmovdqu32(va, x86::ptr(a)); 2443 cc.vmovdqu32(vb, x86::ptr(b)); 2444 cc.kmovd(k_in, pred); 2445 cc.k(k_in).vpcmpeqd(k_out, va, vb); 2446 cc.kmovd(result, k_out); 2447 cc.ret(result); 2448 cc.end_func(); 2449 } 2450 2451 bool run(void* _func, String& result, String& expect) override { 2452 using Func = uint32_t (*)(const void*, const void*, uint32_t pred_k); 2453 Func func = ptr_as_func<Func>(_func); 2454 2455 static const uint32_t src_a[16] = { 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 }; 2456 static const uint32_t src_b[16] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1 }; 2457 2458 uint32_t ret = func(src_a, src_b, 0xF0F0); 2459 2460 result.assign_format("0x%08X", ret); 2461 expect.assign_format("0x%08X", 0xA040u); 2462 2463 return result == expect; 2464 } 2465 }; 2466 2467 // x86::Compiler - X86Test_AVX512_TernLog 2468 // ====================================== 2469 2470 class X86Test_AVX512_TernLog : public X86TestCase { 2471 public: 2472 X86Test_AVX512_TernLog() : X86TestCase("AVX512_TernLog") {} 2473 2474 static void add(TestApp& app) { 2475 const CpuInfo& cpu_info = CpuInfo::host(); 2476 2477 if (cpu_info.features().x86().has_avx512_f()) { 2478 app.add(new X86Test_AVX512_TernLog()); 2479 } 2480 } 2481 2482 void compile(x86::Compiler& cc) override { 2483 FuncNode* func_node = cc.add_func(FuncSignature::build<void, void*>()); 2484 2485 x86::Gp out_ptr = cc.new_gp_ptr("out_ptr"); 2486 x86::Vec vec = cc.new_zmm("vec"); 2487 2488 func_node->set_arg(0, out_ptr); 2489 2490 cc.vpternlogd(vec, vec, vec, 0xFFu); 2491 cc.vmovdqu8(x86::ptr(out_ptr), vec); 2492 cc.end_func(); 2493 } 2494 2495 bool run(void* _func, String& result, String& expect) override { 2496 using Func = void (*)(void*); 2497 Func func = ptr_as_func<Func>(_func); 2498 2499 uint32_t out[16] {}; 2500 func(out); 2501 2502 result.assign("{"); 2503 expect.assign("{"); 2504 2505 for (uint32_t i = 0; i < 16; i++) { 2506 if (i) { 2507 result.append(", "); 2508 expect.append(", "); 2509 } 2510 result.append_format("0x%08X", out[i]); 2511 expect.append_format("0x%08X", 0xFFFFFFFFu); 2512 } 2513 2514 result.append("}"); 2515 expect.append("}"); 2516 2517 return result == expect; 2518 } 2519 }; 2520 2521 // x86::Compiler - X86Test_FuncArgInt8 2522 // =================================== 2523 2524 class X86Test_FuncArgInt8 : public X86TestCase { 2525 public: 2526 X86Test_FuncArgInt8() : X86TestCase("FuncArgInt8") {} 2527 2528 static void add(TestApp& app) { 2529 app.add(new X86Test_FuncArgInt8()); 2530 } 2531 2532 void compile(x86::Compiler& cc) override { 2533 x86::Gp v0 = cc.new_gp32("v0"); 2534 x86::Gp v1 = cc.new_gp32("v1"); 2535 2536 FuncNode* func_node = cc.add_func(FuncSignature::build<unsigned, uint8_t, uint8_t, uint32_t>()); 2537 func_node->set_arg(0, v0); 2538 func_node->set_arg(1, v1); 2539 2540 cc.add(v0, v1); 2541 2542 cc.ret(v0); 2543 cc.end_func(); 2544 } 2545 2546 bool run(void* _func, String& result, String& expect) override { 2547 using Func = uint32_t (*)(uint8_t, uint8_t, uint32_t); 2548 Func func = ptr_as_func<Func>(_func); 2549 2550 uint32_t arg = uint32_t(uintptr_t(_func) & 0xFFFFFFFF); 2551 2552 unsigned result_ret = func(uint8_t(arg & 0xFF), uint8_t(arg & 0xFF), arg); 2553 unsigned expect_ret = (arg & 0xFF) * 2; 2554 2555 result.assign_format("ret=%u", result_ret); 2556 expect.assign_format("ret=%u", expect_ret); 2557 2558 return result == expect; 2559 } 2560 }; 2561 2562 // x86::Compiler - X86Test_FuncCallBase1 2563 // ===================================== 2564 2565 class X86Test_FuncCallBase1 : public X86TestCase { 2566 public: 2567 X86Test_FuncCallBase1() : X86TestCase("FuncCallBase1") {} 2568 2569 static void add(TestApp& app) { 2570 app.add(new X86Test_FuncCallBase1()); 2571 } 2572 2573 void compile(x86::Compiler& cc) override { 2574 x86::Gp v0 = cc.new_gp32("v0"); 2575 x86::Gp v1 = cc.new_gp32("v1"); 2576 x86::Gp v2 = cc.new_gp32("v2"); 2577 2578 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int, int>()); 2579 func_node->set_arg(0, v0); 2580 func_node->set_arg(1, v1); 2581 func_node->set_arg(2, v2); 2582 2583 // Just do something. 2584 cc.shl(v0, 1); 2585 cc.shl(v1, 1); 2586 cc.shl(v2, 1); 2587 2588 // Call a function. 2589 InvokeNode* invoke_node; 2590 cc.invoke(Out(invoke_node), imm((void*)called_fn), FuncSignature::build<int, int, int, int>()); 2591 invoke_node->set_arg(0, v2); 2592 invoke_node->set_arg(1, v1); 2593 invoke_node->set_arg(2, v0); 2594 invoke_node->set_ret(0, v0); 2595 2596 cc.ret(v0); 2597 cc.end_func(); 2598 } 2599 2600 bool run(void* _func, String& result, String& expect) override { 2601 using Func = int (*)(int, int, int); 2602 Func func = ptr_as_func<Func>(_func); 2603 2604 int result_ret = func(3, 2, 1); 2605 int expect_ret = 36; 2606 2607 result.assign_format("ret=%d", result_ret); 2608 expect.assign_format("ret=%d", expect_ret); 2609 2610 return result == expect; 2611 } 2612 2613 static int called_fn(int a, int b, int c) { return (a + b) * c; } 2614 }; 2615 2616 // x86::Compiler - X86Test_FuncCallBase2 2617 // ===================================== 2618 2619 class X86Test_FuncCallBase2 : public X86TestCase { 2620 public: 2621 X86Test_FuncCallBase2() : X86TestCase("FuncCallBase2") {} 2622 2623 static inline constexpr uint32_t kSize = 256u; 2624 2625 static void add(TestApp& app) { 2626 app.add(new X86Test_FuncCallBase2()); 2627 } 2628 2629 void compile(x86::Compiler& cc) override { 2630 cc.add_func(FuncSignature::build<int>()); 2631 2632 const int kTokenSize = 32; 2633 2634 x86::Mem s1 = cc.new_stack(kTokenSize, 32); 2635 x86::Mem s2 = cc.new_stack(kTokenSize, 32); 2636 2637 x86::Gp p1 = cc.new_gp_ptr("p1"); 2638 x86::Gp p2 = cc.new_gp_ptr("p2"); 2639 2640 x86::Gp ret = cc.new_gp32("ret"); 2641 Label L_Exit = cc.new_label(); 2642 2643 static const char token[kTokenSize] = "-+:|abcdefghijklmnopqrstuvwxyz|"; 2644 InvokeNode* invoke_node; 2645 2646 cc.lea(p1, s1); 2647 cc.lea(p2, s2); 2648 2649 // Try to corrupt the stack if wrongly allocated. 2650 cc.invoke(Out(invoke_node), imm((void*)memcpy), FuncSignature::build<void*, void*, void*, size_t>()); 2651 invoke_node->set_arg(0, p1); 2652 invoke_node->set_arg(1, imm(token)); 2653 invoke_node->set_arg(2, imm(kTokenSize)); 2654 invoke_node->set_ret(0, p1); 2655 2656 cc.invoke(Out(invoke_node), imm((void*)memcpy), FuncSignature::build<void*, void*, void*, size_t>()); 2657 invoke_node->set_arg(0, p2); 2658 invoke_node->set_arg(1, imm(token)); 2659 invoke_node->set_arg(2, imm(kTokenSize)); 2660 invoke_node->set_ret(0, p2); 2661 2662 cc.invoke(Out(invoke_node), imm((void*)memcmp), FuncSignature::build<int, void*, void*, size_t>()); 2663 invoke_node->set_arg(0, p1); 2664 invoke_node->set_arg(1, p2); 2665 invoke_node->set_arg(2, imm(kTokenSize)); 2666 invoke_node->set_ret(0, ret); 2667 2668 // This should be 0 on success, however, if both `p1` and `p2` were 2669 // allocated in the same address this check will still pass. 2670 cc.cmp(ret, 0); 2671 cc.jnz(L_Exit); 2672 2673 // Checks whether `p1` and `p2` are different (must be). 2674 cc.xor_(ret, ret); 2675 cc.cmp(p1, p2); 2676 cc.setz(ret.r8()); 2677 2678 cc.bind(L_Exit); 2679 cc.ret(ret); 2680 cc.end_func(); 2681 } 2682 2683 bool run(void* _func, String& result, String& expect) override { 2684 using Func = int (*)(void); 2685 Func func = ptr_as_func<Func>(_func); 2686 2687 int result_ret = func(); 2688 int expect_ret = 0; // Must be zero, stack addresses must be different. 2689 2690 result.assign_int(result_ret); 2691 expect.assign_int(expect_ret); 2692 2693 return result == expect; 2694 } 2695 }; 2696 2697 // x86::Compiler - X86Test_FuncCallStd 2698 // =================================== 2699 2700 class X86Test_FuncCallStd : public X86TestCase { 2701 public: 2702 X86Test_FuncCallStd() : X86TestCase("FuncCallStd") {} 2703 2704 static void add(TestApp& app) { 2705 app.add(new X86Test_FuncCallStd()); 2706 } 2707 2708 void compile(x86::Compiler& cc) override { 2709 x86::Gp x = cc.new_gp32("x"); 2710 x86::Gp y = cc.new_gp32("y"); 2711 x86::Gp z = cc.new_gp32("z"); 2712 2713 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int, int>()); 2714 func_node->set_arg(0, x); 2715 func_node->set_arg(1, y); 2716 func_node->set_arg(2, z); 2717 2718 InvokeNode* invoke_node; 2719 cc.invoke(Out(invoke_node), 2720 imm((void*)called_fn), 2721 FuncSignature::build<int, int, int, int>(CallConvId::kStdCall)); 2722 invoke_node->set_arg(0, x); 2723 invoke_node->set_arg(1, y); 2724 invoke_node->set_arg(2, z); 2725 invoke_node->set_ret(0, x); 2726 2727 cc.ret(x); 2728 cc.end_func(); 2729 } 2730 2731 bool run(void* _func, String& result, String& expect) override { 2732 using Func = int (*)(int, int, int); 2733 Func func = ptr_as_func<Func>(_func); 2734 2735 int result_ret = func(1, 42, 3); 2736 int expect_ret = called_fn(1, 42, 3); 2737 2738 result.assign_format("ret=%d", result_ret); 2739 expect.assign_format("ret=%d", expect_ret); 2740 2741 return result == expect; 2742 } 2743 2744 // STDCALL function that is called inside the generated one. 2745 static int ASMJIT_STDCALL called_fn(int a, int b, int c) noexcept { 2746 return (a + b) * c; 2747 } 2748 }; 2749 2750 // x86::Compiler - X86Test_FuncCallFast 2751 // ==================================== 2752 2753 class X86Test_FuncCallFast : public X86TestCase { 2754 public: 2755 X86Test_FuncCallFast() : X86TestCase("FuncCallFast") {} 2756 2757 static void add(TestApp& app) { 2758 app.add(new X86Test_FuncCallFast()); 2759 } 2760 2761 void compile(x86::Compiler& cc) override { 2762 x86::Gp var = cc.new_gp32("var"); 2763 2764 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int>()); 2765 func_node->set_arg(0, var); 2766 2767 InvokeNode* invoke_node; 2768 2769 cc.invoke(Out(invoke_node), imm((void*)called_fn), FuncSignature::build<int, int>(CallConvId::kFastCall)); 2770 invoke_node->set_arg(0, var); 2771 invoke_node->set_ret(0, var); 2772 2773 cc.invoke(Out(invoke_node), imm((void*)called_fn), FuncSignature::build<int, int>(CallConvId::kFastCall)); 2774 invoke_node->set_arg(0, var); 2775 invoke_node->set_ret(0, var); 2776 2777 cc.ret(var); 2778 cc.end_func(); 2779 } 2780 2781 bool run(void* _func, String& result, String& expect) override { 2782 using Func = int (*)(int); 2783 Func func = ptr_as_func<Func>(_func); 2784 2785 int result_ret = func(9); 2786 int expect_ret = (9 * 9) * (9 * 9); 2787 2788 result.assign_format("ret=%d", result_ret); 2789 expect.assign_format("ret=%d", expect_ret); 2790 2791 return result == expect; 2792 } 2793 2794 // FASTCALL function that is called inside the generated one. 2795 static int ASMJIT_FASTCALL called_fn(int a) noexcept { 2796 return a * a; 2797 } 2798 }; 2799 2800 // x86::Compiler - X86Test_FuncCallSIMD 2801 // ==================================== 2802 2803 #if ASMJIT_ARCH_X86 2804 class X86Test_FuncCallSIMD : public X86TestCase { 2805 public: 2806 bool _use_vector_call; 2807 2808 X86Test_FuncCallSIMD(bool use_vector_call) 2809 : X86TestCase(), 2810 _use_vector_call(use_vector_call) { 2811 _name.assign_format("FuncCallSIMD {%s}", _use_vector_call ? "__vectorcall" : "__cdecl"); 2812 } 2813 2814 static void add(TestApp& app) { 2815 app.add(new X86Test_FuncCallSIMD(false)); 2816 #ifdef _MSC_VER 2817 app.add(new X86Test_FuncCallSIMD(true)); 2818 #endif 2819 } 2820 2821 void compile(x86::Compiler& cc) override { 2822 FuncNode* func_node = cc.add_func(FuncSignature::build<void, void*, const void*, const void*>()); 2823 2824 x86::Gp result_ptr = cc.new_gp_ptr("result_ptr"); 2825 x86::Gp a_ptr = cc.new_gp_ptr("a_ptr"); 2826 x86::Gp b_ptr = cc.new_gp_ptr("b_ptr"); 2827 x86::Gp p_fn = cc.new_gp_ptr("p_fn"); 2828 2829 x86::Vec xmm_a = cc.new_xmm("xmm_a"); 2830 x86::Vec xmm_b = cc.new_xmm("xmm_b"); 2831 2832 func_node->set_arg(0, result_ptr); 2833 func_node->set_arg(1, a_ptr); 2834 func_node->set_arg(2, b_ptr); 2835 2836 CallConvId call_conv_id = CallConvId::kCDecl; 2837 Imm p_fn_imm = imm((void*)called_fn_cdecl); 2838 2839 #ifdef _MSC_VER 2840 if (_use_vector_call) { 2841 call_conv_id = CallConvId::kVectorCall; 2842 p_fn_imm = imm((void*)called_fn_vectorcall); 2843 } 2844 #endif 2845 2846 cc.mov(p_fn, p_fn_imm); 2847 cc.movdqu(xmm_a, x86::ptr(a_ptr)); 2848 cc.movdqu(xmm_b, x86::ptr(b_ptr)); 2849 2850 InvokeNode* invoke_node; 2851 cc.invoke(Out(invoke_node), p_fn, FuncSignature::build<Type::Vec128, Type::Vec128, Type::Vec128>(call_conv_id)); 2852 2853 invoke_node->set_arg(0, xmm_a); 2854 invoke_node->set_arg(1, xmm_b); 2855 invoke_node->set_ret(0, xmm_a); 2856 2857 cc.movdqu(x86::ptr(result_ptr), xmm_a); 2858 2859 cc.end_func(); 2860 } 2861 2862 bool run(void* _func, String& result, String& expect) override { 2863 using Func = void (*)(void*, const void*, const void*); 2864 Func func = ptr_as_func<Func>(_func); 2865 2866 uint8_t a_data[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; 2867 uint8_t b_data[16] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; 2868 2869 uint8_t r_data[16] {}; 2870 uint8_t e_data[16] = { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; 2871 2872 func(r_data, a_data, b_data); 2873 2874 result.append_hex(r_data, 16); 2875 expect.append_hex(e_data, 16); 2876 2877 return result == expect; 2878 } 2879 2880 static __m128i called_fn_cdecl(__m128i a, __m128i b) { 2881 return _mm_add_epi8(a, b); 2882 } 2883 2884 #ifdef _MSC_VER 2885 static __m128i __vectorcall called_fn_vectorcall(__m128i a, __m128i b) { 2886 return _mm_add_epi8(a, b); 2887 } 2888 #endif 2889 }; 2890 #endif // ASMJIT_ARCH_X86 2891 2892 // x86::Compiler - X86Test_FuncCallLight 2893 // ===================================== 2894 2895 class X86Test_FuncCallLight : public X86TestCase { 2896 public: 2897 X86Test_FuncCallLight() : X86TestCase("FuncCallLight") {} 2898 2899 static void add(TestApp& app) { 2900 app.add(new X86Test_FuncCallLight()); 2901 } 2902 2903 void compile(x86::Compiler& cc) override { 2904 FuncSignature f1_signature = FuncSignature::build<void, const void*, const void*, const void*, const void*, void*>(); 2905 FuncSignature f2_signature = FuncSignature::build<Type::Vec128, Type::Vec128, Type::Vec128>(CallConvId::kLightCall2); 2906 2907 FuncNode* f1_node = cc.new_func(f1_signature); 2908 FuncNode* f2_node = cc.new_func(f2_signature); 2909 2910 { 2911 x86::Gp a_ptr = cc.new_gp_ptr("a_ptr"); 2912 x86::Gp b_ptr = cc.new_gp_ptr("b_ptr"); 2913 x86::Gp c_ptr = cc.new_gp_ptr("c_ptr"); 2914 x86::Gp d_ptr = cc.new_gp_ptr("d_ptr"); 2915 x86::Gp p_out = cc.new_gp_ptr("p_out"); 2916 2917 x86::Vec xmm_a = cc.new_xmm("xmm_a"); 2918 x86::Vec xmm_b = cc.new_xmm("xmm_b"); 2919 x86::Vec xmm_c = cc.new_xmm("xmm_c"); 2920 x86::Vec xmm_d = cc.new_xmm("xmm_d"); 2921 2922 cc.add_func(f1_node); 2923 f1_node->set_arg(0, a_ptr); 2924 f1_node->set_arg(1, b_ptr); 2925 f1_node->set_arg(2, c_ptr); 2926 f1_node->set_arg(3, d_ptr); 2927 f1_node->set_arg(4, p_out); 2928 2929 cc.movups(xmm_a, x86::ptr(a_ptr)); 2930 cc.movups(xmm_b, x86::ptr(b_ptr)); 2931 cc.movups(xmm_c, x86::ptr(c_ptr)); 2932 cc.movups(xmm_d, x86::ptr(d_ptr)); 2933 2934 x86::Vec xmm_x = cc.new_xmm("xmm_x"); 2935 x86::Vec xmm_y = cc.new_xmm("xmm_y"); 2936 2937 InvokeNode* invoke_node; 2938 2939 cc.invoke(Out(invoke_node), f2_node->label(), f2_signature); 2940 invoke_node->set_arg(0, xmm_a); 2941 invoke_node->set_arg(1, xmm_b); 2942 invoke_node->set_ret(0, xmm_x); 2943 2944 cc.invoke(Out(invoke_node), f2_node->label(), f2_signature); 2945 invoke_node->set_arg(0, xmm_c); 2946 invoke_node->set_arg(1, xmm_d); 2947 invoke_node->set_ret(0, xmm_y); 2948 2949 cc.pmullw(xmm_x, xmm_y); 2950 cc.movups(x86::ptr(p_out), xmm_x); 2951 2952 cc.end_func(); 2953 } 2954 2955 { 2956 x86::Vec xmm_a = cc.new_xmm("xmm_a"); 2957 x86::Vec xmm_b = cc.new_xmm("xmm_b"); 2958 2959 cc.add_func(f2_node); 2960 f2_node->set_arg(0, xmm_a); 2961 f2_node->set_arg(1, xmm_b); 2962 cc.paddw(xmm_a, xmm_b); 2963 cc.ret(xmm_a); 2964 cc.end_func(); 2965 } 2966 } 2967 2968 bool run(void* _func, String& result, String& expect) override { 2969 using Func = void (*)(const void*, const void*, const void*, const void*, void*); 2970 2971 Func func = ptr_as_func<Func>(_func); 2972 2973 int16_t a[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; 2974 int16_t b[8] = { 7, 6, 5, 4, 3, 2, 1, 0 }; 2975 int16_t c[8] = { 1, 3, 9, 7, 5, 4, 2, 1 }; 2976 int16_t d[8] = { 2, 0,-6,-4,-2,-1, 1, 2 }; 2977 2978 int16_t o[8] {}; 2979 int oexp = 7 * 3; 2980 2981 func(a, b, c, d, o); 2982 2983 result.assign_format("ret={%02X %02X %02X %02X %02X %02X %02X %02X}", o[0], o[1], o[2], o[3], o[4], o[5], o[6], o[7]); 2984 expect.assign_format("ret={%02X %02X %02X %02X %02X %02X %02X %02X}", oexp, oexp, oexp, oexp, oexp, oexp, oexp, oexp); 2985 2986 return result == expect; 2987 } 2988 }; 2989 2990 // x86::Compiler - X86Test_FuncCallManyArgs 2991 // ======================================== 2992 2993 class X86Test_FuncCallManyArgs : public X86TestCase { 2994 public: 2995 X86Test_FuncCallManyArgs() : X86TestCase("FuncCallManyArgs") {} 2996 2997 static void add(TestApp& app) { 2998 app.add(new X86Test_FuncCallManyArgs()); 2999 } 3000 3001 static int called_fn(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { 3002 return (a * b * c * d * e) + (f * g * h * i * j); 3003 } 3004 3005 void compile(x86::Compiler& cc) override { 3006 cc.add_func(FuncSignature::build<int>()); 3007 3008 // Prepare. 3009 x86::Gp va = cc.new_gp32("va"); 3010 x86::Gp vb = cc.new_gp32("vb"); 3011 x86::Gp vc = cc.new_gp32("vc"); 3012 x86::Gp vd = cc.new_gp32("vd"); 3013 x86::Gp ve = cc.new_gp32("ve"); 3014 x86::Gp vf = cc.new_gp32("vf"); 3015 x86::Gp vg = cc.new_gp32("vg"); 3016 x86::Gp vh = cc.new_gp32("vh"); 3017 x86::Gp vi = cc.new_gp32("vi"); 3018 x86::Gp vj = cc.new_gp32("vj"); 3019 3020 cc.mov(va, 0x03); 3021 cc.mov(vb, 0x12); 3022 cc.mov(vc, 0xA0); 3023 cc.mov(vd, 0x0B); 3024 cc.mov(ve, 0x2F); 3025 cc.mov(vf, 0x02); 3026 cc.mov(vg, 0x0C); 3027 cc.mov(vh, 0x12); 3028 cc.mov(vi, 0x18); 3029 cc.mov(vj, 0x1E); 3030 3031 // Function call. 3032 InvokeNode* invoke_node; 3033 cc.invoke(Out(invoke_node), 3034 imm((void*)called_fn), 3035 FuncSignature::build<int, int, int, int, int, int, int, int, int, int, int>()); 3036 invoke_node->set_arg(0, va); 3037 invoke_node->set_arg(1, vb); 3038 invoke_node->set_arg(2, vc); 3039 invoke_node->set_arg(3, vd); 3040 invoke_node->set_arg(4, ve); 3041 invoke_node->set_arg(5, vf); 3042 invoke_node->set_arg(6, vg); 3043 invoke_node->set_arg(7, vh); 3044 invoke_node->set_arg(8, vi); 3045 invoke_node->set_arg(9, vj); 3046 invoke_node->set_ret(0, va); 3047 3048 cc.ret(va); 3049 cc.end_func(); 3050 } 3051 3052 bool run(void* _func, String& result, String& expect) override { 3053 using Func = int (*)(void); 3054 Func func = ptr_as_func<Func>(_func); 3055 3056 int result_ret = func(); 3057 int expect_ret = called_fn(0x03, 0x12, 0xA0, 0x0B, 0x2F, 0x02, 0x0C, 0x12, 0x18, 0x1E); 3058 3059 result.assign_format("ret=%d", result_ret); 3060 expect.assign_format("ret=%d", expect_ret); 3061 3062 return result == expect; 3063 } 3064 }; 3065 3066 // x86::Compiler - X86Test_FuncCallDuplicateArgs 3067 // ============================================= 3068 3069 class X86Test_FuncCallDuplicateArgs : public X86TestCase { 3070 public: 3071 X86Test_FuncCallDuplicateArgs() : X86TestCase("FuncCallDuplicateArgs") {} 3072 3073 static void add(TestApp& app) { 3074 app.add(new X86Test_FuncCallDuplicateArgs()); 3075 } 3076 3077 static int called_fn(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { 3078 return (a * b * c * d * e) + (f * g * h * i * j); 3079 } 3080 3081 void compile(x86::Compiler& cc) override { 3082 cc.add_func(FuncSignature::build<int>()); 3083 3084 // Prepare. 3085 x86::Gp a = cc.new_gp32("a"); 3086 cc.mov(a, 3); 3087 3088 // Call function. 3089 InvokeNode* invoke_node; 3090 cc.invoke(Out(invoke_node), 3091 imm((void*)called_fn), 3092 FuncSignature::build<int, int, int, int, int, int, int, int, int, int, int>()); 3093 invoke_node->set_arg(0, a); 3094 invoke_node->set_arg(1, a); 3095 invoke_node->set_arg(2, a); 3096 invoke_node->set_arg(3, a); 3097 invoke_node->set_arg(4, a); 3098 invoke_node->set_arg(5, a); 3099 invoke_node->set_arg(6, a); 3100 invoke_node->set_arg(7, a); 3101 invoke_node->set_arg(8, a); 3102 invoke_node->set_arg(9, a); 3103 invoke_node->set_ret(0, a); 3104 3105 cc.ret(a); 3106 cc.end_func(); 3107 } 3108 3109 bool run(void* _func, String& result, String& expect) override { 3110 using Func = int (*)(void); 3111 Func func = ptr_as_func<Func>(_func); 3112 3113 int result_ret = func(); 3114 int expect_ret = called_fn(3, 3, 3, 3, 3, 3, 3, 3, 3, 3); 3115 3116 result.assign_format("ret=%d", result_ret); 3117 expect.assign_format("ret=%d", expect_ret); 3118 3119 return result == expect; 3120 } 3121 }; 3122 3123 // x86::Compiler - X86Test_FuncCallImmArgs 3124 // ======================================= 3125 3126 class X86Test_FuncCallImmArgs : public X86TestCase { 3127 public: 3128 X86Test_FuncCallImmArgs() : X86TestCase("FuncCallImmArgs") {} 3129 3130 static void add(TestApp& app) { 3131 app.add(new X86Test_FuncCallImmArgs()); 3132 } 3133 3134 void compile(x86::Compiler& cc) override { 3135 cc.add_func(FuncSignature::build<int>()); 3136 3137 // Prepare. 3138 x86::Gp rv = cc.new_gp32("rv"); 3139 3140 // Call function. 3141 InvokeNode* invoke_node; 3142 cc.invoke(Out(invoke_node), 3143 imm((void*)X86Test_FuncCallManyArgs::called_fn), 3144 FuncSignature::build<int, int, int, int, int, int, int, int, int, int, int>()); 3145 3146 invoke_node->set_arg(0, imm(0x03)); 3147 invoke_node->set_arg(1, imm(0x12)); 3148 invoke_node->set_arg(2, imm(0xA0)); 3149 invoke_node->set_arg(3, imm(0x0B)); 3150 invoke_node->set_arg(4, imm(0x2F)); 3151 invoke_node->set_arg(5, imm(0x02)); 3152 invoke_node->set_arg(6, imm(0x0C)); 3153 invoke_node->set_arg(7, imm(0x12)); 3154 invoke_node->set_arg(8, imm(0x18)); 3155 invoke_node->set_arg(9, imm(0x1E)); 3156 invoke_node->set_ret(0, rv); 3157 3158 cc.ret(rv); 3159 cc.end_func(); 3160 } 3161 3162 bool run(void* _func, String& result, String& expect) override { 3163 using Func = int (*)(void); 3164 Func func = ptr_as_func<Func>(_func); 3165 3166 int result_ret = func(); 3167 int expect_ret = X86Test_FuncCallManyArgs::called_fn(0x03, 0x12, 0xA0, 0x0B, 0x2F, 0x02, 0x0C, 0x12, 0x18, 0x1E); 3168 3169 result.assign_format("ret=%d", result_ret); 3170 expect.assign_format("ret=%d", expect_ret); 3171 3172 return result == expect; 3173 } 3174 }; 3175 3176 // x86::Compiler - X86Test_FuncCallPtrArgs 3177 // ======================================= 3178 3179 class X86Test_FuncCallPtrArgs : public X86TestCase { 3180 public: 3181 X86Test_FuncCallPtrArgs() : X86TestCase("FuncCallPtrArgs") {} 3182 3183 static void add(TestApp& app) { 3184 app.add(new X86Test_FuncCallPtrArgs()); 3185 } 3186 3187 static int called_fn(void* a, void* b, void* c, void* d, void* e, void* f, void* g, void* h, void* i, void* j) { 3188 return int((intptr_t)a) + 3189 int((intptr_t)b) + 3190 int((intptr_t)c) + 3191 int((intptr_t)d) + 3192 int((intptr_t)e) + 3193 int((intptr_t)f) + 3194 int((intptr_t)g) + 3195 int((intptr_t)h) + 3196 int((intptr_t)i) + 3197 int((intptr_t)j) ; 3198 } 3199 3200 void compile(x86::Compiler& cc) override { 3201 cc.add_func(FuncSignature::build<int>()); 3202 3203 // Prepare. 3204 x86::Gp rv = cc.new_gp32("rv"); 3205 3206 // Call function. 3207 InvokeNode* invoke_node; 3208 cc.invoke(Out(invoke_node), 3209 imm((void*)called_fn), 3210 FuncSignature::build<int, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*>()); 3211 3212 invoke_node->set_arg(0, imm(0x01)); 3213 invoke_node->set_arg(1, imm(0x02)); 3214 invoke_node->set_arg(2, imm(0x03)); 3215 invoke_node->set_arg(3, imm(0x04)); 3216 invoke_node->set_arg(4, imm(0x05)); 3217 invoke_node->set_arg(5, imm(0x06)); 3218 invoke_node->set_arg(6, imm(0x07)); 3219 invoke_node->set_arg(7, imm(0x08)); 3220 invoke_node->set_arg(8, imm(0x09)); 3221 invoke_node->set_arg(9, imm(0x0A)); 3222 invoke_node->set_ret(0, rv); 3223 3224 cc.ret(rv); 3225 cc.end_func(); 3226 } 3227 3228 bool run(void* _func, String& result, String& expect) override { 3229 using Func = int (*)(void); 3230 Func func = ptr_as_func<Func>(_func); 3231 3232 int result_ret = func(); 3233 int expect_ret = 55; 3234 3235 result.assign_format("ret=%d", result_ret); 3236 expect.assign_format("ret=%d", expect_ret); 3237 3238 return result == expect; 3239 } 3240 }; 3241 3242 // x86::Compiler - X86Test_FuncCallRefArgs 3243 // ======================================= 3244 3245 class X86Test_FuncCallRefArgs : public X86TestCase { 3246 public: 3247 X86Test_FuncCallRefArgs() : X86TestCase("FuncCallRefArgs") {} 3248 3249 static void add(TestApp& app) { 3250 app.add(new X86Test_FuncCallRefArgs()); 3251 } 3252 3253 static int called_fn(int& a, int& b, int& c, int& d) { 3254 a += a; 3255 b += b; 3256 c += c; 3257 d += d; 3258 return a + b + c + d; 3259 } 3260 3261 void compile(x86::Compiler& cc) override { 3262 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int&, int&, int&, int&>()); 3263 3264 // Prepare. 3265 x86::Gp arg1 = cc.new_gp32(); 3266 x86::Gp arg2 = cc.new_gp32(); 3267 x86::Gp arg3 = cc.new_gp32(); 3268 x86::Gp arg4 = cc.new_gp32(); 3269 x86::Gp rv = cc.new_gp32("rv"); 3270 3271 func_node->set_arg(0, arg1); 3272 func_node->set_arg(1, arg2); 3273 func_node->set_arg(2, arg3); 3274 func_node->set_arg(3, arg4); 3275 3276 // Call function. 3277 InvokeNode* invoke_node; 3278 cc.invoke(Out(invoke_node), 3279 imm((void*)called_fn), 3280 FuncSignature::build<int, int&, int&, int&, int&>()); 3281 3282 invoke_node->set_arg(0, arg1); 3283 invoke_node->set_arg(1, arg2); 3284 invoke_node->set_arg(2, arg3); 3285 invoke_node->set_arg(3, arg4); 3286 invoke_node->set_ret(0, rv); 3287 3288 cc.ret(rv); 3289 cc.end_func(); 3290 } 3291 3292 bool run(void* _func, String& result, String& expect) override { 3293 using Func = int (*)(int&, int&, int&, int&); 3294 Func func = ptr_as_func<Func>(_func); 3295 3296 int inputs[4] = { 1, 2, 3, 4 }; 3297 int outputs[4] = { 2, 4, 6, 8 }; 3298 int result_ret = func(inputs[0], inputs[1], inputs[2], inputs[3]); 3299 int expect_ret = 20; 3300 3301 result.assign_format("ret={%08X %08X %08X %08X %08X}", result_ret, inputs[0], inputs[1], inputs[2], inputs[3]); 3302 expect.assign_format("ret={%08X %08X %08X %08X %08X}", expect_ret, outputs[0], outputs[1], outputs[2], outputs[3]); 3303 3304 return result == expect; 3305 } 3306 }; 3307 3308 // x86::Compiler - X86Test_FuncCallFloatAsXmmRet 3309 // ============================================= 3310 3311 class X86Test_FuncCallFloatAsXmmRet : public X86TestCase { 3312 public: 3313 X86Test_FuncCallFloatAsXmmRet() : X86TestCase("FuncCallFloatAsXmmRet") {} 3314 3315 static void add(TestApp& app) { 3316 app.add(new X86Test_FuncCallFloatAsXmmRet()); 3317 } 3318 3319 static float called_fn(float a, float b) { 3320 return a * b; 3321 } 3322 3323 void compile(x86::Compiler& cc) override { 3324 FuncNode* func_node = cc.add_func(FuncSignature::build<float, float, float>()); 3325 3326 x86::Vec a = cc.new_xmm_ss("a"); 3327 x86::Vec b = cc.new_xmm_ss("b"); 3328 x86::Vec ret = cc.new_xmm_ss("ret"); 3329 3330 func_node->set_arg(0, a); 3331 func_node->set_arg(1, b); 3332 3333 // Call function. 3334 InvokeNode* invoke_node; 3335 cc.invoke(Out(invoke_node), imm((void*)called_fn), FuncSignature::build<float, float, float>()); 3336 invoke_node->set_arg(0, a); 3337 invoke_node->set_arg(1, b); 3338 invoke_node->set_ret(0, ret); 3339 3340 cc.ret(ret); 3341 cc.end_func(); 3342 } 3343 3344 bool run(void* _func, String& result, String& expect) override { 3345 using Func = float (*)(float, float); 3346 Func func = ptr_as_func<Func>(_func); 3347 3348 float result_ret = func(15.5f, 2.0f); 3349 float expect_ret = called_fn(15.5f, 2.0f); 3350 3351 result.assign_format("ret=%g", double(result_ret)); 3352 expect.assign_format("ret=%g", double(expect_ret)); 3353 3354 return result == expect; 3355 } 3356 }; 3357 3358 // x86::Compiler - X86Test_FuncCallDoubleAsXmmRet 3359 // ============================================== 3360 3361 class X86Test_FuncCallDoubleAsXmmRet : public X86TestCase { 3362 public: 3363 X86Test_FuncCallDoubleAsXmmRet() : X86TestCase("FuncCallDoubleAsXmmRet") {} 3364 3365 static void add(TestApp& app) { 3366 app.add(new X86Test_FuncCallDoubleAsXmmRet()); 3367 } 3368 3369 static double called_fn(double a, double b) { 3370 return a * b; 3371 } 3372 3373 void compile(x86::Compiler& cc) override { 3374 FuncNode* func_node = cc.add_func(FuncSignature::build<double, double, double>()); 3375 3376 x86::Vec a = cc.new_xmm_sd("a"); 3377 x86::Vec b = cc.new_xmm_sd("b"); 3378 x86::Vec ret = cc.new_xmm_sd("ret"); 3379 3380 func_node->set_arg(0, a); 3381 func_node->set_arg(1, b); 3382 3383 InvokeNode* invoke_node; 3384 cc.invoke(Out(invoke_node), imm((void*)called_fn), FuncSignature::build<double, double, double>()); 3385 invoke_node->set_arg(0, a); 3386 invoke_node->set_arg(1, b); 3387 invoke_node->set_ret(0, ret); 3388 3389 cc.ret(ret); 3390 cc.end_func(); 3391 } 3392 3393 bool run(void* _func, String& result, String& expect) override { 3394 using Func = double (*)(double, double); 3395 Func func = ptr_as_func<Func>(_func); 3396 3397 double result_ret = func(15.5, 2.0); 3398 double expect_ret = called_fn(15.5, 2.0); 3399 3400 result.assign_format("ret=%g", result_ret); 3401 expect.assign_format("ret=%g", expect_ret); 3402 3403 return result == expect; 3404 } 3405 }; 3406 3407 // x86::Compiler - X86Test_FuncCallConditional 3408 // =========================================== 3409 3410 class X86Test_FuncCallConditional : public X86TestCase { 3411 public: 3412 X86Test_FuncCallConditional() : X86TestCase("FuncCallConditional") {} 3413 3414 static void add(TestApp& app) { 3415 app.add(new X86Test_FuncCallConditional()); 3416 } 3417 3418 void compile(x86::Compiler& cc) override { 3419 x86::Gp x = cc.new_gp32("x"); 3420 x86::Gp y = cc.new_gp32("y"); 3421 x86::Gp op = cc.new_gp32("op"); 3422 3423 InvokeNode* invoke_node; 3424 x86::Gp result; 3425 3426 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int, int>()); 3427 func_node->set_arg(0, x); 3428 func_node->set_arg(1, y); 3429 func_node->set_arg(2, op); 3430 3431 Label op_add = cc.new_label(); 3432 Label op_mul = cc.new_label(); 3433 3434 cc.cmp(op, 0); 3435 cc.jz(op_add); 3436 cc.cmp(op, 1); 3437 cc.jz(op_mul); 3438 3439 result = cc.new_gp32("result_0"); 3440 cc.mov(result, 0); 3441 cc.ret(result); 3442 3443 cc.bind(op_add); 3444 result = cc.new_gp32("result_1"); 3445 3446 cc.invoke(Out(invoke_node), (uint64_t)called_fn_add, FuncSignature::build<int, int, int>()); 3447 invoke_node->set_arg(0, x); 3448 invoke_node->set_arg(1, y); 3449 invoke_node->set_ret(0, result); 3450 cc.ret(result); 3451 3452 cc.bind(op_mul); 3453 result = cc.new_gp32("result_2"); 3454 3455 cc.invoke(Out(invoke_node), (uint64_t)called_fn_mul, FuncSignature::build<int, int, int>()); 3456 invoke_node->set_arg(0, x); 3457 invoke_node->set_arg(1, y); 3458 invoke_node->set_ret(0, result); 3459 3460 cc.ret(result); 3461 cc.end_func(); 3462 } 3463 3464 bool run(void* _func, String& result, String& expect) override { 3465 using Func = int (*)(int, int, int); 3466 Func func = ptr_as_func<Func>(_func); 3467 3468 int arg1 = 4; 3469 int arg2 = 8; 3470 3471 int result_add = func(arg1, arg2, 0); 3472 int expect_add = called_fn_add(arg1, arg2); 3473 3474 int result_mul = func(arg1, arg2, 1); 3475 int expect_mul = called_fn_mul(arg1, arg2); 3476 3477 result.assign_format("ret={add=%d, mul=%d}", result_add, result_mul); 3478 expect.assign_format("ret={add=%d, mul=%d}", expect_add, expect_mul); 3479 3480 return (result_add == expect_add) && (result_mul == expect_mul); 3481 } 3482 3483 static int called_fn_add(int x, int y) { return x + y; } 3484 static int called_fn_mul(int x, int y) { return x * y; } 3485 }; 3486 3487 // x86::Compiler - X86Test_FuncCallMultiple 3488 // ======================================== 3489 3490 class X86Test_FuncCallMultiple : public X86TestCase { 3491 public: 3492 X86Test_FuncCallMultiple() : X86TestCase("FuncCallMultiple") {} 3493 3494 static void add(TestApp& app) { 3495 app.add(new X86Test_FuncCallMultiple()); 3496 } 3497 3498 static int ASMJIT_FASTCALL called_fn(int* p_int, int index) { 3499 return p_int[index]; 3500 } 3501 3502 void compile(x86::Compiler& cc) override { 3503 unsigned int i; 3504 3505 x86::Gp buf = cc.new_gp_ptr("buf"); 3506 x86::Gp acc0 = cc.new_gp32("acc0"); 3507 x86::Gp acc1 = cc.new_gp32("acc1"); 3508 3509 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int*>()); 3510 func_node->set_arg(0, buf); 3511 3512 cc.mov(acc0, 0); 3513 cc.mov(acc1, 0); 3514 3515 for (i = 0; i < 4; i++) { 3516 x86::Gp ret = cc.new_gp32("ret"); 3517 x86::Gp ptr = cc.new_gp_ptr("ptr"); 3518 x86::Gp idx = cc.new_gp32("idx"); 3519 InvokeNode* invoke_node; 3520 3521 cc.mov(ptr, buf); 3522 cc.mov(idx, int(i)); 3523 3524 cc.invoke(Out(invoke_node), (uint64_t)called_fn, FuncSignature::build<int, int*, int>(CallConvId::kFastCall)); 3525 invoke_node->set_arg(0, ptr); 3526 invoke_node->set_arg(1, idx); 3527 invoke_node->set_ret(0, ret); 3528 3529 cc.add(acc0, ret); 3530 3531 cc.mov(ptr, buf); 3532 cc.mov(idx, int(i)); 3533 3534 cc.invoke(Out(invoke_node), (uint64_t)called_fn, FuncSignature::build<int, int*, int>(CallConvId::kFastCall)); 3535 invoke_node->set_arg(0, ptr); 3536 invoke_node->set_arg(1, idx); 3537 invoke_node->set_ret(0, ret); 3538 3539 cc.sub(acc1, ret); 3540 } 3541 3542 cc.add(acc0, acc1); 3543 cc.ret(acc0); 3544 cc.end_func(); 3545 } 3546 3547 bool run(void* _func, String& result, String& expect) override { 3548 using Func = int (*)(int*); 3549 Func func = ptr_as_func<Func>(_func); 3550 3551 int buffer[4] = { 127, 87, 23, 17 }; 3552 3553 int result_ret = func(buffer); 3554 int expect_ret = 0; 3555 3556 result.assign_format("ret=%d", result_ret); 3557 expect.assign_format("ret=%d", expect_ret); 3558 3559 return result == expect; 3560 } 3561 }; 3562 3563 // x86::Compiler - X86Test_FuncCallRecursive 3564 // ========================================= 3565 3566 class X86Test_FuncCallRecursive : public X86TestCase { 3567 public: 3568 X86Test_FuncCallRecursive() : X86TestCase("FuncCallRecursive") {} 3569 3570 static void add(TestApp& app) { 3571 app.add(new X86Test_FuncCallRecursive()); 3572 } 3573 3574 void compile(x86::Compiler& cc) override { 3575 x86::Gp val = cc.new_gp32("val"); 3576 Label skip = cc.new_label(); 3577 3578 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int>()); 3579 func_node->set_arg(0, val); 3580 3581 cc.cmp(val, 1); 3582 cc.jle(skip); 3583 3584 x86::Gp tmp = cc.new_gp32("tmp"); 3585 cc.mov(tmp, val); 3586 cc.dec(tmp); 3587 3588 InvokeNode* invoke_node; 3589 3590 cc.invoke(Out(invoke_node), func_node->label(), FuncSignature::build<int, int>()); 3591 invoke_node->set_arg(0, tmp); 3592 invoke_node->set_ret(0, tmp); 3593 cc.mul(cc.new_gp32(), val, tmp); 3594 3595 cc.bind(skip); 3596 cc.ret(val); 3597 cc.end_func(); 3598 } 3599 3600 bool run(void* _func, String& result, String& expect) override { 3601 using Func = int (*)(int); 3602 Func func = ptr_as_func<Func>(_func); 3603 3604 int result_ret = func(5); 3605 int expect_ret = 1 * 2 * 3 * 4 * 5; 3606 3607 result.assign_format("ret=%d", result_ret); 3608 expect.assign_format("ret=%d", expect_ret); 3609 3610 return result == expect; 3611 } 3612 }; 3613 3614 // x86::Compiler - X86Test_FuncCallVarArg1 3615 // ======================================= 3616 3617 class X86Test_FuncCallVarArg1 : public X86TestCase { 3618 public: 3619 X86Test_FuncCallVarArg1() : X86TestCase("FuncCallVarArg1") {} 3620 3621 static void add(TestApp& app) { 3622 app.add(new X86Test_FuncCallVarArg1()); 3623 } 3624 3625 void compile(x86::Compiler& cc) override { 3626 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int, int, int>()); 3627 3628 x86::Gp a0 = cc.new_gp32("a0"); 3629 x86::Gp a1 = cc.new_gp32("a1"); 3630 x86::Gp a2 = cc.new_gp32("a2"); 3631 x86::Gp a3 = cc.new_gp32("a3"); 3632 3633 func_node->set_arg(0, a0); 3634 func_node->set_arg(1, a1); 3635 func_node->set_arg(2, a2); 3636 func_node->set_arg(3, a3); 3637 3638 // We call `int func(size_t, ...)` 3639 // - The `va_index` must be 1 (first argument after size_t). 3640 // - The full signature of varargs (int, int, int, int) must follow. 3641 InvokeNode* invoke_node; 3642 cc.invoke(Out(invoke_node), 3643 imm((void*)called_fn), 3644 FuncSignature::build<int, size_t, int, int, int, int>(CallConvId::kCDecl, 1)); 3645 invoke_node->set_arg(0, imm(4)); 3646 invoke_node->set_arg(1, a0); 3647 invoke_node->set_arg(2, a1); 3648 invoke_node->set_arg(3, a2); 3649 invoke_node->set_arg(4, a3); 3650 invoke_node->set_ret(0, a0); 3651 3652 cc.ret(a0); 3653 cc.end_func(); 3654 } 3655 3656 bool run(void* _func, String& result, String& expect) override { 3657 using Func = int (*)(int, int, int, int); 3658 Func func = ptr_as_func<Func>(_func); 3659 3660 int result_ret = func(1, 2, 3, 4); 3661 int expect_ret = 1 + 2 + 3 + 4; 3662 3663 result.assign_format("ret=%d", result_ret); 3664 expect.assign_format("ret=%d", expect_ret); 3665 3666 return result == expect; 3667 } 3668 3669 static int called_fn(size_t n, ...) { 3670 int sum = 0; 3671 va_list ap; 3672 va_start(ap, n); 3673 for (size_t i = 0; i < n; i++) { 3674 int arg = va_arg(ap, int); 3675 sum += arg; 3676 } 3677 va_end(ap); 3678 return sum; 3679 } 3680 }; 3681 3682 // x86::Compiler - X86Test_FuncCallVarArg2 3683 // ======================================= 3684 3685 class X86Test_FuncCallVarArg2 : public X86TestCase { 3686 public: 3687 X86Test_FuncCallVarArg2() : X86TestCase("FuncCallVarArg2") {} 3688 3689 static void add(TestApp& app) { 3690 app.add(new X86Test_FuncCallVarArg2()); 3691 } 3692 3693 void compile(x86::Compiler& cc) override { 3694 FuncNode* func_node = cc.add_func(FuncSignature::build<double, double, double, double, double>()); 3695 3696 x86::Vec a0 = cc.new_xmm_sd("a0"); 3697 x86::Vec a1 = cc.new_xmm_sd("a1"); 3698 x86::Vec a2 = cc.new_xmm_sd("a2"); 3699 x86::Vec a3 = cc.new_xmm_sd("a3"); 3700 3701 func_node->set_arg(0, a0); 3702 func_node->set_arg(1, a1); 3703 func_node->set_arg(2, a2); 3704 func_node->set_arg(3, a3); 3705 3706 // We call `double func(size_t, ...)` 3707 // - The `va_index` must be 1 (first argument after size_t). 3708 // - The full signature of varargs (double, double, double, double) must follow. 3709 InvokeNode* invoke_node; 3710 cc.invoke(Out(invoke_node), 3711 imm((void*)called_fn), 3712 FuncSignature::build<double, size_t, double, double, double, double>(CallConvId::kCDecl, 1)); 3713 invoke_node->set_arg(0, imm(4)); 3714 invoke_node->set_arg(1, a0); 3715 invoke_node->set_arg(2, a1); 3716 invoke_node->set_arg(3, a2); 3717 invoke_node->set_arg(4, a3); 3718 invoke_node->set_ret(0, a0); 3719 3720 cc.ret(a0); 3721 cc.end_func(); 3722 } 3723 3724 bool run(void* _func, String& result, String& expect) override { 3725 using Func = double (*)(double, double, double, double); 3726 Func func = ptr_as_func<Func>(_func); 3727 3728 double result_ret = func(1.0, 2.0, 3.0, 4.0); 3729 double expect_ret = 1.0 + 2.0 + 3.0 + 4.0; 3730 3731 result.assign_format("ret=%f", result_ret); 3732 expect.assign_format("ret=%f", expect_ret); 3733 3734 return result == expect; 3735 } 3736 3737 static double called_fn(size_t n, ...) { 3738 double sum = 0; 3739 va_list ap; 3740 va_start(ap, n); 3741 for (size_t i = 0; i < n; i++) { 3742 double arg = va_arg(ap, double); 3743 sum += arg; 3744 } 3745 va_end(ap); 3746 return sum; 3747 } 3748 }; 3749 3750 // x86::Compiler - X86Test_FuncCallInt64Arg 3751 // ======================================== 3752 3753 class X86Test_FuncCallInt64Arg : public X86TestCase { 3754 public: 3755 X86Test_FuncCallInt64Arg() : X86TestCase("FuncCallInt64Arg") {} 3756 3757 static void add(TestApp& app) { 3758 app.add(new X86Test_FuncCallInt64Arg()); 3759 } 3760 3761 void compile(x86::Compiler& cc) override { 3762 FuncNode* func_node = cc.add_func(FuncSignature::build<uint64_t, uint64_t>()); 3763 3764 if (cc.is_64bit()) { 3765 x86::Gp reg = cc.new_gp64(); 3766 func_node->set_arg(0, reg); 3767 cc.add(reg, 1); 3768 cc.ret(reg); 3769 } 3770 else { 3771 x86::Gp hi = cc.new_gp32("hi"); 3772 x86::Gp lo = cc.new_gp32("lo"); 3773 3774 func_node->set_arg(0, 0, lo); 3775 func_node->set_arg(0, 1, hi); 3776 3777 cc.add(lo, 1); 3778 cc.adc(hi, 0); 3779 cc.ret(lo, hi); 3780 } 3781 3782 cc.end_func(); 3783 } 3784 3785 bool run(void* _func, String& result, String& expect) override { 3786 using Func = uint64_t (*)(uint64_t); 3787 Func func = ptr_as_func<Func>(_func); 3788 3789 uint64_t result_ret = func(uint64_t(0xFFFFFFFF)); 3790 uint64_t expect_ret = 0x100000000; 3791 3792 result.assign_format("ret=%llu", (unsigned long long)result_ret); 3793 expect.assign_format("ret=%llu", (unsigned long long)expect_ret); 3794 3795 return result == expect; 3796 } 3797 3798 static double called_fn(size_t n, ...) { 3799 double sum = 0; 3800 va_list ap; 3801 va_start(ap, n); 3802 for (size_t i = 0; i < n; i++) { 3803 double arg = va_arg(ap, double); 3804 sum += arg; 3805 } 3806 va_end(ap); 3807 return sum; 3808 } 3809 }; 3810 3811 // x86::Compiler - X86Test_FuncCallMisc1 3812 // ===================================== 3813 3814 class X86Test_FuncCallMisc1 : public X86TestCase { 3815 public: 3816 X86Test_FuncCallMisc1() : X86TestCase("FuncCallMisc1") {} 3817 3818 static void add(TestApp& app) { 3819 app.add(new X86Test_FuncCallMisc1()); 3820 } 3821 3822 static void dummy(int, int) {} 3823 3824 void compile(x86::Compiler& cc) override { 3825 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int>()); 3826 3827 x86::Gp a = cc.new_gp32("a"); 3828 x86::Gp b = cc.new_gp32("b"); 3829 x86::Gp r = cc.new_gp32("r"); 3830 3831 func_node->set_arg(0, a); 3832 func_node->set_arg(1, b); 3833 3834 InvokeNode* invoke_node; 3835 cc.invoke(Out(invoke_node), 3836 imm((void*)dummy), 3837 FuncSignature::build<void, int, int>()); 3838 invoke_node->set_arg(0, a); 3839 invoke_node->set_arg(1, b); 3840 3841 cc.lea(r, x86::ptr(a, b)); 3842 cc.ret(r); 3843 3844 cc.end_func(); 3845 } 3846 3847 bool run(void* _func, String& result, String& expect) override { 3848 using Func = int (*)(int, int); 3849 Func func = ptr_as_func<Func>(_func); 3850 3851 int result_ret = func(44, 199); 3852 int expect_ret = 243; 3853 3854 result.assign_format("ret=%d", result_ret); 3855 expect.assign_format("ret=%d", expect_ret); 3856 3857 return result == expect; 3858 } 3859 }; 3860 3861 // x86::Compiler - X86Test_FuncCallMisc2 3862 // ===================================== 3863 3864 class X86Test_FuncCallMisc2 : public X86TestCase { 3865 public: 3866 X86Test_FuncCallMisc2() : X86TestCase("FuncCallMisc2") {} 3867 3868 static void add(TestApp& app) { 3869 app.add(new X86Test_FuncCallMisc2()); 3870 } 3871 3872 void compile(x86::Compiler& cc) override { 3873 FuncNode* func_node = cc.add_func(FuncSignature::build<double, const double*>()); 3874 3875 x86::Gp p = cc.new_gp_ptr("p"); 3876 x86::Vec arg = cc.new_xmm_sd("arg"); 3877 x86::Vec ret = cc.new_xmm_sd("ret"); 3878 3879 func_node->set_arg(0, p); 3880 cc.movsd(arg, x86::ptr(p)); 3881 3882 InvokeNode* invoke_node; 3883 cc.invoke(Out(invoke_node), 3884 imm((void*)op), 3885 FuncSignature::build<double, double>()); 3886 invoke_node->set_arg(0, arg); 3887 invoke_node->set_ret(0, ret); 3888 3889 cc.ret(ret); 3890 cc.end_func(); 3891 } 3892 3893 bool run(void* _func, String& result, String& expect) override { 3894 using Func = double (*)(const double*); 3895 Func func = ptr_as_func<Func>(_func); 3896 3897 double arg = 2; 3898 3899 double result_ret = func(&arg); 3900 double expect_ret = op(arg); 3901 3902 result.assign_format("ret=%g", result_ret); 3903 expect.assign_format("ret=%g", expect_ret); 3904 3905 return result == expect; 3906 } 3907 3908 static double op(double a) { return a * a; } 3909 }; 3910 3911 // x86::Compiler - X86Test_FuncCallMisc3 3912 // ===================================== 3913 3914 class X86Test_FuncCallMisc3 : public X86TestCase { 3915 public: 3916 X86Test_FuncCallMisc3() : X86TestCase("FuncCallMisc3") {} 3917 3918 static void add(TestApp& app) { 3919 app.add(new X86Test_FuncCallMisc3()); 3920 } 3921 3922 void compile(x86::Compiler& cc) override { 3923 FuncNode* func_node = cc.add_func(FuncSignature::build<double, const double*>()); 3924 3925 x86::Gp p = cc.new_gp_ptr("p"); 3926 x86::Vec arg = cc.new_xmm_sd("arg"); 3927 x86::Vec ret = cc.new_xmm_sd("ret"); 3928 3929 func_node->set_arg(0, p); 3930 cc.movsd(arg, x86::ptr(p)); 3931 3932 InvokeNode* invoke_node; 3933 cc.invoke(Out(invoke_node), 3934 imm((void*)op), 3935 FuncSignature::build<double, double>()); 3936 invoke_node->set_arg(0, arg); 3937 invoke_node->set_ret(0, ret); 3938 3939 cc.xorps(arg, arg); 3940 cc.subsd(arg, ret); 3941 3942 cc.ret(arg); 3943 cc.end_func(); 3944 } 3945 3946 bool run(void* _func, String& result, String& expect) override { 3947 using Func = double (*)(const double*); 3948 Func func = ptr_as_func<Func>(_func); 3949 3950 double arg = 2; 3951 3952 double result_ret = func(&arg); 3953 double expect_ret = -op(arg); 3954 3955 result.assign_format("ret=%g", result_ret); 3956 expect.assign_format("ret=%g", expect_ret); 3957 3958 return result == expect; 3959 } 3960 3961 static double op(double a) { return a * a; } 3962 }; 3963 3964 // x86::Compiler - X86Test_FuncCallMisc4 3965 // ===================================== 3966 3967 class X86Test_FuncCallMisc4 : public X86TestCase { 3968 public: 3969 X86Test_FuncCallMisc4() : X86TestCase("FuncCallMisc4") {} 3970 3971 static void add(TestApp& app) { 3972 app.add(new X86Test_FuncCallMisc4()); 3973 } 3974 3975 void compile(x86::Compiler& cc) override { 3976 InvokeNode* invoke_node; 3977 3978 FuncSignature func_signature; 3979 func_signature.set_call_conv_id(CallConvId::kCDecl); 3980 func_signature.set_ret(TypeId::kFloat64); 3981 cc.add_func(func_signature); 3982 3983 FuncSignature invoke_signature; 3984 invoke_signature.set_call_conv_id(CallConvId::kCDecl); 3985 invoke_signature.set_ret(TypeId::kFloat64); 3986 3987 cc.invoke(Out(invoke_node), imm((void*)called_fn), invoke_signature); 3988 x86::Vec ret = cc.new_xmm_sd("ret"); 3989 invoke_node->set_ret(0, ret); 3990 cc.ret(ret); 3991 3992 cc.end_func(); 3993 } 3994 3995 bool run(void* _func, String& result, String& expect) override { 3996 using Func = double (*)(void); 3997 Func func = ptr_as_func<Func>(_func); 3998 3999 double result_ret = func(); 4000 double expect_ret = 3.14; 4001 4002 result.assign_format("ret=%g", result_ret); 4003 expect.assign_format("ret=%g", expect_ret); 4004 4005 return result == expect; 4006 } 4007 4008 static double called_fn() { return 3.14; } 4009 }; 4010 4011 // x86::Compiler - X86Test_FuncCallMisc5 4012 // ===================================== 4013 4014 // The register allocator should clobber the register used by the `call` itself. 4015 class X86Test_FuncCallMisc5 : public X86TestCase { 4016 public: 4017 X86Test_FuncCallMisc5() : X86TestCase("FuncCallMisc5") {} 4018 4019 static void add(TestApp& app) { 4020 app.add(new X86Test_FuncCallMisc5()); 4021 } 4022 4023 void compile(x86::Compiler& cc) override { 4024 cc.add_func(FuncSignature::build<int>()); 4025 4026 x86::Gp p_fn = cc.new_gp_ptr("p_fn"); 4027 x86::Gp vars[16]; 4028 4029 uint32_t i, reg_count = cc.arch() == Arch::kX86 ? 8 : 16; 4030 ASMJIT_ASSERT(reg_count <= ASMJIT_ARRAY_SIZE(vars)); 4031 4032 cc.mov(p_fn, imm((void*)called_fn)); 4033 4034 for (i = 0; i < reg_count; i++) { 4035 if (i == x86::Gp::kIdBp || i == x86::Gp::kIdSp) 4036 continue; 4037 4038 vars[i] = cc.new_gp32("%%%u", unsigned(i)); 4039 cc.mov(vars[i], 1); 4040 } 4041 4042 InvokeNode* invoke_node; 4043 cc.invoke(Out(invoke_node), p_fn, FuncSignature::build<void>()); 4044 4045 for (i = 1; i < reg_count; i++) 4046 if (vars[i].is_valid()) 4047 cc.add(vars[0], vars[i]); 4048 cc.ret(vars[0]); 4049 4050 cc.end_func(); 4051 } 4052 4053 bool run(void* _func, String& result, String& expect) override { 4054 using Func = int (*)(void); 4055 Func func = ptr_as_func<Func>(_func); 4056 4057 int result_ret = func(); 4058 int expect_ret = sizeof(void*) == 4 ? 6 : 14; 4059 4060 result.assign_format("ret=%d", result_ret); 4061 expect.assign_format("ret=%d", expect_ret); 4062 4063 return result == expect; 4064 } 4065 4066 static void called_fn() {} 4067 }; 4068 4069 // x86::Compiler - X86Test_FuncCallMisc6 4070 // ===================================== 4071 4072 class X86Test_FuncCallMisc6 : public X86TestCase { 4073 public: 4074 X86Test_FuncCallMisc6() : X86TestCase("FuncCallMisc6") {} 4075 4076 static void add(TestApp& app) { 4077 app.add(new X86Test_FuncCallMisc6()); 4078 } 4079 4080 void compile(x86::Compiler& cc) override { 4081 FuncNode* func_node = cc.add_func(FuncSignature::build<uint32_t, uint32_t>()); 4082 4083 constexpr uint32_t kCount = 16; 4084 4085 x86::Gp v[kCount]; 4086 x86::Gp arg_val = cc.new_gp32("arg_val"); 4087 x86::Gp ret_val = cc.new_gp32("ret_val"); 4088 4089 func_node->set_arg(0, arg_val); 4090 cc.add(arg_val, 1); 4091 4092 for (uint32_t i = 0; i < kCount; i++) { 4093 v[i] = cc.new_gp32("v%u", i); 4094 } 4095 4096 InvokeNode* invoke_node; 4097 cc.invoke(Out(invoke_node), imm((void*)called_fn), FuncSignature::build<uint32_t, uint32_t>()); 4098 invoke_node->set_arg(0, arg_val); 4099 invoke_node->set_ret(0, ret_val); 4100 4101 for (uint32_t i = 0; i < kCount; i++) { 4102 cc.mov(v[i], i + 1); 4103 } 4104 4105 for (uint32_t i = 0; i < kCount; i++) { 4106 cc.add(arg_val, v[i]); 4107 } 4108 4109 cc.add(ret_val, arg_val); 4110 cc.ret(ret_val); 4111 4112 cc.end_func(); 4113 } 4114 4115 bool run(void* _func, String& result, String& expect) override { 4116 using Func = uint32_t (*)(uint32_t x); 4117 Func func = ptr_as_func<Func>(_func); 4118 4119 uint32_t result_ret = func(111); 4120 uint32_t expect_ret = 111 + 112 + 2 + (1 + 16) * 8; 4121 4122 result.assign_format("ret=%u", result_ret); 4123 expect.assign_format("ret=%u", expect_ret); 4124 4125 return result == expect; 4126 } 4127 4128 static uint32_t called_fn(uint32_t x) { return x + 1; } 4129 }; 4130 4131 // x86::Compiler - X86Test_FuncCallAVXClobber 4132 // ========================================== 4133 4134 class X86Test_FuncCallAVXClobber : public X86TestCase { 4135 public: 4136 X86Test_FuncCallAVXClobber() : X86TestCase("FuncCallAVXClobber") {} 4137 4138 static void add(TestApp& app) { 4139 const CpuInfo& cpu_info = CpuInfo::host(); 4140 4141 if (cpu_info.features().x86().has_avx2() && sizeof(void*) == 8) { 4142 app.add(new X86Test_FuncCallAVXClobber()); 4143 } 4144 } 4145 4146 void compile(x86::Compiler& cc) override { 4147 FuncNode* main_func = cc.add_func(FuncSignature::build<void, void*, const void*, const void*>()); 4148 main_func->frame().set_avx_enabled(); 4149 main_func->frame().set_avx_cleanup(); 4150 4151 // We need a Windows calling convention to test this properly also on a non-Windows machine. 4152 FuncNode* helper_func = cc.new_func(FuncSignature::build<void, void*, const void*>(CallConvId::kX64Windows)); 4153 helper_func->frame().set_avx_enabled(); 4154 helper_func->frame().set_avx_cleanup(); 4155 4156 { 4157 size_t i; 4158 4159 x86::Gp d_ptr = cc.new_gp_ptr("d_ptr"); 4160 x86::Gp a_ptr = cc.new_gp_ptr("a_ptr"); 4161 x86::Gp b_ptr = cc.new_gp_ptr("b_ptr"); 4162 x86::Gp t_ptr = cc.new_gp_ptr("t_ptr"); 4163 x86::Vec acc[8]; 4164 x86::Mem stack = cc.new_stack(32, 1, "stack"); 4165 4166 main_func->set_arg(0, d_ptr); 4167 main_func->set_arg(1, a_ptr); 4168 main_func->set_arg(2, b_ptr); 4169 4170 cc.lea(t_ptr, stack); 4171 for (i = 0; i < 8; i++) { 4172 acc[i] = cc.new_ymm("acc%zu", i); 4173 cc.vmovdqu(acc[i], x86::ptr(a_ptr)); 4174 } 4175 4176 InvokeNode* invoke_node; 4177 cc.invoke(Out(invoke_node), 4178 helper_func->label(), 4179 FuncSignature::build<void, void*, const void*>(CallConvId::kX64Windows)); 4180 invoke_node->set_arg(0, t_ptr); 4181 invoke_node->set_arg(1, b_ptr); 4182 4183 for (i = 1; i < 8; i++) { 4184 cc.vpaddd(acc[0], acc[0], acc[i]); 4185 } 4186 4187 cc.vpaddd(acc[0], acc[0], x86::ptr(t_ptr)); 4188 cc.vmovdqu(x86::ptr(d_ptr), acc[0]); 4189 4190 cc.end_func(); 4191 } 4192 4193 { 4194 cc.add_func(helper_func); 4195 4196 x86::Gp d_ptr = cc.new_gp_ptr("d_ptr"); 4197 x86::Gp a_ptr = cc.new_gp_ptr("a_ptr"); 4198 4199 helper_func->set_arg(0, d_ptr); 4200 helper_func->set_arg(1, a_ptr); 4201 4202 x86::Gp tmp = cc.new_gp_ptr("tmp"); 4203 x86::Vec acc = cc.new_ymm("acc"); 4204 4205 cc.mov(tmp, 1); 4206 cc.vmovd(acc.xmm(), tmp); 4207 cc.vpbroadcastd(acc, acc.xmm()); 4208 cc.vpaddd(acc, acc, x86::ptr(a_ptr)); 4209 cc.vmovdqu(x86::ptr(d_ptr), acc); 4210 4211 cc.end_func(); 4212 } 4213 } 4214 4215 bool run(void* _func, String& result, String& expect) override { 4216 using Func = void (*)(void*, const void*, const void*); 4217 Func func = ptr_as_func<Func>(_func); 4218 4219 size_t i; 4220 4221 static const uint32_t a_data[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; 4222 static const uint32_t b_data[8] = { 6, 3, 5, 9, 1, 8, 7, 2 }; 4223 4224 uint32_t result_data[8] {}; 4225 uint32_t expect_data[8] {}; 4226 4227 for (i = 0; i < 8; i++) 4228 expect_data[i] = a_data[i] * 8 + b_data[i] + 1; 4229 4230 func(result_data, a_data, b_data); 4231 4232 result.assign("{"); 4233 expect.assign("{"); 4234 4235 for (i = 0; i < 8; i++) { 4236 result.append_format("%u", result_data[i]); 4237 expect.append_format("%u", expect_data[i]); 4238 4239 if (i != 7) result.append(", "); 4240 if (i != 7) expect.append(", "); 4241 } 4242 4243 result.append("}"); 4244 expect.append("}"); 4245 4246 return result == expect; 4247 } 4248 }; 4249 4250 // x86::Compiler - X86Test_VecToScalar 4251 // =================================== 4252 4253 class X86Test_VecToScalar : public X86TestCase { 4254 public: 4255 static inline constexpr uint32_t kVecCount = 64; 4256 4257 X86Test_VecToScalar() : X86TestCase("VecToScalar") {} 4258 4259 static void add(TestApp& app) { 4260 app.add(new X86Test_VecToScalar()); 4261 } 4262 4263 void compile(x86::Compiler& cc) override { 4264 FuncNode* func = cc.add_func(FuncSignature::build<uint32_t, uint32_t>()); 4265 4266 x86::Gp x = cc.new_gp32("x"); 4267 x86::Gp t = cc.new_gp32("t"); 4268 x86::Vec v[kVecCount]; 4269 4270 func->set_arg(0, x); 4271 4272 for (size_t i = 0; i < kVecCount; i++) { 4273 v[i] = cc.new_xmm("v%d", i); 4274 if (i != 0) 4275 cc.add(x, 1); 4276 cc.movd(v[i], x); 4277 } 4278 4279 cc.xor_(x, x); 4280 4281 for (size_t i = 0; i < kVecCount; i++) { 4282 cc.movd(t, v[i]); 4283 cc.add(x, t); 4284 } 4285 4286 cc.ret(x); 4287 cc.end_func(); 4288 } 4289 4290 bool run(void* _func, String& result, String& expect) override { 4291 using Func = uint32_t (*)(uint32_t); 4292 Func func = ptr_as_func<Func>(_func); 4293 4294 uint32_t result_ret = func(1); 4295 uint32_t expect_ret = 2080; // 1 + 2 + 3 + ... + 64 4296 4297 result.assign_format("ret=%d", result_ret); 4298 expect.assign_format("ret=%d", expect_ret); 4299 4300 return result == expect; 4301 } 4302 }; 4303 4304 // x86::Compiler - X86Test_MiscLocalConstPool 4305 // ========================================== 4306 4307 class X86Test_MiscLocalConstPool : public X86TestCase { 4308 public: 4309 X86Test_MiscLocalConstPool() : X86TestCase("MiscLocalConstPool") {} 4310 4311 static void add(TestApp& app) { 4312 app.add(new X86Test_MiscLocalConstPool()); 4313 } 4314 4315 void compile(x86::Compiler& cc) override { 4316 cc.add_func(FuncSignature::build<int>()); 4317 4318 x86::Gp v0 = cc.new_gp32("v0"); 4319 x86::Gp v1 = cc.new_gp32("v1"); 4320 4321 x86::Mem c0 = cc.new_int32_const(ConstPoolScope::kLocal, 200); 4322 x86::Mem c1 = cc.new_int32_const(ConstPoolScope::kLocal, 33); 4323 4324 cc.mov(v0, c0); 4325 cc.mov(v1, c1); 4326 cc.add(v0, v1); 4327 4328 cc.ret(v0); 4329 cc.end_func(); 4330 } 4331 4332 bool run(void* _func, String& result, String& expect) override { 4333 using Func = int (*)(void); 4334 Func func = ptr_as_func<Func>(_func); 4335 4336 int result_ret = func(); 4337 int expect_ret = 233; 4338 4339 result.assign_format("ret=%d", result_ret); 4340 expect.assign_format("ret=%d", expect_ret); 4341 4342 return result == expect; 4343 } 4344 }; 4345 4346 // x86::Compiler - X86Test_MiscGlobalConstPool 4347 // =========================================== 4348 4349 class X86Test_MiscGlobalConstPool : public X86TestCase { 4350 public: 4351 X86Test_MiscGlobalConstPool() : X86TestCase("MiscGlobalConstPool") {} 4352 4353 static void add(TestApp& app) { 4354 app.add(new X86Test_MiscGlobalConstPool()); 4355 } 4356 4357 void compile(x86::Compiler& cc) override { 4358 cc.add_func(FuncSignature::build<int>()); 4359 4360 x86::Gp v0 = cc.new_gp32("v0"); 4361 x86::Gp v1 = cc.new_gp32("v1"); 4362 4363 x86::Mem c0 = cc.new_int32_const(ConstPoolScope::kGlobal, 200); 4364 x86::Mem c1 = cc.new_int32_const(ConstPoolScope::kGlobal, 33); 4365 4366 cc.mov(v0, c0); 4367 cc.mov(v1, c1); 4368 cc.add(v0, v1); 4369 4370 cc.ret(v0); 4371 cc.end_func(); 4372 } 4373 4374 bool run(void* _func, String& result, String& expect) override { 4375 using Func = int (*)(void); 4376 Func func = ptr_as_func<Func>(_func); 4377 4378 int result_ret = func(); 4379 int expect_ret = 233; 4380 4381 result.assign_format("ret=%d", result_ret); 4382 expect.assign_format("ret=%d", expect_ret); 4383 4384 return result == expect; 4385 } 4386 }; 4387 4388 // x86::Compiler - X86Test_MiscMultiRet 4389 // ==================================== 4390 4391 struct X86Test_MiscMultiRet : public X86TestCase { 4392 X86Test_MiscMultiRet() : X86TestCase("MiscMultiRet") {} 4393 4394 static void add(TestApp& app) { 4395 app.add(new X86Test_MiscMultiRet()); 4396 } 4397 4398 void compile(x86::Compiler& cc) override { 4399 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, int, int>()); 4400 4401 x86::Gp op = cc.new_gp32("op"); 4402 x86::Gp a = cc.new_gp32("a"); 4403 x86::Gp b = cc.new_gp32("b"); 4404 4405 Label L_Zero = cc.new_label(); 4406 Label L_Add = cc.new_label(); 4407 Label L_Sub = cc.new_label(); 4408 Label L_Mul = cc.new_label(); 4409 Label L_Div = cc.new_label(); 4410 4411 func_node->set_arg(0, op); 4412 func_node->set_arg(1, a); 4413 func_node->set_arg(2, b); 4414 4415 cc.cmp(op, 0); 4416 cc.jz(L_Add); 4417 4418 cc.cmp(op, 1); 4419 cc.jz(L_Sub); 4420 4421 cc.cmp(op, 2); 4422 cc.jz(L_Mul); 4423 4424 cc.cmp(op, 3); 4425 cc.jz(L_Div); 4426 4427 cc.bind(L_Zero); 4428 cc.xor_(a, a); 4429 cc.ret(a); 4430 4431 cc.bind(L_Add); 4432 cc.add(a, b); 4433 cc.ret(a); 4434 4435 cc.bind(L_Sub); 4436 cc.sub(a, b); 4437 cc.ret(a); 4438 4439 cc.bind(L_Mul); 4440 cc.imul(a, b); 4441 cc.ret(a); 4442 4443 cc.bind(L_Div); 4444 cc.cmp(b, 0); 4445 cc.jz(L_Zero); 4446 4447 x86::Gp zero = cc.new_gp32("zero"); 4448 cc.xor_(zero, zero); 4449 cc.idiv(zero, a, b); 4450 cc.ret(a); 4451 4452 cc.end_func(); 4453 } 4454 4455 bool run(void* _func, String& result, String& expect) override { 4456 using Func = int (*)(int, int, int); 4457 4458 Func func = ptr_as_func<Func>(_func); 4459 4460 int a = 44; 4461 int b = 3; 4462 4463 int r0 = func(0, a, b); 4464 int r1 = func(1, a, b); 4465 int r2 = func(2, a, b); 4466 int r3 = func(3, a, b); 4467 int e0 = a + b; 4468 int e1 = a - b; 4469 int e2 = a * b; 4470 int e3 = a / b; 4471 4472 result.assign_format("ret={%d %d %d %d}", r0, r1, r2, r3); 4473 expect.assign_format("ret={%d %d %d %d}", e0, e1, e2, e3); 4474 4475 return result == expect; 4476 } 4477 }; 4478 4479 // x86::Compiler - X86Test_MiscMultiFunc 4480 // ===================================== 4481 4482 class X86Test_MiscMultiFunc : public X86TestCase { 4483 public: 4484 X86Test_MiscMultiFunc() : X86TestCase("MiscMultiFunc") {} 4485 4486 static void add(TestApp& app) { 4487 app.add(new X86Test_MiscMultiFunc()); 4488 } 4489 4490 void compile(x86::Compiler& cc) override { 4491 FuncNode* f1_node = cc.new_func(FuncSignature::build<int, int, int>()); 4492 FuncNode* f2_node = cc.new_func(FuncSignature::build<int, int, int>()); 4493 4494 { 4495 x86::Gp a = cc.new_gp32("a"); 4496 x86::Gp b = cc.new_gp32("b"); 4497 4498 cc.add_func(f1_node); 4499 f1_node->set_arg(0, a); 4500 f1_node->set_arg(1, b); 4501 4502 InvokeNode* invoke_node; 4503 cc.invoke(Out(invoke_node), f2_node->label(), FuncSignature::build<int, int, int>()); 4504 invoke_node->set_arg(0, a); 4505 invoke_node->set_arg(1, b); 4506 invoke_node->set_ret(0, a); 4507 4508 cc.ret(a); 4509 cc.end_func(); 4510 } 4511 4512 { 4513 x86::Gp a = cc.new_gp32("a"); 4514 x86::Gp b = cc.new_gp32("b"); 4515 4516 cc.add_func(f2_node); 4517 f2_node->set_arg(0, a); 4518 f2_node->set_arg(1, b); 4519 4520 cc.add(a, b); 4521 cc.ret(a); 4522 cc.end_func(); 4523 } 4524 } 4525 4526 bool run(void* _func, String& result, String& expect) override { 4527 using Func = int (*)(int, int); 4528 4529 Func func = ptr_as_func<Func>(_func); 4530 4531 int result_ret = func(56, 22); 4532 int expect_ret = 56 + 22; 4533 4534 result.assign_format("ret=%d", result_ret); 4535 expect.assign_format("ret=%d", expect_ret); 4536 4537 return result == expect; 4538 } 4539 }; 4540 4541 // x86::Compiler - X86Test_MiscUnfollow 4542 // ==================================== 4543 4544 // Global (I didn't find a better way to test this). 4545 static jmp_buf global_jmp_buf; 4546 4547 class X86Test_MiscUnfollow : public X86TestCase { 4548 public: 4549 X86Test_MiscUnfollow() : X86TestCase("MiscUnfollow") {} 4550 4551 static void add(TestApp& app) { 4552 app.add(new X86Test_MiscUnfollow()); 4553 } 4554 4555 void compile(x86::Compiler& cc) override { 4556 // NOTE: Fastcall calling convention is the most appropriate here as all arguments are passed via registers and 4557 // there won't be any stack misalignment in the `handler()`. This was failing on MacOS when targeting 32-bit mode. 4558 x86::Gp a = cc.new_gp32("a"); 4559 x86::Gp b = cc.new_gp_ptr("b"); 4560 Label tramp = cc.new_label(); 4561 4562 FuncNode* func_node = cc.add_func(FuncSignature::build<int, int, void*>(CallConvId::kFastCall)); 4563 func_node->set_arg(0, a); 4564 func_node->set_arg(1, b); 4565 4566 cc.cmp(a, 0); 4567 cc.jz(tramp); 4568 cc.ret(a); 4569 cc.bind(tramp); 4570 cc.unfollow().jmp(b); 4571 cc.end_func(); 4572 } 4573 4574 bool run(void* _func, String& result, String& expect) override { 4575 using Func = int (ASMJIT_FASTCALL*)(int, void*); 4576 Func func = ptr_as_func<Func>(_func); 4577 4578 int result_ret = 0; 4579 int expect_ret = 1; 4580 4581 if (!setjmp(global_jmp_buf)) 4582 result_ret = func(0, (void*)handler); 4583 else 4584 result_ret = 1; 4585 4586 result.assign_format("ret={%d}", result_ret); 4587 expect.assign_format("ret={%d}", expect_ret); 4588 4589 return result == expect; 4590 } 4591 4592 static void ASMJIT_FASTCALL handler() { longjmp(global_jmp_buf, 1); } 4593 }; 4594 4595 // x86::Compiler - Tests 4596 // ===================== 4597 4598 void compiler_add_x86_tests(TestApp& app) { 4599 // Base tests. 4600 app.add_t<X86Test_NoCode>(); 4601 app.add_t<X86Test_NoAlign>(); 4602 app.add_t<X86Test_IndirectBranchProtection>(); 4603 app.add_t<X86Test_AlignBase>(); 4604 4605 // Jump tests. 4606 app.add_t<X86Test_JumpMerge>(); 4607 app.add_t<X86Test_JumpCross>(); 4608 app.add_t<X86Test_JumpMany>(); 4609 app.add_t<X86Test_JumpUnreachable1>(); 4610 app.add_t<X86Test_JumpUnreachable2>(); 4611 app.add_t<X86Test_JumpTable1>(); 4612 app.add_t<X86Test_JumpTable2>(); 4613 app.add_t<X86Test_JumpTable3>(); 4614 app.add_t<X86Test_JumpTable4>(); 4615 4616 // Alloc and instruction tests. 4617 app.add_t<X86Test_AllocBase>(); 4618 app.add_t<X86Test_AllocMany1>(); 4619 app.add_t<X86Test_AllocMany2>(); 4620 app.add_t<X86Test_AllocInt8>(); 4621 app.add_t<X86Test_AllocUnhandledArg>(); 4622 app.add_t<X86Test_AllocArgsIntPtr>(); 4623 app.add_t<X86Test_AllocArgsFloat>(); 4624 app.add_t<X86Test_AllocArgsDouble>(); 4625 #if ASMJIT_ARCH_X86 4626 app.add_t<X86Test_AllocArgsVec>(); 4627 #endif 4628 app.add_t<X86Test_AllocRetFloat1>(); 4629 app.add_t<X86Test_AllocRetFloat2>(); 4630 app.add_t<X86Test_AllocRetDouble1>(); 4631 app.add_t<X86Test_AllocRetDouble2>(); 4632 app.add_t<X86Test_AllocStack>(); 4633 app.add_t<X86Test_Imul1>(); 4634 app.add_t<X86Test_Imul2>(); 4635 app.add_t<X86Test_Idiv1>(); 4636 app.add_t<X86Test_Setz>(); 4637 app.add_t<X86Test_ShlRor>(); 4638 app.add_t<X86Test_GpbLo1>(); 4639 app.add_t<X86Test_GpbLo2>(); 4640 app.add_t<X86Test_RepMovsb>(); 4641 app.add_t<X86Test_IfElse1>(); 4642 app.add_t<X86Test_IfElse2>(); 4643 app.add_t<X86Test_IfElse3>(); 4644 app.add_t<X86Test_IfElse4>(); 4645 app.add_t<X86Test_Memcpy>(); 4646 app.add_t<X86Test_ExtraBlock>(); 4647 app.add_t<X86Test_AlphaBlend>(); 4648 app.add_t<X86Test_AVX512_KK>(); 4649 app.add_t<X86Test_AVX512_TernLog>(); 4650 4651 // Function arguments handling tests. 4652 app.add_t<X86Test_FuncArgInt8>(); 4653 4654 // Function call tests. 4655 app.add_t<X86Test_FuncCallBase1>(); 4656 app.add_t<X86Test_FuncCallBase2>(); 4657 app.add_t<X86Test_FuncCallStd>(); 4658 app.add_t<X86Test_FuncCallFast>(); 4659 #if ASMJIT_ARCH_X86 4660 app.add_t<X86Test_FuncCallSIMD>(); 4661 #endif 4662 app.add_t<X86Test_FuncCallLight>(); 4663 app.add_t<X86Test_FuncCallManyArgs>(); 4664 app.add_t<X86Test_FuncCallDuplicateArgs>(); 4665 app.add_t<X86Test_FuncCallImmArgs>(); 4666 app.add_t<X86Test_FuncCallPtrArgs>(); 4667 app.add_t<X86Test_FuncCallRefArgs>(); 4668 app.add_t<X86Test_FuncCallFloatAsXmmRet>(); 4669 app.add_t<X86Test_FuncCallDoubleAsXmmRet>(); 4670 app.add_t<X86Test_FuncCallConditional>(); 4671 app.add_t<X86Test_FuncCallMultiple>(); 4672 app.add_t<X86Test_FuncCallRecursive>(); 4673 app.add_t<X86Test_FuncCallVarArg1>(); 4674 app.add_t<X86Test_FuncCallVarArg2>(); 4675 app.add_t<X86Test_FuncCallInt64Arg>(); 4676 app.add_t<X86Test_FuncCallMisc1>(); 4677 app.add_t<X86Test_FuncCallMisc2>(); 4678 app.add_t<X86Test_FuncCallMisc3>(); 4679 app.add_t<X86Test_FuncCallMisc4>(); 4680 app.add_t<X86Test_FuncCallMisc5>(); 4681 app.add_t<X86Test_FuncCallMisc6>(); 4682 app.add_t<X86Test_FuncCallAVXClobber>(); 4683 4684 // Miscellaneous tests. 4685 app.add_t<X86Test_VecToScalar>(); 4686 app.add_t<X86Test_MiscLocalConstPool>(); 4687 app.add_t<X86Test_MiscGlobalConstPool>(); 4688 app.add_t<X86Test_MiscMultiRet>(); 4689 app.add_t<X86Test_MiscMultiFunc>(); 4690 app.add_t<X86Test_MiscUnfollow>(); 4691 } 4692 4693 #endif // !ASMJIT_NO_X86 && !ASMJIT_NO_COMPILER