Assembler-mips-shared.h (53356B)
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 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_mips_shared_Assembler_mips_shared_h 8 #define jit_mips_shared_Assembler_mips_shared_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/Sprintf.h" 12 13 #include "jit/CompactBuffer.h" 14 #include "jit/JitCode.h" 15 #include "jit/JitSpewer.h" 16 #include "jit/mips-shared/Architecture-mips-shared.h" 17 #include "jit/shared/Assembler-shared.h" 18 #include "jit/shared/IonAssemblerBuffer.h" 19 #include "wasm/WasmTypeDecls.h" 20 21 namespace js { 22 namespace jit { 23 24 static constexpr Register zero{Registers::zero}; 25 static constexpr Register at{Registers::at}; 26 static constexpr Register v0{Registers::v0}; 27 static constexpr Register v1{Registers::v1}; 28 static constexpr Register a0{Registers::a0}; 29 static constexpr Register a1{Registers::a1}; 30 static constexpr Register a2{Registers::a2}; 31 static constexpr Register a3{Registers::a3}; 32 static constexpr Register a4{Registers::a4}; 33 static constexpr Register a5{Registers::a5}; 34 static constexpr Register a6{Registers::a6}; 35 static constexpr Register a7{Registers::a7}; 36 static constexpr Register t4{Registers::t4}; 37 static constexpr Register t5{Registers::t5}; 38 static constexpr Register t6{Registers::t6}; 39 static constexpr Register t7{Registers::t7}; 40 static constexpr Register s0{Registers::s0}; 41 static constexpr Register s1{Registers::s1}; 42 static constexpr Register s2{Registers::s2}; 43 static constexpr Register s3{Registers::s3}; 44 static constexpr Register s4{Registers::s4}; 45 static constexpr Register s5{Registers::s5}; 46 static constexpr Register s6{Registers::s6}; 47 static constexpr Register s7{Registers::s7}; 48 static constexpr Register t8{Registers::t8}; 49 static constexpr Register t9{Registers::t9}; 50 static constexpr Register k0{Registers::k0}; 51 static constexpr Register k1{Registers::k1}; 52 static constexpr Register gp{Registers::gp}; 53 static constexpr Register sp{Registers::sp}; 54 static constexpr Register fp{Registers::fp}; 55 static constexpr Register ra{Registers::ra}; 56 57 // Scratch register set aside for runtime patching. 58 // See also Assembler::PatchWrite_NearCall, MacroAssembler::patchNopToCall. 59 static constexpr Register ScratchRegister = t9; 60 61 class AssemblerMIPSShared; 62 63 class UseScratchRegisterScope { 64 public: 65 explicit UseScratchRegisterScope(AssemblerMIPSShared& assembler); 66 explicit UseScratchRegisterScope(AssemblerMIPSShared* assembler); 67 ~UseScratchRegisterScope(); 68 69 Register Acquire(); 70 void Release(const Register& reg); 71 bool hasAvailable() const; 72 void Include(const GeneralRegisterSet& list) { 73 *available_ = GeneralRegisterSet::Union(*available_, list); 74 } 75 void Exclude(const GeneralRegisterSet& list) { 76 *available_ = GeneralRegisterSet::Subtract(*available_, list); 77 } 78 79 private: 80 GeneralRegisterSet* available_; 81 GeneralRegisterSet old_available_; 82 }; 83 84 // Use arg reg from EnterJIT function as OsrFrameReg. 85 static constexpr Register OsrFrameReg = a3; 86 static constexpr Register CallTempReg0 = t4; 87 static constexpr Register CallTempReg1 = t5; 88 static constexpr Register CallTempReg2 = t6; 89 static constexpr Register CallTempReg3 = t7; 90 91 static constexpr Register IntArgReg0 = a0; 92 static constexpr Register IntArgReg1 = a1; 93 static constexpr Register IntArgReg2 = a2; 94 static constexpr Register IntArgReg3 = a3; 95 static constexpr Register IntArgReg4 = a4; 96 static constexpr Register IntArgReg5 = a5; 97 static constexpr Register IntArgReg6 = a6; 98 static constexpr Register IntArgReg7 = a7; 99 static constexpr Register GlobalReg = s6; // used by Odin 100 static constexpr Register HeapReg = s7; // used by Odin 101 102 static constexpr Register PreBarrierReg = a1; 103 104 static constexpr Register InvalidReg{Registers::invalid_reg}; 105 static constexpr FloatRegister InvalidFloatReg; 106 107 static constexpr Register StackPointer = sp; 108 static constexpr Register FramePointer = fp; 109 static constexpr Register ReturnReg = v0; 110 static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg; 111 static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg; 112 113 // A bias applied to the GlobalReg to allow the use of instructions with small 114 // negative immediate offsets which doubles the range of global data that can be 115 // accessed with a single instruction. 116 static const int32_t WasmGlobalRegBias = 32768; 117 118 // Registers used by RegExpMatcher and RegExpExecMatch stubs (do not use 119 // JSReturnOperand). 120 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0; 121 static constexpr Register RegExpMatcherStringReg = CallTempReg1; 122 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2; 123 124 // Registers used by RegExpExecTest stub (do not use ReturnReg). 125 static constexpr Register RegExpExecTestRegExpReg = CallTempReg0; 126 static constexpr Register RegExpExecTestStringReg = CallTempReg1; 127 128 // Registers used by RegExpSearcher stub (do not use ReturnReg). 129 static constexpr Register RegExpSearcherRegExpReg = CallTempReg0; 130 static constexpr Register RegExpSearcherStringReg = CallTempReg1; 131 static constexpr Register RegExpSearcherLastIndexReg = CallTempReg2; 132 133 static constexpr uint32_t CodeAlignment = 8; 134 135 /* clang-format off */ 136 // MIPS instruction types 137 // +---------------------------------------------------------------+ 138 // | 6 | 5 | 5 | 5 | 5 | 6 | 139 // +---------------------------------------------------------------+ 140 // Register type | Opcode | Rs | Rt | Rd | Sa | Function | 141 // +---------------------------------------------------------------+ 142 // | 6 | 5 | 5 | 16 | 143 // +---------------------------------------------------------------+ 144 // Immediate type | Opcode | Rs | Rt | 2's complement constant | 145 // +---------------------------------------------------------------+ 146 // | 6 | 26 | 147 // +---------------------------------------------------------------+ 148 // Jump type | Opcode | jump_target | 149 // +---------------------------------------------------------------+ 150 // 31 bit bit 0 151 /* clang-format on */ 152 153 // MIPS instruction encoding constants. 154 static const uint32_t OpcodeShift = 26; 155 static const uint32_t OpcodeBits = 6; 156 static const uint32_t RSShift = 21; 157 static const uint32_t RSBits = 5; 158 static const uint32_t RTShift = 16; 159 static const uint32_t RTBits = 5; 160 static const uint32_t RDShift = 11; 161 static const uint32_t RDBits = 5; 162 static const uint32_t RZShift = 0; 163 static const uint32_t RZBits = 5; 164 static const uint32_t SAShift = 6; 165 static const uint32_t SABits = 5; 166 static const uint32_t FunctionShift = 0; 167 static const uint32_t FunctionBits = 6; 168 static const uint32_t Imm16Shift = 0; 169 static const uint32_t Imm16Bits = 16; 170 static const uint32_t Imm26Shift = 0; 171 static const uint32_t Imm26Bits = 26; 172 static const uint32_t Imm28Shift = 0; 173 static const uint32_t Imm28Bits = 28; 174 static const uint32_t ImmFieldShift = 2; 175 static const uint32_t FRBits = 5; 176 static const uint32_t FRShift = 21; 177 static const uint32_t FSShift = 11; 178 static const uint32_t FSBits = 5; 179 static const uint32_t FTShift = 16; 180 static const uint32_t FTBits = 5; 181 static const uint32_t FDShift = 6; 182 static const uint32_t FDBits = 5; 183 static const uint32_t FCccShift = 8; 184 static const uint32_t FCccBits = 3; 185 static const uint32_t FBccShift = 18; 186 static const uint32_t FBccBits = 3; 187 static const uint32_t FBtrueShift = 16; 188 static const uint32_t FBtrueBits = 1; 189 static const uint32_t FccMask = 0x7; 190 static const uint32_t FccShift = 2; 191 192 // MIPS instruction field bit masks. 193 static const uint32_t OpcodeMask = ((1 << OpcodeBits) - 1) << OpcodeShift; 194 static const uint32_t Imm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift; 195 static const uint32_t Imm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift; 196 static const uint32_t Imm28Mask = ((1 << Imm28Bits) - 1) << Imm28Shift; 197 static const uint32_t RSMask = ((1 << RSBits) - 1) << RSShift; 198 static const uint32_t RTMask = ((1 << RTBits) - 1) << RTShift; 199 static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift; 200 static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift; 201 static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift; 202 static const uint32_t RegMask = Registers::Total - 1; 203 204 static const uint32_t BREAK_STACK_UNALIGNED = 1; 205 static const uint32_t MAX_BREAK_CODE = 1024 - 1; 206 static const uint32_t WASM_TRAP = 6; // BRK_OVERFLOW 207 208 class Instruction; 209 class InstReg; 210 class InstImm; 211 class InstJump; 212 213 uint32_t RS(Register r); 214 uint32_t RT(Register r); 215 uint32_t RT(FloatRegister r); 216 uint32_t RD(Register r); 217 uint32_t RD(FloatRegister r); 218 uint32_t RZ(Register r); 219 uint32_t RZ(FloatRegister r); 220 uint32_t SA(uint32_t value); 221 uint32_t SA(FloatRegister r); 222 uint32_t FS(uint32_t value); 223 224 Register toRS(Instruction& i); 225 Register toRT(Instruction& i); 226 Register toRD(Instruction& i); 227 Register toR(Instruction& i); 228 229 // MIPS enums for instruction fields 230 enum OpcodeField { 231 op_special = 0 << OpcodeShift, 232 op_regimm = 1 << OpcodeShift, 233 234 op_j = 2 << OpcodeShift, 235 op_jal = 3 << OpcodeShift, 236 op_beq = 4 << OpcodeShift, 237 op_bne = 5 << OpcodeShift, 238 op_blez = 6 << OpcodeShift, 239 op_bgtz = 7 << OpcodeShift, 240 241 op_addi = 8 << OpcodeShift, 242 op_addiu = 9 << OpcodeShift, 243 op_slti = 10 << OpcodeShift, 244 op_sltiu = 11 << OpcodeShift, 245 op_andi = 12 << OpcodeShift, 246 op_ori = 13 << OpcodeShift, 247 op_xori = 14 << OpcodeShift, 248 op_lui = 15 << OpcodeShift, 249 250 op_cop1 = 17 << OpcodeShift, 251 op_cop1x = 19 << OpcodeShift, 252 253 op_beql = 20 << OpcodeShift, 254 op_bnel = 21 << OpcodeShift, 255 op_blezl = 22 << OpcodeShift, 256 op_bgtzl = 23 << OpcodeShift, 257 258 op_daddi = 24 << OpcodeShift, 259 op_daddiu = 25 << OpcodeShift, 260 261 op_ldl = 26 << OpcodeShift, 262 op_ldr = 27 << OpcodeShift, 263 264 op_special2 = 28 << OpcodeShift, 265 op_special3 = 31 << OpcodeShift, 266 267 op_lb = 32 << OpcodeShift, 268 op_lh = 33 << OpcodeShift, 269 op_lwl = 34 << OpcodeShift, 270 op_lw = 35 << OpcodeShift, 271 op_lbu = 36 << OpcodeShift, 272 op_lhu = 37 << OpcodeShift, 273 op_lwr = 38 << OpcodeShift, 274 op_lwu = 39 << OpcodeShift, 275 op_sb = 40 << OpcodeShift, 276 op_sh = 41 << OpcodeShift, 277 op_swl = 42 << OpcodeShift, 278 op_sw = 43 << OpcodeShift, 279 op_sdl = 44 << OpcodeShift, 280 op_sdr = 45 << OpcodeShift, 281 op_swr = 46 << OpcodeShift, 282 283 op_ll = 48 << OpcodeShift, 284 op_lwc1 = 49 << OpcodeShift, 285 op_lwc2 = 50 << OpcodeShift, 286 op_lld = 52 << OpcodeShift, 287 op_ldc1 = 53 << OpcodeShift, 288 op_ldc2 = 54 << OpcodeShift, 289 op_ld = 55 << OpcodeShift, 290 291 op_sc = 56 << OpcodeShift, 292 op_swc1 = 57 << OpcodeShift, 293 op_swc2 = 58 << OpcodeShift, 294 op_scd = 60 << OpcodeShift, 295 op_sdc1 = 61 << OpcodeShift, 296 op_sdc2 = 62 << OpcodeShift, 297 op_sd = 63 << OpcodeShift, 298 }; 299 300 enum RSField { 301 rs_zero = 0 << RSShift, 302 // cop1 encoding of RS field. 303 rs_mfc1 = 0 << RSShift, 304 rs_one = 1 << RSShift, 305 rs_dmfc1 = 1 << RSShift, 306 rs_cfc1 = 2 << RSShift, 307 rs_mfhc1 = 3 << RSShift, 308 rs_mtc1 = 4 << RSShift, 309 rs_dmtc1 = 5 << RSShift, 310 rs_ctc1 = 6 << RSShift, 311 rs_mthc1 = 7 << RSShift, 312 rs_bc1 = 8 << RSShift, 313 rs_f = 0x9 << RSShift, 314 rs_t = 0xd << RSShift, 315 rs_s_r6 = 20 << RSShift, 316 rs_d_r6 = 21 << RSShift, 317 rs_s = 16 << RSShift, 318 rs_d = 17 << RSShift, 319 rs_w = 20 << RSShift, 320 rs_l = 21 << RSShift, 321 rs_ps = 22 << RSShift 322 }; 323 324 enum RTField { 325 rt_zero = 0 << RTShift, 326 // regimm encoding of RT field. 327 rt_bltz = 0 << RTShift, 328 rt_bgez = 1 << RTShift, 329 rt_bltzal = 16 << RTShift, 330 rt_bgezal = 17 << RTShift 331 }; 332 333 enum FunctionField { 334 // special encoding of function field. 335 ff_sll = 0, 336 ff_movci = 1, 337 ff_srl = 2, 338 ff_sra = 3, 339 ff_sllv = 4, 340 ff_srlv = 6, 341 ff_srav = 7, 342 343 ff_jr = 8, 344 ff_jalr = 9, 345 ff_movz = 10, 346 ff_movn = 11, 347 ff_break = 13, 348 ff_sync = 15, 349 350 ff_mfhi = 16, 351 ff_mflo = 18, 352 353 ff_dsllv = 20, 354 ff_dsrlv = 22, 355 ff_dsrav = 23, 356 357 ff_mult = 24, 358 ff_multu = 25, 359 360 ff_mulu = 25, 361 ff_muh = 24, 362 ff_muhu = 25, 363 ff_dmul = 28, 364 ff_dmulu = 29, 365 ff_dmuh = 28, 366 ff_dmuhu = 29, 367 368 ff_div = 26, 369 ff_mod = 26, 370 ff_divu = 27, 371 ff_modu = 27, 372 ff_dmult = 28, 373 ff_dmultu = 29, 374 ff_ddiv = 30, 375 ff_dmod = 30, 376 ff_ddivu = 31, 377 ff_dmodu = 31, 378 379 ff_add = 32, 380 ff_addu = 33, 381 ff_sub = 34, 382 ff_subu = 35, 383 ff_and = 36, 384 ff_or = 37, 385 ff_xor = 38, 386 ff_nor = 39, 387 388 ff_slt = 42, 389 ff_sltu = 43, 390 ff_dadd = 44, 391 ff_daddu = 45, 392 ff_dsub = 46, 393 ff_dsubu = 47, 394 395 ff_tge = 48, 396 ff_tgeu = 49, 397 ff_tlt = 50, 398 ff_tltu = 51, 399 ff_teq = 52, 400 ff_seleqz = 53, 401 ff_tne = 54, 402 ff_selnez = 55, 403 ff_dsll = 56, 404 ff_dsrl = 58, 405 ff_dsra = 59, 406 ff_dsll32 = 60, 407 ff_dsrl32 = 62, 408 ff_dsra32 = 63, 409 410 // special2 encoding of function field. 411 ff_madd = 0, 412 ff_maddu = 1, 413 #ifdef MIPSR6 414 ff_clz = 16, 415 ff_dclz = 18, 416 ff_mul = 24, 417 #else 418 ff_mul = 2, 419 ff_clz = 32, 420 ff_dclz = 36, 421 #endif 422 ff_clo = 33, 423 424 // special3 encoding of function field. 425 ff_ext = 0, 426 ff_dextm = 1, 427 ff_dextu = 2, 428 ff_dext = 3, 429 ff_ins = 4, 430 ff_dinsm = 5, 431 ff_dinsu = 6, 432 ff_dins = 7, 433 ff_bshfl = 32, 434 ff_dbshfl = 36, 435 ff_sc = 38, 436 ff_scd = 39, 437 ff_ll = 54, 438 ff_lld = 55, 439 440 // cop1 encoding of function field. 441 ff_add_fmt = 0, 442 ff_sub_fmt = 1, 443 ff_mul_fmt = 2, 444 ff_div_fmt = 3, 445 ff_sqrt_fmt = 4, 446 ff_abs_fmt = 5, 447 ff_mov_fmt = 6, 448 ff_neg_fmt = 7, 449 450 ff_round_l_fmt = 8, 451 ff_trunc_l_fmt = 9, 452 ff_ceil_l_fmt = 10, 453 ff_floor_l_fmt = 11, 454 455 ff_round_w_fmt = 12, 456 ff_trunc_w_fmt = 13, 457 ff_ceil_w_fmt = 14, 458 ff_floor_w_fmt = 15, 459 460 ff_movf_fmt = 17, 461 ff_movz_fmt = 18, 462 ff_movn_fmt = 19, 463 464 ff_min = 28, 465 ff_max = 30, 466 467 ff_cvt_s_fmt = 32, 468 ff_cvt_d_fmt = 33, 469 ff_cvt_w_fmt = 36, 470 ff_cvt_l_fmt = 37, 471 ff_cvt_ps_s = 38, 472 473 #ifdef MIPSR6 474 ff_c_f_fmt = 0, 475 ff_c_un_fmt = 1, 476 ff_c_eq_fmt = 2, 477 ff_c_ueq_fmt = 3, 478 ff_c_olt_fmt = 4, 479 ff_c_ult_fmt = 5, 480 ff_c_ole_fmt = 6, 481 ff_c_ule_fmt = 7, 482 #else 483 ff_c_f_fmt = 48, 484 ff_c_un_fmt = 49, 485 ff_c_eq_fmt = 50, 486 ff_c_ueq_fmt = 51, 487 ff_c_olt_fmt = 52, 488 ff_c_ult_fmt = 53, 489 ff_c_ole_fmt = 54, 490 ff_c_ule_fmt = 55, 491 #endif 492 493 ff_madd_s = 32, 494 ff_madd_d = 33, 495 496 // Loongson encoding of function field. 497 ff_gsxbx = 0, 498 ff_gsxhx = 1, 499 ff_gsxwx = 2, 500 ff_gsxdx = 3, 501 ff_gsxwlc1 = 4, 502 ff_gsxwrc1 = 5, 503 ff_gsxdlc1 = 6, 504 ff_gsxdrc1 = 7, 505 ff_gsxwxc1 = 6, 506 ff_gsxdxc1 = 7, 507 ff_gsxq = 0x20, 508 ff_gsxqc1 = 0x8020, 509 510 ff_null = 0 511 }; 512 513 class Operand; 514 515 // A BOffImm16 is a 16 bit immediate that is used for branches. 516 class BOffImm16 { 517 uint32_t data; 518 519 public: 520 uint32_t encode() { 521 MOZ_ASSERT(!isInvalid()); 522 return data; 523 } 524 int32_t decode() { 525 MOZ_ASSERT(!isInvalid()); 526 return (int32_t(data << 18) >> 16) + 4; 527 } 528 529 explicit BOffImm16(int offset) : data((offset - 4) >> 2 & Imm16Mask) { 530 MOZ_ASSERT((offset & 0x3) == 0); 531 MOZ_ASSERT(IsInRange(offset)); 532 } 533 static bool IsInRange(int offset) { 534 if ((offset - 4) < int(unsigned(INT16_MIN) << 2)) { 535 return false; 536 } 537 if ((offset - 4) > (INT16_MAX << 2)) { 538 return false; 539 } 540 return true; 541 } 542 static const uint32_t INVALID = 0x00020000; 543 BOffImm16() : data(INVALID) {} 544 545 bool isInvalid() { return data == INVALID; } 546 Instruction* getDest(Instruction* src) const; 547 548 explicit BOffImm16(InstImm inst); 549 }; 550 551 // A JOffImm26 is a 26 bit immediate that is used for unconditional jumps. 552 class JOffImm26 { 553 uint32_t data; 554 555 public: 556 uint32_t encode() { 557 MOZ_ASSERT(!isInvalid()); 558 return data; 559 } 560 int32_t decode() { 561 MOZ_ASSERT(!isInvalid()); 562 return (int32_t(data << 8) >> 6) + 4; 563 } 564 565 explicit JOffImm26(int offset) : data((offset - 4) >> 2 & Imm26Mask) { 566 MOZ_ASSERT((offset & 0x3) == 0); 567 MOZ_ASSERT(IsInRange(offset)); 568 } 569 static bool IsInRange(int offset) { 570 if ((offset - 4) < -536870912) { 571 return false; 572 } 573 if ((offset - 4) > 536870908) { 574 return false; 575 } 576 return true; 577 } 578 static const uint32_t INVALID = 0x20000000; 579 JOffImm26() : data(INVALID) {} 580 581 bool isInvalid() { return data == INVALID; } 582 Instruction* getDest(Instruction* src); 583 }; 584 585 class Imm16 { 586 uint16_t value; 587 588 public: 589 Imm16(); 590 explicit Imm16(uint32_t imm) : value(imm) {} 591 uint32_t encode() { return value; } 592 int32_t decodeSigned() { return value; } 593 uint32_t decodeUnsigned() { return value; } 594 static bool IsInSignedRange(int32_t imm) { 595 return imm >= INT16_MIN && imm <= INT16_MAX; 596 } 597 static bool IsInSignedRange(int64_t imm) { 598 return imm >= INT16_MIN && imm <= INT16_MAX; 599 } 600 static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT16_MAX; } 601 static Imm16 Lower(Imm32 imm) { return Imm16(imm.value & 0xffff); } 602 static Imm16 Upper(Imm32 imm) { return Imm16((imm.value >> 16) & 0xffff); } 603 }; 604 605 class Imm8 { 606 uint8_t value; 607 608 public: 609 Imm8(); 610 explicit Imm8(uint32_t imm) : value(imm) {} 611 uint32_t encode(uint32_t shift) { return value << shift; } 612 int32_t decodeSigned() { return value; } 613 uint32_t decodeUnsigned() { return value; } 614 static bool IsInSignedRange(int32_t imm) { 615 return imm >= INT8_MIN && imm <= INT8_MAX; 616 } 617 static bool IsInSignedRange(intptr_t imm) { 618 return imm >= INT8_MIN && imm <= INT8_MAX; 619 } 620 static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT8_MAX; } 621 static Imm8 Lower(Imm16 imm) { return Imm8(imm.decodeSigned() & 0xff); } 622 static Imm8 Upper(Imm16 imm) { 623 return Imm8((imm.decodeSigned() >> 8) & 0xff); 624 } 625 }; 626 627 class GSImm13 { 628 uint16_t value; 629 630 public: 631 GSImm13(); 632 explicit GSImm13(uint32_t imm) : value(imm & ~0xf) {} 633 uint32_t encode(uint32_t shift) { return ((value >> 4) & 0x1ff) << shift; } 634 int32_t decodeSigned() { return value; } 635 uint32_t decodeUnsigned() { return value; } 636 static bool IsInRange(int32_t imm) { 637 return imm >= int32_t(uint32_t(-256) << 4) && imm <= (255 << 4); 638 } 639 }; 640 641 class Operand { 642 public: 643 enum Tag { REG, FREG, MEM }; 644 645 private: 646 Tag tag : 3; 647 uint32_t reg : 5; 648 int32_t offset; 649 650 public: 651 explicit Operand(Register reg_) : tag(REG), reg(reg_.code()) {} 652 653 explicit Operand(FloatRegister freg) : tag(FREG), reg(freg.code()) {} 654 655 Operand(Register base, Imm32 off) 656 : tag(MEM), reg(base.code()), offset(off.value) {} 657 658 Operand(Register base, int32_t off) 659 : tag(MEM), reg(base.code()), offset(off) {} 660 661 explicit Operand(const Address& addr) 662 : tag(MEM), reg(addr.base.code()), offset(addr.offset) {} 663 664 Tag getTag() const { return tag; } 665 666 Register toReg() const { 667 MOZ_ASSERT(tag == REG); 668 return Register::FromCode(reg); 669 } 670 671 FloatRegister toFReg() const { 672 MOZ_ASSERT(tag == FREG); 673 return FloatRegister::FromCode(reg); 674 } 675 676 void toAddr(Register* r, Imm32* dest) const { 677 MOZ_ASSERT(tag == MEM); 678 *r = Register::FromCode(reg); 679 *dest = Imm32(offset); 680 } 681 Address toAddress() const { 682 MOZ_ASSERT(tag == MEM); 683 return Address(Register::FromCode(reg), offset); 684 } 685 int32_t disp() const { 686 MOZ_ASSERT(tag == MEM); 687 return offset; 688 } 689 690 int32_t base() const { 691 MOZ_ASSERT(tag == MEM); 692 return reg; 693 } 694 Register baseReg() const { 695 MOZ_ASSERT(tag == MEM); 696 return Register::FromCode(reg); 697 } 698 }; 699 700 static constexpr int32_t SliceSize = 1024; 701 typedef js::jit::AssemblerBuffer<SliceSize, Instruction> MIPSBuffer; 702 703 class MIPSBufferWithExecutableCopy : public MIPSBuffer { 704 public: 705 void executableCopy(uint8_t* buffer) { 706 if (this->oom()) { 707 return; 708 } 709 710 for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) { 711 memcpy(buffer, &cur->instructions, cur->length()); 712 buffer += cur->length(); 713 } 714 } 715 716 bool appendRawCode(const uint8_t* code, size_t numBytes) { 717 if (this->oom()) { 718 return false; 719 } 720 while (numBytes > SliceSize) { 721 this->putBytes(SliceSize, code); 722 numBytes -= SliceSize; 723 code += SliceSize; 724 } 725 this->putBytes(numBytes, code); 726 return !this->oom(); 727 } 728 }; 729 730 class AssemblerMIPSShared : public AssemblerShared { 731 public: 732 enum Condition { 733 Equal, 734 NotEqual, 735 Above, 736 AboveOrEqual, 737 Below, 738 BelowOrEqual, 739 GreaterThan, 740 GreaterThanOrEqual, 741 LessThan, 742 LessThanOrEqual, 743 Overflow, 744 CarrySet, 745 CarryClear, 746 Signed, 747 NotSigned, 748 Zero, 749 NonZero, 750 Always, 751 }; 752 753 enum DoubleCondition { 754 // These conditions will only evaluate to true if the comparison is ordered 755 // - i.e. neither operand is NaN. 756 DoubleOrdered, 757 DoubleEqual, 758 DoubleNotEqual, 759 DoubleGreaterThan, 760 DoubleGreaterThanOrEqual, 761 DoubleLessThan, 762 DoubleLessThanOrEqual, 763 // If either operand is NaN, these conditions always evaluate to true. 764 DoubleUnordered, 765 DoubleEqualOrUnordered, 766 DoubleNotEqualOrUnordered, 767 DoubleGreaterThanOrUnordered, 768 DoubleGreaterThanOrEqualOrUnordered, 769 DoubleLessThanOrUnordered, 770 DoubleLessThanOrEqualOrUnordered 771 }; 772 773 enum FPConditionBit { FCC0 = 0, FCC1, FCC2, FCC3, FCC4, FCC5, FCC6, FCC7 }; 774 775 enum FPControl { 776 FIR = 0, 777 UFR, 778 UNFR = 4, 779 FCCR = 25, 780 FEXR, 781 FENR = 28, 782 FCSR = 31 783 }; 784 785 enum FCSRBit { CauseI = 12, CauseU, CauseO, CauseZ, CauseV }; 786 787 enum FloatFormat { SingleFloat, DoubleFloat }; 788 789 enum JumpOrCall { BranchIsJump, BranchIsCall }; 790 791 enum FloatTestKind { TestForTrue, TestForFalse }; 792 793 // :( this should be protected, but since CodeGenerator 794 // wants to use it, It needs to go out here :( 795 796 BufferOffset nextOffset() { return m_buffer.nextOffset(); } 797 798 protected: 799 Instruction* editSrc(BufferOffset bo) { return m_buffer.getInst(bo); } 800 801 // structure for fixing up pc-relative loads/jumps when a the machine code 802 // gets moved (executable copy, gc, etc.) 803 struct RelativePatch { 804 // the offset within the code buffer where the value is loaded that 805 // we want to fix-up 806 BufferOffset offset; 807 void* target; 808 RelocationKind kind; 809 810 RelativePatch(BufferOffset offset, void* target, RelocationKind kind) 811 : offset(offset), target(target), kind(kind) {} 812 }; 813 814 js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_; 815 816 CompactBufferWriter jumpRelocations_; 817 CompactBufferWriter dataRelocations_; 818 819 MIPSBufferWithExecutableCopy m_buffer; 820 821 #ifdef JS_JITSPEW 822 Sprinter* printer; 823 #endif 824 825 public: 826 AssemblerMIPSShared() 827 : m_buffer(), 828 #ifdef JS_JITSPEW 829 printer(nullptr), 830 #endif 831 isFinished(false), 832 scratch_register_list_((1 << at.code()) | (1 << t8.code())) { 833 } 834 835 static Condition InvertCondition(Condition cond); 836 static DoubleCondition InvertCondition(DoubleCondition cond); 837 838 // As opposed to x86/x64 version, the data relocation has to be executed 839 // before to recover the pointer, and not after. 840 void writeDataRelocation(ImmGCPtr ptr) { 841 // Raw GC pointer relocations and Value relocations both end up in 842 // TraceOneDataRelocation. 843 if (ptr.value) { 844 if (gc::IsInsideNursery(ptr.value)) { 845 embedsNurseryPointers_ = true; 846 } 847 dataRelocations_.writeUnsigned(nextOffset().getOffset()); 848 } 849 } 850 851 void assertNoGCThings() const { 852 #ifdef DEBUG 853 MOZ_ASSERT(dataRelocations_.length() == 0); 854 for (auto& j : jumps_) { 855 MOZ_ASSERT(j.kind == RelocationKind::HARDCODED); 856 } 857 #endif 858 } 859 860 public: 861 void setUnlimitedBuffer() { m_buffer.setUnlimited(); } 862 bool oom() const; 863 864 void setPrinter(Sprinter* sp) { 865 #ifdef JS_JITSPEW 866 printer = sp; 867 #endif 868 } 869 870 #ifdef JS_JITSPEW 871 inline void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) { 872 if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) { 873 va_list va; 874 va_start(va, fmt); 875 spew(fmt, va); 876 va_end(va); 877 } 878 } 879 880 void decodeBranchInstAndSpew(InstImm branch); 881 #else 882 MOZ_ALWAYS_INLINE void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {} 883 #endif 884 885 #ifdef JS_JITSPEW 886 MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0) { 887 // Buffer to hold the formatted string. Note that this may contain 888 // '%' characters, so do not pass it directly to printf functions. 889 char buf[200]; 890 891 int i = VsprintfLiteral(buf, fmt, va); 892 if (i > -1) { 893 if (printer) { 894 printer->printf("%s\n", buf); 895 } 896 js::jit::JitSpew(js::jit::JitSpew_Codegen, "%s", buf); 897 } 898 } 899 #endif 900 901 Register getStackPointer() const { return StackPointer; } 902 903 protected: 904 bool isFinished; 905 906 public: 907 void finish(); 908 bool appendRawCode(const uint8_t* code, size_t numBytes); 909 bool reserve(size_t size); 910 bool swapBuffer(wasm::Bytes& bytes); 911 void executableCopy(void* buffer); 912 void copyJumpRelocationTable(uint8_t* dest); 913 void copyDataRelocationTable(uint8_t* dest); 914 915 // Size of the instruction stream, in bytes. 916 size_t size() const; 917 // Size of the jump relocation table, in bytes. 918 size_t jumpRelocationTableBytes() const; 919 size_t dataRelocationTableBytes() const; 920 921 // Size of the data table, in bytes. 922 size_t bytesNeeded() const; 923 924 // Write a blob of binary into the instruction stream *OR* 925 // into a destination address. If dest is nullptr (the default), then the 926 // instruction gets written into the instruction stream. If dest is not null 927 // it is interpreted as a pointer to the location that we want the 928 // instruction to be written. 929 BufferOffset writeInst(uint32_t x, uint32_t* dest = nullptr); 930 // A static variant for the cases where we don't want to have an assembler 931 // object at all. Normally, you would use the dummy (nullptr) object. 932 static void WriteInstStatic(uint32_t x, uint32_t* dest); 933 934 public: 935 BufferOffset haltingAlign(int alignment); 936 BufferOffset nopAlign(int alignment); 937 BufferOffset as_nop(); 938 939 // Branch and jump instructions 940 BufferOffset as_bal(BOffImm16 off); 941 BufferOffset as_b(BOffImm16 off); 942 943 InstImm getBranchCode(JumpOrCall jumpOrCall); 944 InstImm getBranchCode(Register s, Register t, Condition c); 945 InstImm getBranchCode(Register s, Condition c); 946 InstImm getBranchCode(FloatTestKind testKind, FPConditionBit fcc); 947 948 BufferOffset as_j(JOffImm26 off); 949 BufferOffset as_jal(JOffImm26 off); 950 951 BufferOffset as_jr(Register rs); 952 BufferOffset as_jalr(Register rs); 953 954 // Arithmetic instructions 955 BufferOffset as_addu(Register rd, Register rs, Register rt); 956 BufferOffset as_addiu(Register rd, Register rs, int32_t j); 957 BufferOffset as_daddu(Register rd, Register rs, Register rt); 958 BufferOffset as_daddiu(Register rd, Register rs, int32_t j); 959 BufferOffset as_subu(Register rd, Register rs, Register rt); 960 BufferOffset as_dsubu(Register rd, Register rs, Register rt); 961 BufferOffset as_mult(Register rs, Register rt); 962 BufferOffset as_multu(Register rs, Register rt); 963 BufferOffset as_dmult(Register rs, Register rt); 964 BufferOffset as_dmultu(Register rs, Register rt); 965 BufferOffset as_div(Register rs, Register rt); 966 BufferOffset as_divu(Register rs, Register rt); 967 BufferOffset as_mul(Register rd, Register rs, Register rt); 968 BufferOffset as_madd(Register rs, Register rt); 969 BufferOffset as_maddu(Register rs, Register rt); 970 BufferOffset as_ddiv(Register rs, Register rt); 971 BufferOffset as_ddivu(Register rs, Register rt); 972 973 BufferOffset as_muh(Register rd, Register rs, Register rt); 974 BufferOffset as_muhu(Register rd, Register rs, Register rt); 975 BufferOffset as_mulu(Register rd, Register rs, Register rt); 976 BufferOffset as_dmuh(Register rd, Register rs, Register rt); 977 BufferOffset as_dmuhu(Register rd, Register rs, Register rt); 978 BufferOffset as_dmul(Register rd, Register rs, Register rt); 979 BufferOffset as_dmulu(Register rd, Register rs, Register rt); 980 BufferOffset as_div(Register rd, Register rs, Register rt); 981 BufferOffset as_divu(Register rd, Register rs, Register rt); 982 BufferOffset as_mod(Register rd, Register rs, Register rt); 983 BufferOffset as_modu(Register rd, Register rs, Register rt); 984 BufferOffset as_ddiv(Register rd, Register rs, Register rt); 985 BufferOffset as_ddivu(Register rd, Register rs, Register rt); 986 BufferOffset as_dmod(Register rd, Register rs, Register rt); 987 BufferOffset as_dmodu(Register rd, Register rs, Register rt); 988 989 // Logical instructions 990 BufferOffset as_and(Register rd, Register rs, Register rt); 991 BufferOffset as_or(Register rd, Register rs, Register rt); 992 BufferOffset as_xor(Register rd, Register rs, Register rt); 993 BufferOffset as_nor(Register rd, Register rs, Register rt); 994 995 BufferOffset as_andi(Register rd, Register rs, int32_t j); 996 BufferOffset as_ori(Register rd, Register rs, int32_t j); 997 BufferOffset as_xori(Register rd, Register rs, int32_t j); 998 BufferOffset as_lui(Register rd, int32_t j); 999 1000 // Shift instructions 1001 // as_sll(zero, zero, x) instructions are reserved as nop 1002 BufferOffset as_sll(Register rd, Register rt, uint16_t sa); 1003 BufferOffset as_dsll(Register rd, Register rt, uint16_t sa); 1004 BufferOffset as_dsll32(Register rd, Register rt, uint16_t sa); 1005 BufferOffset as_sllv(Register rd, Register rt, Register rs); 1006 BufferOffset as_dsllv(Register rd, Register rt, Register rs); 1007 BufferOffset as_srl(Register rd, Register rt, uint16_t sa); 1008 BufferOffset as_dsrl(Register rd, Register rt, uint16_t sa); 1009 BufferOffset as_dsrl32(Register rd, Register rt, uint16_t sa); 1010 BufferOffset as_srlv(Register rd, Register rt, Register rs); 1011 BufferOffset as_dsrlv(Register rd, Register rt, Register rs); 1012 BufferOffset as_sra(Register rd, Register rt, uint16_t sa); 1013 BufferOffset as_dsra(Register rd, Register rt, uint16_t sa); 1014 BufferOffset as_dsra32(Register rd, Register rt, uint16_t sa); 1015 BufferOffset as_srav(Register rd, Register rt, Register rs); 1016 BufferOffset as_rotr(Register rd, Register rt, uint16_t sa); 1017 BufferOffset as_rotrv(Register rd, Register rt, Register rs); 1018 BufferOffset as_dsrav(Register rd, Register rt, Register rs); 1019 BufferOffset as_drotr(Register rd, Register rt, uint16_t sa); 1020 BufferOffset as_drotr32(Register rd, Register rt, uint16_t sa); 1021 BufferOffset as_drotrv(Register rd, Register rt, Register rs); 1022 1023 // Load and store instructions 1024 BufferOffset as_lb(Register rd, Register rs, int16_t off); 1025 BufferOffset as_lbu(Register rd, Register rs, int16_t off); 1026 BufferOffset as_lh(Register rd, Register rs, int16_t off); 1027 BufferOffset as_lhu(Register rd, Register rs, int16_t off); 1028 BufferOffset as_lw(Register rd, Register rs, int16_t off); 1029 BufferOffset as_lwu(Register rd, Register rs, int16_t off); 1030 BufferOffset as_lwl(Register rd, Register rs, int16_t off); 1031 BufferOffset as_lwr(Register rd, Register rs, int16_t off); 1032 BufferOffset as_ll(Register rd, Register rs, int16_t off); 1033 BufferOffset as_lld(Register rd, Register rs, int16_t off); 1034 BufferOffset as_ld(Register rd, Register rs, int16_t off); 1035 BufferOffset as_ldl(Register rd, Register rs, int16_t off); 1036 BufferOffset as_ldr(Register rd, Register rs, int16_t off); 1037 BufferOffset as_sb(Register rd, Register rs, int16_t off); 1038 BufferOffset as_sh(Register rd, Register rs, int16_t off); 1039 BufferOffset as_sw(Register rd, Register rs, int16_t off); 1040 BufferOffset as_swl(Register rd, Register rs, int16_t off); 1041 BufferOffset as_swr(Register rd, Register rs, int16_t off); 1042 BufferOffset as_sc(Register rd, Register rs, int16_t off); 1043 BufferOffset as_scd(Register rd, Register rs, int16_t off); 1044 BufferOffset as_sd(Register rd, Register rs, int16_t off); 1045 BufferOffset as_sdl(Register rd, Register rs, int16_t off); 1046 BufferOffset as_sdr(Register rd, Register rs, int16_t off); 1047 1048 // Loongson-specific load and store instructions 1049 BufferOffset as_gslbx(Register rd, Register rs, Register ri, int16_t off); 1050 BufferOffset as_gssbx(Register rd, Register rs, Register ri, int16_t off); 1051 BufferOffset as_gslhx(Register rd, Register rs, Register ri, int16_t off); 1052 BufferOffset as_gsshx(Register rd, Register rs, Register ri, int16_t off); 1053 BufferOffset as_gslwx(Register rd, Register rs, Register ri, int16_t off); 1054 BufferOffset as_gsswx(Register rd, Register rs, Register ri, int16_t off); 1055 BufferOffset as_gsldx(Register rd, Register rs, Register ri, int16_t off); 1056 BufferOffset as_gssdx(Register rd, Register rs, Register ri, int16_t off); 1057 BufferOffset as_gslq(Register rh, Register rl, Register rs, int16_t off); 1058 BufferOffset as_gssq(Register rh, Register rl, Register rs, int16_t off); 1059 1060 // Move from HI/LO register. 1061 BufferOffset as_mfhi(Register rd); 1062 BufferOffset as_mflo(Register rd); 1063 1064 // Set on less than. 1065 BufferOffset as_slt(Register rd, Register rs, Register rt); 1066 BufferOffset as_sltu(Register rd, Register rs, Register rt); 1067 BufferOffset as_slti(Register rd, Register rs, int32_t j); 1068 BufferOffset as_sltiu(Register rd, Register rs, uint32_t j); 1069 1070 // Conditional move. 1071 BufferOffset as_movz(Register rd, Register rs, Register rt); 1072 BufferOffset as_movn(Register rd, Register rs, Register rt); 1073 BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0); 1074 BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0); 1075 BufferOffset as_seleqz(Register rd, Register rs, Register rt); 1076 BufferOffset as_selnez(Register rd, Register rs, Register rt); 1077 1078 // Bit twiddling. 1079 BufferOffset as_clz(Register rd, Register rs); 1080 BufferOffset as_dclz(Register rd, Register rs); 1081 BufferOffset as_wsbh(Register rd, Register rt); 1082 BufferOffset as_dsbh(Register rd, Register rt); 1083 BufferOffset as_dshd(Register rd, Register rt); 1084 BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size); 1085 BufferOffset as_dins(Register rt, Register rs, uint16_t pos, uint16_t size); 1086 BufferOffset as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size); 1087 BufferOffset as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size); 1088 BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size); 1089 BufferOffset as_dext(Register rt, Register rs, uint16_t pos, uint16_t size); 1090 BufferOffset as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size); 1091 BufferOffset as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size); 1092 1093 // Sign extend 1094 BufferOffset as_seb(Register rd, Register rt); 1095 BufferOffset as_seh(Register rd, Register rt); 1096 1097 // FP instructions 1098 1099 BufferOffset as_ldc1(FloatRegister ft, Register base, int32_t off); 1100 BufferOffset as_sdc1(FloatRegister ft, Register base, int32_t off); 1101 1102 BufferOffset as_lwc1(FloatRegister ft, Register base, int32_t off); 1103 BufferOffset as_swc1(FloatRegister ft, Register base, int32_t off); 1104 1105 // Loongson-specific FP load and store instructions 1106 BufferOffset as_gsldl(FloatRegister fd, Register base, int32_t off); 1107 BufferOffset as_gsldr(FloatRegister fd, Register base, int32_t off); 1108 BufferOffset as_gssdl(FloatRegister fd, Register base, int32_t off); 1109 BufferOffset as_gssdr(FloatRegister fd, Register base, int32_t off); 1110 BufferOffset as_gslsl(FloatRegister fd, Register base, int32_t off); 1111 BufferOffset as_gslsr(FloatRegister fd, Register base, int32_t off); 1112 BufferOffset as_gsssl(FloatRegister fd, Register base, int32_t off); 1113 BufferOffset as_gsssr(FloatRegister fd, Register base, int32_t off); 1114 BufferOffset as_gslsx(FloatRegister fd, Register rs, Register ri, 1115 int16_t off); 1116 BufferOffset as_gsssx(FloatRegister fd, Register rs, Register ri, 1117 int16_t off); 1118 BufferOffset as_gsldx(FloatRegister fd, Register rs, Register ri, 1119 int16_t off); 1120 BufferOffset as_gssdx(FloatRegister fd, Register rs, Register ri, 1121 int16_t off); 1122 BufferOffset as_gslq(FloatRegister rh, FloatRegister rl, Register rs, 1123 int16_t off); 1124 BufferOffset as_gssq(FloatRegister rh, FloatRegister rl, Register rs, 1125 int16_t off); 1126 1127 BufferOffset as_movs(FloatRegister fd, FloatRegister fs); 1128 BufferOffset as_movd(FloatRegister fd, FloatRegister fs); 1129 1130 BufferOffset as_ctc1(Register rt, FPControl fc); 1131 BufferOffset as_cfc1(Register rt, FPControl fc); 1132 1133 BufferOffset as_mtc1(Register rt, FloatRegister fs); 1134 BufferOffset as_mfc1(Register rt, FloatRegister fs); 1135 1136 BufferOffset as_mthc1(Register rt, FloatRegister fs); 1137 BufferOffset as_mfhc1(Register rt, FloatRegister fs); 1138 BufferOffset as_dmtc1(Register rt, FloatRegister fs); 1139 BufferOffset as_dmfc1(Register rt, FloatRegister fs); 1140 1141 public: 1142 // FP convert instructions 1143 BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs); 1144 BufferOffset as_ceills(FloatRegister fd, FloatRegister fs); 1145 BufferOffset as_floorws(FloatRegister fd, FloatRegister fs); 1146 BufferOffset as_floorls(FloatRegister fd, FloatRegister fs); 1147 BufferOffset as_roundws(FloatRegister fd, FloatRegister fs); 1148 BufferOffset as_roundls(FloatRegister fd, FloatRegister fs); 1149 BufferOffset as_truncws(FloatRegister fd, FloatRegister fs); 1150 BufferOffset as_truncls(FloatRegister fd, FloatRegister fs); 1151 1152 BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fs); 1153 BufferOffset as_ceilld(FloatRegister fd, FloatRegister fs); 1154 BufferOffset as_floorwd(FloatRegister fd, FloatRegister fs); 1155 BufferOffset as_floorld(FloatRegister fd, FloatRegister fs); 1156 BufferOffset as_roundwd(FloatRegister fd, FloatRegister fs); 1157 BufferOffset as_roundld(FloatRegister fd, FloatRegister fs); 1158 BufferOffset as_truncwd(FloatRegister fd, FloatRegister fs); 1159 BufferOffset as_truncld(FloatRegister fd, FloatRegister fs); 1160 1161 BufferOffset as_cvtdl(FloatRegister fd, FloatRegister fs); 1162 BufferOffset as_cvtds(FloatRegister fd, FloatRegister fs); 1163 BufferOffset as_cvtdw(FloatRegister fd, FloatRegister fs); 1164 BufferOffset as_cvtld(FloatRegister fd, FloatRegister fs); 1165 BufferOffset as_cvtls(FloatRegister fd, FloatRegister fs); 1166 BufferOffset as_cvtsd(FloatRegister fd, FloatRegister fs); 1167 BufferOffset as_cvtsl(FloatRegister fd, FloatRegister fs); 1168 BufferOffset as_cvtsw(FloatRegister fd, FloatRegister fs); 1169 BufferOffset as_cvtwd(FloatRegister fd, FloatRegister fs); 1170 BufferOffset as_cvtws(FloatRegister fd, FloatRegister fs); 1171 1172 // FP arithmetic instructions 1173 BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft); 1174 BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft); 1175 BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft); 1176 BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft); 1177 1178 BufferOffset as_abss(FloatRegister fd, FloatRegister fs); 1179 BufferOffset as_absd(FloatRegister fd, FloatRegister fs); 1180 BufferOffset as_negs(FloatRegister fd, FloatRegister fs); 1181 BufferOffset as_negd(FloatRegister fd, FloatRegister fs); 1182 1183 BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft); 1184 BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft); 1185 BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft); 1186 BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft); 1187 BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs); 1188 BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs); 1189 1190 BufferOffset as_max(FloatFormat fmt, FloatRegister fd, FloatRegister fs, 1191 FloatRegister ft); 1192 BufferOffset as_min(FloatFormat fmt, FloatRegister fd, FloatRegister fs, 1193 FloatRegister ft); 1194 1195 // FP compare instructions 1196 BufferOffset as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, 1197 FPConditionBit fcc = FCC0); 1198 BufferOffset as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, 1199 FPConditionBit fcc = FCC0); 1200 BufferOffset as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, 1201 FPConditionBit fcc = FCC0); 1202 BufferOffset as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, 1203 FPConditionBit fcc = FCC0); 1204 BufferOffset as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, 1205 FPConditionBit fcc = FCC0); 1206 BufferOffset as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, 1207 FPConditionBit fcc = FCC0); 1208 BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, 1209 FPConditionBit fcc = FCC0); 1210 BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, 1211 FPConditionBit fcc = FCC0); 1212 1213 // FP conditional move. 1214 BufferOffset as_movt(FloatFormat fmt, FloatRegister fd, FloatRegister fs, 1215 FPConditionBit fcc = FCC0); 1216 BufferOffset as_movf(FloatFormat fmt, FloatRegister fd, FloatRegister fs, 1217 FPConditionBit fcc = FCC0); 1218 BufferOffset as_movz(FloatFormat fmt, FloatRegister fd, FloatRegister fs, 1219 Register rt); 1220 BufferOffset as_movn(FloatFormat fmt, FloatRegister fd, FloatRegister fs, 1221 Register rt); 1222 1223 // Conditional trap operations 1224 BufferOffset as_tge(Register rs, Register rt, uint32_t code = 0); 1225 BufferOffset as_tgeu(Register rs, Register rt, uint32_t code = 0); 1226 BufferOffset as_tlt(Register rs, Register rt, uint32_t code = 0); 1227 BufferOffset as_tltu(Register rs, Register rt, uint32_t code = 0); 1228 BufferOffset as_teq(Register rs, Register rt, uint32_t code = 0); 1229 BufferOffset as_tne(Register rs, Register rt, uint32_t code = 0); 1230 1231 // label operations 1232 void bind(Label* label, BufferOffset boff = BufferOffset()); 1233 virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0; 1234 void bind(CodeLabel* label) { label->target()->bind(currentOffset()); } 1235 uint32_t currentOffset() { return nextOffset().getOffset(); } 1236 void retarget(Label* label, Label* target); 1237 1238 void call(Label* label); 1239 void call(void* target); 1240 1241 void as_break(uint32_t code); 1242 void as_sync(uint32_t stype = 0); 1243 1244 public: 1245 static bool SupportsFloatingPoint() { 1246 #if (defined(__mips_hard_float) && !defined(__mips_single_float)) || \ 1247 defined(JS_SIMULATOR_MIPS64) 1248 return true; 1249 #else 1250 return false; 1251 #endif 1252 } 1253 static bool SupportsUnalignedAccesses() { return true; } 1254 static bool SupportsFastUnalignedFPAccesses() { return false; } 1255 static bool SupportsFloat64To16() { return false; } 1256 static bool SupportsFloat32To16() { return false; } 1257 1258 static bool HasRoundInstruction(RoundingMode mode) { return false; } 1259 1260 protected: 1261 InstImm invertBranch(InstImm branch, BOffImm16 skipOffset); 1262 void addPendingJump(BufferOffset src, ImmPtr target, RelocationKind kind) { 1263 enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); 1264 if (kind == RelocationKind::JITCODE) { 1265 jumpRelocations_.writeUnsigned(src.getOffset()); 1266 } 1267 } 1268 1269 void addLongJump(BufferOffset src, BufferOffset dst) { 1270 CodeLabel cl; 1271 cl.patchAt()->bind(src.getOffset()); 1272 cl.target()->bind(dst.getOffset()); 1273 cl.setLinkMode(CodeLabel::JumpImmediate); 1274 addCodeLabel(std::move(cl)); 1275 } 1276 1277 public: 1278 void flushBuffer() {} 1279 1280 void comment(const char* msg) { spew("; %s", msg); } 1281 1282 static uint32_t NopSize() { return 4; } 1283 1284 static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm); 1285 1286 static uint32_t AlignDoubleArg(uint32_t offset) { 1287 return (offset + 1U) & ~1U; 1288 } 1289 1290 static uint8_t* NextInstruction(uint8_t* instruction, 1291 uint32_t* count = nullptr); 1292 1293 static void ToggleToJmp(CodeLocationLabel inst_); 1294 static void ToggleToCmp(CodeLocationLabel inst_); 1295 1296 static void UpdateLuiOriValue(Instruction* inst0, Instruction* inst1, 1297 uint32_t value); 1298 1299 void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, 1300 const Disassembler::HeapAccess& heapAccess) { 1301 // Implement this if we implement a disassembler. 1302 } 1303 1304 private: 1305 GeneralRegisterSet scratch_register_list_; 1306 1307 public: 1308 GeneralRegisterSet* GetScratchRegisterList() { 1309 return &scratch_register_list_; 1310 } 1311 }; // AssemblerMIPSShared 1312 1313 // sll zero, zero, 0 1314 const uint32_t NopInst = 0x00000000; 1315 1316 // An Instruction is a structure for both encoding and decoding any and all 1317 // MIPS instructions. 1318 class Instruction { 1319 protected: 1320 uint32_t data; 1321 1322 // Standard constructor 1323 explicit Instruction(uint32_t data_) : data(data_) {} 1324 1325 // You should never create an instruction directly. You should create a 1326 // more specific instruction which will eventually call one of these 1327 // constructors for you. 1328 public: 1329 uint32_t encode() const { return data; } 1330 1331 void makeNop() { data = NopInst; } 1332 1333 void setData(uint32_t data) { this->data = data; } 1334 1335 const Instruction& operator=(const Instruction& src) { 1336 data = src.data; 1337 return *this; 1338 } 1339 1340 // Extract the one particular bit. 1341 uint32_t extractBit(uint32_t bit) { return (encode() >> bit) & 1; } 1342 // Extract a bit field out of the instruction 1343 uint32_t extractBitField(uint32_t hi, uint32_t lo) { 1344 return (encode() >> lo) & ((2 << (hi - lo)) - 1); 1345 } 1346 // Since all MIPS instructions have opcode, the opcode 1347 // extractor resides in the base class. 1348 uint32_t extractOpcode() { 1349 return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); 1350 } 1351 // Return the fields at their original place in the instruction encoding. 1352 OpcodeField OpcodeFieldRaw() const { 1353 return static_cast<OpcodeField>(encode() & OpcodeMask); 1354 } 1355 1356 // Get the next instruction in the instruction stream. 1357 // This does neat things like ignoreconstant pools and their guards. 1358 Instruction* next(); 1359 1360 // Sometimes, an api wants a uint32_t (or a pointer to it) rather than 1361 // an instruction. raw() just coerces this into a pointer to a uint32_t 1362 const uint32_t* raw() const { return &data; } 1363 uint32_t size() const { return 4; } 1364 }; // Instruction 1365 1366 // make sure that it is the right size 1367 static_assert(sizeof(Instruction) == 4, 1368 "Size of Instruction class has to be 4 bytes."); 1369 1370 class InstNOP : public Instruction { 1371 public: 1372 InstNOP() : Instruction(NopInst) {} 1373 }; 1374 1375 // Class for register type instructions. 1376 class InstReg : public Instruction { 1377 public: 1378 InstReg(OpcodeField op, Register rd, FunctionField ff) 1379 : Instruction(static_cast<uint32_t>(op) | RD(rd) | 1380 static_cast<uint32_t>(ff)) {} 1381 InstReg(OpcodeField op, Register rs, Register rt, FunctionField ff) 1382 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | 1383 static_cast<uint32_t>(ff)) {} 1384 InstReg(OpcodeField op, Register rs, Register rt, Register rd, 1385 FunctionField ff) 1386 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RD(rd) | 1387 static_cast<uint32_t>(ff)) {} 1388 InstReg(OpcodeField op, Register rs, Register rt, Register rd, uint32_t sa, 1389 FunctionField ff) 1390 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RD(rd) | 1391 SA(sa) | static_cast<uint32_t>(ff)) {} 1392 InstReg(OpcodeField op, RSField rs, Register rt, Register rd, uint32_t sa, 1393 FunctionField ff) 1394 : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | 1395 RT(rt) | RD(rd) | SA(sa) | static_cast<uint32_t>(ff)) {} 1396 InstReg(OpcodeField op, Register rs, RTField rt, Register rd, uint32_t sa, 1397 FunctionField ff) 1398 : Instruction(static_cast<uint32_t>(op) | RS(rs) | 1399 static_cast<uint32_t>(rt) | RD(rd) | SA(sa) | 1400 static_cast<uint32_t>(ff)) {} 1401 InstReg(OpcodeField op, Register rs, uint32_t cc, Register rd, uint32_t sa, 1402 FunctionField ff) 1403 : Instruction(static_cast<uint32_t>(op) | RS(rs) | cc | RD(rd) | SA(sa) | 1404 static_cast<uint32_t>(ff)) {} 1405 InstReg(OpcodeField op, uint32_t code, FunctionField ff) 1406 : Instruction(static_cast<uint32_t>(op) | code | 1407 static_cast<uint32_t>(ff)) {} 1408 // for float point 1409 InstReg(OpcodeField op, RSField rs, Register rt, uint32_t fs) 1410 : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | 1411 RT(rt) | FS(fs)) {} 1412 InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister rd) 1413 : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | 1414 RT(rt) | RD(rd)) {} 1415 InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister rd, 1416 uint32_t sa, FunctionField ff) 1417 : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | 1418 RT(rt) | RD(rd) | SA(sa) | static_cast<uint32_t>(ff)) {} 1419 InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister fs, 1420 FloatRegister fd, FunctionField ff) 1421 : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | 1422 RT(rt) | RD(fs) | SA(fd) | static_cast<uint32_t>(ff)) {} 1423 InstReg(OpcodeField op, RSField rs, FloatRegister ft, FloatRegister fs, 1424 FloatRegister fd, FunctionField ff) 1425 : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | 1426 RT(ft) | RD(fs) | SA(fd) | static_cast<uint32_t>(ff)) {} 1427 InstReg(OpcodeField op, RSField rs, FloatRegister ft, FloatRegister fd, 1428 uint32_t sa, FunctionField ff) 1429 : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | 1430 RT(ft) | RD(fd) | SA(sa) | static_cast<uint32_t>(ff)) {} 1431 1432 uint32_t extractRS() { 1433 return extractBitField(RSShift + RSBits - 1, RSShift); 1434 } 1435 uint32_t extractRT() { 1436 return extractBitField(RTShift + RTBits - 1, RTShift); 1437 } 1438 uint32_t extractRD() { 1439 return extractBitField(RDShift + RDBits - 1, RDShift); 1440 } 1441 uint32_t extractSA() { 1442 return extractBitField(SAShift + SABits - 1, SAShift); 1443 } 1444 uint32_t extractFunctionField() { 1445 return extractBitField(FunctionShift + FunctionBits - 1, FunctionShift); 1446 } 1447 }; 1448 1449 // Class for branch, load and store instructions with immediate offset. 1450 class InstImm : public Instruction { 1451 public: 1452 void extractImm16(BOffImm16* dest); 1453 1454 InstImm(OpcodeField op, Register rs, Register rt, BOffImm16 off) 1455 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | 1456 off.encode()) {} 1457 InstImm(OpcodeField op, Register rs, RTField rt, BOffImm16 off) 1458 : Instruction(static_cast<uint32_t>(op) | RS(rs) | 1459 static_cast<uint32_t>(rt) | off.encode()) {} 1460 InstImm(OpcodeField op, RSField rs, uint32_t cc, BOffImm16 off) 1461 : Instruction(static_cast<uint32_t>(op) | static_cast<uint32_t>(rs) | cc | 1462 off.encode()) {} 1463 InstImm(OpcodeField op, Register rs, Register rt, Imm16 off) 1464 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | 1465 off.encode()) {} 1466 MOZ_IMPLICIT InstImm(uint32_t raw) : Instruction(raw) {} 1467 // For floating-point loads and stores. 1468 InstImm(OpcodeField op, Register rs, FloatRegister rt, Imm16 off) 1469 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | 1470 off.encode()) {} 1471 1472 uint32_t extractOpcode() { 1473 return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); 1474 } 1475 void setOpcode(OpcodeField op) { data = (data & ~OpcodeMask) | op; } 1476 uint32_t extractRS() { 1477 return extractBitField(RSShift + RSBits - 1, RSShift); 1478 } 1479 uint32_t extractRT() { 1480 return extractBitField(RTShift + RTBits - 1, RTShift); 1481 } 1482 void setRT(RTField rt) { data = (data & ~RTMask) | rt; } 1483 uint32_t extractImm16Value() { 1484 return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift); 1485 } 1486 void setBOffImm16(BOffImm16 off) { 1487 // Reset immediate field and replace it 1488 data = (data & ~Imm16Mask) | off.encode(); 1489 } 1490 void setImm16(Imm16 off) { 1491 // Reset immediate field and replace it 1492 data = (data & ~Imm16Mask) | off.encode(); 1493 } 1494 }; 1495 1496 // Class for Jump type instructions. 1497 class InstJump : public Instruction { 1498 public: 1499 InstJump(OpcodeField op, JOffImm26 off) 1500 : Instruction(static_cast<uint32_t>(op) | off.encode()) {} 1501 1502 uint32_t extractImm26Value() { 1503 return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift); 1504 } 1505 }; 1506 1507 // Class for Loongson-specific instructions 1508 class InstGS : public Instruction { 1509 public: 1510 // For indexed loads and stores. 1511 InstGS(OpcodeField op, Register rs, Register rt, Register rd, Imm8 off, 1512 FunctionField ff) 1513 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RD(rd) | 1514 off.encode(3) | static_cast<uint32_t>(ff)) {} 1515 InstGS(OpcodeField op, Register rs, FloatRegister rt, Register rd, Imm8 off, 1516 FunctionField ff) 1517 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RD(rd) | 1518 off.encode(3) | static_cast<uint32_t>(ff)) {} 1519 // For quad-word loads and stores. 1520 InstGS(OpcodeField op, Register rs, Register rt, Register rz, GSImm13 off, 1521 FunctionField ff) 1522 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RZ(rz) | 1523 off.encode(6) | static_cast<uint32_t>(ff)) {} 1524 InstGS(OpcodeField op, Register rs, FloatRegister rt, FloatRegister rz, 1525 GSImm13 off, FunctionField ff) 1526 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | RZ(rz) | 1527 off.encode(6) | static_cast<uint32_t>(ff)) {} 1528 explicit InstGS(uint32_t raw) : Instruction(raw) {} 1529 // For floating-point unaligned loads and stores. 1530 InstGS(OpcodeField op, Register rs, FloatRegister rt, Imm8 off, 1531 FunctionField ff) 1532 : Instruction(static_cast<uint32_t>(op) | RS(rs) | RT(rt) | 1533 off.encode(6) | ff) {} 1534 }; 1535 1536 inline bool IsUnaligned(const wasm::MemoryAccessDesc& access) { 1537 if (!access.align()) { 1538 return false; 1539 } 1540 1541 return access.align() < access.byteSize(); 1542 } 1543 1544 } // namespace jit 1545 } // namespace js 1546 1547 #endif /* jit_mips_shared_Assembler_mips_shared_h */