Simulator-loong64.cpp (140470B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright 2020 the V8 project authors. All rights reserved. 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following 12 // disclaimer in the documentation and/or other materials provided 13 // with the distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived 16 // from this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 #include "jit/loong64/Simulator-loong64.h" 31 32 #include <cinttypes> 33 #include <float.h> 34 #include <limits> 35 36 #include "jit/AtomicOperations.h" 37 #include "jit/loong64/Assembler-loong64.h" 38 #include "js/Conversions.h" 39 #include "threading/LockGuard.h" 40 #include "vm/JSContext.h" 41 #include "vm/Runtime.h" 42 #include "wasm/WasmInstance.h" 43 #include "wasm/WasmSignalHandlers.h" 44 45 #define I8(v) static_cast<int8_t>(v) 46 #define I16(v) static_cast<int16_t>(v) 47 #define U16(v) static_cast<uint16_t>(v) 48 #define I32(v) static_cast<int32_t>(v) 49 #define U32(v) static_cast<uint32_t>(v) 50 #define I64(v) static_cast<int64_t>(v) 51 #define U64(v) static_cast<uint64_t>(v) 52 #define I128(v) static_cast<__int128_t>(v) 53 #define U128(v) static_cast<__uint128_t>(v) 54 55 #define I32_CHECK(v) \ 56 ({ \ 57 MOZ_ASSERT(I64(I32(v)) == I64(v)); \ 58 I32((v)); \ 59 }) 60 61 namespace js { 62 namespace jit { 63 64 static int64_t MultiplyHighSigned(int64_t u, int64_t v) { 65 uint64_t u0, v0, w0; 66 int64_t u1, v1, w1, w2, t; 67 68 u0 = u & 0xFFFFFFFFL; 69 u1 = u >> 32; 70 v0 = v & 0xFFFFFFFFL; 71 v1 = v >> 32; 72 73 w0 = u0 * v0; 74 t = u1 * v0 + (w0 >> 32); 75 w1 = t & 0xFFFFFFFFL; 76 w2 = t >> 32; 77 w1 = u0 * v1 + w1; 78 79 return u1 * v1 + w2 + (w1 >> 32); 80 } 81 82 static uint64_t MultiplyHighUnsigned(uint64_t u, uint64_t v) { 83 uint64_t u0, v0, w0; 84 uint64_t u1, v1, w1, w2, t; 85 86 u0 = u & 0xFFFFFFFFL; 87 u1 = u >> 32; 88 v0 = v & 0xFFFFFFFFL; 89 v1 = v >> 32; 90 91 w0 = u0 * v0; 92 t = u1 * v0 + (w0 >> 32); 93 w1 = t & 0xFFFFFFFFL; 94 w2 = t >> 32; 95 w1 = u0 * v1 + w1; 96 97 return u1 * v1 + w2 + (w1 >> 32); 98 } 99 100 // Precondition: 0 <= shift < 32 101 inline constexpr uint32_t RotateRight32(uint32_t value, uint32_t shift) { 102 return (value >> shift) | (value << ((32 - shift) & 31)); 103 } 104 105 // Precondition: 0 <= shift < 32 106 inline constexpr uint32_t RotateLeft32(uint32_t value, uint32_t shift) { 107 return (value << shift) | (value >> ((32 - shift) & 31)); 108 } 109 110 // Precondition: 0 <= shift < 64 111 inline constexpr uint64_t RotateRight64(uint64_t value, uint64_t shift) { 112 return (value >> shift) | (value << ((64 - shift) & 63)); 113 } 114 115 // Precondition: 0 <= shift < 64 116 inline constexpr uint64_t RotateLeft64(uint64_t value, uint64_t shift) { 117 return (value << shift) | (value >> ((64 - shift) & 63)); 118 } 119 120 // break instr with MAX_BREAK_CODE. 121 static const Instr kCallRedirInstr = op_break | CODEMask; 122 123 // ----------------------------------------------------------------------------- 124 // LoongArch64 assembly various constants. 125 126 class SimInstruction { 127 public: 128 enum { 129 kInstrSize = 4, 130 // On LoongArch, PC cannot actually be directly accessed. We behave as if PC 131 // was always the value of the current instruction being executed. 132 kPCReadOffset = 0 133 }; 134 135 // Get the raw instruction bits. 136 inline Instr instructionBits() const { 137 return *reinterpret_cast<const Instr*>(this); 138 } 139 140 // Set the raw instruction bits to value. 141 inline void setInstructionBits(Instr value) { 142 *reinterpret_cast<Instr*>(this) = value; 143 } 144 145 // Read one particular bit out of the instruction bits. 146 inline int bit(int nr) const { return (instructionBits() >> nr) & 1; } 147 148 // Read a bit field out of the instruction bits. 149 inline int bits(int hi, int lo) const { 150 return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1); 151 } 152 153 // Instruction type. 154 enum Type { 155 kUnsupported = -1, 156 kOp6Type, 157 kOp7Type, 158 kOp8Type, 159 kOp10Type, 160 kOp11Type, 161 kOp12Type, 162 kOp14Type, 163 kOp15Type, 164 kOp16Type, 165 kOp17Type, 166 kOp22Type, 167 kOp24Type 168 }; 169 170 // Get the encoding type of the instruction. 171 Type instructionType() const; 172 173 inline int rjValue() const { return bits(RJShift + RJBits - 1, RJShift); } 174 175 inline int rkValue() const { return bits(RKShift + RKBits - 1, RKShift); } 176 177 inline int rdValue() const { return bits(RDShift + RDBits - 1, RDShift); } 178 179 inline int sa2Value() const { return bits(SAShift + SA2Bits - 1, SAShift); } 180 181 inline int sa3Value() const { return bits(SAShift + SA3Bits - 1, SAShift); } 182 183 inline int lsbwValue() const { 184 return bits(LSBWShift + LSBWBits - 1, LSBWShift); 185 } 186 187 inline int msbwValue() const { 188 return bits(MSBWShift + MSBWBits - 1, MSBWShift); 189 } 190 191 inline int lsbdValue() const { 192 return bits(LSBDShift + LSBDBits - 1, LSBDShift); 193 } 194 195 inline int msbdValue() const { 196 return bits(MSBDShift + MSBDBits - 1, MSBDShift); 197 } 198 199 inline int fdValue() const { return bits(FDShift + FDBits - 1, FDShift); } 200 201 inline int fjValue() const { return bits(FJShift + FJBits - 1, FJShift); } 202 203 inline int fkValue() const { return bits(FKShift + FKBits - 1, FKShift); } 204 205 inline int faValue() const { return bits(FAShift + FABits - 1, FAShift); } 206 207 inline int cdValue() const { return bits(CDShift + CDBits - 1, CDShift); } 208 209 inline int cjValue() const { return bits(CJShift + CJBits - 1, CJShift); } 210 211 inline int caValue() const { return bits(CAShift + CABits - 1, CAShift); } 212 213 inline int condValue() const { 214 return bits(CONDShift + CONDBits - 1, CONDShift); 215 } 216 217 inline int imm5Value() const { 218 return bits(Imm5Shift + Imm5Bits - 1, Imm5Shift); 219 } 220 221 inline int imm6Value() const { 222 return bits(Imm6Shift + Imm6Bits - 1, Imm6Shift); 223 } 224 225 inline int imm12Value() const { 226 return bits(Imm12Shift + Imm12Bits - 1, Imm12Shift); 227 } 228 229 inline int imm14Value() const { 230 return bits(Imm14Shift + Imm14Bits - 1, Imm14Shift); 231 } 232 233 inline int imm16Value() const { 234 return bits(Imm16Shift + Imm16Bits - 1, Imm16Shift); 235 } 236 237 inline int imm20Value() const { 238 return bits(Imm20Shift + Imm20Bits - 1, Imm20Shift); 239 } 240 241 inline int32_t imm26Value() const { 242 return bits(Imm26Shift + Imm26Bits - 1, Imm26Shift); 243 } 244 245 // Say if the instruction is a debugger break/trap. 246 bool isTrap() const; 247 248 private: 249 SimInstruction() = delete; 250 SimInstruction(const SimInstruction& other) = delete; 251 void operator=(const SimInstruction& other) = delete; 252 }; 253 254 bool SimInstruction::isTrap() const { 255 // is break?? 256 switch (bits(31, 15) << 15) { 257 case op_break: 258 return (instructionBits() != kCallRedirInstr) && (bits(15, 0) != 6); 259 default: 260 return false; 261 }; 262 } 263 264 SimInstruction::Type SimInstruction::instructionType() const { 265 SimInstruction::Type kType = kUnsupported; 266 267 // Check for kOp6Type 268 switch (bits(31, 26) << 26) { 269 case op_beqz: 270 case op_bnez: 271 case op_bcz: 272 case op_jirl: 273 case op_b: 274 case op_bl: 275 case op_beq: 276 case op_bne: 277 case op_blt: 278 case op_bge: 279 case op_bltu: 280 case op_bgeu: 281 case op_addu16i_d: 282 kType = kOp6Type; 283 break; 284 default: 285 kType = kUnsupported; 286 } 287 288 if (kType == kUnsupported) { 289 // Check for kOp7Type 290 switch (bits(31, 25) << 25) { 291 case op_lu12i_w: 292 case op_lu32i_d: 293 case op_pcaddi: 294 case op_pcalau12i: 295 case op_pcaddu12i: 296 case op_pcaddu18i: 297 kType = kOp7Type; 298 break; 299 default: 300 kType = kUnsupported; 301 } 302 } 303 304 if (kType == kUnsupported) { 305 // Check for kOp8Type 306 switch (bits(31, 24) << 24) { 307 case op_ll_w: 308 case op_sc_w: 309 case op_ll_d: 310 case op_sc_d: 311 case op_ldptr_w: 312 case op_stptr_w: 313 case op_ldptr_d: 314 case op_stptr_d: 315 kType = kOp8Type; 316 break; 317 default: 318 kType = kUnsupported; 319 } 320 } 321 322 if (kType == kUnsupported) { 323 // Check for kOp10Type 324 switch (bits(31, 22) << 22) { 325 case op_bstrins_d: 326 case op_bstrpick_d: 327 case op_slti: 328 case op_sltui: 329 case op_addi_w: 330 case op_addi_d: 331 case op_lu52i_d: 332 case op_andi: 333 case op_ori: 334 case op_xori: 335 case op_ld_b: 336 case op_ld_h: 337 case op_ld_w: 338 case op_ld_d: 339 case op_st_b: 340 case op_st_h: 341 case op_st_w: 342 case op_st_d: 343 case op_ld_bu: 344 case op_ld_hu: 345 case op_ld_wu: 346 case op_preld: 347 case op_fld_s: 348 case op_fst_s: 349 case op_fld_d: 350 case op_fst_d: 351 case op_bstr_w: // BSTRINS_W & BSTRPICK_W 352 kType = kOp10Type; 353 break; 354 default: 355 kType = kUnsupported; 356 } 357 } 358 359 if (kType == kUnsupported) { 360 // Check for kOp11Type 361 switch (bits(31, 21) << 21) { 362 case op_bstr_w: 363 kType = kOp11Type; 364 break; 365 default: 366 kType = kUnsupported; 367 } 368 } 369 370 if (kType == kUnsupported) { 371 // Check for kOp12Type 372 switch (bits(31, 20) << 20) { 373 case op_fmadd_s: 374 case op_fmadd_d: 375 case op_fmsub_s: 376 case op_fmsub_d: 377 case op_fnmadd_s: 378 case op_fnmadd_d: 379 case op_fnmsub_s: 380 case op_fnmsub_d: 381 case op_fcmp_cond_s: 382 case op_fcmp_cond_d: 383 kType = kOp12Type; 384 break; 385 default: 386 kType = kUnsupported; 387 } 388 } 389 390 if (kType == kUnsupported) { 391 // Check for kOp14Type 392 switch (bits(31, 18) << 18) { 393 case op_bytepick_d: 394 case op_fsel: 395 kType = kOp14Type; 396 break; 397 default: 398 kType = kUnsupported; 399 } 400 } 401 402 if (kType == kUnsupported) { 403 // Check for kOp15Type 404 switch (bits(31, 17) << 17) { 405 case op_bytepick_w: 406 case op_alsl_w: 407 case op_alsl_wu: 408 case op_alsl_d: 409 kType = kOp15Type; 410 break; 411 default: 412 kType = kUnsupported; 413 } 414 } 415 416 if (kType == kUnsupported) { 417 // Check for kOp16Type 418 switch (bits(31, 16) << 16) { 419 case op_slli_d: 420 case op_srli_d: 421 case op_srai_d: 422 case op_rotri_d: 423 kType = kOp16Type; 424 break; 425 default: 426 kType = kUnsupported; 427 } 428 } 429 430 if (kType == kUnsupported) { 431 // Check for kOp17Type 432 switch (bits(31, 15) << 15) { 433 case op_slli_w: 434 case op_srli_w: 435 case op_srai_w: 436 case op_rotri_w: 437 case op_add_w: 438 case op_add_d: 439 case op_sub_w: 440 case op_sub_d: 441 case op_slt: 442 case op_sltu: 443 case op_maskeqz: 444 case op_masknez: 445 case op_nor: 446 case op_and: 447 case op_or: 448 case op_xor: 449 case op_orn: 450 case op_andn: 451 case op_sll_w: 452 case op_srl_w: 453 case op_sra_w: 454 case op_sll_d: 455 case op_srl_d: 456 case op_sra_d: 457 case op_rotr_w: 458 case op_rotr_d: 459 case op_mul_w: 460 case op_mul_d: 461 case op_mulh_d: 462 case op_mulh_du: 463 case op_mulh_w: 464 case op_mulh_wu: 465 case op_mulw_d_w: 466 case op_mulw_d_wu: 467 case op_div_w: 468 case op_mod_w: 469 case op_div_wu: 470 case op_mod_wu: 471 case op_div_d: 472 case op_mod_d: 473 case op_div_du: 474 case op_mod_du: 475 case op_break: 476 case op_fadd_s: 477 case op_fadd_d: 478 case op_fsub_s: 479 case op_fsub_d: 480 case op_fmul_s: 481 case op_fmul_d: 482 case op_fdiv_s: 483 case op_fdiv_d: 484 case op_fmax_s: 485 case op_fmax_d: 486 case op_fmin_s: 487 case op_fmin_d: 488 case op_fmaxa_s: 489 case op_fmaxa_d: 490 case op_fmina_s: 491 case op_fmina_d: 492 case op_fcopysign_s: 493 case op_fcopysign_d: 494 case op_ldx_b: 495 case op_ldx_h: 496 case op_ldx_w: 497 case op_ldx_d: 498 case op_stx_b: 499 case op_stx_h: 500 case op_stx_w: 501 case op_stx_d: 502 case op_ldx_bu: 503 case op_ldx_hu: 504 case op_ldx_wu: 505 case op_fldx_s: 506 case op_fldx_d: 507 case op_fstx_s: 508 case op_fstx_d: 509 case op_amswap_w: 510 case op_amswap_d: 511 case op_amadd_w: 512 case op_amadd_d: 513 case op_amand_w: 514 case op_amand_d: 515 case op_amor_w: 516 case op_amor_d: 517 case op_amxor_w: 518 case op_amxor_d: 519 case op_ammax_w: 520 case op_ammax_d: 521 case op_ammin_w: 522 case op_ammin_d: 523 case op_ammax_wu: 524 case op_ammax_du: 525 case op_ammin_wu: 526 case op_ammin_du: 527 case op_amswap_db_w: 528 case op_amswap_db_d: 529 case op_amadd_db_w: 530 case op_amadd_db_d: 531 case op_amand_db_w: 532 case op_amand_db_d: 533 case op_amor_db_w: 534 case op_amor_db_d: 535 case op_amxor_db_w: 536 case op_amxor_db_d: 537 case op_ammax_db_w: 538 case op_ammax_db_d: 539 case op_ammin_db_w: 540 case op_ammin_db_d: 541 case op_ammax_db_wu: 542 case op_ammax_db_du: 543 case op_ammin_db_wu: 544 case op_ammin_db_du: 545 case op_dbar: 546 case op_ibar: 547 kType = kOp17Type; 548 break; 549 default: 550 kType = kUnsupported; 551 } 552 } 553 554 if (kType == kUnsupported) { 555 // Check for kOp22Type 556 switch (bits(31, 10) << 10) { 557 case op_clo_w: 558 case op_clz_w: 559 case op_cto_w: 560 case op_ctz_w: 561 case op_clo_d: 562 case op_clz_d: 563 case op_cto_d: 564 case op_ctz_d: 565 case op_revb_2h: 566 case op_revb_4h: 567 case op_revb_2w: 568 case op_revb_d: 569 case op_revh_2w: 570 case op_revh_d: 571 case op_bitrev_4b: 572 case op_bitrev_8b: 573 case op_bitrev_w: 574 case op_bitrev_d: 575 case op_ext_w_h: 576 case op_ext_w_b: 577 case op_fabs_s: 578 case op_fabs_d: 579 case op_fneg_s: 580 case op_fneg_d: 581 case op_fsqrt_s: 582 case op_fsqrt_d: 583 case op_fmov_s: 584 case op_fmov_d: 585 case op_movgr2fr_w: 586 case op_movgr2fr_d: 587 case op_movgr2frh_w: 588 case op_movfr2gr_s: 589 case op_movfr2gr_d: 590 case op_movfrh2gr_s: 591 case op_movfcsr2gr: 592 case op_movfr2cf: 593 case op_movgr2cf: 594 case op_fcvt_s_d: 595 case op_fcvt_d_s: 596 case op_ftintrm_w_s: 597 case op_ftintrm_w_d: 598 case op_ftintrm_l_s: 599 case op_ftintrm_l_d: 600 case op_ftintrp_w_s: 601 case op_ftintrp_w_d: 602 case op_ftintrp_l_s: 603 case op_ftintrp_l_d: 604 case op_ftintrz_w_s: 605 case op_ftintrz_w_d: 606 case op_ftintrz_l_s: 607 case op_ftintrz_l_d: 608 case op_ftintrne_w_s: 609 case op_ftintrne_w_d: 610 case op_ftintrne_l_s: 611 case op_ftintrne_l_d: 612 case op_ftint_w_s: 613 case op_ftint_w_d: 614 case op_ftint_l_s: 615 case op_ftint_l_d: 616 case op_ffint_s_w: 617 case op_ffint_s_l: 618 case op_ffint_d_w: 619 case op_ffint_d_l: 620 case op_frint_s: 621 case op_frint_d: 622 kType = kOp22Type; 623 break; 624 default: 625 kType = kUnsupported; 626 } 627 } 628 629 if (kType == kUnsupported) { 630 // Check for kOp24Type 631 switch (bits(31, 8) << 8) { 632 case op_movcf2fr: 633 case op_movcf2gr: 634 kType = kOp24Type; 635 break; 636 default: 637 kType = kUnsupported; 638 } 639 } 640 641 return kType; 642 } 643 644 // C/C++ argument slots size. 645 const int kCArgSlotCount = 0; 646 const int kCArgsSlotsSize = kCArgSlotCount * sizeof(uintptr_t); 647 648 class CachePage { 649 public: 650 static const int LINE_VALID = 0; 651 static const int LINE_INVALID = 1; 652 653 static const int kPageShift = 12; 654 static const int kPageSize = 1 << kPageShift; 655 static const int kPageMask = kPageSize - 1; 656 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 657 static const int kLineLength = 1 << kLineShift; 658 static const int kLineMask = kLineLength - 1; 659 660 CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); } 661 662 char* validityByte(int offset) { 663 return &validity_map_[offset >> kLineShift]; 664 } 665 666 char* cachedData(int offset) { return &data_[offset]; } 667 668 private: 669 char data_[kPageSize]; // The cached data. 670 static const int kValidityMapSize = kPageSize >> kLineShift; 671 char validity_map_[kValidityMapSize]; // One byte per line. 672 }; 673 674 // Protects the icache() and redirection() properties of the 675 // Simulator. 676 class AutoLockSimulatorCache : public LockGuard<Mutex> { 677 using Base = LockGuard<Mutex>; 678 679 public: 680 explicit AutoLockSimulatorCache() 681 : Base(SimulatorProcess::singleton_->cacheLock_) {} 682 }; 683 684 mozilla::Atomic<size_t, mozilla::ReleaseAcquire> 685 SimulatorProcess::ICacheCheckingDisableCount( 686 1); // Checking is disabled by default. 687 SimulatorProcess* SimulatorProcess::singleton_ = nullptr; 688 689 int64_t Simulator::StopSimAt = -1; 690 691 Simulator* Simulator::Create() { 692 auto sim = MakeUnique<Simulator>(); 693 if (!sim) { 694 return nullptr; 695 } 696 697 if (!sim->init()) { 698 return nullptr; 699 } 700 701 int64_t stopAt; 702 char* stopAtStr = getenv("LOONG64_SIM_STOP_AT"); 703 if (stopAtStr && sscanf(stopAtStr, "%" PRIi64, &stopAt) == 1) { 704 fprintf(stderr, "\nStopping simulation at icount %" PRIi64 "\n", stopAt); 705 Simulator::StopSimAt = stopAt; 706 } 707 708 return sim.release(); 709 } 710 711 void Simulator::Destroy(Simulator* sim) { js_delete(sim); } 712 713 // The loong64Debugger class is used by the simulator while debugging simulated 714 // code. 715 class loong64Debugger { 716 public: 717 explicit loong64Debugger(Simulator* sim) : sim_(sim) {} 718 719 void stop(SimInstruction* instr); 720 void debug(); 721 // Print all registers with a nice formatting. 722 void printAllRegs(); 723 void printAllRegsIncludingFPU(); 724 725 private: 726 // We set the breakpoint code to 0x7fff to easily recognize it. 727 static const Instr kBreakpointInstr = op_break | (0x7fff & CODEMask); 728 static const Instr kNopInstr = 0x0; 729 730 Simulator* sim_; 731 732 int64_t getRegisterValue(int regnum); 733 int64_t getFPURegisterValueLong(int regnum); 734 float getFPURegisterValueFloat(int regnum); 735 double getFPURegisterValueDouble(int regnum); 736 bool getValue(const char* desc, int64_t* value); 737 738 // Set or delete a breakpoint. Returns true if successful. 739 bool setBreakpoint(SimInstruction* breakpc); 740 bool deleteBreakpoint(SimInstruction* breakpc); 741 742 // Undo and redo all breakpoints. This is needed to bracket disassembly and 743 // execution to skip past breakpoints when run from the debugger. 744 void undoBreakpoints(); 745 void redoBreakpoints(); 746 }; 747 748 static void UNIMPLEMENTED() { 749 printf("UNIMPLEMENTED instruction.\n"); 750 MOZ_CRASH(); 751 } 752 static void UNREACHABLE() { 753 printf("UNREACHABLE instruction.\n"); 754 MOZ_CRASH(); 755 } 756 static void UNSUPPORTED() { 757 printf("Unsupported instruction.\n"); 758 MOZ_CRASH(); 759 } 760 761 void loong64Debugger::stop(SimInstruction* instr) { 762 // Get the stop code. 763 uint32_t code = instr->bits(25, 6); 764 // Retrieve the encoded address, which comes just after this stop. 765 char* msg = 766 *reinterpret_cast<char**>(sim_->get_pc() + SimInstruction::kInstrSize); 767 // Update this stop description. 768 if (!sim_->watchedStops_[code].desc_) { 769 sim_->watchedStops_[code].desc_ = msg; 770 } 771 // Print the stop message and code if it is not the default code. 772 if (code != kMaxStopCode) { 773 printf("Simulator hit stop %u: %s\n", code, msg); 774 } else { 775 printf("Simulator hit %s\n", msg); 776 } 777 sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize); 778 debug(); 779 } 780 781 int64_t loong64Debugger::getRegisterValue(int regnum) { 782 if (regnum == kPCRegister) { 783 return sim_->get_pc(); 784 } 785 return sim_->getRegister(regnum); 786 } 787 788 int64_t loong64Debugger::getFPURegisterValueLong(int regnum) { 789 return sim_->getFpuRegister(regnum); 790 } 791 792 float loong64Debugger::getFPURegisterValueFloat(int regnum) { 793 return sim_->getFpuRegisterFloat(regnum); 794 } 795 796 double loong64Debugger::getFPURegisterValueDouble(int regnum) { 797 return sim_->getFpuRegisterDouble(regnum); 798 } 799 800 bool loong64Debugger::getValue(const char* desc, int64_t* value) { 801 Register reg = Register::FromName(desc); 802 if (reg != InvalidReg) { 803 *value = getRegisterValue(reg.code()); 804 return true; 805 } 806 807 if (strncmp(desc, "0x", 2) == 0) { 808 return sscanf(desc + 2, "%" PRIx64, reinterpret_cast<uint64_t*>(value)) == 809 1; 810 } 811 return sscanf(desc, "%" PRIu64, reinterpret_cast<uint64_t*>(value)) == 1; 812 } 813 814 bool loong64Debugger::setBreakpoint(SimInstruction* breakpc) { 815 // Check if a breakpoint can be set. If not return without any side-effects. 816 if (sim_->break_pc_ != nullptr) { 817 return false; 818 } 819 820 // Set the breakpoint. 821 sim_->break_pc_ = breakpc; 822 sim_->break_instr_ = breakpc->instructionBits(); 823 // Not setting the breakpoint instruction in the code itself. It will be set 824 // when the debugger shell continues. 825 return true; 826 } 827 828 bool loong64Debugger::deleteBreakpoint(SimInstruction* breakpc) { 829 if (sim_->break_pc_ != nullptr) { 830 sim_->break_pc_->setInstructionBits(sim_->break_instr_); 831 } 832 833 sim_->break_pc_ = nullptr; 834 sim_->break_instr_ = 0; 835 return true; 836 } 837 838 void loong64Debugger::undoBreakpoints() { 839 if (sim_->break_pc_) { 840 sim_->break_pc_->setInstructionBits(sim_->break_instr_); 841 } 842 } 843 844 void loong64Debugger::redoBreakpoints() { 845 if (sim_->break_pc_) { 846 sim_->break_pc_->setInstructionBits(kBreakpointInstr); 847 } 848 } 849 850 void loong64Debugger::printAllRegs() { 851 int64_t value; 852 for (uint32_t i = 0; i < Registers::Total; i++) { 853 value = getRegisterValue(i); 854 printf("%3s: 0x%016" PRIx64 " %20" PRIi64 " ", Registers::GetName(i), 855 value, value); 856 857 if (i % 2) { 858 printf("\n"); 859 } 860 } 861 printf("\n"); 862 863 value = getRegisterValue(Simulator::pc); 864 printf(" pc: 0x%016" PRIx64 "\n", value); 865 } 866 867 void loong64Debugger::printAllRegsIncludingFPU() { 868 printAllRegs(); 869 870 printf("\n\n"); 871 // f0, f1, f2, ... f31. 872 for (uint32_t i = 0; i < FloatRegisters::TotalPhys; i++) { 873 printf("%3s: 0x%016" PRIi64 "\tflt: %-8.4g\tdbl: %-16.4g\n", 874 FloatRegisters::GetName(i), getFPURegisterValueLong(i), 875 getFPURegisterValueFloat(i), getFPURegisterValueDouble(i)); 876 } 877 } 878 879 static char* ReadLine(const char* prompt) { 880 UniqueChars result; 881 char lineBuf[256]; 882 int offset = 0; 883 bool keepGoing = true; 884 fprintf(stdout, "%s", prompt); 885 fflush(stdout); 886 while (keepGoing) { 887 if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) { 888 // fgets got an error. Just give up. 889 return nullptr; 890 } 891 int len = strlen(lineBuf); 892 if (len > 0 && lineBuf[len - 1] == '\n') { 893 // Since we read a new line we are done reading the line. This 894 // will exit the loop after copying this buffer into the result. 895 keepGoing = false; 896 } 897 if (!result) { 898 // Allocate the initial result and make room for the terminating '\0' 899 result.reset(js_pod_malloc<char>(len + 1)); 900 if (!result) { 901 return nullptr; 902 } 903 } else { 904 // Allocate a new result with enough room for the new addition. 905 int new_len = offset + len + 1; 906 char* new_result = js_pod_malloc<char>(new_len); 907 if (!new_result) { 908 return nullptr; 909 } 910 // Copy the existing input into the new array and set the new 911 // array as the result. 912 memcpy(new_result, result.get(), offset * sizeof(char)); 913 result.reset(new_result); 914 } 915 // Copy the newly read line into the result. 916 memcpy(result.get() + offset, lineBuf, len * sizeof(char)); 917 offset += len; 918 } 919 920 MOZ_ASSERT(result); 921 result[offset] = '\0'; 922 return result.release(); 923 } 924 925 static void DisassembleInstruction(uint64_t pc) { 926 printf("Not supported on loongarch64 yet\n"); 927 } 928 929 void loong64Debugger::debug() { 930 intptr_t lastPC = -1; 931 bool done = false; 932 933 #define COMMAND_SIZE 63 934 #define ARG_SIZE 255 935 936 #define STR(a) #a 937 #define XSTR(a) STR(a) 938 939 char cmd[COMMAND_SIZE + 1]; 940 char arg1[ARG_SIZE + 1]; 941 char arg2[ARG_SIZE + 1]; 942 char* argv[3] = {cmd, arg1, arg2}; 943 944 // Make sure to have a proper terminating character if reaching the limit. 945 cmd[COMMAND_SIZE] = 0; 946 arg1[ARG_SIZE] = 0; 947 arg2[ARG_SIZE] = 0; 948 949 // Undo all set breakpoints while running in the debugger shell. This will 950 // make them invisible to all commands. 951 undoBreakpoints(); 952 953 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) { 954 if (lastPC != sim_->get_pc()) { 955 DisassembleInstruction(sim_->get_pc()); 956 printf(" 0x%016" PRIi64 " \n", sim_->get_pc()); 957 lastPC = sim_->get_pc(); 958 } 959 char* line = ReadLine("sim> "); 960 if (line == nullptr) { 961 break; 962 } else { 963 char* last_input = sim_->lastDebuggerInput(); 964 if (strcmp(line, "\n") == 0 && last_input != nullptr) { 965 line = last_input; 966 } else { 967 // Ownership is transferred to sim_; 968 sim_->setLastDebuggerInput(line); 969 } 970 // Use sscanf to parse the individual parts of the command line. At the 971 // moment no command expects more than two parameters. 972 int argc = sscanf(line, 973 "%" XSTR(COMMAND_SIZE) "s " 974 "%" XSTR(ARG_SIZE) "s " 975 "%" XSTR(ARG_SIZE) "s", 976 cmd, arg1, arg2); 977 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { 978 SimInstruction* instr = 979 reinterpret_cast<SimInstruction*>(sim_->get_pc()); 980 if (!instr->isTrap()) { 981 sim_->instructionDecode( 982 reinterpret_cast<SimInstruction*>(sim_->get_pc())); 983 } else { 984 // Allow si to jump over generated breakpoints. 985 printf("/!\\ Jumping over generated breakpoint.\n"); 986 sim_->set_pc(sim_->get_pc() + SimInstruction::kInstrSize); 987 } 988 sim_->icount_++; 989 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { 990 // Execute the one instruction we broke at with breakpoints disabled. 991 sim_->instructionDecode( 992 reinterpret_cast<SimInstruction*>(sim_->get_pc())); 993 sim_->icount_++; 994 // Leave the debugger shell. 995 done = true; 996 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { 997 if (argc == 2) { 998 int64_t value; 999 if (strcmp(arg1, "all") == 0) { 1000 printAllRegs(); 1001 } else if (strcmp(arg1, "allf") == 0) { 1002 printAllRegsIncludingFPU(); 1003 } else { 1004 Register reg = Register::FromName(arg1); 1005 FloatRegisters::Code fReg = FloatRegisters::FromName(arg1); 1006 if (reg != InvalidReg) { 1007 value = getRegisterValue(reg.code()); 1008 printf("%s: 0x%016" PRIi64 " %20" PRIi64 " \n", arg1, value, 1009 value); 1010 } else if (fReg != FloatRegisters::Invalid) { 1011 printf("%3s: 0x%016" PRIi64 "\tflt: %-8.4g\tdbl: %-16.4g\n", 1012 FloatRegisters::GetName(fReg), 1013 getFPURegisterValueLong(fReg), 1014 getFPURegisterValueFloat(fReg), 1015 getFPURegisterValueDouble(fReg)); 1016 } else { 1017 printf("%s unrecognized\n", arg1); 1018 } 1019 } 1020 } else { 1021 printf("print <register> or print <fpu register> single\n"); 1022 } 1023 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { 1024 int64_t* cur = nullptr; 1025 int64_t* end = nullptr; 1026 int next_arg = 1; 1027 1028 if (strcmp(cmd, "stack") == 0) { 1029 cur = reinterpret_cast<int64_t*>(sim_->getRegister(Simulator::sp)); 1030 } else { // Command "mem". 1031 int64_t value; 1032 if (!getValue(arg1, &value)) { 1033 printf("%s unrecognized\n", arg1); 1034 continue; 1035 } 1036 cur = reinterpret_cast<int64_t*>(value); 1037 next_arg++; 1038 } 1039 1040 int64_t words; 1041 if (argc == next_arg) { 1042 words = 10; 1043 } else { 1044 if (!getValue(argv[next_arg], &words)) { 1045 words = 10; 1046 } 1047 } 1048 end = cur + words; 1049 1050 while (cur < end) { 1051 printf(" %p: 0x%016" PRIx64 " %20" PRIi64, cur, *cur, *cur); 1052 printf("\n"); 1053 cur++; 1054 } 1055 1056 } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) || 1057 (strcmp(cmd, "di") == 0)) { 1058 uint8_t* cur = nullptr; 1059 uint8_t* end = nullptr; 1060 1061 if (argc == 1) { 1062 cur = reinterpret_cast<uint8_t*>(sim_->get_pc()); 1063 end = cur + (10 * SimInstruction::kInstrSize); 1064 } else if (argc == 2) { 1065 Register reg = Register::FromName(arg1); 1066 if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) { 1067 // The argument is an address or a register name. 1068 int64_t value; 1069 if (getValue(arg1, &value)) { 1070 cur = reinterpret_cast<uint8_t*>(value); 1071 // Disassemble 10 instructions at <arg1>. 1072 end = cur + (10 * SimInstruction::kInstrSize); 1073 } 1074 } else { 1075 // The argument is the number of instructions. 1076 int64_t value; 1077 if (getValue(arg1, &value)) { 1078 cur = reinterpret_cast<uint8_t*>(sim_->get_pc()); 1079 // Disassemble <arg1> instructions. 1080 end = cur + (value * SimInstruction::kInstrSize); 1081 } 1082 } 1083 } else { 1084 int64_t value1; 1085 int64_t value2; 1086 if (getValue(arg1, &value1) && getValue(arg2, &value2)) { 1087 cur = reinterpret_cast<uint8_t*>(value1); 1088 end = cur + (value2 * SimInstruction::kInstrSize); 1089 } 1090 } 1091 1092 while (cur < end) { 1093 DisassembleInstruction(uint64_t(cur)); 1094 cur += SimInstruction::kInstrSize; 1095 } 1096 } else if (strcmp(cmd, "gdb") == 0) { 1097 printf("relinquishing control to gdb\n"); 1098 #if defined(__x86_64__) 1099 asm("int $3"); 1100 #elif defined(__aarch64__) 1101 // see masm.breakpoint for arm64 1102 asm("brk #0xf000"); 1103 #endif 1104 printf("regaining control from gdb\n"); 1105 } else if (strcmp(cmd, "break") == 0) { 1106 if (argc == 2) { 1107 int64_t value; 1108 if (getValue(arg1, &value)) { 1109 if (!setBreakpoint(reinterpret_cast<SimInstruction*>(value))) { 1110 printf("setting breakpoint failed\n"); 1111 } 1112 } else { 1113 printf("%s unrecognized\n", arg1); 1114 } 1115 } else { 1116 printf("break <address>\n"); 1117 } 1118 } else if (strcmp(cmd, "del") == 0) { 1119 if (!deleteBreakpoint(nullptr)) { 1120 printf("deleting breakpoint failed\n"); 1121 } 1122 } else if (strcmp(cmd, "flags") == 0) { 1123 printf("No flags on LOONG64 !\n"); 1124 } else if (strcmp(cmd, "stop") == 0) { 1125 int64_t value; 1126 intptr_t stop_pc = sim_->get_pc() - 2 * SimInstruction::kInstrSize; 1127 SimInstruction* stop_instr = reinterpret_cast<SimInstruction*>(stop_pc); 1128 SimInstruction* msg_address = reinterpret_cast<SimInstruction*>( 1129 stop_pc + SimInstruction::kInstrSize); 1130 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) { 1131 // Remove the current stop. 1132 if (sim_->isStopInstruction(stop_instr)) { 1133 stop_instr->setInstructionBits(kNopInstr); 1134 msg_address->setInstructionBits(kNopInstr); 1135 } else { 1136 printf("Not at debugger stop.\n"); 1137 } 1138 } else if (argc == 3) { 1139 // Print information about all/the specified breakpoint(s). 1140 if (strcmp(arg1, "info") == 0) { 1141 if (strcmp(arg2, "all") == 0) { 1142 printf("Stop information:\n"); 1143 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; 1144 i++) { 1145 sim_->printStopInfo(i); 1146 } 1147 } else if (getValue(arg2, &value)) { 1148 sim_->printStopInfo(value); 1149 } else { 1150 printf("Unrecognized argument.\n"); 1151 } 1152 } else if (strcmp(arg1, "enable") == 0) { 1153 // Enable all/the specified breakpoint(s). 1154 if (strcmp(arg2, "all") == 0) { 1155 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; 1156 i++) { 1157 sim_->enableStop(i); 1158 } 1159 } else if (getValue(arg2, &value)) { 1160 sim_->enableStop(value); 1161 } else { 1162 printf("Unrecognized argument.\n"); 1163 } 1164 } else if (strcmp(arg1, "disable") == 0) { 1165 // Disable all/the specified breakpoint(s). 1166 if (strcmp(arg2, "all") == 0) { 1167 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode; 1168 i++) { 1169 sim_->disableStop(i); 1170 } 1171 } else if (getValue(arg2, &value)) { 1172 sim_->disableStop(value); 1173 } else { 1174 printf("Unrecognized argument.\n"); 1175 } 1176 } 1177 } else { 1178 printf("Wrong usage. Use help command for more information.\n"); 1179 } 1180 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { 1181 printf("cont\n"); 1182 printf(" continue execution (alias 'c')\n"); 1183 printf("stepi\n"); 1184 printf(" step one instruction (alias 'si')\n"); 1185 printf("print <register>\n"); 1186 printf(" print register content (alias 'p')\n"); 1187 printf(" use register name 'all' to print all registers\n"); 1188 printf("printobject <register>\n"); 1189 printf(" print an object from a register (alias 'po')\n"); 1190 printf("stack [<words>]\n"); 1191 printf(" dump stack content, default dump 10 words)\n"); 1192 printf("mem <address> [<words>]\n"); 1193 printf(" dump memory content, default dump 10 words)\n"); 1194 printf("flags\n"); 1195 printf(" print flags\n"); 1196 printf("disasm [<instructions>]\n"); 1197 printf("disasm [<address/register>]\n"); 1198 printf("disasm [[<address/register>] <instructions>]\n"); 1199 printf(" disassemble code, default is 10 instructions\n"); 1200 printf(" from pc (alias 'di')\n"); 1201 printf("gdb\n"); 1202 printf(" enter gdb\n"); 1203 printf("break <address>\n"); 1204 printf(" set a break point on the address\n"); 1205 printf("del\n"); 1206 printf(" delete the breakpoint\n"); 1207 printf("stop feature:\n"); 1208 printf(" Description:\n"); 1209 printf(" Stops are debug instructions inserted by\n"); 1210 printf(" the Assembler::stop() function.\n"); 1211 printf(" When hitting a stop, the Simulator will\n"); 1212 printf(" stop and and give control to the Debugger.\n"); 1213 printf(" All stop codes are watched:\n"); 1214 printf(" - They can be enabled / disabled: the Simulator\n"); 1215 printf(" will / won't stop when hitting them.\n"); 1216 printf(" - The Simulator keeps track of how many times they \n"); 1217 printf(" are met. (See the info command.) Going over a\n"); 1218 printf(" disabled stop still increases its counter. \n"); 1219 printf(" Commands:\n"); 1220 printf(" stop info all/<code> : print infos about number <code>\n"); 1221 printf(" or all stop(s).\n"); 1222 printf(" stop enable/disable all/<code> : enables / disables\n"); 1223 printf(" all or number <code> stop(s)\n"); 1224 printf(" stop unstop\n"); 1225 printf(" ignore the stop instruction at the current location\n"); 1226 printf(" from now on\n"); 1227 } else { 1228 printf("Unknown command: %s\n", cmd); 1229 } 1230 } 1231 } 1232 1233 // Add all the breakpoints back to stop execution and enter the debugger 1234 // shell when hit. 1235 redoBreakpoints(); 1236 1237 #undef COMMAND_SIZE 1238 #undef ARG_SIZE 1239 1240 #undef STR 1241 #undef XSTR 1242 } 1243 1244 static bool AllOnOnePage(uintptr_t start, int size) { 1245 intptr_t start_page = (start & ~CachePage::kPageMask); 1246 intptr_t end_page = ((start + size) & ~CachePage::kPageMask); 1247 return start_page == end_page; 1248 } 1249 1250 void Simulator::setLastDebuggerInput(char* input) { 1251 js_free(lastDebuggerInput_); 1252 lastDebuggerInput_ = input; 1253 } 1254 1255 static CachePage* GetCachePageLocked(SimulatorProcess::ICacheMap& i_cache, 1256 void* page) { 1257 SimulatorProcess::ICacheMap::AddPtr p = i_cache.lookupForAdd(page); 1258 if (p) { 1259 return p->value(); 1260 } 1261 AutoEnterOOMUnsafeRegion oomUnsafe; 1262 CachePage* new_page = js_new<CachePage>(); 1263 if (!new_page || !i_cache.add(p, page, new_page)) { 1264 oomUnsafe.crash("Simulator CachePage"); 1265 } 1266 return new_page; 1267 } 1268 1269 // Flush from start up to and not including start + size. 1270 static void FlushOnePageLocked(SimulatorProcess::ICacheMap& i_cache, 1271 intptr_t start, int size) { 1272 MOZ_ASSERT(size <= CachePage::kPageSize); 1273 MOZ_ASSERT(AllOnOnePage(start, size - 1)); 1274 MOZ_ASSERT((start & CachePage::kLineMask) == 0); 1275 MOZ_ASSERT((size & CachePage::kLineMask) == 0); 1276 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); 1277 int offset = (start & CachePage::kPageMask); 1278 CachePage* cache_page = GetCachePageLocked(i_cache, page); 1279 char* valid_bytemap = cache_page->validityByte(offset); 1280 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); 1281 } 1282 1283 static void FlushICacheLocked(SimulatorProcess::ICacheMap& i_cache, 1284 void* start_addr, size_t size) { 1285 intptr_t start = reinterpret_cast<intptr_t>(start_addr); 1286 int intra_line = (start & CachePage::kLineMask); 1287 start -= intra_line; 1288 size += intra_line; 1289 size = ((size - 1) | CachePage::kLineMask) + 1; 1290 int offset = (start & CachePage::kPageMask); 1291 while (!AllOnOnePage(start, size - 1)) { 1292 int bytes_to_flush = CachePage::kPageSize - offset; 1293 FlushOnePageLocked(i_cache, start, bytes_to_flush); 1294 start += bytes_to_flush; 1295 size -= bytes_to_flush; 1296 MOZ_ASSERT((start & CachePage::kPageMask) == 0); 1297 offset = 0; 1298 } 1299 if (size != 0) { 1300 FlushOnePageLocked(i_cache, start, size); 1301 } 1302 } 1303 1304 /* static */ 1305 void SimulatorProcess::checkICacheLocked(SimInstruction* instr) { 1306 intptr_t address = reinterpret_cast<intptr_t>(instr); 1307 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); 1308 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); 1309 int offset = (address & CachePage::kPageMask); 1310 CachePage* cache_page = GetCachePageLocked(icache(), page); 1311 char* cache_valid_byte = cache_page->validityByte(offset); 1312 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); 1313 char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask); 1314 1315 if (cache_hit) { 1316 // Check that the data in memory matches the contents of the I-cache. 1317 mozilla::DebugOnly<int> cmpret = 1318 memcmp(reinterpret_cast<void*>(instr), cache_page->cachedData(offset), 1319 SimInstruction::kInstrSize); 1320 MOZ_ASSERT(cmpret == 0); 1321 } else { 1322 // Cache miss. Load memory into the cache. 1323 memcpy(cached_line, line, CachePage::kLineLength); 1324 *cache_valid_byte = CachePage::LINE_VALID; 1325 } 1326 } 1327 1328 HashNumber SimulatorProcess::ICacheHasher::hash(const Lookup& l) { 1329 return U32(reinterpret_cast<uintptr_t>(l)) >> 2; 1330 } 1331 1332 bool SimulatorProcess::ICacheHasher::match(const Key& k, const Lookup& l) { 1333 MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0); 1334 MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0); 1335 return k == l; 1336 } 1337 1338 /* static */ 1339 void SimulatorProcess::FlushICache(void* start_addr, size_t size) { 1340 if (!ICacheCheckingDisableCount) { 1341 AutoLockSimulatorCache als; 1342 js::jit::FlushICacheLocked(icache(), start_addr, size); 1343 } 1344 } 1345 1346 Simulator::Simulator() { 1347 // Set up simulator support first. Some of this information is needed to 1348 // setup the architecture state. 1349 1350 // Note, allocation and anything that depends on allocated memory is 1351 // deferred until init(), in order to handle OOM properly. 1352 1353 stack_ = nullptr; 1354 stackLimit_ = 0; 1355 pc_modified_ = false; 1356 icount_ = 0; 1357 break_count_ = 0; 1358 break_pc_ = nullptr; 1359 break_instr_ = 0; 1360 single_stepping_ = false; 1361 single_step_callback_ = nullptr; 1362 single_step_callback_arg_ = nullptr; 1363 1364 // Set up architecture state. 1365 // All registers are initialized to zero to start with. 1366 for (int i = 0; i < Register::kNumSimuRegisters; i++) { 1367 registers_[i] = 0; 1368 } 1369 for (int i = 0; i < Simulator::FPURegister::kNumFPURegisters; i++) { 1370 FPUregisters_[i] = 0; 1371 } 1372 1373 for (int i = 0; i < kNumCFRegisters; i++) { 1374 CFregisters_[i] = 0; 1375 } 1376 1377 FCSR_ = 0; 1378 LLBit_ = false; 1379 LLAddr_ = 0; 1380 lastLLValue_ = 0; 1381 1382 // The ra and pc are initialized to a known bad value that will cause an 1383 // access violation if the simulator ever tries to execute it. 1384 registers_[pc] = bad_ra; 1385 registers_[ra] = bad_ra; 1386 1387 for (int i = 0; i < kNumExceptions; i++) { 1388 exceptions[i] = 0; 1389 } 1390 1391 lastDebuggerInput_ = nullptr; 1392 } 1393 1394 bool Simulator::init() { 1395 // Allocate 2MB for the stack. Note that we will only use 1MB, see below. 1396 static const size_t stackSize = 2 * 1024 * 1024; 1397 stack_ = js_pod_malloc<char>(stackSize); 1398 if (!stack_) { 1399 return false; 1400 } 1401 1402 // Leave a safety margin of 1MB to prevent overrunning the stack when 1403 // pushing values (total stack size is 2MB). 1404 stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024; 1405 1406 // The sp is initialized to point to the bottom (high address) of the 1407 // allocated stack area. To be safe in potential stack underflows we leave 1408 // some buffer below. 1409 registers_[sp] = reinterpret_cast<int64_t>(stack_) + stackSize - 64; 1410 1411 return true; 1412 } 1413 1414 // When the generated code calls an external reference we need to catch that in 1415 // the simulator. The external reference will be a function compiled for the 1416 // host architecture. We need to call that function instead of trying to 1417 // execute it with the simulator. We do that by redirecting the external 1418 // reference to a swi (software-interrupt) instruction that is handled by 1419 // the simulator. We write the original destination of the jump just at a known 1420 // offset from the swi instruction so the simulator knows what to call. 1421 class Redirection { 1422 friend class SimulatorProcess; 1423 1424 // sim's lock must already be held. 1425 Redirection(void* nativeFunction, ABIFunctionType type) 1426 : nativeFunction_(nativeFunction), 1427 swiInstruction_(kCallRedirInstr), 1428 type_(type), 1429 next_(nullptr) { 1430 next_ = SimulatorProcess::redirection(); 1431 if (!SimulatorProcess::ICacheCheckingDisableCount) { 1432 FlushICacheLocked(SimulatorProcess::icache(), addressOfSwiInstruction(), 1433 SimInstruction::kInstrSize); 1434 } 1435 SimulatorProcess::setRedirection(this); 1436 } 1437 1438 public: 1439 void* addressOfSwiInstruction() { return &swiInstruction_; } 1440 void* nativeFunction() const { return nativeFunction_; } 1441 ABIFunctionType type() const { return type_; } 1442 1443 static Redirection* Get(void* nativeFunction, ABIFunctionType type) { 1444 AutoLockSimulatorCache als; 1445 1446 Redirection* current = SimulatorProcess::redirection(); 1447 for (; current != nullptr; current = current->next_) { 1448 if (current->nativeFunction_ == nativeFunction) { 1449 MOZ_ASSERT(current->type() == type); 1450 return current; 1451 } 1452 } 1453 1454 // Note: we can't use js_new here because the constructor is private. 1455 AutoEnterOOMUnsafeRegion oomUnsafe; 1456 Redirection* redir = js_pod_malloc<Redirection>(1); 1457 if (!redir) { 1458 oomUnsafe.crash("Simulator redirection"); 1459 } 1460 new (redir) Redirection(nativeFunction, type); 1461 return redir; 1462 } 1463 1464 static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) { 1465 uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction); 1466 uint8_t* addrOfRedirection = 1467 addrOfSwi - offsetof(Redirection, swiInstruction_); 1468 return reinterpret_cast<Redirection*>(addrOfRedirection); 1469 } 1470 1471 private: 1472 void* nativeFunction_; 1473 uint32_t swiInstruction_; 1474 ABIFunctionType type_; 1475 Redirection* next_; 1476 }; 1477 1478 Simulator::~Simulator() { js_free(stack_); } 1479 1480 SimulatorProcess::SimulatorProcess() 1481 : cacheLock_(mutexid::SimulatorCacheLock), redirection_(nullptr) { 1482 if (getenv("LOONG64_SIM_ICACHE_CHECKS")) { 1483 ICacheCheckingDisableCount = 0; 1484 } 1485 } 1486 1487 SimulatorProcess::~SimulatorProcess() { 1488 Redirection* r = redirection_; 1489 while (r) { 1490 Redirection* next = r->next_; 1491 js_delete(r); 1492 r = next; 1493 } 1494 } 1495 1496 /* static */ 1497 void* Simulator::RedirectNativeFunction(void* nativeFunction, 1498 ABIFunctionType type) { 1499 Redirection* redirection = Redirection::Get(nativeFunction, type); 1500 return redirection->addressOfSwiInstruction(); 1501 } 1502 1503 // Get the active Simulator for the current thread. 1504 Simulator* Simulator::Current() { 1505 JSContext* cx = TlsContext.get(); 1506 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); 1507 return cx->simulator(); 1508 } 1509 1510 // Sets the register in the architecture state. It will also deal with updating 1511 // Simulator internal state for special registers such as PC. 1512 void Simulator::setRegister(int reg, int64_t value) { 1513 MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters)); 1514 if (reg == pc) { 1515 pc_modified_ = true; 1516 } 1517 1518 // Zero register always holds 0. 1519 registers_[reg] = (reg == 0) ? 0 : value; 1520 } 1521 1522 void Simulator::setFpuRegister(int fpureg, int64_t value) { 1523 MOZ_ASSERT((fpureg >= 0) && 1524 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1525 FPUregisters_[fpureg] = value; 1526 } 1527 1528 void Simulator::setFpuRegisterHiWord(int fpureg, int32_t value) { 1529 // Set ONLY upper 32-bits, leaving lower bits untouched. 1530 MOZ_ASSERT((fpureg >= 0) && 1531 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1532 int32_t* phiword; 1533 phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1; 1534 1535 *phiword = value; 1536 } 1537 1538 void Simulator::setFpuRegisterWord(int fpureg, int32_t value) { 1539 // Set ONLY lower 32-bits, leaving upper bits untouched. 1540 MOZ_ASSERT((fpureg >= 0) && 1541 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1542 int32_t* pword; 1543 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]); 1544 1545 *pword = value; 1546 } 1547 1548 void Simulator::setFpuRegisterWordInvalidResult(float original, float rounded, 1549 int fpureg) { 1550 double max_int32 = static_cast<double>(INT32_MAX); 1551 double min_int32 = static_cast<double>(INT32_MIN); 1552 1553 if (std::isnan(original)) { 1554 setFpuRegisterWord(fpureg, 0); 1555 } else if (rounded > max_int32) { 1556 setFpuRegister(fpureg, kFPUInvalidResult); 1557 } else if (rounded < min_int32) { 1558 setFpuRegister(fpureg, kFPUInvalidResultNegative); 1559 } else { 1560 UNREACHABLE(); 1561 } 1562 } 1563 1564 void Simulator::setFpuRegisterWordInvalidResult(double original, double rounded, 1565 int fpureg) { 1566 double max_int32 = static_cast<double>(INT32_MAX); 1567 double min_int32 = static_cast<double>(INT32_MIN); 1568 1569 if (std::isnan(original)) { 1570 setFpuRegisterWord(fpureg, 0); 1571 } else if (rounded > max_int32) { 1572 setFpuRegisterWord(fpureg, kFPUInvalidResult); 1573 } else if (rounded < min_int32) { 1574 setFpuRegisterWord(fpureg, kFPUInvalidResultNegative); 1575 } else { 1576 UNREACHABLE(); 1577 } 1578 } 1579 1580 void Simulator::setFpuRegisterInvalidResult(float original, float rounded, 1581 int fpureg) { 1582 double max_int32 = static_cast<double>(INT32_MAX); 1583 double min_int32 = static_cast<double>(INT32_MIN); 1584 1585 if (std::isnan(original)) { 1586 setFpuRegister(fpureg, 0); 1587 } else if (rounded > max_int32) { 1588 setFpuRegister(fpureg, kFPUInvalidResult); 1589 } else if (rounded < min_int32) { 1590 setFpuRegister(fpureg, kFPUInvalidResultNegative); 1591 } else { 1592 UNREACHABLE(); 1593 } 1594 } 1595 1596 void Simulator::setFpuRegisterInvalidResult(double original, double rounded, 1597 int fpureg) { 1598 double max_int32 = static_cast<double>(INT32_MAX); 1599 double min_int32 = static_cast<double>(INT32_MIN); 1600 1601 if (std::isnan(original)) { 1602 setFpuRegister(fpureg, 0); 1603 } else if (rounded > max_int32) { 1604 setFpuRegister(fpureg, kFPUInvalidResult); 1605 } else if (rounded < min_int32) { 1606 setFpuRegister(fpureg, kFPUInvalidResultNegative); 1607 } else { 1608 UNREACHABLE(); 1609 } 1610 } 1611 1612 void Simulator::setFpuRegisterInvalidResult64(float original, float rounded, 1613 int fpureg) { 1614 // The value of INT64_MAX (2^63-1) can't be represented as double exactly, 1615 // loading the most accurate representation into max_int64, which is 2^63. 1616 double max_int64 = static_cast<double>(INT64_MAX); 1617 double min_int64 = static_cast<double>(INT64_MIN); 1618 1619 if (std::isnan(original)) { 1620 setFpuRegister(fpureg, 0); 1621 } else if (rounded >= max_int64) { 1622 setFpuRegister(fpureg, kFPU64InvalidResult); 1623 } else if (rounded < min_int64) { 1624 setFpuRegister(fpureg, kFPU64InvalidResultNegative); 1625 } else { 1626 UNREACHABLE(); 1627 } 1628 } 1629 1630 void Simulator::setFpuRegisterInvalidResult64(double original, double rounded, 1631 int fpureg) { 1632 // The value of INT64_MAX (2^63-1) can't be represented as double exactly, 1633 // loading the most accurate representation into max_int64, which is 2^63. 1634 double max_int64 = static_cast<double>(INT64_MAX); 1635 double min_int64 = static_cast<double>(INT64_MIN); 1636 1637 if (std::isnan(original)) { 1638 setFpuRegister(fpureg, 0); 1639 } else if (rounded >= max_int64) { 1640 setFpuRegister(fpureg, kFPU64InvalidResult); 1641 } else if (rounded < min_int64) { 1642 setFpuRegister(fpureg, kFPU64InvalidResultNegative); 1643 } else { 1644 UNREACHABLE(); 1645 } 1646 } 1647 1648 void Simulator::setFpuRegisterFloat(int fpureg, float value) { 1649 MOZ_ASSERT((fpureg >= 0) && 1650 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1651 *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]) = value; 1652 } 1653 1654 void Simulator::setFpuRegisterDouble(int fpureg, double value) { 1655 MOZ_ASSERT((fpureg >= 0) && 1656 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1657 *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]) = value; 1658 } 1659 1660 void Simulator::setCFRegister(int cfreg, bool value) { 1661 MOZ_ASSERT((cfreg >= 0) && (cfreg < kNumCFRegisters)); 1662 CFregisters_[cfreg] = value; 1663 } 1664 1665 bool Simulator::getCFRegister(int cfreg) const { 1666 MOZ_ASSERT((cfreg >= 0) && (cfreg < kNumCFRegisters)); 1667 return CFregisters_[cfreg]; 1668 } 1669 1670 // Get the register from the architecture state. This function does handle 1671 // the special case of accessing the PC register. 1672 int64_t Simulator::getRegister(int reg) const { 1673 MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters)); 1674 if (reg == 0) { 1675 return 0; 1676 } 1677 return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0); 1678 } 1679 1680 int64_t Simulator::getFpuRegister(int fpureg) const { 1681 MOZ_ASSERT((fpureg >= 0) && 1682 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1683 return FPUregisters_[fpureg]; 1684 } 1685 1686 int32_t Simulator::getFpuRegisterWord(int fpureg) const { 1687 MOZ_ASSERT((fpureg >= 0) && 1688 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1689 return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]); 1690 } 1691 1692 int32_t Simulator::getFpuRegisterSignedWord(int fpureg) const { 1693 MOZ_ASSERT((fpureg >= 0) && 1694 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1695 return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]); 1696 } 1697 1698 int32_t Simulator::getFpuRegisterHiWord(int fpureg) const { 1699 MOZ_ASSERT((fpureg >= 0) && 1700 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1701 return *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1); 1702 } 1703 1704 float Simulator::getFpuRegisterFloat(int fpureg) const { 1705 MOZ_ASSERT((fpureg >= 0) && 1706 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1707 return *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]); 1708 } 1709 1710 double Simulator::getFpuRegisterDouble(int fpureg) const { 1711 MOZ_ASSERT((fpureg >= 0) && 1712 (fpureg < Simulator::FPURegister::kNumFPURegisters)); 1713 return *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]); 1714 } 1715 1716 void Simulator::setCallResultDouble(double result) { 1717 setFpuRegisterDouble(f0, result); 1718 } 1719 1720 void Simulator::setCallResultFloat(float result) { 1721 setFpuRegisterFloat(f0, result); 1722 } 1723 1724 void Simulator::setCallResult(int64_t res) { setRegister(a0, res); } 1725 #ifdef XP_DARWIN 1726 // add a dedicated setCallResult for intptr_t on Darwin 1727 void Simulator::setCallResult(intptr_t res) { setRegister(v0, I64(res)); } 1728 #endif 1729 void Simulator::setCallResult(__int128_t res) { 1730 setRegister(a0, I64(res)); 1731 setRegister(a1, I64(res >> 64)); 1732 } 1733 1734 // Helper functions for setting and testing the FCSR register's bits. 1735 void Simulator::setFCSRBit(uint32_t cc, bool value) { 1736 if (value) { 1737 FCSR_ |= (1 << cc); 1738 } else { 1739 FCSR_ &= ~(1 << cc); 1740 } 1741 } 1742 1743 bool Simulator::testFCSRBit(uint32_t cc) { return FCSR_ & (1 << cc); } 1744 1745 unsigned int Simulator::getFCSRRoundingMode() { 1746 return FCSR_ & kFPURoundingModeMask; 1747 } 1748 1749 // Sets the rounding error codes in FCSR based on the result of the rounding. 1750 // Returns true if the operation was invalid. 1751 template <typename T> 1752 bool Simulator::setFCSRRoundError(double original, double rounded) { 1753 bool ret = false; 1754 1755 setFCSRBit(kFCSRInexactCauseBit, false); 1756 setFCSRBit(kFCSRUnderflowCauseBit, false); 1757 setFCSRBit(kFCSROverflowCauseBit, false); 1758 setFCSRBit(kFCSRInvalidOpCauseBit, false); 1759 1760 if (!std::isfinite(original) || !std::isfinite(rounded)) { 1761 setFCSRBit(kFCSRInvalidOpFlagBit, true); 1762 setFCSRBit(kFCSRInvalidOpCauseBit, true); 1763 ret = true; 1764 } 1765 1766 if (original != rounded) { 1767 setFCSRBit(kFCSRInexactFlagBit, true); 1768 setFCSRBit(kFCSRInexactCauseBit, true); 1769 } 1770 1771 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) { 1772 setFCSRBit(kFCSRUnderflowFlagBit, true); 1773 setFCSRBit(kFCSRUnderflowCauseBit, true); 1774 ret = true; 1775 } 1776 1777 if ((long double)rounded > (long double)std::numeric_limits<T>::max() || 1778 (long double)rounded < (long double)std::numeric_limits<T>::min()) { 1779 setFCSRBit(kFCSROverflowFlagBit, true); 1780 setFCSRBit(kFCSROverflowCauseBit, true); 1781 // The reference is not really clear but it seems this is required: 1782 setFCSRBit(kFCSRInvalidOpFlagBit, true); 1783 setFCSRBit(kFCSRInvalidOpCauseBit, true); 1784 ret = true; 1785 } 1786 1787 return ret; 1788 } 1789 1790 // For cvt instructions only 1791 template <typename T> 1792 void Simulator::roundAccordingToFCSR(T toRound, T* rounded, 1793 int32_t* rounded_int) { 1794 switch ((FCSR_ >> 8) & 3) { 1795 case kRoundToNearest: 1796 *rounded = std::floor(toRound + 0.5); 1797 *rounded_int = static_cast<int32_t>(*rounded); 1798 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) { 1799 // If the number is halfway between two integers, 1800 // round to the even one. 1801 *rounded_int -= 1; 1802 *rounded -= 1.; 1803 } 1804 break; 1805 case kRoundToZero: 1806 *rounded = trunc(toRound); 1807 *rounded_int = static_cast<int32_t>(*rounded); 1808 break; 1809 case kRoundToPlusInf: 1810 *rounded = std::ceil(toRound); 1811 *rounded_int = static_cast<int32_t>(*rounded); 1812 break; 1813 case kRoundToMinusInf: 1814 *rounded = std::floor(toRound); 1815 *rounded_int = static_cast<int32_t>(*rounded); 1816 break; 1817 } 1818 } 1819 1820 template <typename T> 1821 void Simulator::round64AccordingToFCSR(T toRound, T* rounded, 1822 int64_t* rounded_int) { 1823 switch ((FCSR_ >> 8) & 3) { 1824 case kRoundToNearest: 1825 *rounded = std::floor(toRound + 0.5); 1826 *rounded_int = static_cast<int64_t>(*rounded); 1827 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) { 1828 // If the number is halfway between two integers, 1829 // round to the even one. 1830 *rounded_int -= 1; 1831 *rounded -= 1.; 1832 } 1833 break; 1834 case kRoundToZero: 1835 *rounded = trunc(toRound); 1836 *rounded_int = static_cast<int64_t>(*rounded); 1837 break; 1838 case kRoundToPlusInf: 1839 *rounded = std::ceil(toRound); 1840 *rounded_int = static_cast<int64_t>(*rounded); 1841 break; 1842 case kRoundToMinusInf: 1843 *rounded = std::floor(toRound); 1844 *rounded_int = static_cast<int64_t>(*rounded); 1845 break; 1846 } 1847 } 1848 1849 // Raw access to the PC register. 1850 void Simulator::set_pc(int64_t value) { 1851 pc_modified_ = true; 1852 registers_[pc] = value; 1853 } 1854 1855 bool Simulator::has_bad_pc() const { 1856 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc)); 1857 } 1858 1859 // Raw access to the PC register without the special adjustment when reading. 1860 int64_t Simulator::get_pc() const { return registers_[pc]; } 1861 1862 JS::ProfilingFrameIterator::RegisterState Simulator::registerState() { 1863 wasm::RegisterState state; 1864 state.pc = (void*)get_pc(); 1865 state.fp = (void*)getRegister(fp); 1866 state.sp = (void*)getRegister(sp); 1867 state.lr = (void*)getRegister(ra); 1868 return state; 1869 } 1870 1871 uint8_t Simulator::readBU(uint64_t addr) { 1872 if (handleWasmSegFault(addr, 1)) { 1873 return 0xff; 1874 } 1875 1876 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); 1877 return *ptr; 1878 } 1879 1880 int8_t Simulator::readB(uint64_t addr) { 1881 if (handleWasmSegFault(addr, 1)) { 1882 return -1; 1883 } 1884 1885 int8_t* ptr = reinterpret_cast<int8_t*>(addr); 1886 return *ptr; 1887 } 1888 1889 void Simulator::writeB(uint64_t addr, uint8_t value) { 1890 if (handleWasmSegFault(addr, 1)) { 1891 return; 1892 } 1893 1894 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); 1895 *ptr = value; 1896 } 1897 1898 void Simulator::writeB(uint64_t addr, int8_t value) { 1899 if (handleWasmSegFault(addr, 1)) { 1900 return; 1901 } 1902 1903 int8_t* ptr = reinterpret_cast<int8_t*>(addr); 1904 *ptr = value; 1905 } 1906 1907 uint16_t Simulator::readHU(uint64_t addr, SimInstruction* instr) { 1908 if (handleWasmSegFault(addr, 2)) { 1909 return 0xffff; 1910 } 1911 1912 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); 1913 return *ptr; 1914 } 1915 1916 int16_t Simulator::readH(uint64_t addr, SimInstruction* instr) { 1917 if (handleWasmSegFault(addr, 2)) { 1918 return -1; 1919 } 1920 1921 int16_t* ptr = reinterpret_cast<int16_t*>(addr); 1922 return *ptr; 1923 } 1924 1925 void Simulator::writeH(uint64_t addr, uint16_t value, SimInstruction* instr) { 1926 if (handleWasmSegFault(addr, 2)) { 1927 return; 1928 } 1929 1930 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); 1931 LLBit_ = false; 1932 *ptr = value; 1933 return; 1934 } 1935 1936 void Simulator::writeH(uint64_t addr, int16_t value, SimInstruction* instr) { 1937 if (handleWasmSegFault(addr, 2)) { 1938 return; 1939 } 1940 1941 int16_t* ptr = reinterpret_cast<int16_t*>(addr); 1942 LLBit_ = false; 1943 *ptr = value; 1944 return; 1945 } 1946 1947 uint32_t Simulator::readWU(uint64_t addr, SimInstruction* instr) { 1948 if (handleWasmSegFault(addr, 4)) { 1949 return -1; 1950 } 1951 1952 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); 1953 return *ptr; 1954 } 1955 1956 int32_t Simulator::readW(uint64_t addr, SimInstruction* instr) { 1957 if (handleWasmSegFault(addr, 4)) { 1958 return -1; 1959 } 1960 1961 int32_t* ptr = reinterpret_cast<int32_t*>(addr); 1962 return *ptr; 1963 } 1964 1965 void Simulator::writeW(uint64_t addr, uint32_t value, SimInstruction* instr) { 1966 if (handleWasmSegFault(addr, 4)) { 1967 return; 1968 } 1969 1970 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr); 1971 LLBit_ = false; 1972 *ptr = value; 1973 return; 1974 } 1975 1976 void Simulator::writeW(uint64_t addr, int32_t value, SimInstruction* instr) { 1977 if (handleWasmSegFault(addr, 4)) { 1978 return; 1979 } 1980 1981 int32_t* ptr = reinterpret_cast<int32_t*>(addr); 1982 LLBit_ = false; 1983 *ptr = value; 1984 return; 1985 } 1986 1987 int64_t Simulator::readDW(uint64_t addr, SimInstruction* instr) { 1988 if (handleWasmSegFault(addr, 8)) { 1989 return -1; 1990 } 1991 1992 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); 1993 return *ptr; 1994 } 1995 1996 void Simulator::writeDW(uint64_t addr, int64_t value, SimInstruction* instr) { 1997 if (handleWasmSegFault(addr, 8)) { 1998 return; 1999 } 2000 2001 int64_t* ptr = reinterpret_cast<int64_t*>(addr); 2002 LLBit_ = false; 2003 *ptr = value; 2004 return; 2005 } 2006 2007 double Simulator::readD(uint64_t addr, SimInstruction* instr) { 2008 if (handleWasmSegFault(addr, 8)) { 2009 return NAN; 2010 } 2011 2012 double* ptr = reinterpret_cast<double*>(addr); 2013 return *ptr; 2014 } 2015 2016 void Simulator::writeD(uint64_t addr, double value, SimInstruction* instr) { 2017 if (handleWasmSegFault(addr, 8)) { 2018 return; 2019 } 2020 2021 double* ptr = reinterpret_cast<double*>(addr); 2022 LLBit_ = false; 2023 *ptr = value; 2024 return; 2025 } 2026 2027 int Simulator::loadLinkedW(uint64_t addr, SimInstruction* instr) { 2028 if ((addr & 3) == 0) { 2029 if (handleWasmSegFault(addr, 4)) { 2030 return -1; 2031 } 2032 2033 volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(addr); 2034 int32_t value = *ptr; 2035 lastLLValue_ = value; 2036 LLAddr_ = addr; 2037 // Note that any memory write or "external" interrupt should reset this 2038 // value to false. 2039 LLBit_ = true; 2040 return value; 2041 } 2042 printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr, 2043 reinterpret_cast<intptr_t>(instr)); 2044 MOZ_CRASH(); 2045 return 0; 2046 } 2047 2048 int Simulator::storeConditionalW(uint64_t addr, int value, 2049 SimInstruction* instr) { 2050 // Correct behavior in this case, as defined by architecture, is to just 2051 // return 0, but there is no point at allowing that. It is certainly an 2052 // indicator of a bug. 2053 if (addr != LLAddr_) { 2054 printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR 2055 ", expected: 0x%016" PRIxPTR "\n", 2056 addr, reinterpret_cast<intptr_t>(instr), LLAddr_); 2057 MOZ_CRASH(); 2058 } 2059 2060 if ((addr & 3) == 0) { 2061 SharedMem<int32_t*> ptr = 2062 SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr)); 2063 2064 if (!LLBit_) { 2065 return 0; 2066 } 2067 2068 LLBit_ = false; 2069 LLAddr_ = 0; 2070 int32_t expected = int32_t(lastLLValue_); 2071 int32_t old = 2072 AtomicOperations::compareExchangeSeqCst(ptr, expected, int32_t(value)); 2073 return (old == expected) ? 1 : 0; 2074 } 2075 printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr, 2076 reinterpret_cast<intptr_t>(instr)); 2077 MOZ_CRASH(); 2078 return 0; 2079 } 2080 2081 int64_t Simulator::loadLinkedD(uint64_t addr, SimInstruction* instr) { 2082 if ((addr & kPointerAlignmentMask) == 0) { 2083 if (handleWasmSegFault(addr, 8)) { 2084 return -1; 2085 } 2086 2087 volatile int64_t* ptr = reinterpret_cast<volatile int64_t*>(addr); 2088 int64_t value = *ptr; 2089 lastLLValue_ = value; 2090 LLAddr_ = addr; 2091 // Note that any memory write or "external" interrupt should reset this 2092 // value to false. 2093 LLBit_ = true; 2094 return value; 2095 } 2096 printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr, 2097 reinterpret_cast<intptr_t>(instr)); 2098 MOZ_CRASH(); 2099 return 0; 2100 } 2101 2102 int Simulator::storeConditionalD(uint64_t addr, int64_t value, 2103 SimInstruction* instr) { 2104 // Correct behavior in this case, as defined by architecture, is to just 2105 // return 0, but there is no point at allowing that. It is certainly an 2106 // indicator of a bug. 2107 if (addr != LLAddr_) { 2108 printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR 2109 ", expected: 0x%016" PRIxPTR "\n", 2110 addr, reinterpret_cast<intptr_t>(instr), LLAddr_); 2111 MOZ_CRASH(); 2112 } 2113 2114 if ((addr & kPointerAlignmentMask) == 0) { 2115 SharedMem<int64_t*> ptr = 2116 SharedMem<int64_t*>::shared(reinterpret_cast<int64_t*>(addr)); 2117 2118 if (!LLBit_) { 2119 return 0; 2120 } 2121 2122 LLBit_ = false; 2123 LLAddr_ = 0; 2124 int64_t expected = lastLLValue_; 2125 int64_t old = 2126 AtomicOperations::compareExchangeSeqCst(ptr, expected, int64_t(value)); 2127 return (old == expected) ? 1 : 0; 2128 } 2129 printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr, 2130 reinterpret_cast<intptr_t>(instr)); 2131 MOZ_CRASH(); 2132 return 0; 2133 } 2134 2135 uintptr_t Simulator::stackLimit() const { return stackLimit_; } 2136 2137 uintptr_t* Simulator::addressOfStackLimit() { return &stackLimit_; } 2138 2139 bool Simulator::overRecursed(uintptr_t newsp) const { 2140 if (newsp == 0) { 2141 newsp = getRegister(sp); 2142 } 2143 return newsp <= stackLimit(); 2144 } 2145 2146 bool Simulator::overRecursedWithExtra(uint32_t extra) const { 2147 uintptr_t newsp = getRegister(sp) - extra; 2148 return newsp <= stackLimit(); 2149 } 2150 2151 // Unsupported instructions use format to print an error and stop execution. 2152 void Simulator::format(SimInstruction* instr, const char* format) { 2153 printf("Simulator found unsupported instruction:\n 0x%016" PRIxPTR ": %s\n", 2154 reinterpret_cast<intptr_t>(instr), format); 2155 MOZ_CRASH(); 2156 } 2157 2158 inline int32_t Simulator::rj_reg(SimInstruction* instr) const { 2159 return instr->rjValue(); 2160 } 2161 2162 inline int64_t Simulator::rj(SimInstruction* instr) const { 2163 return getRegister(rj_reg(instr)); 2164 } 2165 2166 inline uint64_t Simulator::rj_u(SimInstruction* instr) const { 2167 return static_cast<uint64_t>(getRegister(rj_reg(instr))); 2168 } 2169 2170 inline int32_t Simulator::rk_reg(SimInstruction* instr) const { 2171 return instr->rkValue(); 2172 } 2173 2174 inline int64_t Simulator::rk(SimInstruction* instr) const { 2175 return getRegister(rk_reg(instr)); 2176 } 2177 2178 inline uint64_t Simulator::rk_u(SimInstruction* instr) const { 2179 return static_cast<uint64_t>(getRegister(rk_reg(instr))); 2180 } 2181 2182 inline int32_t Simulator::rd_reg(SimInstruction* instr) const { 2183 return instr->rdValue(); 2184 } 2185 2186 inline int64_t Simulator::rd(SimInstruction* instr) const { 2187 return getRegister(rd_reg(instr)); 2188 } 2189 2190 inline uint64_t Simulator::rd_u(SimInstruction* instr) const { 2191 return static_cast<uint64_t>(getRegister(rd_reg(instr))); 2192 } 2193 2194 inline int32_t Simulator::fa_reg(SimInstruction* instr) const { 2195 return instr->faValue(); 2196 } 2197 2198 inline float Simulator::fa_float(SimInstruction* instr) const { 2199 return getFpuRegisterFloat(fa_reg(instr)); 2200 } 2201 2202 inline double Simulator::fa_double(SimInstruction* instr) const { 2203 return getFpuRegisterDouble(fa_reg(instr)); 2204 } 2205 2206 inline int32_t Simulator::fj_reg(SimInstruction* instr) const { 2207 return instr->fjValue(); 2208 } 2209 2210 inline float Simulator::fj_float(SimInstruction* instr) const { 2211 return getFpuRegisterFloat(fj_reg(instr)); 2212 } 2213 2214 inline double Simulator::fj_double(SimInstruction* instr) const { 2215 return getFpuRegisterDouble(fj_reg(instr)); 2216 } 2217 2218 inline int32_t Simulator::fk_reg(SimInstruction* instr) const { 2219 return instr->fkValue(); 2220 } 2221 2222 inline float Simulator::fk_float(SimInstruction* instr) const { 2223 return getFpuRegisterFloat(fk_reg(instr)); 2224 } 2225 2226 inline double Simulator::fk_double(SimInstruction* instr) const { 2227 return getFpuRegisterDouble(fk_reg(instr)); 2228 } 2229 2230 inline int32_t Simulator::fd_reg(SimInstruction* instr) const { 2231 return instr->fdValue(); 2232 } 2233 2234 inline float Simulator::fd_float(SimInstruction* instr) const { 2235 return getFpuRegisterFloat(fd_reg(instr)); 2236 } 2237 2238 inline double Simulator::fd_double(SimInstruction* instr) const { 2239 return getFpuRegisterDouble(fd_reg(instr)); 2240 } 2241 2242 inline int32_t Simulator::cj_reg(SimInstruction* instr) const { 2243 return instr->cjValue(); 2244 } 2245 2246 inline bool Simulator::cj(SimInstruction* instr) const { 2247 return getCFRegister(cj_reg(instr)); 2248 } 2249 2250 inline int32_t Simulator::cd_reg(SimInstruction* instr) const { 2251 return instr->cdValue(); 2252 } 2253 2254 inline bool Simulator::cd(SimInstruction* instr) const { 2255 return getCFRegister(cd_reg(instr)); 2256 } 2257 2258 inline int32_t Simulator::ca_reg(SimInstruction* instr) const { 2259 return instr->caValue(); 2260 } 2261 2262 inline bool Simulator::ca(SimInstruction* instr) const { 2263 return getCFRegister(ca_reg(instr)); 2264 } 2265 2266 inline uint32_t Simulator::sa2(SimInstruction* instr) const { 2267 return instr->sa2Value(); 2268 } 2269 2270 inline uint32_t Simulator::sa3(SimInstruction* instr) const { 2271 return instr->sa3Value(); 2272 } 2273 2274 inline uint32_t Simulator::ui5(SimInstruction* instr) const { 2275 return instr->imm5Value(); 2276 } 2277 2278 inline uint32_t Simulator::ui6(SimInstruction* instr) const { 2279 return instr->imm6Value(); 2280 } 2281 2282 inline uint32_t Simulator::lsbw(SimInstruction* instr) const { 2283 return instr->lsbwValue(); 2284 } 2285 2286 inline uint32_t Simulator::msbw(SimInstruction* instr) const { 2287 return instr->msbwValue(); 2288 } 2289 2290 inline uint32_t Simulator::lsbd(SimInstruction* instr) const { 2291 return instr->lsbdValue(); 2292 } 2293 2294 inline uint32_t Simulator::msbd(SimInstruction* instr) const { 2295 return instr->msbdValue(); 2296 } 2297 2298 inline uint32_t Simulator::cond(SimInstruction* instr) const { 2299 return instr->condValue(); 2300 } 2301 2302 inline int32_t Simulator::si12(SimInstruction* instr) const { 2303 return (instr->imm12Value() << 20) >> 20; 2304 } 2305 2306 inline uint32_t Simulator::ui12(SimInstruction* instr) const { 2307 return instr->imm12Value(); 2308 } 2309 2310 inline int32_t Simulator::si14(SimInstruction* instr) const { 2311 return (instr->imm14Value() << 18) >> 18; 2312 } 2313 2314 inline int32_t Simulator::si16(SimInstruction* instr) const { 2315 return (instr->imm16Value() << 16) >> 16; 2316 } 2317 2318 inline int32_t Simulator::si20(SimInstruction* instr) const { 2319 return (instr->imm20Value() << 12) >> 12; 2320 } 2321 2322 ABI_FUNCTION_TYPE_SIM_PROTOTYPES 2323 2324 // Software interrupt instructions are used by the simulator to call into C++. 2325 void Simulator::softwareInterrupt(SimInstruction* instr) { 2326 // the break_ instruction could get us here. 2327 mozilla::DebugOnly<int32_t> opcode_hi15 = instr->bits(31, 17); 2328 MOZ_ASSERT(opcode_hi15 == 0x15); 2329 uint32_t code = instr->bits(14, 0); 2330 2331 if (instr->instructionBits() == kCallRedirInstr) { 2332 Redirection* redirection = Redirection::FromSwiInstruction(instr); 2333 uintptr_t nativeFn = 2334 reinterpret_cast<uintptr_t>(redirection->nativeFunction()); 2335 2336 // Get the SP for reading stack arguments 2337 int64_t* sp_ = reinterpret_cast<int64_t*>(getRegister(sp)); 2338 2339 // Store argument register values in local variables for ease of use below. 2340 int64_t a0_ = getRegister(a0); 2341 int64_t a1_ = getRegister(a1); 2342 int64_t a2_ = getRegister(a2); 2343 int64_t a3_ = getRegister(a3); 2344 int64_t a4_ = getRegister(a4); 2345 int64_t a5_ = getRegister(a5); 2346 int64_t a6_ = getRegister(a6); 2347 int64_t a7_ = getRegister(a7); 2348 float f0_s = getFpuRegisterFloat(f0); 2349 float f1_s = getFpuRegisterFloat(f1); 2350 float f2_s = getFpuRegisterFloat(f2); 2351 float f3_s = getFpuRegisterFloat(f3); 2352 float f4_s = getFpuRegisterFloat(f4); 2353 double f0_d = getFpuRegisterDouble(f0); 2354 double f1_d = getFpuRegisterDouble(f1); 2355 double f2_d = getFpuRegisterDouble(f2); 2356 double f3_d = getFpuRegisterDouble(f3); 2357 2358 // This is dodgy but it works because the C entry stubs are never moved. 2359 // See comment in codegen-arm.cc and bug 1242173. 2360 int64_t saved_ra = getRegister(ra); 2361 2362 bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0; 2363 if (!stack_aligned) { 2364 fprintf(stderr, "Runtime call with unaligned stack!\n"); 2365 MOZ_CRASH(); 2366 } 2367 2368 if (single_stepping_) { 2369 single_step_callback_(single_step_callback_arg_, this, nullptr); 2370 } 2371 2372 switch (redirection->type()) { 2373 ABI_FUNCTION_TYPE_LOONGARCH64_SIM_DISPATCH 2374 2375 default: 2376 MOZ_CRASH("Unknown function type."); 2377 } 2378 2379 if (single_stepping_) { 2380 single_step_callback_(single_step_callback_arg_, this, nullptr); 2381 } 2382 2383 setRegister(ra, saved_ra); 2384 set_pc(getRegister(ra)); 2385 } else if ((instr->bits(31, 15) << 15 == op_break) && code == kWasmTrapCode) { 2386 uint8_t* newPC; 2387 if (wasm::HandleIllegalInstruction(registerState(), &newPC)) { 2388 set_pc(int64_t(newPC)); 2389 return; 2390 } 2391 } else if ((instr->bits(31, 15) << 15 == op_break) && code <= kMaxStopCode && 2392 code != 6) { 2393 if (isWatchpoint(code)) { 2394 // printWatchpoint(code); 2395 } else { 2396 increaseStopCounter(code); 2397 handleStop(code, instr); 2398 } 2399 } else { 2400 // All remaining break_ codes, and all traps are handled here. 2401 loong64Debugger dbg(this); 2402 dbg.debug(); 2403 } 2404 } 2405 2406 // Stop helper functions. 2407 bool Simulator::isWatchpoint(uint32_t code) { 2408 return (code <= kMaxWatchpointCode); 2409 } 2410 2411 void Simulator::printWatchpoint(uint32_t code) { 2412 loong64Debugger dbg(this); 2413 ++break_count_; 2414 printf("\n---- break %d marker: %20" PRIi64 " (instr count: %20" PRIi64 2415 ") ----\n", 2416 code, break_count_, icount_); 2417 dbg.printAllRegs(); // Print registers and continue running. 2418 } 2419 2420 void Simulator::handleStop(uint32_t code, SimInstruction* instr) { 2421 // Stop if it is enabled, otherwise go on jumping over the stop 2422 // and the message address. 2423 if (isEnabledStop(code)) { 2424 loong64Debugger dbg(this); 2425 dbg.stop(instr); 2426 } else { 2427 set_pc(get_pc() + 1 * SimInstruction::kInstrSize); 2428 } 2429 } 2430 2431 bool Simulator::isStopInstruction(SimInstruction* instr) { 2432 int32_t opcode_hi15 = instr->bits(31, 17); 2433 uint32_t code = static_cast<uint32_t>(instr->bits(14, 0)); 2434 return (opcode_hi15 == 0x15) && code > kMaxWatchpointCode && 2435 code <= kMaxStopCode; 2436 } 2437 2438 bool Simulator::isEnabledStop(uint32_t code) { 2439 MOZ_ASSERT(code <= kMaxStopCode); 2440 MOZ_ASSERT(code > kMaxWatchpointCode); 2441 return !(watchedStops_[code].count_ & kStopDisabledBit); 2442 } 2443 2444 void Simulator::enableStop(uint32_t code) { 2445 if (!isEnabledStop(code)) { 2446 watchedStops_[code].count_ &= ~kStopDisabledBit; 2447 } 2448 } 2449 2450 void Simulator::disableStop(uint32_t code) { 2451 if (isEnabledStop(code)) { 2452 watchedStops_[code].count_ |= kStopDisabledBit; 2453 } 2454 } 2455 2456 void Simulator::increaseStopCounter(uint32_t code) { 2457 MOZ_ASSERT(code <= kMaxStopCode); 2458 if ((watchedStops_[code].count_ & ~(1 << 31)) == 0x7fffffff) { 2459 printf( 2460 "Stop counter for code %i has overflowed.\n" 2461 "Enabling this code and reseting the counter to 0.\n", 2462 code); 2463 watchedStops_[code].count_ = 0; 2464 enableStop(code); 2465 } else { 2466 watchedStops_[code].count_++; 2467 } 2468 } 2469 2470 // Print a stop status. 2471 void Simulator::printStopInfo(uint32_t code) { 2472 if (code <= kMaxWatchpointCode) { 2473 printf("That is a watchpoint, not a stop.\n"); 2474 return; 2475 } else if (code > kMaxStopCode) { 2476 printf("Code too large, only %u stops can be used\n", kMaxStopCode + 1); 2477 return; 2478 } 2479 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled"; 2480 int32_t count = watchedStops_[code].count_ & ~kStopDisabledBit; 2481 // Don't print the state of unused breakpoints. 2482 if (count != 0) { 2483 if (watchedStops_[code].desc_) { 2484 printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code, state, 2485 count, watchedStops_[code].desc_); 2486 } else { 2487 printf("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state, 2488 count); 2489 } 2490 } 2491 } 2492 2493 void Simulator::signalExceptions() { 2494 for (int i = 1; i < kNumExceptions; i++) { 2495 if (exceptions[i] != 0) { 2496 MOZ_CRASH("Error: Exception raised."); 2497 } 2498 } 2499 } 2500 2501 // ReverseBits(value) returns |value| in reverse bit order. 2502 template <typename T> 2503 T ReverseBits(T value) { 2504 MOZ_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) || 2505 (sizeof(value) == 4) || (sizeof(value) == 8)); 2506 T result = 0; 2507 for (unsigned i = 0; i < (sizeof(value) * 8); i++) { 2508 result = (result << 1) | (value & 1); 2509 value >>= 1; 2510 } 2511 return result; 2512 } 2513 2514 // Min/Max template functions for Double and Single arguments. 2515 2516 template <typename T> 2517 static T FPAbs(T a); 2518 2519 template <> 2520 double FPAbs<double>(double a) { 2521 return fabs(a); 2522 } 2523 2524 template <> 2525 float FPAbs<float>(float a) { 2526 return fabsf(a); 2527 } 2528 2529 enum class MaxMinKind : int { kMin = 0, kMax = 1 }; 2530 2531 template <typename T> 2532 static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T* result) { 2533 if (std::isnan(a) && std::isnan(b)) { 2534 *result = a; 2535 } else if (std::isnan(a)) { 2536 *result = b; 2537 } else if (std::isnan(b)) { 2538 *result = a; 2539 } else if (b == a) { 2540 // Handle -0.0 == 0.0 case. 2541 // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax 2542 // negates the result. 2543 *result = std::signbit(b) - static_cast<int>(kind) ? b : a; 2544 } else { 2545 return false; 2546 } 2547 return true; 2548 } 2549 2550 template <typename T> 2551 static T FPUMin(T a, T b) { 2552 T result; 2553 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) { 2554 return result; 2555 } else { 2556 return b < a ? b : a; 2557 } 2558 } 2559 2560 template <typename T> 2561 static T FPUMax(T a, T b) { 2562 T result; 2563 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, &result)) { 2564 return result; 2565 } else { 2566 return b > a ? b : a; 2567 } 2568 } 2569 2570 template <typename T> 2571 static T FPUMinA(T a, T b) { 2572 T result; 2573 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) { 2574 if (FPAbs(a) < FPAbs(b)) { 2575 result = a; 2576 } else if (FPAbs(b) < FPAbs(a)) { 2577 result = b; 2578 } else { 2579 result = a < b ? a : b; 2580 } 2581 } 2582 return result; 2583 } 2584 2585 template <typename T> 2586 static T FPUMaxA(T a, T b) { 2587 T result; 2588 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) { 2589 if (FPAbs(a) > FPAbs(b)) { 2590 result = a; 2591 } else if (FPAbs(b) > FPAbs(a)) { 2592 result = b; 2593 } else { 2594 result = a > b ? a : b; 2595 } 2596 } 2597 return result; 2598 } 2599 2600 enum class KeepSign : bool { no = false, yes }; 2601 2602 // Handle execution based on instruction types. 2603 // decodeTypeImmediate 2604 void Simulator::decodeTypeOp6(SimInstruction* instr) { 2605 // Next pc. 2606 int64_t next_pc = bad_ra; 2607 2608 // Used for memory instructions. 2609 int64_t alu_out = 0; 2610 2611 // Branch instructions common part. 2612 auto BranchAndLinkHelper = [this, &next_pc](SimInstruction* instr) { 2613 int64_t current_pc = get_pc(); 2614 setRegister(ra, current_pc + SimInstruction::kInstrSize); 2615 int32_t offs26_low16 = 2616 static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16; 2617 int32_t offs26_high10 = static_cast<int32_t>(instr->bits(9, 0) << 22) >> 6; 2618 int32_t offs26 = offs26_low16 | offs26_high10; 2619 next_pc = current_pc + (offs26 << 2); 2620 set_pc(next_pc); 2621 }; 2622 2623 auto BranchOff16Helper = [this, &next_pc](SimInstruction* instr, 2624 bool do_branch) { 2625 int64_t current_pc = get_pc(); 2626 int32_t offs16 = static_cast<int32_t>(instr->bits(25, 10) << 16) >> 16; 2627 int32_t offs = do_branch ? (offs16 << 2) : SimInstruction::kInstrSize; 2628 next_pc = current_pc + offs; 2629 set_pc(next_pc); 2630 }; 2631 2632 auto BranchOff21Helper = [this, &next_pc](SimInstruction* instr, 2633 bool do_branch) { 2634 int64_t current_pc = get_pc(); 2635 int32_t offs21_low16 = 2636 static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16; 2637 int32_t offs21_high5 = static_cast<int32_t>(instr->bits(4, 0) << 27) >> 11; 2638 int32_t offs = offs21_low16 | offs21_high5; 2639 offs = do_branch ? (offs << 2) : SimInstruction::kInstrSize; 2640 next_pc = current_pc + offs; 2641 set_pc(next_pc); 2642 }; 2643 2644 auto BranchOff26Helper = [this, &next_pc](SimInstruction* instr) { 2645 int64_t current_pc = get_pc(); 2646 int32_t offs26_low16 = 2647 static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16; 2648 int32_t offs26_high10 = static_cast<int32_t>(instr->bits(9, 0) << 22) >> 6; 2649 int32_t offs26 = offs26_low16 | offs26_high10; 2650 next_pc = current_pc + (offs26 << 2); 2651 set_pc(next_pc); 2652 }; 2653 2654 auto JumpOff16Helper = [this, &next_pc](SimInstruction* instr) { 2655 int32_t offs16 = static_cast<int32_t>(instr->bits(25, 10) << 16) >> 16; 2656 setRegister(rd_reg(instr), get_pc() + SimInstruction::kInstrSize); 2657 next_pc = rj(instr) + (offs16 << 2); 2658 set_pc(next_pc); 2659 }; 2660 2661 switch (instr->bits(31, 26) << 26) { 2662 case op_addu16i_d: { 2663 int32_t si16_upper = static_cast<int32_t>(si16(instr)) << 16; 2664 alu_out = static_cast<int64_t>(si16_upper) + rj(instr); 2665 setRegister(rd_reg(instr), alu_out); 2666 break; 2667 } 2668 case op_beqz: { 2669 BranchOff21Helper(instr, rj(instr) == 0); 2670 break; 2671 } 2672 case op_bnez: { 2673 BranchOff21Helper(instr, rj(instr) != 0); 2674 break; 2675 } 2676 case op_bcz: { 2677 if (instr->bits(9, 8) == 0b00) { 2678 // BCEQZ 2679 BranchOff21Helper(instr, cj(instr) == false); 2680 } else if (instr->bits(9, 8) == 0b01) { 2681 // BCNEZ 2682 BranchOff21Helper(instr, cj(instr) == true); 2683 } else { 2684 UNREACHABLE(); 2685 } 2686 break; 2687 } 2688 case op_jirl: { 2689 JumpOff16Helper(instr); 2690 break; 2691 } 2692 case op_b: { 2693 BranchOff26Helper(instr); 2694 break; 2695 } 2696 case op_bl: { 2697 BranchAndLinkHelper(instr); 2698 break; 2699 } 2700 case op_beq: { 2701 BranchOff16Helper(instr, rj(instr) == rd(instr)); 2702 break; 2703 } 2704 case op_bne: { 2705 BranchOff16Helper(instr, rj(instr) != rd(instr)); 2706 break; 2707 } 2708 case op_blt: { 2709 BranchOff16Helper(instr, rj(instr) < rd(instr)); 2710 break; 2711 } 2712 case op_bge: { 2713 BranchOff16Helper(instr, rj(instr) >= rd(instr)); 2714 break; 2715 } 2716 case op_bltu: { 2717 BranchOff16Helper(instr, rj_u(instr) < rd_u(instr)); 2718 break; 2719 } 2720 case op_bgeu: { 2721 BranchOff16Helper(instr, rj_u(instr) >= rd_u(instr)); 2722 break; 2723 } 2724 default: 2725 UNREACHABLE(); 2726 } 2727 } 2728 2729 void Simulator::decodeTypeOp7(SimInstruction* instr) { 2730 int64_t alu_out; 2731 2732 switch (instr->bits(31, 25) << 25) { 2733 case op_lu12i_w: { 2734 int32_t si20_upper = static_cast<int32_t>(si20(instr) << 12); 2735 setRegister(rd_reg(instr), static_cast<int64_t>(si20_upper)); 2736 break; 2737 } 2738 case op_lu32i_d: { 2739 int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12) >> 12; 2740 int64_t lower_32bit_mask = 0xFFFFFFFF; 2741 alu_out = (static_cast<int64_t>(si20_signExtend) << 32) | 2742 (rd(instr) & lower_32bit_mask); 2743 setRegister(rd_reg(instr), alu_out); 2744 break; 2745 } 2746 case op_pcaddi: { 2747 int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12) >> 10; 2748 int64_t current_pc = get_pc(); 2749 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc; 2750 setRegister(rd_reg(instr), alu_out); 2751 break; 2752 } 2753 case op_pcalau12i: { 2754 int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12); 2755 int64_t current_pc = get_pc(); 2756 int64_t clear_lower12bit_mask = 0xFFFFFFFFFFFFF000; 2757 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc; 2758 setRegister(rd_reg(instr), alu_out & clear_lower12bit_mask); 2759 break; 2760 } 2761 case op_pcaddu12i: { 2762 int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12); 2763 int64_t current_pc = get_pc(); 2764 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc; 2765 setRegister(rd_reg(instr), alu_out); 2766 break; 2767 } 2768 case op_pcaddu18i: { 2769 int64_t si20_signExtend = (static_cast<int64_t>(si20(instr)) << 44) >> 26; 2770 int64_t current_pc = get_pc(); 2771 alu_out = si20_signExtend + current_pc; 2772 setRegister(rd_reg(instr), alu_out); 2773 break; 2774 } 2775 default: 2776 UNREACHABLE(); 2777 } 2778 } 2779 2780 void Simulator::decodeTypeOp8(SimInstruction* instr) { 2781 int64_t addr = 0x0; 2782 int64_t si14_se = (static_cast<int64_t>(si14(instr)) << 50) >> 48; 2783 2784 switch (instr->bits(31, 24) << 24) { 2785 case op_ldptr_w: { 2786 setRegister(rd_reg(instr), readW(rj(instr) + si14_se, instr)); 2787 break; 2788 } 2789 case op_stptr_w: { 2790 writeW(rj(instr) + si14_se, static_cast<int32_t>(rd(instr)), instr); 2791 break; 2792 } 2793 case op_ldptr_d: { 2794 setRegister(rd_reg(instr), readDW(rj(instr) + si14_se, instr)); 2795 break; 2796 } 2797 case op_stptr_d: { 2798 writeDW(rj(instr) + si14_se, rd(instr), instr); 2799 break; 2800 } 2801 case op_ll_w: { 2802 addr = si14_se + rj(instr); 2803 setRegister(rd_reg(instr), loadLinkedW(addr, instr)); 2804 break; 2805 } 2806 case op_sc_w: { 2807 addr = si14_se + rj(instr); 2808 setRegister( 2809 rd_reg(instr), 2810 storeConditionalW(addr, static_cast<int32_t>(rd(instr)), instr)); 2811 break; 2812 } 2813 case op_ll_d: { 2814 addr = si14_se + rj(instr); 2815 setRegister(rd_reg(instr), loadLinkedD(addr, instr)); 2816 break; 2817 } 2818 case op_sc_d: { 2819 addr = si14_se + rj(instr); 2820 setRegister(rd_reg(instr), storeConditionalD(addr, rd(instr), instr)); 2821 break; 2822 } 2823 default: 2824 UNREACHABLE(); 2825 } 2826 } 2827 2828 void Simulator::decodeTypeOp10(SimInstruction* instr) { 2829 int64_t alu_out = 0x0; 2830 int64_t si12_se = (static_cast<int64_t>(si12(instr)) << 52) >> 52; 2831 uint64_t si12_ze = (static_cast<uint64_t>(ui12(instr)) << 52) >> 52; 2832 2833 switch (instr->bits(31, 22) << 22) { 2834 case op_bstrins_d: { 2835 uint8_t lsbd_ = lsbd(instr); 2836 uint8_t msbd_ = msbd(instr); 2837 MOZ_ASSERT(lsbd_ <= msbd_); 2838 uint8_t size = msbd_ - lsbd_ + 1; 2839 if (size < 64) { 2840 uint64_t mask = (1ULL << size) - 1; 2841 alu_out = 2842 (rd_u(instr) & ~(mask << lsbd_)) | ((rj_u(instr) & mask) << lsbd_); 2843 setRegister(rd_reg(instr), alu_out); 2844 } else if (size == 64) { 2845 setRegister(rd_reg(instr), rj(instr)); 2846 } 2847 break; 2848 } 2849 case op_bstrpick_d: { 2850 uint8_t lsbd_ = lsbd(instr); 2851 uint8_t msbd_ = msbd(instr); 2852 MOZ_ASSERT(lsbd_ <= msbd_); 2853 uint8_t size = msbd_ - lsbd_ + 1; 2854 if (size < 64) { 2855 uint64_t mask = (1ULL << size) - 1; 2856 alu_out = (rj_u(instr) & (mask << lsbd_)) >> lsbd_; 2857 setRegister(rd_reg(instr), alu_out); 2858 } else if (size == 64) { 2859 setRegister(rd_reg(instr), rj(instr)); 2860 } 2861 break; 2862 } 2863 case op_slti: { 2864 setRegister(rd_reg(instr), rj(instr) < si12_se ? 1 : 0); 2865 break; 2866 } 2867 case op_sltui: { 2868 setRegister(rd_reg(instr), 2869 rj_u(instr) < static_cast<uint64_t>(si12_se) ? 1 : 0); 2870 break; 2871 } 2872 case op_addi_w: { 2873 int32_t alu32_out = 2874 static_cast<int32_t>(rj(instr)) + static_cast<int32_t>(si12_se); 2875 setRegister(rd_reg(instr), alu32_out); 2876 break; 2877 } 2878 case op_addi_d: { 2879 setRegister(rd_reg(instr), rj(instr) + si12_se); 2880 break; 2881 } 2882 case op_lu52i_d: { 2883 int64_t si12_se = static_cast<int64_t>(si12(instr)) << 52; 2884 uint64_t mask = (1ULL << 52) - 1; 2885 alu_out = si12_se + (rj(instr) & mask); 2886 setRegister(rd_reg(instr), alu_out); 2887 break; 2888 } 2889 case op_andi: { 2890 setRegister(rd_reg(instr), rj(instr) & si12_ze); 2891 break; 2892 } 2893 case op_ori: { 2894 setRegister(rd_reg(instr), rj_u(instr) | si12_ze); 2895 break; 2896 } 2897 case op_xori: { 2898 setRegister(rd_reg(instr), rj_u(instr) ^ si12_ze); 2899 break; 2900 } 2901 case op_ld_b: { 2902 setRegister(rd_reg(instr), readB(rj(instr) + si12_se)); 2903 break; 2904 } 2905 case op_ld_h: { 2906 setRegister(rd_reg(instr), readH(rj(instr) + si12_se, instr)); 2907 break; 2908 } 2909 case op_ld_w: { 2910 setRegister(rd_reg(instr), readW(rj(instr) + si12_se, instr)); 2911 break; 2912 } 2913 case op_ld_d: { 2914 setRegister(rd_reg(instr), readDW(rj(instr) + si12_se, instr)); 2915 break; 2916 } 2917 case op_st_b: { 2918 writeB(rj(instr) + si12_se, static_cast<int8_t>(rd(instr))); 2919 break; 2920 } 2921 case op_st_h: { 2922 writeH(rj(instr) + si12_se, static_cast<int16_t>(rd(instr)), instr); 2923 break; 2924 } 2925 case op_st_w: { 2926 writeW(rj(instr) + si12_se, static_cast<int32_t>(rd(instr)), instr); 2927 break; 2928 } 2929 case op_st_d: { 2930 writeDW(rj(instr) + si12_se, rd(instr), instr); 2931 break; 2932 } 2933 case op_ld_bu: { 2934 setRegister(rd_reg(instr), readBU(rj(instr) + si12_se)); 2935 break; 2936 } 2937 case op_ld_hu: { 2938 setRegister(rd_reg(instr), readHU(rj(instr) + si12_se, instr)); 2939 break; 2940 } 2941 case op_ld_wu: { 2942 setRegister(rd_reg(instr), readWU(rj(instr) + si12_se, instr)); 2943 break; 2944 } 2945 case op_fld_s: { 2946 setFpuRegister(fd_reg(instr), kFPUInvalidResult); // Trash upper 32 bits. 2947 setFpuRegisterWord(fd_reg(instr), readW(rj(instr) + si12_se, instr)); 2948 break; 2949 } 2950 case op_fst_s: { 2951 int32_t alu_out_32 = static_cast<int32_t>(getFpuRegister(fd_reg(instr))); 2952 writeW(rj(instr) + si12_se, alu_out_32, instr); 2953 break; 2954 } 2955 case op_fld_d: { 2956 setFpuRegisterDouble(fd_reg(instr), readD(rj(instr) + si12_se, instr)); 2957 break; 2958 } 2959 case op_fst_d: { 2960 writeD(rj(instr) + si12_se, getFpuRegisterDouble(fd_reg(instr)), instr); 2961 break; 2962 } 2963 case op_preld: 2964 UNIMPLEMENTED(); 2965 break; 2966 default: 2967 UNREACHABLE(); 2968 } 2969 } 2970 2971 void Simulator::decodeTypeOp11(SimInstruction* instr) { 2972 int64_t alu_out = 0x0; 2973 2974 switch (instr->bits(31, 21) << 21) { 2975 case op_bstr_w: { 2976 MOZ_ASSERT(instr->bit(21) == 1); 2977 uint8_t lsbw_ = lsbw(instr); 2978 uint8_t msbw_ = msbw(instr); 2979 MOZ_ASSERT(lsbw_ <= msbw_); 2980 uint8_t size = msbw_ - lsbw_ + 1; 2981 uint64_t mask = (1ULL << size) - 1; 2982 if (instr->bit(15) == 0) { 2983 // BSTRINS_W 2984 alu_out = static_cast<int32_t>((rd_u(instr) & ~(mask << lsbw_)) | 2985 ((rj_u(instr) & mask) << lsbw_)); 2986 } else { 2987 // BSTRPICK_W 2988 alu_out = 2989 static_cast<int32_t>((rj_u(instr) & (mask << lsbw_)) >> lsbw_); 2990 } 2991 setRegister(rd_reg(instr), alu_out); 2992 break; 2993 } 2994 default: 2995 UNREACHABLE(); 2996 } 2997 } 2998 2999 void Simulator::decodeTypeOp12(SimInstruction* instr) { 3000 switch (instr->bits(31, 20) << 20) { 3001 case op_fmadd_s: { 3002 setFpuRegisterFloat( 3003 fd_reg(instr), 3004 std::fma(fj_float(instr), fk_float(instr), fa_float(instr))); 3005 break; 3006 } 3007 case op_fmadd_d: { 3008 setFpuRegisterDouble( 3009 fd_reg(instr), 3010 std::fma(fj_double(instr), fk_double(instr), fa_double(instr))); 3011 break; 3012 } 3013 case op_fmsub_s: { 3014 setFpuRegisterFloat( 3015 fd_reg(instr), 3016 std::fma(-fj_float(instr), fk_float(instr), fa_float(instr))); 3017 break; 3018 } 3019 case op_fmsub_d: { 3020 setFpuRegisterDouble( 3021 fd_reg(instr), 3022 std::fma(-fj_double(instr), fk_double(instr), fa_double(instr))); 3023 break; 3024 } 3025 case op_fnmadd_s: { 3026 setFpuRegisterFloat( 3027 fd_reg(instr), 3028 std::fma(-fj_float(instr), fk_float(instr), -fa_float(instr))); 3029 break; 3030 } 3031 case op_fnmadd_d: { 3032 setFpuRegisterDouble( 3033 fd_reg(instr), 3034 std::fma(-fj_double(instr), fk_double(instr), -fa_double(instr))); 3035 break; 3036 } 3037 case op_fnmsub_s: { 3038 setFpuRegisterFloat( 3039 fd_reg(instr), 3040 std::fma(fj_float(instr), fk_float(instr), -fa_float(instr))); 3041 break; 3042 } 3043 case op_fnmsub_d: { 3044 setFpuRegisterDouble( 3045 fd_reg(instr), 3046 std::fma(fj_double(instr), fk_double(instr), -fa_double(instr))); 3047 break; 3048 } 3049 case op_fcmp_cond_s: { 3050 MOZ_ASSERT(instr->bits(4, 3) == 0); 3051 float fj = fj_float(instr); 3052 float fk = fk_float(instr); 3053 switch (cond(instr)) { 3054 case AssemblerLOONG64::CAF: { 3055 setCFRegister(cd_reg(instr), false); 3056 break; 3057 } 3058 case AssemblerLOONG64::CUN: { 3059 setCFRegister(cd_reg(instr), std::isnan(fj) || std::isnan(fk)); 3060 break; 3061 } 3062 case AssemblerLOONG64::CEQ: { 3063 setCFRegister(cd_reg(instr), fj == fk); 3064 break; 3065 } 3066 case AssemblerLOONG64::CUEQ: { 3067 setCFRegister(cd_reg(instr), 3068 (fj == fk) || std::isnan(fj) || std::isnan(fk)); 3069 break; 3070 } 3071 case AssemblerLOONG64::CLT: { 3072 setCFRegister(cd_reg(instr), fj < fk); 3073 break; 3074 } 3075 case AssemblerLOONG64::CULT: { 3076 setCFRegister(cd_reg(instr), 3077 (fj < fk) || std::isnan(fj) || std::isnan(fk)); 3078 break; 3079 } 3080 case AssemblerLOONG64::CLE: { 3081 setCFRegister(cd_reg(instr), fj <= fk); 3082 break; 3083 } 3084 case AssemblerLOONG64::CULE: { 3085 setCFRegister(cd_reg(instr), 3086 (fj <= fk) || std::isnan(fj) || std::isnan(fk)); 3087 break; 3088 } 3089 case AssemblerLOONG64::CNE: { 3090 setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk)); 3091 break; 3092 } 3093 case AssemblerLOONG64::COR: { 3094 setCFRegister(cd_reg(instr), !std::isnan(fj) && !std::isnan(fk)); 3095 break; 3096 } 3097 case AssemblerLOONG64::CUNE: { 3098 setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk) || 3099 std::isnan(fj) || std::isnan(fk)); 3100 break; 3101 } 3102 case AssemblerLOONG64::SAF: 3103 UNIMPLEMENTED(); 3104 break; 3105 case AssemblerLOONG64::SUN: 3106 UNIMPLEMENTED(); 3107 break; 3108 case AssemblerLOONG64::SEQ: 3109 UNIMPLEMENTED(); 3110 break; 3111 case AssemblerLOONG64::SUEQ: 3112 UNIMPLEMENTED(); 3113 break; 3114 case AssemblerLOONG64::SLT: 3115 UNIMPLEMENTED(); 3116 break; 3117 case AssemblerLOONG64::SULT: 3118 UNIMPLEMENTED(); 3119 break; 3120 case AssemblerLOONG64::SLE: 3121 UNIMPLEMENTED(); 3122 break; 3123 case AssemblerLOONG64::SULE: 3124 UNIMPLEMENTED(); 3125 break; 3126 case AssemblerLOONG64::SNE: 3127 UNIMPLEMENTED(); 3128 break; 3129 case AssemblerLOONG64::SOR: 3130 UNIMPLEMENTED(); 3131 break; 3132 case AssemblerLOONG64::SUNE: 3133 UNIMPLEMENTED(); 3134 break; 3135 default: 3136 UNREACHABLE(); 3137 } 3138 break; 3139 } 3140 case op_fcmp_cond_d: { 3141 MOZ_ASSERT(instr->bits(4, 3) == 0); 3142 double fj = fj_double(instr); 3143 double fk = fk_double(instr); 3144 switch (cond(instr)) { 3145 case AssemblerLOONG64::CAF: { 3146 setCFRegister(cd_reg(instr), false); 3147 break; 3148 } 3149 case AssemblerLOONG64::CUN: { 3150 setCFRegister(cd_reg(instr), std::isnan(fj) || std::isnan(fk)); 3151 break; 3152 } 3153 case AssemblerLOONG64::CEQ: { 3154 setCFRegister(cd_reg(instr), fj == fk); 3155 break; 3156 } 3157 case AssemblerLOONG64::CUEQ: { 3158 setCFRegister(cd_reg(instr), 3159 (fj == fk) || std::isnan(fj) || std::isnan(fk)); 3160 break; 3161 } 3162 case AssemblerLOONG64::CLT: { 3163 setCFRegister(cd_reg(instr), fj < fk); 3164 break; 3165 } 3166 case AssemblerLOONG64::CULT: { 3167 setCFRegister(cd_reg(instr), 3168 (fj < fk) || std::isnan(fj) || std::isnan(fk)); 3169 break; 3170 } 3171 case AssemblerLOONG64::CLE: { 3172 setCFRegister(cd_reg(instr), fj <= fk); 3173 break; 3174 } 3175 case AssemblerLOONG64::CULE: { 3176 setCFRegister(cd_reg(instr), 3177 (fj <= fk) || std::isnan(fj) || std::isnan(fk)); 3178 break; 3179 } 3180 case AssemblerLOONG64::CNE: { 3181 setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk)); 3182 break; 3183 } 3184 case AssemblerLOONG64::COR: { 3185 setCFRegister(cd_reg(instr), !std::isnan(fj) && !std::isnan(fk)); 3186 break; 3187 } 3188 case AssemblerLOONG64::CUNE: { 3189 setCFRegister(cd_reg(instr), 3190 (fj != fk) || std::isnan(fj) || std::isnan(fk)); 3191 break; 3192 } 3193 case AssemblerLOONG64::SAF: 3194 UNIMPLEMENTED(); 3195 break; 3196 case AssemblerLOONG64::SUN: 3197 UNIMPLEMENTED(); 3198 break; 3199 case AssemblerLOONG64::SEQ: 3200 UNIMPLEMENTED(); 3201 break; 3202 case AssemblerLOONG64::SUEQ: 3203 UNIMPLEMENTED(); 3204 break; 3205 case AssemblerLOONG64::SLT: 3206 UNIMPLEMENTED(); 3207 break; 3208 case AssemblerLOONG64::SULT: 3209 UNIMPLEMENTED(); 3210 break; 3211 case AssemblerLOONG64::SLE: 3212 UNIMPLEMENTED(); 3213 break; 3214 case AssemblerLOONG64::SULE: 3215 UNIMPLEMENTED(); 3216 break; 3217 case AssemblerLOONG64::SNE: 3218 UNIMPLEMENTED(); 3219 break; 3220 case AssemblerLOONG64::SOR: 3221 UNIMPLEMENTED(); 3222 break; 3223 case AssemblerLOONG64::SUNE: 3224 UNIMPLEMENTED(); 3225 break; 3226 default: 3227 UNREACHABLE(); 3228 } 3229 break; 3230 } 3231 default: 3232 UNREACHABLE(); 3233 } 3234 } 3235 3236 void Simulator::decodeTypeOp14(SimInstruction* instr) { 3237 int64_t alu_out = 0x0; 3238 3239 switch (instr->bits(31, 18) << 18) { 3240 case op_bytepick_d: { 3241 uint8_t sa = sa3(instr) * 8; 3242 if (sa == 0) { 3243 alu_out = rk(instr); 3244 } else { 3245 int64_t mask = (1ULL << 63) >> (sa - 1); 3246 int64_t rk_hi = (rk(instr) & (~mask)) << sa; 3247 int64_t rj_lo = (rj(instr) & mask) >> (64 - sa); 3248 alu_out = rk_hi | rj_lo; 3249 } 3250 setRegister(rd_reg(instr), alu_out); 3251 break; 3252 } 3253 case op_fsel: { 3254 MOZ_ASSERT(instr->bits(19, 18) == 0); 3255 if (ca(instr) == 0) { 3256 setFpuRegisterDouble(fd_reg(instr), fj_double(instr)); 3257 } else { 3258 setFpuRegisterDouble(fd_reg(instr), fk_double(instr)); 3259 } 3260 break; 3261 } 3262 default: 3263 UNREACHABLE(); 3264 } 3265 } 3266 3267 void Simulator::decodeTypeOp15(SimInstruction* instr) { 3268 int64_t alu_out = 0x0; 3269 int32_t alu32_out = 0x0; 3270 3271 switch (instr->bits(31, 17) << 17) { 3272 case op_bytepick_w: { 3273 MOZ_ASSERT(instr->bit(17) == 0); 3274 uint8_t sa = sa2(instr) * 8; 3275 if (sa == 0) { 3276 alu32_out = static_cast<int32_t>(rk(instr)); 3277 } else { 3278 int32_t mask = (1 << 31) >> (sa - 1); 3279 int32_t rk_hi = (static_cast<int32_t>(rk(instr)) & (~mask)) << sa; 3280 int32_t rj_lo = (static_cast<uint32_t>(rj(instr)) & mask) >> (32 - sa); 3281 alu32_out = rk_hi | rj_lo; 3282 } 3283 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out)); 3284 break; 3285 } 3286 case op_alsl_w: { 3287 uint8_t sa = sa2(instr) + 1; 3288 alu32_out = (static_cast<int32_t>(rj(instr)) << sa) + 3289 static_cast<int32_t>(rk(instr)); 3290 setRegister(rd_reg(instr), alu32_out); 3291 break; 3292 } 3293 case op_alsl_wu: { 3294 uint8_t sa = sa2(instr) + 1; 3295 alu32_out = (static_cast<int32_t>(rj(instr)) << sa) + 3296 static_cast<int32_t>(rk(instr)); 3297 setRegister(rd_reg(instr), static_cast<uint32_t>(alu32_out)); 3298 break; 3299 } 3300 case op_alsl_d: { 3301 MOZ_ASSERT(instr->bit(17) == 0); 3302 uint8_t sa = sa2(instr) + 1; 3303 alu_out = (rj(instr) << sa) + rk(instr); 3304 setRegister(rd_reg(instr), alu_out); 3305 break; 3306 } 3307 default: 3308 UNREACHABLE(); 3309 } 3310 } 3311 3312 void Simulator::decodeTypeOp16(SimInstruction* instr) { 3313 int64_t alu_out; 3314 switch (instr->bits(31, 16) << 16) { 3315 case op_slli_d: { 3316 MOZ_ASSERT(instr->bit(17) == 0); 3317 MOZ_ASSERT(instr->bits(17, 16) == 0b01); 3318 setRegister(rd_reg(instr), rj(instr) << ui6(instr)); 3319 break; 3320 } 3321 case op_srli_d: { 3322 MOZ_ASSERT(instr->bit(17) == 0); 3323 setRegister(rd_reg(instr), rj_u(instr) >> ui6(instr)); 3324 break; 3325 } 3326 case op_srai_d: { 3327 MOZ_ASSERT(instr->bit(17) == 0); 3328 setRegister(rd_reg(instr), rj(instr) >> ui6(instr)); 3329 break; 3330 } 3331 case op_rotri_d: { 3332 MOZ_ASSERT(instr->bit(17) == 0); 3333 MOZ_ASSERT(instr->bits(17, 16) == 0b01); 3334 alu_out = static_cast<int64_t>(RotateRight64(rj_u(instr), ui6(instr))); 3335 setRegister(rd_reg(instr), alu_out); 3336 break; 3337 } 3338 default: 3339 UNREACHABLE(); 3340 } 3341 } 3342 3343 void Simulator::decodeTypeOp17(SimInstruction* instr) { 3344 int64_t alu_out; 3345 int32_t alu32_out; 3346 3347 switch (instr->bits(31, 15) << 15) { 3348 case op_slli_w: { 3349 MOZ_ASSERT(instr->bit(17) == 0); 3350 MOZ_ASSERT(instr->bits(17, 15) == 0b001); 3351 alu32_out = static_cast<int32_t>(rj(instr)) << ui5(instr); 3352 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out)); 3353 break; 3354 } 3355 case op_srai_w: { 3356 MOZ_ASSERT(instr->bit(17) == 0); 3357 MOZ_ASSERT(instr->bits(17, 15) == 0b001); 3358 alu32_out = static_cast<int32_t>(rj(instr)) >> ui5(instr); 3359 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out)); 3360 break; 3361 } 3362 case op_rotri_w: { 3363 MOZ_ASSERT(instr->bit(17) == 0); 3364 MOZ_ASSERT(instr->bits(17, 15) == 0b001); 3365 alu32_out = static_cast<int32_t>( 3366 RotateRight32(static_cast<const uint32_t>(rj_u(instr)), 3367 static_cast<const uint32_t>(ui5(instr)))); 3368 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out)); 3369 break; 3370 } 3371 case op_srli_w: { 3372 MOZ_ASSERT(instr->bit(17) == 0); 3373 MOZ_ASSERT(instr->bits(17, 15) == 0b001); 3374 alu32_out = static_cast<uint32_t>(rj(instr)) >> ui5(instr); 3375 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out)); 3376 break; 3377 } 3378 case op_add_w: { 3379 int32_t alu32_out = static_cast<int32_t>(rj(instr) + rk(instr)); 3380 // Sign-extend result of 32bit operation into 64bit register. 3381 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out)); 3382 break; 3383 } 3384 case op_add_d: 3385 setRegister(rd_reg(instr), rj(instr) + rk(instr)); 3386 break; 3387 case op_sub_w: { 3388 int32_t alu32_out = static_cast<int32_t>(rj(instr) - rk(instr)); 3389 // Sign-extend result of 32bit operation into 64bit register. 3390 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out)); 3391 break; 3392 } 3393 case op_sub_d: 3394 setRegister(rd_reg(instr), rj(instr) - rk(instr)); 3395 break; 3396 case op_slt: 3397 setRegister(rd_reg(instr), rj(instr) < rk(instr) ? 1 : 0); 3398 break; 3399 case op_sltu: 3400 setRegister(rd_reg(instr), rj_u(instr) < rk_u(instr) ? 1 : 0); 3401 break; 3402 case op_maskeqz: 3403 setRegister(rd_reg(instr), rk(instr) == 0 ? 0 : rj(instr)); 3404 break; 3405 case op_masknez: 3406 setRegister(rd_reg(instr), rk(instr) != 0 ? 0 : rj(instr)); 3407 break; 3408 case op_nor: 3409 setRegister(rd_reg(instr), ~(rj(instr) | rk(instr))); 3410 break; 3411 case op_and: 3412 setRegister(rd_reg(instr), rj(instr) & rk(instr)); 3413 break; 3414 case op_or: 3415 setRegister(rd_reg(instr), rj(instr) | rk(instr)); 3416 break; 3417 case op_xor: 3418 setRegister(rd_reg(instr), rj(instr) ^ rk(instr)); 3419 break; 3420 case op_orn: 3421 setRegister(rd_reg(instr), rj(instr) | (~rk(instr))); 3422 break; 3423 case op_andn: 3424 setRegister(rd_reg(instr), rj(instr) & (~rk(instr))); 3425 break; 3426 case op_sll_w: 3427 setRegister(rd_reg(instr), (int32_t)rj(instr) << (rk_u(instr) & 0x1f)); 3428 break; 3429 case op_srl_w: { 3430 alu_out = 3431 static_cast<int32_t>((uint32_t)rj_u(instr) >> (rk_u(instr) & 0x1f)); 3432 setRegister(rd_reg(instr), alu_out); 3433 break; 3434 } 3435 case op_sra_w: 3436 setRegister(rd_reg(instr), (int32_t)rj(instr) >> (rk_u(instr) & 0x1f)); 3437 break; 3438 case op_sll_d: 3439 setRegister(rd_reg(instr), rj(instr) << (rk_u(instr) & 0x3f)); 3440 break; 3441 case op_srl_d: { 3442 alu_out = static_cast<int64_t>(rj_u(instr) >> (rk_u(instr) & 0x3f)); 3443 setRegister(rd_reg(instr), alu_out); 3444 break; 3445 } 3446 case op_sra_d: 3447 setRegister(rd_reg(instr), rj(instr) >> (rk_u(instr) & 0x3f)); 3448 break; 3449 case op_rotr_w: { 3450 alu_out = static_cast<int32_t>( 3451 RotateRight32(static_cast<const uint32_t>(rj_u(instr)), 3452 static_cast<const uint32_t>(rk_u(instr) & 0x1f))); 3453 setRegister(rd_reg(instr), alu_out); 3454 break; 3455 } 3456 case op_rotr_d: { 3457 alu_out = static_cast<int64_t>( 3458 RotateRight64((rj_u(instr)), (rk_u(instr) & 0x3f))); 3459 setRegister(rd_reg(instr), alu_out); 3460 break; 3461 } 3462 case op_mul_w: { 3463 alu_out = 3464 static_cast<int32_t>(rj(instr)) * static_cast<int32_t>(rk(instr)); 3465 setRegister(rd_reg(instr), alu_out); 3466 break; 3467 } 3468 case op_mulh_w: { 3469 int32_t rj_lo = static_cast<int32_t>(rj(instr)); 3470 int32_t rk_lo = static_cast<int32_t>(rk(instr)); 3471 alu_out = static_cast<int64_t>(rj_lo) * static_cast<int64_t>(rk_lo); 3472 setRegister(rd_reg(instr), alu_out >> 32); 3473 break; 3474 } 3475 case op_mulh_wu: { 3476 uint32_t rj_lo = static_cast<uint32_t>(rj_u(instr)); 3477 uint32_t rk_lo = static_cast<uint32_t>(rk_u(instr)); 3478 alu_out = static_cast<uint64_t>(rj_lo) * static_cast<uint64_t>(rk_lo); 3479 setRegister(rd_reg(instr), alu_out >> 32); 3480 break; 3481 } 3482 case op_mul_d: 3483 setRegister(rd_reg(instr), rj(instr) * rk(instr)); 3484 break; 3485 case op_mulh_d: 3486 setRegister(rd_reg(instr), MultiplyHighSigned(rj(instr), rk(instr))); 3487 break; 3488 case op_mulh_du: 3489 setRegister(rd_reg(instr), 3490 MultiplyHighUnsigned(rj_u(instr), rk_u(instr))); 3491 break; 3492 case op_mulw_d_w: { 3493 int64_t rj_i32 = static_cast<int32_t>(rj(instr)); 3494 int64_t rk_i32 = static_cast<int32_t>(rk(instr)); 3495 setRegister(rd_reg(instr), rj_i32 * rk_i32); 3496 break; 3497 } 3498 case op_mulw_d_wu: { 3499 uint64_t rj_u32 = static_cast<uint32_t>(rj_u(instr)); 3500 uint64_t rk_u32 = static_cast<uint32_t>(rk_u(instr)); 3501 setRegister(rd_reg(instr), rj_u32 * rk_u32); 3502 break; 3503 } 3504 case op_div_w: { 3505 int32_t rj_i32 = static_cast<int32_t>(rj(instr)); 3506 int32_t rk_i32 = static_cast<int32_t>(rk(instr)); 3507 if (rj_i32 == INT_MIN && rk_i32 == -1) { 3508 setRegister(rd_reg(instr), INT_MIN); 3509 } else if (rk_i32 != 0) { 3510 setRegister(rd_reg(instr), rj_i32 / rk_i32); 3511 } 3512 break; 3513 } 3514 case op_mod_w: { 3515 int32_t rj_i32 = static_cast<int32_t>(rj(instr)); 3516 int32_t rk_i32 = static_cast<int32_t>(rk(instr)); 3517 if (rj_i32 == INT_MIN && rk_i32 == -1) { 3518 setRegister(rd_reg(instr), 0); 3519 } else if (rk_i32 != 0) { 3520 setRegister(rd_reg(instr), rj_i32 % rk_i32); 3521 } 3522 break; 3523 } 3524 case op_div_wu: { 3525 uint32_t rj_u32 = static_cast<uint32_t>(rj(instr)); 3526 uint32_t rk_u32 = static_cast<uint32_t>(rk(instr)); 3527 if (rk_u32 != 0) { 3528 setRegister(rd_reg(instr), static_cast<int32_t>(rj_u32 / rk_u32)); 3529 } 3530 break; 3531 } 3532 case op_mod_wu: { 3533 uint32_t rj_u32 = static_cast<uint32_t>(rj(instr)); 3534 uint32_t rk_u32 = static_cast<uint32_t>(rk(instr)); 3535 if (rk_u32 != 0) { 3536 setRegister(rd_reg(instr), static_cast<int32_t>(rj_u32 % rk_u32)); 3537 } 3538 break; 3539 } 3540 case op_div_d: { 3541 if (rj(instr) == INT64_MIN && rk(instr) == -1) { 3542 setRegister(rd_reg(instr), INT64_MIN); 3543 } else if (rk(instr) != 0) { 3544 setRegister(rd_reg(instr), rj(instr) / rk(instr)); 3545 } 3546 break; 3547 } 3548 case op_mod_d: { 3549 if (rj(instr) == LONG_MIN && rk(instr) == -1) { 3550 setRegister(rd_reg(instr), 0); 3551 } else if (rk(instr) != 0) { 3552 setRegister(rd_reg(instr), rj(instr) % rk(instr)); 3553 } 3554 break; 3555 } 3556 case op_div_du: { 3557 if (rk_u(instr) != 0) { 3558 setRegister(rd_reg(instr), 3559 static_cast<int64_t>(rj_u(instr) / rk_u(instr))); 3560 } 3561 break; 3562 } 3563 case op_mod_du: { 3564 if (rk_u(instr) != 0) { 3565 setRegister(rd_reg(instr), 3566 static_cast<int64_t>(rj_u(instr) % rk_u(instr))); 3567 } 3568 break; 3569 } 3570 case op_break: 3571 softwareInterrupt(instr); 3572 break; 3573 case op_fadd_s: { 3574 setFpuRegisterFloat(fd_reg(instr), fj_float(instr) + fk_float(instr)); 3575 break; 3576 } 3577 case op_fadd_d: { 3578 setFpuRegisterDouble(fd_reg(instr), fj_double(instr) + fk_double(instr)); 3579 break; 3580 } 3581 case op_fsub_s: { 3582 setFpuRegisterFloat(fd_reg(instr), fj_float(instr) - fk_float(instr)); 3583 break; 3584 } 3585 case op_fsub_d: { 3586 setFpuRegisterDouble(fd_reg(instr), fj_double(instr) - fk_double(instr)); 3587 break; 3588 } 3589 case op_fmul_s: { 3590 setFpuRegisterFloat(fd_reg(instr), fj_float(instr) * fk_float(instr)); 3591 break; 3592 } 3593 case op_fmul_d: { 3594 setFpuRegisterDouble(fd_reg(instr), fj_double(instr) * fk_double(instr)); 3595 break; 3596 } 3597 case op_fdiv_s: { 3598 setFpuRegisterFloat(fd_reg(instr), fj_float(instr) / fk_float(instr)); 3599 break; 3600 } 3601 3602 case op_fdiv_d: { 3603 setFpuRegisterDouble(fd_reg(instr), fj_double(instr) / fk_double(instr)); 3604 break; 3605 } 3606 case op_fmax_s: { 3607 setFpuRegisterFloat(fd_reg(instr), 3608 FPUMax(fk_float(instr), fj_float(instr))); 3609 break; 3610 } 3611 case op_fmax_d: { 3612 setFpuRegisterDouble(fd_reg(instr), 3613 FPUMax(fk_double(instr), fj_double(instr))); 3614 break; 3615 } 3616 case op_fmin_s: { 3617 setFpuRegisterFloat(fd_reg(instr), 3618 FPUMin(fk_float(instr), fj_float(instr))); 3619 break; 3620 } 3621 case op_fmin_d: { 3622 setFpuRegisterDouble(fd_reg(instr), 3623 FPUMin(fk_double(instr), fj_double(instr))); 3624 break; 3625 } 3626 case op_fmaxa_s: { 3627 setFpuRegisterFloat(fd_reg(instr), 3628 FPUMaxA(fk_float(instr), fj_float(instr))); 3629 break; 3630 } 3631 case op_fmaxa_d: { 3632 setFpuRegisterDouble(fd_reg(instr), 3633 FPUMaxA(fk_double(instr), fj_double(instr))); 3634 break; 3635 } 3636 case op_fmina_s: { 3637 setFpuRegisterFloat(fd_reg(instr), 3638 FPUMinA(fk_float(instr), fj_float(instr))); 3639 break; 3640 } 3641 case op_fmina_d: { 3642 setFpuRegisterDouble(fd_reg(instr), 3643 FPUMinA(fk_double(instr), fj_double(instr))); 3644 break; 3645 } 3646 case op_ldx_b: 3647 setRegister(rd_reg(instr), readB(rj(instr) + rk(instr))); 3648 break; 3649 case op_ldx_h: 3650 setRegister(rd_reg(instr), readH(rj(instr) + rk(instr), instr)); 3651 break; 3652 case op_ldx_w: 3653 setRegister(rd_reg(instr), readW(rj(instr) + rk(instr), instr)); 3654 break; 3655 case op_ldx_d: 3656 setRegister(rd_reg(instr), readDW(rj(instr) + rk(instr), instr)); 3657 break; 3658 case op_stx_b: 3659 writeB(rj(instr) + rk(instr), static_cast<int8_t>(rd(instr))); 3660 break; 3661 case op_stx_h: 3662 writeH(rj(instr) + rk(instr), static_cast<int16_t>(rd(instr)), instr); 3663 break; 3664 case op_stx_w: 3665 writeW(rj(instr) + rk(instr), static_cast<int32_t>(rd(instr)), instr); 3666 break; 3667 case op_stx_d: 3668 writeDW(rj(instr) + rk(instr), rd(instr), instr); 3669 break; 3670 case op_ldx_bu: 3671 setRegister(rd_reg(instr), readBU(rj(instr) + rk(instr))); 3672 break; 3673 case op_ldx_hu: 3674 setRegister(rd_reg(instr), readHU(rj(instr) + rk(instr), instr)); 3675 break; 3676 case op_ldx_wu: 3677 setRegister(rd_reg(instr), readWU(rj(instr) + rk(instr), instr)); 3678 break; 3679 case op_fldx_s: 3680 setFpuRegister(fd_reg(instr), kFPUInvalidResult); // Trash upper 32 bits. 3681 setFpuRegisterWord(fd_reg(instr), readW(rj(instr) + rk(instr), instr)); 3682 break; 3683 case op_fldx_d: 3684 setFpuRegister(fd_reg(instr), kFPUInvalidResult); // Trash upper 32 bits. 3685 setFpuRegisterDouble(fd_reg(instr), readD(rj(instr) + rk(instr), instr)); 3686 break; 3687 case op_fstx_s: { 3688 int32_t alu_out_32 = static_cast<int32_t>(getFpuRegister(fd_reg(instr))); 3689 writeW(rj(instr) + rk(instr), alu_out_32, instr); 3690 break; 3691 } 3692 case op_fstx_d: { 3693 writeD(rj(instr) + rk(instr), getFpuRegisterDouble(fd_reg(instr)), instr); 3694 break; 3695 } 3696 case op_amswap_w: 3697 UNIMPLEMENTED(); 3698 break; 3699 case op_amswap_d: 3700 UNIMPLEMENTED(); 3701 break; 3702 case op_amadd_w: 3703 UNIMPLEMENTED(); 3704 break; 3705 case op_amadd_d: 3706 UNIMPLEMENTED(); 3707 break; 3708 case op_amand_w: 3709 UNIMPLEMENTED(); 3710 break; 3711 case op_amand_d: 3712 UNIMPLEMENTED(); 3713 break; 3714 case op_amor_w: 3715 UNIMPLEMENTED(); 3716 break; 3717 case op_amor_d: 3718 UNIMPLEMENTED(); 3719 break; 3720 case op_amxor_w: 3721 UNIMPLEMENTED(); 3722 break; 3723 case op_amxor_d: 3724 UNIMPLEMENTED(); 3725 break; 3726 case op_ammax_w: 3727 UNIMPLEMENTED(); 3728 break; 3729 case op_ammax_d: 3730 UNIMPLEMENTED(); 3731 break; 3732 case op_ammin_w: 3733 UNIMPLEMENTED(); 3734 break; 3735 case op_ammin_d: 3736 UNIMPLEMENTED(); 3737 break; 3738 case op_ammax_wu: 3739 UNIMPLEMENTED(); 3740 break; 3741 case op_ammax_du: 3742 UNIMPLEMENTED(); 3743 break; 3744 case op_ammin_wu: 3745 UNIMPLEMENTED(); 3746 break; 3747 case op_ammin_du: 3748 UNIMPLEMENTED(); 3749 break; 3750 case op_amswap_db_w: 3751 UNIMPLEMENTED(); 3752 break; 3753 case op_amswap_db_d: 3754 UNIMPLEMENTED(); 3755 break; 3756 case op_amadd_db_w: 3757 UNIMPLEMENTED(); 3758 break; 3759 case op_amadd_db_d: 3760 UNIMPLEMENTED(); 3761 break; 3762 case op_amand_db_w: 3763 UNIMPLEMENTED(); 3764 break; 3765 case op_amand_db_d: 3766 UNIMPLEMENTED(); 3767 break; 3768 case op_amor_db_w: 3769 UNIMPLEMENTED(); 3770 break; 3771 case op_amor_db_d: 3772 UNIMPLEMENTED(); 3773 break; 3774 case op_amxor_db_w: 3775 UNIMPLEMENTED(); 3776 break; 3777 case op_amxor_db_d: 3778 UNIMPLEMENTED(); 3779 break; 3780 case op_ammax_db_w: 3781 UNIMPLEMENTED(); 3782 break; 3783 case op_ammax_db_d: 3784 UNIMPLEMENTED(); 3785 break; 3786 case op_ammin_db_w: 3787 UNIMPLEMENTED(); 3788 break; 3789 case op_ammin_db_d: 3790 UNIMPLEMENTED(); 3791 break; 3792 case op_ammax_db_wu: 3793 UNIMPLEMENTED(); 3794 break; 3795 case op_ammax_db_du: 3796 UNIMPLEMENTED(); 3797 break; 3798 case op_ammin_db_wu: 3799 UNIMPLEMENTED(); 3800 break; 3801 case op_ammin_db_du: 3802 UNIMPLEMENTED(); 3803 break; 3804 case op_dbar: 3805 // TODO(loong64): dbar simulation 3806 break; 3807 case op_ibar: 3808 UNIMPLEMENTED(); 3809 break; 3810 case op_fcopysign_s: 3811 setFpuRegisterFloat(fd_reg(instr), 3812 std::copysign(fj_float(instr), fk_float(instr))); 3813 break; 3814 case op_fcopysign_d: 3815 setFpuRegisterDouble(fd_reg(instr), 3816 std::copysign(fj_double(instr), fk_double(instr))); 3817 break; 3818 default: 3819 UNREACHABLE(); 3820 } 3821 } 3822 3823 void Simulator::decodeTypeOp22(SimInstruction* instr) { 3824 int64_t alu_out; 3825 3826 switch (instr->bits(31, 10) << 10) { 3827 case op_clz_w: { 3828 alu_out = U32(rj_u(instr)) ? __builtin_clz(U32(rj_u(instr))) : 32; 3829 setRegister(rd_reg(instr), alu_out); 3830 break; 3831 } 3832 case op_ctz_w: { 3833 alu_out = U32(rj_u(instr)) ? __builtin_ctz(U32(rj_u(instr))) : 32; 3834 setRegister(rd_reg(instr), alu_out); 3835 break; 3836 } 3837 case op_clz_d: { 3838 alu_out = U64(rj_u(instr)) ? __builtin_clzll(U64(rj_u(instr))) : 64; 3839 setRegister(rd_reg(instr), alu_out); 3840 break; 3841 } 3842 case op_ctz_d: { 3843 alu_out = U64(rj_u(instr)) ? __builtin_ctzll(U64(rj_u(instr))) : 64; 3844 setRegister(rd_reg(instr), alu_out); 3845 break; 3846 } 3847 case op_revb_2h: { 3848 uint32_t input = static_cast<uint32_t>(rj(instr)); 3849 uint64_t output = 0; 3850 3851 uint32_t mask = 0xFF000000; 3852 for (int i = 0; i < 4; i++) { 3853 uint32_t tmp = mask & input; 3854 if (i % 2 == 0) { 3855 tmp = tmp >> 8; 3856 } else { 3857 tmp = tmp << 8; 3858 } 3859 output = output | tmp; 3860 mask = mask >> 8; 3861 } 3862 3863 alu_out = static_cast<int64_t>(static_cast<int32_t>(output)); 3864 setRegister(rd_reg(instr), alu_out); 3865 break; 3866 } 3867 case op_revb_4h: { 3868 uint64_t input = rj_u(instr); 3869 uint64_t output = 0; 3870 3871 uint64_t mask = 0xFF00000000000000; 3872 for (int i = 0; i < 8; i++) { 3873 uint64_t tmp = mask & input; 3874 if (i % 2 == 0) { 3875 tmp = tmp >> 8; 3876 } else { 3877 tmp = tmp << 8; 3878 } 3879 output = output | tmp; 3880 mask = mask >> 8; 3881 } 3882 3883 alu_out = static_cast<int64_t>(output); 3884 setRegister(rd_reg(instr), alu_out); 3885 break; 3886 } 3887 case op_revb_2w: { 3888 uint64_t input = rj_u(instr); 3889 uint64_t output = 0; 3890 3891 uint64_t mask = 0xFF000000FF000000; 3892 for (int i = 0; i < 4; i++) { 3893 uint64_t tmp = mask & input; 3894 if (i <= 1) { 3895 tmp = tmp >> (24 - i * 16); 3896 } else { 3897 tmp = tmp << (i * 16 - 24); 3898 } 3899 output = output | tmp; 3900 mask = mask >> 8; 3901 } 3902 3903 alu_out = static_cast<int64_t>(output); 3904 setRegister(rd_reg(instr), alu_out); 3905 break; 3906 } 3907 case op_revb_d: { 3908 uint64_t input = rj_u(instr); 3909 uint64_t output = 0; 3910 3911 uint64_t mask = 0xFF00000000000000; 3912 for (int i = 0; i < 8; i++) { 3913 uint64_t tmp = mask & input; 3914 if (i <= 3) { 3915 tmp = tmp >> (56 - i * 16); 3916 } else { 3917 tmp = tmp << (i * 16 - 56); 3918 } 3919 output = output | tmp; 3920 mask = mask >> 8; 3921 } 3922 3923 alu_out = static_cast<int64_t>(output); 3924 setRegister(rd_reg(instr), alu_out); 3925 break; 3926 } 3927 case op_revh_2w: { 3928 uint64_t input = rj_u(instr); 3929 uint64_t output = 0; 3930 3931 uint64_t mask = 0xFFFF000000000000; 3932 for (int i = 0; i < 4; i++) { 3933 uint64_t tmp = mask & input; 3934 if (i % 2 == 0) { 3935 tmp = tmp >> 16; 3936 } else { 3937 tmp = tmp << 16; 3938 } 3939 output = output | tmp; 3940 mask = mask >> 16; 3941 } 3942 3943 alu_out = static_cast<int64_t>(output); 3944 setRegister(rd_reg(instr), alu_out); 3945 break; 3946 } 3947 case op_revh_d: { 3948 uint64_t input = rj_u(instr); 3949 uint64_t output = 0; 3950 3951 uint64_t mask = 0xFFFF000000000000; 3952 for (int i = 0; i < 4; i++) { 3953 uint64_t tmp = mask & input; 3954 if (i <= 1) { 3955 tmp = tmp >> (48 - i * 32); 3956 } else { 3957 tmp = tmp << (i * 32 - 48); 3958 } 3959 output = output | tmp; 3960 mask = mask >> 16; 3961 } 3962 3963 alu_out = static_cast<int64_t>(output); 3964 setRegister(rd_reg(instr), alu_out); 3965 break; 3966 } 3967 case op_bitrev_4b: { 3968 uint32_t input = static_cast<uint32_t>(rj(instr)); 3969 uint32_t output = 0; 3970 uint8_t i_byte, o_byte; 3971 3972 // Reverse the bit in byte for each individual byte 3973 for (int i = 0; i < 4; i++) { 3974 output = output >> 8; 3975 i_byte = input & 0xFF; 3976 3977 // Fast way to reverse bits in byte 3978 // Devised by Sean Anderson, July 13, 2001 3979 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) | 3980 (i_byte * 0x8020LU & 0x88440LU)) * 3981 0x10101LU >> 3982 16); 3983 3984 output = output | (static_cast<uint32_t>(o_byte << 24)); 3985 input = input >> 8; 3986 } 3987 3988 alu_out = static_cast<int64_t>(static_cast<int32_t>(output)); 3989 setRegister(rd_reg(instr), alu_out); 3990 break; 3991 } 3992 case op_bitrev_8b: { 3993 uint64_t input = rj_u(instr); 3994 uint64_t output = 0; 3995 uint8_t i_byte, o_byte; 3996 3997 // Reverse the bit in byte for each individual byte 3998 for (int i = 0; i < 8; i++) { 3999 output = output >> 8; 4000 i_byte = input & 0xFF; 4001 4002 // Fast way to reverse bits in byte 4003 // Devised by Sean Anderson, July 13, 2001 4004 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) | 4005 (i_byte * 0x8020LU & 0x88440LU)) * 4006 0x10101LU >> 4007 16); 4008 4009 output = output | (static_cast<uint64_t>(o_byte) << 56); 4010 input = input >> 8; 4011 } 4012 4013 alu_out = static_cast<int64_t>(output); 4014 setRegister(rd_reg(instr), alu_out); 4015 break; 4016 } 4017 case op_bitrev_w: { 4018 uint32_t input = static_cast<uint32_t>(rj(instr)); 4019 uint32_t output = 0; 4020 output = ReverseBits(input); 4021 alu_out = static_cast<int64_t>(static_cast<int32_t>(output)); 4022 setRegister(rd_reg(instr), alu_out); 4023 break; 4024 } 4025 case op_bitrev_d: { 4026 alu_out = static_cast<int64_t>(ReverseBits(rj_u(instr))); 4027 setRegister(rd_reg(instr), alu_out); 4028 break; 4029 } 4030 case op_ext_w_b: { 4031 uint8_t input = static_cast<uint8_t>(rj(instr)); 4032 alu_out = static_cast<int64_t>(static_cast<int8_t>(input)); 4033 setRegister(rd_reg(instr), alu_out); 4034 break; 4035 } 4036 case op_ext_w_h: { 4037 uint16_t input = static_cast<uint16_t>(rj(instr)); 4038 alu_out = static_cast<int64_t>(static_cast<int16_t>(input)); 4039 setRegister(rd_reg(instr), alu_out); 4040 break; 4041 } 4042 case op_fabs_s: { 4043 setFpuRegisterFloat(fd_reg(instr), std::abs(fj_float(instr))); 4044 break; 4045 } 4046 case op_fabs_d: { 4047 setFpuRegisterDouble(fd_reg(instr), std::abs(fj_double(instr))); 4048 break; 4049 } 4050 case op_fneg_s: { 4051 setFpuRegisterFloat(fd_reg(instr), -fj_float(instr)); 4052 break; 4053 } 4054 case op_fneg_d: { 4055 setFpuRegisterDouble(fd_reg(instr), -fj_double(instr)); 4056 break; 4057 } 4058 case op_fsqrt_s: { 4059 if (fj_float(instr) >= 0) { 4060 setFpuRegisterFloat(fd_reg(instr), std::sqrt(fj_float(instr))); 4061 } else { 4062 setFpuRegisterFloat(fd_reg(instr), std::sqrt(-1)); // qnan 4063 setFCSRBit(kFCSRInvalidOpFlagBit, true); 4064 } 4065 break; 4066 } 4067 case op_fsqrt_d: { 4068 if (fj_double(instr) >= 0) { 4069 setFpuRegisterDouble(fd_reg(instr), std::sqrt(fj_double(instr))); 4070 } else { 4071 setFpuRegisterDouble(fd_reg(instr), std::sqrt(-1)); // qnan 4072 setFCSRBit(kFCSRInvalidOpFlagBit, true); 4073 } 4074 break; 4075 } 4076 case op_fmov_s: { 4077 setFpuRegisterFloat(fd_reg(instr), fj_float(instr)); 4078 break; 4079 } 4080 case op_fmov_d: { 4081 setFpuRegisterDouble(fd_reg(instr), fj_double(instr)); 4082 break; 4083 } 4084 case op_movgr2fr_w: { 4085 setFpuRegisterWord(fd_reg(instr), static_cast<int32_t>(rj(instr))); 4086 break; 4087 } 4088 case op_movgr2fr_d: { 4089 setFpuRegister(fd_reg(instr), rj(instr)); 4090 break; 4091 } 4092 case op_movgr2frh_w: { 4093 setFpuRegisterHiWord(fd_reg(instr), static_cast<int32_t>(rj(instr))); 4094 break; 4095 } 4096 case op_movfr2gr_s: { 4097 setRegister(rd_reg(instr), 4098 static_cast<int64_t>(getFpuRegisterWord(fj_reg(instr)))); 4099 break; 4100 } 4101 case op_movfr2gr_d: { 4102 setRegister(rd_reg(instr), getFpuRegister(fj_reg(instr))); 4103 break; 4104 } 4105 case op_movfrh2gr_s: { 4106 setRegister(rd_reg(instr), getFpuRegisterHiWord(fj_reg(instr))); 4107 break; 4108 } 4109 case op_movgr2fcsr: { 4110 // fcsr could be 0-3 4111 MOZ_ASSERT(rd_reg(instr) < 4); 4112 FCSR_ = static_cast<uint32_t>(rj(instr)); 4113 break; 4114 } 4115 case op_movfcsr2gr: { 4116 setRegister(rd_reg(instr), FCSR_); 4117 break; 4118 } 4119 case op_fcvt_s_d: { 4120 setFpuRegisterFloat(fd_reg(instr), static_cast<float>(fj_double(instr))); 4121 break; 4122 } 4123 case op_fcvt_d_s: { 4124 setFpuRegisterDouble(fd_reg(instr), static_cast<double>(fj_float(instr))); 4125 break; 4126 } 4127 case op_ftintrm_w_s: { 4128 float fj = fj_float(instr); 4129 float rounded = std::floor(fj); 4130 int32_t result = static_cast<int32_t>(rounded); 4131 setFpuRegisterWord(fd_reg(instr), result); 4132 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4133 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr)); 4134 } 4135 break; 4136 } 4137 case op_ftintrm_w_d: { 4138 double fj = fj_double(instr); 4139 double rounded = std::floor(fj); 4140 int32_t result = static_cast<int32_t>(rounded); 4141 setFpuRegisterWord(fd_reg(instr), result); 4142 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4143 setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr)); 4144 } 4145 break; 4146 } 4147 case op_ftintrm_l_s: { 4148 float fj = fj_float(instr); 4149 float rounded = std::floor(fj); 4150 int64_t result = static_cast<int64_t>(rounded); 4151 setFpuRegister(fd_reg(instr), result); 4152 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4153 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4154 } 4155 break; 4156 } 4157 case op_ftintrm_l_d: { 4158 double fj = fj_double(instr); 4159 double rounded = std::floor(fj); 4160 int64_t result = static_cast<int64_t>(rounded); 4161 setFpuRegister(fd_reg(instr), result); 4162 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4163 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4164 } 4165 break; 4166 } 4167 case op_ftintrp_w_s: { 4168 float fj = fj_float(instr); 4169 float rounded = std::ceil(fj); 4170 int32_t result = static_cast<int32_t>(rounded); 4171 setFpuRegisterWord(fd_reg(instr), result); 4172 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4173 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr)); 4174 } 4175 break; 4176 } 4177 case op_ftintrp_w_d: { 4178 double fj = fj_double(instr); 4179 double rounded = std::ceil(fj); 4180 int32_t result = static_cast<int32_t>(rounded); 4181 setFpuRegisterWord(fd_reg(instr), result); 4182 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4183 setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr)); 4184 } 4185 break; 4186 } 4187 case op_ftintrp_l_s: { 4188 float fj = fj_float(instr); 4189 float rounded = std::ceil(fj); 4190 int64_t result = static_cast<int64_t>(rounded); 4191 setFpuRegister(fd_reg(instr), result); 4192 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4193 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4194 } 4195 break; 4196 } 4197 case op_ftintrp_l_d: { 4198 double fj = fj_double(instr); 4199 double rounded = std::ceil(fj); 4200 int64_t result = static_cast<int64_t>(rounded); 4201 setFpuRegister(fd_reg(instr), result); 4202 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4203 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4204 } 4205 break; 4206 } 4207 case op_ftintrz_w_s: { 4208 float fj = fj_float(instr); 4209 float rounded = std::trunc(fj); 4210 int32_t result = static_cast<int32_t>(rounded); 4211 setFpuRegisterWord(fd_reg(instr), result); 4212 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4213 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr)); 4214 } 4215 break; 4216 } 4217 case op_ftintrz_w_d: { 4218 double fj = fj_double(instr); 4219 double rounded = std::trunc(fj); 4220 int32_t result = static_cast<int32_t>(rounded); 4221 setFpuRegisterWord(fd_reg(instr), result); 4222 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4223 setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr)); 4224 } 4225 break; 4226 } 4227 case op_ftintrz_l_s: { 4228 float fj = fj_float(instr); 4229 float rounded = std::trunc(fj); 4230 int64_t result = static_cast<int64_t>(rounded); 4231 setFpuRegister(fd_reg(instr), result); 4232 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4233 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4234 } 4235 break; 4236 } 4237 case op_ftintrz_l_d: { 4238 double fj = fj_double(instr); 4239 double rounded = std::trunc(fj); 4240 int64_t result = static_cast<int64_t>(rounded); 4241 setFpuRegister(fd_reg(instr), result); 4242 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4243 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4244 } 4245 break; 4246 } 4247 case op_ftintrne_w_s: { 4248 float fj = fj_float(instr); 4249 float rounded = std::floor(fj + 0.5); 4250 int32_t result = static_cast<int32_t>(rounded); 4251 if ((result & 1) != 0 && result - fj == 0.5) { 4252 // If the number is halfway between two integers, 4253 // round to the even one. 4254 result--; 4255 } 4256 setFpuRegisterWord(fd_reg(instr), result); 4257 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4258 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr)); 4259 } 4260 break; 4261 } 4262 case op_ftintrne_w_d: { 4263 double fj = fj_double(instr); 4264 double rounded = std::floor(fj + 0.5); 4265 int32_t result = static_cast<int32_t>(rounded); 4266 if ((result & 1) != 0 && result - fj == 0.5) { 4267 // If the number is halfway between two integers, 4268 // round to the even one. 4269 result--; 4270 } 4271 setFpuRegisterWord(fd_reg(instr), result); 4272 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4273 setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr)); 4274 } 4275 break; 4276 } 4277 case op_ftintrne_l_s: { 4278 float fj = fj_float(instr); 4279 float rounded = std::floor(fj + 0.5); 4280 int64_t result = static_cast<int64_t>(rounded); 4281 if ((result & 1) != 0 && result - fj == 0.5) { 4282 // If the number is halfway between two integers, 4283 // round to the even one. 4284 result--; 4285 } 4286 setFpuRegister(fd_reg(instr), result); 4287 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4288 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4289 } 4290 break; 4291 } 4292 case op_ftintrne_l_d: { 4293 double fj = fj_double(instr); 4294 double rounded = std::floor(fj + 0.5); 4295 int64_t result = static_cast<int64_t>(rounded); 4296 if ((result & 1) != 0 && result - fj == 0.5) { 4297 // If the number is halfway between two integers, 4298 // round to the even one. 4299 result--; 4300 } 4301 setFpuRegister(fd_reg(instr), result); 4302 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4303 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4304 } 4305 break; 4306 } 4307 case op_ftint_w_s: { 4308 float fj = fj_float(instr); 4309 float rounded; 4310 int32_t result; 4311 roundAccordingToFCSR<float>(fj, &rounded, &result); 4312 setFpuRegisterWord(fd_reg(instr), result); 4313 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4314 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr)); 4315 } 4316 break; 4317 } 4318 case op_ftint_w_d: { 4319 double fj = fj_double(instr); 4320 double rounded; 4321 int32_t result; 4322 roundAccordingToFCSR<double>(fj, &rounded, &result); 4323 setFpuRegisterWord(fd_reg(instr), result); 4324 if (setFCSRRoundError<int32_t>(fj, rounded)) { 4325 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr)); 4326 } 4327 break; 4328 } 4329 case op_ftint_l_s: { 4330 float fj = fj_float(instr); 4331 float rounded; 4332 int64_t result; 4333 round64AccordingToFCSR<float>(fj, &rounded, &result); 4334 setFpuRegister(fd_reg(instr), result); 4335 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4336 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4337 } 4338 break; 4339 } 4340 case op_ftint_l_d: { 4341 double fj = fj_double(instr); 4342 double rounded; 4343 int64_t result; 4344 round64AccordingToFCSR<double>(fj, &rounded, &result); 4345 setFpuRegister(fd_reg(instr), result); 4346 if (setFCSRRoundError<int64_t>(fj, rounded)) { 4347 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr)); 4348 } 4349 break; 4350 } 4351 case op_ffint_s_w: { 4352 alu_out = getFpuRegisterSignedWord(fj_reg(instr)); 4353 setFpuRegisterFloat(fd_reg(instr), static_cast<float>(alu_out)); 4354 break; 4355 } 4356 case op_ffint_s_l: { 4357 alu_out = getFpuRegister(fj_reg(instr)); 4358 setFpuRegisterFloat(fd_reg(instr), static_cast<float>(alu_out)); 4359 break; 4360 } 4361 case op_ffint_d_w: { 4362 alu_out = getFpuRegisterSignedWord(fj_reg(instr)); 4363 setFpuRegisterDouble(fd_reg(instr), static_cast<double>(alu_out)); 4364 break; 4365 } 4366 case op_ffint_d_l: { 4367 alu_out = getFpuRegister(fj_reg(instr)); 4368 setFpuRegisterDouble(fd_reg(instr), static_cast<double>(alu_out)); 4369 break; 4370 } 4371 case op_frint_s: { 4372 float fj = fj_float(instr); 4373 float result, temp_result; 4374 double temp; 4375 float upper = std::ceil(fj); 4376 float lower = std::floor(fj); 4377 switch (getFCSRRoundingMode()) { 4378 case kRoundToNearest: 4379 if (upper - fj < fj - lower) { 4380 result = upper; 4381 } else if (upper - fj > fj - lower) { 4382 result = lower; 4383 } else { 4384 temp_result = upper / 2; 4385 float reminder = std::modf(temp_result, &temp); 4386 if (reminder == 0) { 4387 result = upper; 4388 } else { 4389 result = lower; 4390 } 4391 } 4392 break; 4393 case kRoundToZero: 4394 result = (fj > 0 ? lower : upper); 4395 break; 4396 case kRoundToPlusInf: 4397 result = upper; 4398 break; 4399 case kRoundToMinusInf: 4400 result = lower; 4401 break; 4402 } 4403 setFpuRegisterFloat(fd_reg(instr), result); 4404 if (result != fj) { 4405 setFCSRBit(kFCSRInexactFlagBit, true); 4406 } 4407 break; 4408 } 4409 case op_frint_d: { 4410 double fj = fj_double(instr); 4411 double result, temp, temp_result; 4412 double upper = std::ceil(fj); 4413 double lower = std::floor(fj); 4414 switch (getFCSRRoundingMode()) { 4415 case kRoundToNearest: 4416 if (upper - fj < fj - lower) { 4417 result = upper; 4418 } else if (upper - fj > fj - lower) { 4419 result = lower; 4420 } else { 4421 temp_result = upper / 2; 4422 double reminder = std::modf(temp_result, &temp); 4423 if (reminder == 0) { 4424 result = upper; 4425 } else { 4426 result = lower; 4427 } 4428 } 4429 break; 4430 case kRoundToZero: 4431 result = (fj > 0 ? lower : upper); 4432 break; 4433 case kRoundToPlusInf: 4434 result = upper; 4435 break; 4436 case kRoundToMinusInf: 4437 result = lower; 4438 break; 4439 } 4440 setFpuRegisterDouble(fd_reg(instr), result); 4441 if (result != fj) { 4442 setFCSRBit(kFCSRInexactFlagBit, true); 4443 } 4444 break; 4445 } 4446 case op_movfr2cf: 4447 printf("Sim UNIMPLEMENTED: MOVFR2CF\n"); 4448 UNIMPLEMENTED(); 4449 break; 4450 case op_movgr2cf: 4451 printf("Sim UNIMPLEMENTED: MOVGR2CF\n"); 4452 UNIMPLEMENTED(); 4453 break; 4454 case op_clo_w: 4455 printf("Sim UNIMPLEMENTED: FCO_W\n"); 4456 UNIMPLEMENTED(); 4457 break; 4458 case op_cto_w: 4459 printf("Sim UNIMPLEMENTED: FTO_W\n"); 4460 UNIMPLEMENTED(); 4461 break; 4462 case op_clo_d: 4463 printf("Sim UNIMPLEMENTED: FLO_D\n"); 4464 UNIMPLEMENTED(); 4465 break; 4466 case op_cto_d: 4467 printf("Sim UNIMPLEMENTED: FTO_D\n"); 4468 UNIMPLEMENTED(); 4469 break; 4470 // Unimplemented opcodes raised an error in the configuration step before, 4471 // so we can use the default here to set the destination register in common 4472 // cases. 4473 default: 4474 UNREACHABLE(); 4475 } 4476 } 4477 4478 void Simulator::decodeTypeOp24(SimInstruction* instr) { 4479 switch (instr->bits(31, 8) << 8) { 4480 case op_movcf2fr: 4481 UNIMPLEMENTED(); 4482 break; 4483 case op_movcf2gr: 4484 setRegister(rd_reg(instr), getCFRegister(cj_reg(instr))); 4485 break; 4486 UNIMPLEMENTED(); 4487 break; 4488 default: 4489 UNREACHABLE(); 4490 } 4491 } 4492 4493 // Executes the current instruction. 4494 void Simulator::instructionDecode(SimInstruction* instr) { 4495 if (!SimulatorProcess::ICacheCheckingDisableCount) { 4496 AutoLockSimulatorCache als; 4497 SimulatorProcess::checkICacheLocked(instr); 4498 } 4499 pc_modified_ = false; 4500 4501 switch (instr->instructionType()) { 4502 case SimInstruction::kOp6Type: 4503 decodeTypeOp6(instr); 4504 break; 4505 case SimInstruction::kOp7Type: 4506 decodeTypeOp7(instr); 4507 break; 4508 case SimInstruction::kOp8Type: 4509 decodeTypeOp8(instr); 4510 break; 4511 case SimInstruction::kOp10Type: 4512 decodeTypeOp10(instr); 4513 break; 4514 case SimInstruction::kOp11Type: 4515 decodeTypeOp11(instr); 4516 break; 4517 case SimInstruction::kOp12Type: 4518 decodeTypeOp12(instr); 4519 break; 4520 case SimInstruction::kOp14Type: 4521 decodeTypeOp14(instr); 4522 break; 4523 case SimInstruction::kOp15Type: 4524 decodeTypeOp15(instr); 4525 break; 4526 case SimInstruction::kOp16Type: 4527 decodeTypeOp16(instr); 4528 break; 4529 case SimInstruction::kOp17Type: 4530 decodeTypeOp17(instr); 4531 break; 4532 case SimInstruction::kOp22Type: 4533 decodeTypeOp22(instr); 4534 break; 4535 case SimInstruction::kOp24Type: 4536 decodeTypeOp24(instr); 4537 break; 4538 default: 4539 UNSUPPORTED(); 4540 } 4541 if (!pc_modified_) { 4542 setRegister(pc, 4543 reinterpret_cast<int64_t>(instr) + SimInstruction::kInstrSize); 4544 } 4545 } 4546 4547 void Simulator::enable_single_stepping(SingleStepCallback cb, void* arg) { 4548 single_stepping_ = true; 4549 single_step_callback_ = cb; 4550 single_step_callback_arg_ = arg; 4551 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc()); 4552 } 4553 4554 void Simulator::disable_single_stepping() { 4555 if (!single_stepping_) { 4556 return; 4557 } 4558 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc()); 4559 single_stepping_ = false; 4560 single_step_callback_ = nullptr; 4561 single_step_callback_arg_ = nullptr; 4562 } 4563 4564 template <bool enableStopSimAt> 4565 void Simulator::execute() { 4566 if (single_stepping_) { 4567 single_step_callback_(single_step_callback_arg_, this, nullptr); 4568 } 4569 4570 // Get the PC to simulate. Cannot use the accessor here as we need the 4571 // raw PC value and not the one used as input to arithmetic instructions. 4572 int64_t program_counter = get_pc(); 4573 4574 while (program_counter != end_sim_pc) { 4575 if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) { 4576 loong64Debugger dbg(this); 4577 dbg.debug(); 4578 } else { 4579 if (single_stepping_) { 4580 single_step_callback_(single_step_callback_arg_, this, 4581 (void*)program_counter); 4582 } 4583 SimInstruction* instr = 4584 reinterpret_cast<SimInstruction*>(program_counter); 4585 instructionDecode(instr); 4586 icount_++; 4587 } 4588 program_counter = get_pc(); 4589 } 4590 4591 if (single_stepping_) { 4592 single_step_callback_(single_step_callback_arg_, this, nullptr); 4593 } 4594 } 4595 4596 void Simulator::callInternal(uint8_t* entry) { 4597 // Prepare to execute the code at entry. 4598 setRegister(pc, reinterpret_cast<int64_t>(entry)); 4599 // Put down marker for end of simulation. The simulator will stop simulation 4600 // when the PC reaches this value. By saving the "end simulation" value into 4601 // the LR the simulation stops when returning to this call point. 4602 setRegister(ra, end_sim_pc); 4603 4604 // Remember the values of callee-saved registers. 4605 // The code below assumes that r9 is not used as sb (static base) in 4606 // simulator code and therefore is regarded as a callee-saved register. 4607 int64_t s0_val = getRegister(s0); 4608 int64_t s1_val = getRegister(s1); 4609 int64_t s2_val = getRegister(s2); 4610 int64_t s3_val = getRegister(s3); 4611 int64_t s4_val = getRegister(s4); 4612 int64_t s5_val = getRegister(s5); 4613 int64_t s6_val = getRegister(s6); 4614 int64_t s7_val = getRegister(s7); 4615 int64_t s8_val = getRegister(s8); 4616 int64_t gp_val = getRegister(gp); 4617 int64_t sp_val = getRegister(sp); 4618 int64_t tp_val = getRegister(tp); 4619 int64_t fp_val = getRegister(fp); 4620 4621 // Set up the callee-saved registers with a known value. To be able to check 4622 // that they are preserved properly across JS execution. 4623 int64_t callee_saved_value = icount_; 4624 setRegister(s0, callee_saved_value); 4625 setRegister(s1, callee_saved_value); 4626 setRegister(s2, callee_saved_value); 4627 setRegister(s3, callee_saved_value); 4628 setRegister(s4, callee_saved_value); 4629 setRegister(s5, callee_saved_value); 4630 setRegister(s6, callee_saved_value); 4631 setRegister(s7, callee_saved_value); 4632 setRegister(s8, callee_saved_value); 4633 setRegister(gp, callee_saved_value); 4634 setRegister(tp, callee_saved_value); 4635 setRegister(fp, callee_saved_value); 4636 4637 // Start the simulation. 4638 if (Simulator::StopSimAt != -1) { 4639 execute<true>(); 4640 } else { 4641 execute<false>(); 4642 } 4643 4644 // Check that the callee-saved registers have been preserved. 4645 MOZ_ASSERT(callee_saved_value == getRegister(s0)); 4646 MOZ_ASSERT(callee_saved_value == getRegister(s1)); 4647 MOZ_ASSERT(callee_saved_value == getRegister(s2)); 4648 MOZ_ASSERT(callee_saved_value == getRegister(s3)); 4649 MOZ_ASSERT(callee_saved_value == getRegister(s4)); 4650 MOZ_ASSERT(callee_saved_value == getRegister(s5)); 4651 MOZ_ASSERT(callee_saved_value == getRegister(s6)); 4652 MOZ_ASSERT(callee_saved_value == getRegister(s7)); 4653 MOZ_ASSERT(callee_saved_value == getRegister(s8)); 4654 MOZ_ASSERT(callee_saved_value == getRegister(gp)); 4655 MOZ_ASSERT(callee_saved_value == getRegister(tp)); 4656 MOZ_ASSERT(callee_saved_value == getRegister(fp)); 4657 4658 // Restore callee-saved registers with the original value. 4659 setRegister(s0, s0_val); 4660 setRegister(s1, s1_val); 4661 setRegister(s2, s2_val); 4662 setRegister(s3, s3_val); 4663 setRegister(s4, s4_val); 4664 setRegister(s5, s5_val); 4665 setRegister(s6, s6_val); 4666 setRegister(s7, s7_val); 4667 setRegister(s8, s8_val); 4668 setRegister(gp, gp_val); 4669 setRegister(sp, sp_val); 4670 setRegister(tp, tp_val); 4671 setRegister(fp, fp_val); 4672 } 4673 4674 int64_t Simulator::call(uint8_t* entry, int argument_count, ...) { 4675 va_list parameters; 4676 va_start(parameters, argument_count); 4677 4678 int64_t original_stack = getRegister(sp); 4679 // Compute position of stack on entry to generated code. 4680 int64_t entry_stack = original_stack; 4681 if (argument_count > kCArgSlotCount) { 4682 entry_stack = entry_stack - argument_count * sizeof(int64_t); 4683 } else { 4684 entry_stack = entry_stack - kCArgsSlotsSize; 4685 } 4686 4687 entry_stack &= ~U64(ABIStackAlignment - 1); 4688 4689 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); 4690 4691 // Setup the arguments. 4692 for (int i = 0; i < argument_count; i++) { 4693 js::jit::Register argReg; 4694 if (GetIntArgReg(i, &argReg)) { 4695 setRegister(argReg.code(), va_arg(parameters, int64_t)); 4696 } else { 4697 stack_argument[i] = va_arg(parameters, int64_t); 4698 } 4699 } 4700 4701 va_end(parameters); 4702 setRegister(sp, entry_stack); 4703 4704 callInternal(entry); 4705 4706 // Pop stack passed arguments. 4707 MOZ_ASSERT(entry_stack == getRegister(sp)); 4708 setRegister(sp, original_stack); 4709 4710 int64_t result = getRegister(a0); 4711 return result; 4712 } 4713 4714 uintptr_t Simulator::pushAddress(uintptr_t address) { 4715 int new_sp = getRegister(sp) - sizeof(uintptr_t); 4716 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp); 4717 *stack_slot = address; 4718 setRegister(sp, new_sp); 4719 return new_sp; 4720 } 4721 4722 uintptr_t Simulator::popAddress() { 4723 int current_sp = getRegister(sp); 4724 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp); 4725 uintptr_t address = *stack_slot; 4726 setRegister(sp, current_sp + sizeof(uintptr_t)); 4727 return address; 4728 } 4729 4730 } // namespace jit 4731 } // namespace js 4732 4733 js::jit::Simulator* JSContext::simulator() const { return simulator_; }