Assembler-loong64.h (70781B)
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_loong64_Assembler_loong64_h 8 #define jit_loong64_Assembler_loong64_h 9 10 #include "mozilla/Sprintf.h" 11 12 #include "jit/CompactBuffer.h" 13 #include "jit/JitCode.h" 14 #include "jit/JitSpewer.h" 15 #include "jit/loong64/Architecture-loong64.h" 16 #include "jit/shared/Assembler-shared.h" 17 #include "jit/shared/Disassembler-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 ra{Registers::ra}; 26 static constexpr Register tp{Registers::tp}; 27 static constexpr Register sp{Registers::sp}; 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 t0{Registers::t0}; 37 static constexpr Register t1{Registers::t1}; 38 static constexpr Register t2{Registers::t2}; 39 static constexpr Register t3{Registers::t3}; 40 static constexpr Register t4{Registers::t4}; 41 static constexpr Register t5{Registers::t5}; 42 static constexpr Register t6{Registers::t6}; 43 static constexpr Register t7{Registers::t7}; 44 static constexpr Register t8{Registers::t8}; 45 static constexpr Register rx{Registers::rx}; 46 static constexpr Register fp{Registers::fp}; 47 static constexpr Register s0{Registers::s0}; 48 static constexpr Register s1{Registers::s1}; 49 static constexpr Register s2{Registers::s2}; 50 static constexpr Register s3{Registers::s3}; 51 static constexpr Register s4{Registers::s4}; 52 static constexpr Register s5{Registers::s5}; 53 static constexpr Register s6{Registers::s6}; 54 static constexpr Register s7{Registers::s7}; 55 static constexpr Register s8{Registers::s8}; 56 57 static constexpr FloatRegister f0{FloatRegisters::f0, FloatRegisters::Double}; 58 static constexpr FloatRegister f1{FloatRegisters::f1, FloatRegisters::Double}; 59 static constexpr FloatRegister f2{FloatRegisters::f2, FloatRegisters::Double}; 60 static constexpr FloatRegister f3{FloatRegisters::f3, FloatRegisters::Double}; 61 static constexpr FloatRegister f4{FloatRegisters::f4, FloatRegisters::Double}; 62 static constexpr FloatRegister f5{FloatRegisters::f5, FloatRegisters::Double}; 63 static constexpr FloatRegister f6{FloatRegisters::f6, FloatRegisters::Double}; 64 static constexpr FloatRegister f7{FloatRegisters::f7, FloatRegisters::Double}; 65 static constexpr FloatRegister f8{FloatRegisters::f8, FloatRegisters::Double}; 66 static constexpr FloatRegister f9{FloatRegisters::f9, FloatRegisters::Double}; 67 static constexpr FloatRegister f10{FloatRegisters::f10, FloatRegisters::Double}; 68 static constexpr FloatRegister f11{FloatRegisters::f11, FloatRegisters::Double}; 69 static constexpr FloatRegister f12{FloatRegisters::f12, FloatRegisters::Double}; 70 static constexpr FloatRegister f13{FloatRegisters::f13, FloatRegisters::Double}; 71 static constexpr FloatRegister f14{FloatRegisters::f14, FloatRegisters::Double}; 72 static constexpr FloatRegister f15{FloatRegisters::f15, FloatRegisters::Double}; 73 static constexpr FloatRegister f16{FloatRegisters::f16, FloatRegisters::Double}; 74 static constexpr FloatRegister f17{FloatRegisters::f17, FloatRegisters::Double}; 75 static constexpr FloatRegister f18{FloatRegisters::f18, FloatRegisters::Double}; 76 static constexpr FloatRegister f19{FloatRegisters::f19, FloatRegisters::Double}; 77 static constexpr FloatRegister f20{FloatRegisters::f20, FloatRegisters::Double}; 78 static constexpr FloatRegister f21{FloatRegisters::f21, FloatRegisters::Double}; 79 static constexpr FloatRegister f22{FloatRegisters::f22, FloatRegisters::Double}; 80 static constexpr FloatRegister f23{FloatRegisters::f23, FloatRegisters::Double}; 81 static constexpr FloatRegister f24{FloatRegisters::f24, FloatRegisters::Double}; 82 static constexpr FloatRegister f25{FloatRegisters::f25, FloatRegisters::Double}; 83 static constexpr FloatRegister f26{FloatRegisters::f26, FloatRegisters::Double}; 84 static constexpr FloatRegister f27{FloatRegisters::f27, FloatRegisters::Double}; 85 static constexpr FloatRegister f28{FloatRegisters::f28, FloatRegisters::Double}; 86 static constexpr FloatRegister f29{FloatRegisters::f29, FloatRegisters::Double}; 87 static constexpr FloatRegister f30{FloatRegisters::f30, FloatRegisters::Double}; 88 static constexpr FloatRegister f31{FloatRegisters::f31, FloatRegisters::Double}; 89 90 static constexpr Register InvalidReg{Registers::Invalid}; 91 static constexpr FloatRegister InvalidFloatReg; 92 93 static constexpr Register StackPointer = sp; 94 static constexpr Register FramePointer = fp; 95 static constexpr Register ReturnReg = a0; 96 static constexpr Register64 ReturnReg64(ReturnReg); 97 static constexpr FloatRegister ReturnFloat32Reg{FloatRegisters::f0, 98 FloatRegisters::Single}; 99 static constexpr FloatRegister ReturnDoubleReg = f0; 100 static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg; 101 102 // Scratch register used for runtime call patching. 103 // See MacroAssembler::patchNopToCall and MacroAssembler::PatchWrite_NearCall. 104 static constexpr Register SavedScratchRegister = s8; 105 106 static constexpr FloatRegister ScratchFloat32Reg{FloatRegisters::f23, 107 FloatRegisters::Single}; 108 static constexpr FloatRegister ScratchDoubleReg = f23; 109 static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg; 110 111 struct ScratchFloat32Scope : public AutoFloatRegisterScope { 112 explicit ScratchFloat32Scope(MacroAssembler& masm) 113 : AutoFloatRegisterScope(masm, ScratchFloat32Reg) {} 114 }; 115 116 struct ScratchDoubleScope : public AutoFloatRegisterScope { 117 explicit ScratchDoubleScope(MacroAssembler& masm) 118 : AutoFloatRegisterScope(masm, ScratchDoubleReg) {} 119 }; 120 121 class Assembler; 122 123 class UseScratchRegisterScope { 124 public: 125 explicit UseScratchRegisterScope(Assembler& assembler); 126 explicit UseScratchRegisterScope(Assembler* assembler); 127 ~UseScratchRegisterScope(); 128 129 Register Acquire(); 130 void Release(const Register& reg); 131 bool hasAvailable() const; 132 void Include(const GeneralRegisterSet& list) { 133 *available_ = GeneralRegisterSet::Union(*available_, list); 134 } 135 void Exclude(const GeneralRegisterSet& list) { 136 *available_ = GeneralRegisterSet::Subtract(*available_, list); 137 } 138 139 private: 140 GeneralRegisterSet* available_; 141 GeneralRegisterSet old_available_; 142 }; 143 144 // Use arg reg from EnterJIT function as OsrFrameReg. 145 static constexpr Register OsrFrameReg = a3; 146 static constexpr Register PreBarrierReg = a1; 147 static constexpr Register InterpreterPCReg = t0; 148 static constexpr Register CallTempReg0 = t0; 149 static constexpr Register CallTempReg1 = t1; 150 static constexpr Register CallTempReg2 = t2; 151 static constexpr Register CallTempReg3 = t3; 152 static constexpr Register CallTempReg4 = t4; 153 static constexpr Register CallTempReg5 = t5; 154 static constexpr Register CallTempNonArgRegs[] = {t0, t1, t2, t3}; 155 static const uint32_t NumCallTempNonArgRegs = std::size(CallTempNonArgRegs); 156 157 static constexpr Register IntArgReg0 = a0; 158 static constexpr Register IntArgReg1 = a1; 159 static constexpr Register IntArgReg2 = a2; 160 static constexpr Register IntArgReg3 = a3; 161 static constexpr Register IntArgReg4 = a4; 162 static constexpr Register IntArgReg5 = a5; 163 static constexpr Register IntArgReg6 = a6; 164 static constexpr Register IntArgReg7 = a7; 165 166 // Registers used by RegExpMatcher and RegExpExecMatch stubs (do not use 167 // JSReturnOperand). 168 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0; 169 static constexpr Register RegExpMatcherStringReg = CallTempReg1; 170 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2; 171 172 // Registers used by RegExpExecTest stub (do not use ReturnReg). 173 static constexpr Register RegExpExecTestRegExpReg = CallTempReg0; 174 static constexpr Register RegExpExecTestStringReg = CallTempReg1; 175 176 // Registers used by RegExpSearcher stub (do not use ReturnReg). 177 static constexpr Register RegExpSearcherRegExpReg = CallTempReg0; 178 static constexpr Register RegExpSearcherStringReg = CallTempReg1; 179 static constexpr Register RegExpSearcherLastIndexReg = CallTempReg2; 180 181 static constexpr Register JSReturnReg_Type = a3; 182 static constexpr Register JSReturnReg_Data = a2; 183 static constexpr Register JSReturnReg = a2; 184 static constexpr ValueOperand JSReturnOperand = ValueOperand(JSReturnReg); 185 186 // See "ABI special registers" in Assembler-shared.h for more information. 187 static constexpr Register ABINonArgReg0 = t0; 188 static constexpr Register ABINonArgReg1 = t1; 189 static constexpr Register ABINonArgReg2 = t2; 190 static constexpr Register ABINonArgReg3 = t3; 191 192 // See "ABI special registers" in Assembler-shared.h for more information. 193 static constexpr Register ABINonArgReturnReg0 = t0; 194 static constexpr Register ABINonArgReturnReg1 = t1; 195 static constexpr Register ABINonVolatileReg = s0; 196 197 // See "ABI special registers" in Assembler-shared.h for more information. 198 static constexpr Register ABINonArgReturnVolatileReg = ra; 199 200 // See "ABI special registers" in Assembler-shared.h for more information. 201 // Avoid f23 which is the scratch register. 202 static constexpr FloatRegister ABINonArgDoubleReg{FloatRegisters::f21, 203 FloatRegisters::Double}; 204 205 // See "ABI special registers" in Assembler-shared.h, and "The WASM ABIs" in 206 // WasmFrame.h for more information. 207 static constexpr Register InstanceReg = s4; 208 static constexpr Register HeapReg = s7; 209 210 // Registers used for wasm table calls. These registers must be disjoint 211 // from the ABI argument registers, InstanceReg and each other. 212 static constexpr Register WasmTableCallScratchReg0 = ABINonArgReg0; 213 static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1; 214 static constexpr Register WasmTableCallSigReg = ABINonArgReg2; 215 static constexpr Register WasmTableCallIndexReg = ABINonArgReg3; 216 217 // Registers used for ref calls. 218 static constexpr Register WasmCallRefCallScratchReg0 = ABINonArgReg0; 219 static constexpr Register WasmCallRefCallScratchReg1 = ABINonArgReg1; 220 static constexpr Register WasmCallRefCallScratchReg2 = ABINonArgReg2; 221 static constexpr Register WasmCallRefReg = ABINonArgReg3; 222 223 // Registers used for wasm tail calls operations. 224 static constexpr Register WasmTailCallInstanceScratchReg = ABINonArgReg1; 225 static constexpr Register WasmTailCallRAScratchReg = ra; 226 static constexpr Register WasmTailCallFPScratchReg = ABINonArgReg3; 227 228 // Register used as a scratch along the return path in the fast js -> wasm stub 229 // code. This must not overlap ReturnReg, JSReturnOperand, or InstanceReg. 230 // It must be a volatile register. 231 static constexpr Register WasmJitEntryReturnScratch = t1; 232 233 static constexpr uint32_t ABIStackAlignment = 16; 234 static constexpr uint32_t CodeAlignment = 16; 235 static constexpr uint32_t JitStackAlignment = 16; 236 237 static constexpr uint32_t JitStackValueAlignment = 238 JitStackAlignment / sizeof(Value); 239 static_assert(JitStackAlignment % sizeof(Value) == 0 && 240 JitStackValueAlignment >= 1, 241 "Stack alignment should be a non-zero multiple of sizeof(Value)"); 242 243 // TODO(loong64): this is just a filler to prevent a build failure. The 244 // LoongArch SIMD alignment requirements still need to be explored. 245 static constexpr uint32_t SimdMemoryAlignment = 16; 246 247 static_assert(CodeAlignment % SimdMemoryAlignment == 0, 248 "Code alignment should be larger than any of the alignments " 249 "which are used for " 250 "the constant sections of the code buffer. Thus it should be " 251 "larger than the " 252 "alignment for SIMD constants."); 253 254 static constexpr uint32_t WasmStackAlignment = SimdMemoryAlignment; 255 static const uint32_t WasmTrapInstructionLength = 4; 256 257 // See comments in wasm::GenerateFunctionPrologue. The difference between these 258 // is the size of the largest callable prologue on the platform. 259 static constexpr uint32_t WasmCheckedCallEntryOffset = 0u; 260 261 static constexpr Scale ScalePointer = TimesEight; 262 263 // TODO(loong64): Add LoongArch instruction types description. 264 265 // LoongArch instruction encoding constants. 266 static const uint32_t RJShift = 5; 267 static const uint32_t RJBits = 5; 268 static const uint32_t RKShift = 10; 269 static const uint32_t RKBits = 5; 270 static const uint32_t RDShift = 0; 271 static const uint32_t RDBits = 5; 272 static const uint32_t FJShift = 5; 273 static const uint32_t FJBits = 5; 274 static const uint32_t FKShift = 10; 275 static const uint32_t FKBits = 5; 276 static const uint32_t FDShift = 0; 277 static const uint32_t FDBits = 5; 278 static const uint32_t FAShift = 15; 279 static const uint32_t FABits = 5; 280 static const uint32_t CJShift = 5; 281 static const uint32_t CJBits = 3; 282 static const uint32_t CDShift = 0; 283 static const uint32_t CDBits = 3; 284 static const uint32_t CAShift = 15; 285 static const uint32_t CABits = 3; 286 static const uint32_t CONDShift = 15; 287 static const uint32_t CONDBits = 5; 288 289 static const uint32_t SAShift = 15; 290 static const uint32_t SA2Bits = 2; 291 static const uint32_t SA3Bits = 3; 292 static const uint32_t LSBWShift = 10; 293 static const uint32_t LSBWBits = 5; 294 static const uint32_t LSBDShift = 10; 295 static const uint32_t LSBDBits = 6; 296 static const uint32_t MSBWShift = 16; 297 static const uint32_t MSBWBits = 5; 298 static const uint32_t MSBDShift = 16; 299 static const uint32_t MSBDBits = 6; 300 static const uint32_t Imm5Shift = 10; 301 static const uint32_t Imm5Bits = 5; 302 static const uint32_t Imm6Shift = 10; 303 static const uint32_t Imm6Bits = 6; 304 static const uint32_t Imm12Shift = 10; 305 static const uint32_t Imm12Bits = 12; 306 static const uint32_t Imm14Shift = 10; 307 static const uint32_t Imm14Bits = 14; 308 static const uint32_t Imm15Shift = 0; 309 static const uint32_t Imm15Bits = 15; 310 static const uint32_t Imm16Shift = 10; 311 static const uint32_t Imm16Bits = 16; 312 static const uint32_t Imm20Shift = 5; 313 static const uint32_t Imm20Bits = 20; 314 static const uint32_t Imm21Shift = 0; 315 static const uint32_t Imm21Bits = 21; 316 static const uint32_t Imm26Shift = 0; 317 static const uint32_t Imm26Bits = 26; 318 static const uint32_t CODEShift = 0; 319 static const uint32_t CODEBits = 15; 320 static const uint32_t HINTBits = 5; 321 322 // LoongArch instruction field bit masks. 323 static const uint32_t RJMask = (1 << RJBits) - 1; 324 static const uint32_t RKMask = (1 << RKBits) - 1; 325 static const uint32_t RDMask = (1 << RDBits) - 1; 326 static const uint32_t SA2Mask = (1 << SA2Bits) - 1; 327 static const uint32_t SA3Mask = (1 << SA3Bits) - 1; 328 static const uint32_t CDMask = (1 << CDBits) - 1; 329 static const uint32_t CONDMask = (1 << CONDBits) - 1; 330 static const uint32_t HINTMask = (1 << HINTBits) - 1; 331 static const uint32_t LSBWMask = (1 << LSBWBits) - 1; 332 static const uint32_t LSBDMask = (1 << LSBDBits) - 1; 333 static const uint32_t MSBWMask = (1 << MSBWBits) - 1; 334 static const uint32_t MSBDMask = (1 << MSBDBits) - 1; 335 static const uint32_t CODEMask = (1 << CODEBits) - 1; 336 static const uint32_t Imm5Mask = (1 << Imm5Bits) - 1; 337 static const uint32_t Imm6Mask = (1 << Imm6Bits) - 1; 338 static const uint32_t Imm12Mask = (1 << Imm12Bits) - 1; 339 static const uint32_t Imm14Mask = (1 << Imm14Bits) - 1; 340 static const uint32_t Imm15Mask = (1 << Imm15Bits) - 1; 341 static const uint32_t Imm16Mask = (1 << Imm16Bits) - 1; 342 static const uint32_t Imm20Mask = (1 << Imm20Bits) - 1; 343 static const uint32_t Imm21Mask = (1 << Imm21Bits) - 1; 344 static const uint32_t Imm26Mask = (1 << Imm26Bits) - 1; 345 static const uint32_t BOffImm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift; 346 static const uint32_t BOffImm21Mask = ((1 << Imm21Bits) - 1) << Imm21Shift; 347 static const uint32_t BOffImm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift; 348 static const uint32_t RegMask = Registers::Total - 1; 349 350 // TODO(loong64) Change to syscall? 351 static const uint32_t MAX_BREAK_CODE = 1024 - 1; 352 static const uint32_t WASM_TRAP = 6; // BRK_OVERFLOW 353 354 // TODO(loong64) Change to LoongArch instruction type. 355 class Instruction; 356 class InstReg; 357 class InstImm; 358 class InstJump; 359 360 uint32_t RJ(Register r); 361 uint32_t RK(Register r); 362 uint32_t RD(Register r); 363 uint32_t FJ(FloatRegister r); 364 uint32_t FK(FloatRegister r); 365 uint32_t FD(FloatRegister r); 366 uint32_t FA(FloatRegister r); 367 uint32_t SA2(uint32_t value); 368 uint32_t SA2(FloatRegister r); 369 uint32_t SA3(uint32_t value); 370 uint32_t SA3(FloatRegister r); 371 372 Register toRK(Instruction& i); 373 Register toRJ(Instruction& i); 374 Register toRD(Instruction& i); 375 Register toR(Instruction& i); 376 377 // LoongArch enums for instruction fields 378 enum OpcodeField { 379 op_beqz = 0x10U << 26, 380 op_bnez = 0x11U << 26, 381 op_bcz = 0x12U << 26, // bceqz & bcnez 382 op_jirl = 0x13U << 26, 383 op_b = 0x14U << 26, 384 op_bl = 0x15U << 26, 385 op_beq = 0x16U << 26, 386 op_bne = 0x17U << 26, 387 op_blt = 0x18U << 26, 388 op_bge = 0x19U << 26, 389 op_bltu = 0x1aU << 26, 390 op_bgeu = 0x1bU << 26, 391 392 op_addu16i_d = 0x4U << 26, 393 394 op_lu12i_w = 0xaU << 25, 395 op_lu32i_d = 0xbU << 25, 396 op_pcaddi = 0xcU << 25, 397 op_pcalau12i = 0xdU << 25, 398 op_pcaddu12i = 0xeU << 25, 399 op_pcaddu18i = 0xfU << 25, 400 op_ll_w = 0x20U << 24, 401 op_sc_w = 0x21U << 24, 402 op_ll_d = 0x22U << 24, 403 op_sc_d = 0x23U << 24, 404 op_ldptr_w = 0x24U << 24, 405 op_stptr_w = 0x25U << 24, 406 op_ldptr_d = 0x26U << 24, 407 op_stptr_d = 0x27U << 24, 408 op_bstrins_d = 0x2U << 22, 409 op_bstrpick_d = 0x3U << 22, 410 op_slti = 0x8U << 22, 411 op_sltui = 0x9U << 22, 412 op_addi_w = 0xaU << 22, 413 op_addi_d = 0xbU << 22, 414 op_lu52i_d = 0xcU << 22, 415 op_andi = 0xdU << 22, 416 op_ori = 0xeU << 22, 417 op_xori = 0xfU << 22, 418 op_ld_b = 0xa0U << 22, 419 op_ld_h = 0xa1U << 22, 420 op_ld_w = 0xa2U << 22, 421 op_ld_d = 0xa3U << 22, 422 op_st_b = 0xa4U << 22, 423 op_st_h = 0xa5U << 22, 424 op_st_w = 0xa6U << 22, 425 op_st_d = 0xa7U << 22, 426 op_ld_bu = 0xa8U << 22, 427 op_ld_hu = 0xa9U << 22, 428 op_ld_wu = 0xaaU << 22, 429 op_preld = 0xabU << 22, 430 op_fld_s = 0xacU << 22, 431 op_fst_s = 0xadU << 22, 432 op_fld_d = 0xaeU << 22, 433 op_fst_d = 0xafU << 22, 434 op_bstr_w = 0x3U << 21, // BSTRINS_W & BSTRPICK_W 435 op_fmadd_s = 0x81U << 20, 436 op_fmadd_d = 0x82U << 20, 437 op_fmsub_s = 0x85U << 20, 438 op_fmsub_d = 0x86U << 20, 439 op_fnmadd_s = 0x89U << 20, 440 op_fnmadd_d = 0x8aU << 20, 441 op_fnmsub_s = 0x8dU << 20, 442 op_fnmsub_d = 0x8eU << 20, 443 op_fcmp_cond_s = 0xc1U << 20, 444 op_fcmp_cond_d = 0xc2U << 20, 445 446 op_bytepick_d = 0x3U << 18, 447 op_fsel = 0x340U << 18, 448 449 op_bytepick_w = 0x4U << 17, 450 op_alsl_w = 0x2U << 17, 451 op_alsl_wu = 0x3U << 17, 452 op_alsl_d = 0x16U << 17, 453 454 op_slli_d = 0x41U << 16, 455 op_srli_d = 0x45U << 16, 456 op_srai_d = 0x49U << 16, 457 458 op_slli_w = 0x81U << 15, 459 op_srli_w = 0x89U << 15, 460 op_srai_w = 0x91U << 15, 461 op_add_w = 0x20U << 15, 462 op_add_d = 0x21U << 15, 463 op_sub_w = 0x22U << 15, 464 op_sub_d = 0x23U << 15, 465 op_slt = 0x24U << 15, 466 op_sltu = 0x25U << 15, 467 op_maskeqz = 0x26U << 15, 468 op_masknez = 0x27U << 15, 469 op_nor = 0x28U << 15, 470 op_and = 0x29U << 15, 471 op_or = 0x2aU << 15, 472 op_xor = 0x2bU << 15, 473 op_orn = 0x2cU << 15, 474 op_andn = 0x2dU << 15, 475 op_sll_w = 0x2eU << 15, 476 op_srl_w = 0x2fU << 15, 477 op_sra_w = 0x30U << 15, 478 op_sll_d = 0x31U << 15, 479 op_srl_d = 0x32U << 15, 480 op_sra_d = 0x33U << 15, 481 op_rotr_w = 0x36U << 15, 482 op_rotr_d = 0x37U << 15, 483 op_rotri_w = 0x99U << 15, 484 op_rotri_d = 0x4DU << 16, 485 op_mul_w = 0x38U << 15, 486 op_mulh_w = 0x39U << 15, 487 op_mulh_wu = 0x3aU << 15, 488 op_mul_d = 0x3bU << 15, 489 op_mulh_d = 0x3cU << 15, 490 op_mulh_du = 0x3dU << 15, 491 op_mulw_d_w = 0x3eU << 15, 492 op_mulw_d_wu = 0x3fU << 15, 493 op_div_w = 0x40U << 15, 494 op_mod_w = 0x41U << 15, 495 op_div_wu = 0x42U << 15, 496 op_mod_wu = 0x43U << 15, 497 op_div_d = 0x44U << 15, 498 op_mod_d = 0x45U << 15, 499 op_div_du = 0x46U << 15, 500 op_mod_du = 0x47U << 15, 501 op_break = 0x54U << 15, 502 op_syscall = 0x56U << 15, 503 op_fadd_s = 0x201U << 15, 504 op_fadd_d = 0x202U << 15, 505 op_fsub_s = 0x205U << 15, 506 op_fsub_d = 0x206U << 15, 507 op_fmul_s = 0x209U << 15, 508 op_fmul_d = 0x20aU << 15, 509 op_fdiv_s = 0x20dU << 15, 510 op_fdiv_d = 0x20eU << 15, 511 op_fmax_s = 0x211U << 15, 512 op_fmax_d = 0x212U << 15, 513 op_fmin_s = 0x215U << 15, 514 op_fmin_d = 0x216U << 15, 515 op_fmaxa_s = 0x219U << 15, 516 op_fmaxa_d = 0x21aU << 15, 517 op_fmina_s = 0x21dU << 15, 518 op_fmina_d = 0x21eU << 15, 519 op_fcopysign_s = 0x225U << 15, 520 op_fcopysign_d = 0x226U << 15, 521 op_ldx_b = 0x7000U << 15, 522 op_ldx_h = 0x7008U << 15, 523 op_ldx_w = 0x7010U << 15, 524 op_ldx_d = 0x7018U << 15, 525 op_stx_b = 0x7020U << 15, 526 op_stx_h = 0x7028U << 15, 527 op_stx_w = 0x7030U << 15, 528 op_stx_d = 0x7038U << 15, 529 op_ldx_bu = 0x7040U << 15, 530 op_ldx_hu = 0x7048U << 15, 531 op_ldx_wu = 0x7050U << 15, 532 op_fldx_s = 0x7060U << 15, 533 op_fldx_d = 0x7068U << 15, 534 op_fstx_s = 0x7070U << 15, 535 op_fstx_d = 0x7078U << 15, 536 op_amswap_w = 0x70c0U << 15, 537 op_amswap_d = 0x70c1U << 15, 538 op_amadd_w = 0x70c2U << 15, 539 op_amadd_d = 0x70c3U << 15, 540 op_amand_w = 0x70c4U << 15, 541 op_amand_d = 0x70c5U << 15, 542 op_amor_w = 0x70c6U << 15, 543 op_amor_d = 0x70c7U << 15, 544 op_amxor_w = 0x70c8U << 15, 545 op_amxor_d = 0x70c9U << 15, 546 op_ammax_w = 0x70caU << 15, 547 op_ammax_d = 0x70cbU << 15, 548 op_ammin_w = 0x70ccU << 15, 549 op_ammin_d = 0x70cdU << 15, 550 op_ammax_wu = 0x70ceU << 15, 551 op_ammax_du = 0x70cfU << 15, 552 op_ammin_wu = 0x70d0U << 15, 553 op_ammin_du = 0x70d1U << 15, 554 op_amswap_db_w = 0x70d2U << 15, 555 op_amswap_db_d = 0x70d3U << 15, 556 op_amadd_db_w = 0x70d4U << 15, 557 op_amadd_db_d = 0x70d5U << 15, 558 op_amand_db_w = 0x70d6U << 15, 559 op_amand_db_d = 0x70d7U << 15, 560 op_amor_db_w = 0x70d8U << 15, 561 op_amor_db_d = 0x70d9U << 15, 562 op_amxor_db_w = 0x70daU << 15, 563 op_amxor_db_d = 0x70dbU << 15, 564 op_ammax_db_w = 0x70dcU << 15, 565 op_ammax_db_d = 0x70ddU << 15, 566 op_ammin_db_w = 0x70deU << 15, 567 op_ammin_db_d = 0x70dfU << 15, 568 op_ammax_db_wu = 0x70e0U << 15, 569 op_ammax_db_du = 0x70e1U << 15, 570 op_ammin_db_wu = 0x70e2U << 15, 571 op_ammin_db_du = 0x70e3U << 15, 572 op_dbar = 0x70e4U << 15, 573 op_ibar = 0x70e5U << 15, 574 op_clo_w = 0x4U << 10, 575 op_clz_w = 0x5U << 10, 576 op_cto_w = 0x6U << 10, 577 op_ctz_w = 0x7U << 10, 578 op_clo_d = 0x8U << 10, 579 op_clz_d = 0x9U << 10, 580 op_cto_d = 0xaU << 10, 581 op_ctz_d = 0xbU << 10, 582 op_revb_2h = 0xcU << 10, 583 op_revb_4h = 0xdU << 10, 584 op_revb_2w = 0xeU << 10, 585 op_revb_d = 0xfU << 10, 586 op_revh_2w = 0x10U << 10, 587 op_revh_d = 0x11U << 10, 588 op_bitrev_4b = 0x12U << 10, 589 op_bitrev_8b = 0x13U << 10, 590 op_bitrev_w = 0x14U << 10, 591 op_bitrev_d = 0x15U << 10, 592 op_ext_w_h = 0x16U << 10, 593 op_ext_w_b = 0x17U << 10, 594 op_fabs_s = 0x4501U << 10, 595 op_fabs_d = 0x4502U << 10, 596 op_fneg_s = 0x4505U << 10, 597 op_fneg_d = 0x4506U << 10, 598 op_fsqrt_s = 0x4511U << 10, 599 op_fsqrt_d = 0x4512U << 10, 600 op_fmov_s = 0x4525U << 10, 601 op_fmov_d = 0x4526U << 10, 602 op_movgr2fr_w = 0x4529U << 10, 603 op_movgr2fr_d = 0x452aU << 10, 604 op_movgr2frh_w = 0x452bU << 10, 605 op_movfr2gr_s = 0x452dU << 10, 606 op_movfr2gr_d = 0x452eU << 10, 607 op_movfrh2gr_s = 0x452fU << 10, 608 op_movgr2fcsr = 0x4530U << 10, 609 op_movfcsr2gr = 0x4532U << 10, 610 op_movfr2cf = 0x4534U << 10, 611 op_movgr2cf = 0x4536U << 10, 612 op_fcvt_s_d = 0x4646U << 10, 613 op_fcvt_d_s = 0x4649U << 10, 614 op_ftintrm_w_s = 0x4681U << 10, 615 op_ftintrm_w_d = 0x4682U << 10, 616 op_ftintrm_l_s = 0x4689U << 10, 617 op_ftintrm_l_d = 0x468aU << 10, 618 op_ftintrp_w_s = 0x4691U << 10, 619 op_ftintrp_w_d = 0x4692U << 10, 620 op_ftintrp_l_s = 0x4699U << 10, 621 op_ftintrp_l_d = 0x469aU << 10, 622 op_ftintrz_w_s = 0x46a1U << 10, 623 op_ftintrz_w_d = 0x46a2U << 10, 624 op_ftintrz_l_s = 0x46a9U << 10, 625 op_ftintrz_l_d = 0x46aaU << 10, 626 op_ftintrne_w_s = 0x46b1U << 10, 627 op_ftintrne_w_d = 0x46b2U << 10, 628 op_ftintrne_l_s = 0x46b9U << 10, 629 op_ftintrne_l_d = 0x46baU << 10, 630 op_ftint_w_s = 0x46c1U << 10, 631 op_ftint_w_d = 0x46c2U << 10, 632 op_ftint_l_s = 0x46c9U << 10, 633 op_ftint_l_d = 0x46caU << 10, 634 op_ffint_s_w = 0x4744U << 10, 635 op_ffint_s_l = 0x4746U << 10, 636 op_ffint_d_w = 0x4748U << 10, 637 op_ffint_d_l = 0x474aU << 10, 638 op_frint_s = 0x4791U << 10, 639 op_frint_d = 0x4792U << 10, 640 op_movcf2fr = 0x114d4U << 8, 641 op_movcf2gr = 0x114dcU << 8, 642 }; 643 644 class Operand; 645 646 // A BOffImm16 is a 16 bit immediate that is used for branches. 647 class BOffImm16 { 648 uint32_t data; 649 650 public: 651 uint32_t encode() { 652 MOZ_ASSERT(!isInvalid()); 653 return data; 654 } 655 int32_t decode() { 656 MOZ_ASSERT(!isInvalid()); 657 return (int32_t(data << 18) >> 16); 658 } 659 660 explicit BOffImm16(int offset) : data((offset) >> 2 & Imm16Mask) { 661 MOZ_ASSERT((offset & 0x3) == 0); 662 MOZ_ASSERT(IsInRange(offset)); 663 } 664 static bool IsInRange(int offset) { 665 if ((offset) < int(unsigned(INT16_MIN) << 2)) { 666 return false; 667 } 668 if ((offset) > (INT16_MAX << 2)) { 669 return false; 670 } 671 return true; 672 } 673 static const uint32_t INVALID = 0x00020000; 674 BOffImm16() : data(INVALID) {} 675 676 bool isInvalid() { return data == INVALID; } 677 Instruction* getDest(Instruction* src) const; 678 679 explicit BOffImm16(InstImm inst); 680 }; 681 682 // A JOffImm26 is a 26 bit immediate that is used for unconditional jumps. 683 class JOffImm26 { 684 uint32_t data; 685 686 public: 687 uint32_t encode() { 688 MOZ_ASSERT(!isInvalid()); 689 return data; 690 } 691 int32_t decode() { 692 MOZ_ASSERT(!isInvalid()); 693 return (int32_t(data << 8) >> 6); 694 } 695 696 explicit JOffImm26(int offset) : data((offset) >> 2 & Imm26Mask) { 697 MOZ_ASSERT((offset & 0x3) == 0); 698 MOZ_ASSERT(IsInRange(offset)); 699 } 700 static bool IsInRange(int offset) { 701 if ((offset) < -536870912) { 702 return false; 703 } 704 if ((offset) > 536870908) { 705 return false; 706 } 707 return true; 708 } 709 static const uint32_t INVALID = 0x20000000; 710 JOffImm26() : data(INVALID) {} 711 712 bool isInvalid() { return data == INVALID; } 713 Instruction* getDest(Instruction* src); 714 }; 715 716 class Imm16 { 717 uint16_t value; 718 719 public: 720 Imm16(); 721 explicit Imm16(uint32_t imm) : value(imm) {} 722 uint32_t encode() { return value; } 723 int32_t decodeSigned() { return value; } 724 uint32_t decodeUnsigned() { return value; } 725 726 static bool IsInSignedRange(int32_t imm) { 727 return imm >= INT16_MIN && imm <= INT16_MAX; 728 } 729 730 static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT16_MAX; } 731 }; 732 733 class Imm8 { 734 uint8_t value; 735 736 public: 737 Imm8(); 738 explicit Imm8(uint32_t imm) : value(imm) {} 739 uint32_t encode(uint32_t shift) { return value << shift; } 740 int32_t decodeSigned() { return value; } 741 uint32_t decodeUnsigned() { return value; } 742 static bool IsInSignedRange(int32_t imm) { 743 return imm >= INT8_MIN && imm <= INT8_MAX; 744 } 745 static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT8_MAX; } 746 static Imm8 Lower(Imm16 imm) { return Imm8(imm.decodeSigned() & 0xff); } 747 static Imm8 Upper(Imm16 imm) { 748 return Imm8((imm.decodeSigned() >> 8) & 0xff); 749 } 750 }; 751 752 class Operand { 753 public: 754 enum Tag { REG, FREG, MEM }; 755 756 private: 757 Tag tag : 3; 758 uint32_t reg : 5; 759 int32_t offset; 760 761 public: 762 MOZ_IMPLICIT Operand(Register reg_) : tag(REG), reg(reg_.code()) {} 763 764 explicit Operand(FloatRegister freg) : tag(FREG), reg(freg.code()) {} 765 766 Operand(Register base, Imm32 off) 767 : tag(MEM), reg(base.code()), offset(off.value) {} 768 769 Operand(Register base, int32_t off) 770 : tag(MEM), reg(base.code()), offset(off) {} 771 772 explicit Operand(const Address& addr) 773 : tag(MEM), reg(addr.base.code()), offset(addr.offset) {} 774 775 Tag getTag() const { return tag; } 776 777 Register toReg() const { 778 MOZ_ASSERT(tag == REG); 779 return Register::FromCode(reg); 780 } 781 782 FloatRegister toFReg() const { 783 MOZ_ASSERT(tag == FREG); 784 return FloatRegister::FromCode(reg); 785 } 786 787 void toAddr(Register* r, Imm32* dest) const { 788 MOZ_ASSERT(tag == MEM); 789 *r = Register::FromCode(reg); 790 *dest = Imm32(offset); 791 } 792 Address toAddress() const { 793 MOZ_ASSERT(tag == MEM); 794 return Address(Register::FromCode(reg), offset); 795 } 796 int32_t disp() const { 797 MOZ_ASSERT(tag == MEM); 798 return offset; 799 } 800 801 int32_t base() const { 802 MOZ_ASSERT(tag == MEM); 803 return reg; 804 } 805 Register baseReg() const { 806 MOZ_ASSERT(tag == MEM); 807 return Register::FromCode(reg); 808 } 809 }; 810 811 // int check. 812 inline bool is_intN(int64_t x, unsigned n) { 813 MOZ_ASSERT((0 < n) && (n < 64)); 814 int64_t limit = static_cast<int64_t>(1) << (n - 1); 815 return (-limit <= x) && (x < limit); 816 } 817 818 inline bool is_uintN(int32_t x, unsigned n) { 819 MOZ_ASSERT((0 < n) && (n < (sizeof(x) * 8))); 820 return !(x >> n); 821 } 822 823 static constexpr int32_t SliceSize = 1024; 824 typedef js::jit::AssemblerBuffer<SliceSize, Instruction> LOONGBuffer; 825 826 class LOONGBufferWithExecutableCopy : public LOONGBuffer { 827 public: 828 void executableCopy(uint8_t* buffer) { 829 if (this->oom()) { 830 return; 831 } 832 833 for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) { 834 memcpy(buffer, &cur->instructions, cur->length()); 835 buffer += cur->length(); 836 } 837 } 838 839 bool appendRawCode(const uint8_t* code, size_t numBytes) { 840 if (this->oom()) { 841 return false; 842 } 843 while (numBytes > SliceSize) { 844 this->putBytes(SliceSize, code); 845 numBytes -= SliceSize; 846 code += SliceSize; 847 } 848 this->putBytes(numBytes, code); 849 return !this->oom(); 850 } 851 }; 852 853 class AssemblerLOONG64 : public AssemblerShared { 854 public: 855 // TODO(loong64): Should we remove these conditions here? 856 enum Condition { 857 Equal, 858 NotEqual, 859 Above, 860 AboveOrEqual, 861 Below, 862 BelowOrEqual, 863 GreaterThan, 864 GreaterThanOrEqual, 865 GreaterThanOrEqual_Signed, 866 GreaterThanOrEqual_NotSigned, 867 LessThan, 868 LessThan_Signed, 869 LessThan_NotSigned, 870 LessThanOrEqual, 871 Overflow, 872 CarrySet, 873 CarryClear, 874 Signed, 875 NotSigned, 876 Zero, 877 NonZero, 878 Always, 879 }; 880 881 enum DoubleCondition { 882 DoubleOrdered, 883 DoubleEqual, 884 DoubleNotEqual, 885 DoubleGreaterThan, 886 DoubleGreaterThanOrEqual, 887 DoubleLessThan, 888 DoubleLessThanOrEqual, 889 DoubleUnordered, 890 DoubleEqualOrUnordered, 891 DoubleNotEqualOrUnordered, 892 DoubleGreaterThanOrUnordered, 893 DoubleGreaterThanOrEqualOrUnordered, 894 DoubleLessThanOrUnordered, 895 DoubleLessThanOrEqualOrUnordered 896 }; 897 898 enum FPUCondition { 899 kNoFPUCondition = -1, 900 901 CAF = 0x00, 902 SAF = 0x01, 903 CLT = 0x02, 904 SLT = 0x03, 905 CEQ = 0x04, 906 SEQ = 0x05, 907 CLE = 0x06, 908 SLE = 0x07, 909 CUN = 0x08, 910 SUN = 0x09, 911 CULT = 0x0a, 912 SULT = 0x0b, 913 CUEQ = 0x0c, 914 SUEQ = 0x0d, 915 CULE = 0x0e, 916 SULE = 0x0f, 917 CNE = 0x10, 918 SNE = 0x11, 919 COR = 0x14, 920 SOR = 0x15, 921 CUNE = 0x18, 922 SUNE = 0x19, 923 }; 924 925 enum FPConditionBit { FCC0 = 0, FCC1, FFC2, FCC3, FCC4, FCC5, FCC6, FCC7 }; 926 927 enum FPControl { FCSR = 0 }; 928 929 enum FCSRBit { CauseI = 24, CauseU, CauseO, CauseZ, CauseV }; 930 931 enum FloatFormat { SingleFloat, DoubleFloat }; 932 933 enum JumpOrCall { BranchIsJump, BranchIsCall }; 934 935 enum FloatTestKind { TestForTrue, TestForFalse }; 936 937 // :( this should be protected, but since CodeGenerator 938 // wants to use it, It needs to go out here :( 939 940 BufferOffset nextOffset() { return m_buffer.nextOffset(); } 941 942 protected: 943 Instruction* editSrc(BufferOffset bo) { return m_buffer.getInst(bo); } 944 945 // structure for fixing up pc-relative loads/jumps when a the machine code 946 // gets moved (executable copy, gc, etc.) 947 struct RelativePatch { 948 // the offset within the code buffer where the value is loaded that 949 // we want to fix-up 950 BufferOffset offset; 951 void* target; 952 RelocationKind kind; 953 954 RelativePatch(BufferOffset offset, void* target, RelocationKind kind) 955 : offset(offset), target(target), kind(kind) {} 956 }; 957 958 js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_; 959 960 CompactBufferWriter jumpRelocations_; 961 CompactBufferWriter dataRelocations_; 962 963 LOONGBufferWithExecutableCopy m_buffer; 964 965 #ifdef JS_JITSPEW 966 Sprinter* printer; 967 #endif 968 969 public: 970 AssemblerLOONG64() 971 : m_buffer(), 972 #ifdef JS_JITSPEW 973 printer(nullptr), 974 #endif 975 isFinished(false), 976 scratch_register_list_((1 << t7.code()) | (1 << t8.code())) { 977 } 978 979 static Condition InvertCondition(Condition cond); 980 static DoubleCondition InvertCondition(DoubleCondition cond); 981 // This is changing the condition codes for cmp a, b to the same codes for cmp 982 // b, a. 983 static Condition SwapCmpOperandsCondition(Condition cond); 984 985 // As opposed to x86/x64 version, the data relocation has to be executed 986 // before to recover the pointer, and not after. 987 void writeDataRelocation(ImmGCPtr ptr) { 988 // Raw GC pointer relocations and Value relocations both end up in 989 // TraceOneDataRelocation. 990 if (ptr.value) { 991 if (gc::IsInsideNursery(ptr.value)) { 992 embedsNurseryPointers_ = true; 993 } 994 dataRelocations_.writeUnsigned(nextOffset().getOffset()); 995 } 996 } 997 998 void assertNoGCThings() const { 999 #ifdef DEBUG 1000 MOZ_ASSERT(dataRelocations_.length() == 0); 1001 for (auto& j : jumps_) { 1002 MOZ_ASSERT(j.kind == RelocationKind::HARDCODED); 1003 } 1004 #endif 1005 } 1006 1007 public: 1008 void setUnlimitedBuffer() { m_buffer.setUnlimited(); } 1009 bool oom() const; 1010 1011 void setPrinter(Sprinter* sp) { 1012 #ifdef JS_JITSPEW 1013 printer = sp; 1014 #endif 1015 } 1016 1017 #ifdef JS_JITSPEW 1018 inline void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) { 1019 if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) { 1020 va_list va; 1021 va_start(va, fmt); 1022 spew(fmt, va); 1023 va_end(va); 1024 } 1025 } 1026 1027 void decodeBranchInstAndSpew(InstImm branch); 1028 #else 1029 MOZ_ALWAYS_INLINE void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {} 1030 #endif 1031 1032 #ifdef JS_JITSPEW 1033 MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0) { 1034 // Buffer to hold the formatted string. Note that this may contain 1035 // '%' characters, so do not pass it directly to printf functions. 1036 char buf[200]; 1037 1038 int i = VsprintfLiteral(buf, fmt, va); 1039 if (i > -1) { 1040 if (printer) { 1041 printer->printf("%s\n", buf); 1042 } 1043 js::jit::JitSpew(js::jit::JitSpew_Codegen, "%s", buf); 1044 } 1045 } 1046 #endif 1047 1048 Register getStackPointer() const { return StackPointer; } 1049 1050 protected: 1051 bool isFinished; 1052 1053 public: 1054 void finish(); 1055 bool appendRawCode(const uint8_t* code, size_t numBytes); 1056 bool reserve(size_t size); 1057 bool swapBuffer(wasm::Bytes& bytes); 1058 void executableCopy(void* buffer); 1059 void copyJumpRelocationTable(uint8_t* dest); 1060 void copyDataRelocationTable(uint8_t* dest); 1061 1062 // Size of the instruction stream, in bytes. 1063 size_t size() const; 1064 // Size of the jump relocation table, in bytes. 1065 size_t jumpRelocationTableBytes() const; 1066 size_t dataRelocationTableBytes() const; 1067 1068 // Size of the data table, in bytes. 1069 size_t bytesNeeded() const; 1070 1071 // Write a blob of binary into the instruction stream *OR* 1072 // into a destination address. If dest is nullptr (the default), then the 1073 // instruction gets written into the instruction stream. If dest is not null 1074 // it is interpreted as a pointer to the location that we want the 1075 // instruction to be written. 1076 BufferOffset writeInst(uint32_t x, uint32_t* dest = nullptr); 1077 // A static variant for the cases where we don't want to have an assembler 1078 // object at all. Normally, you would use the dummy (nullptr) object. 1079 static void WriteInstStatic(uint32_t x, uint32_t* dest); 1080 1081 public: 1082 BufferOffset haltingAlign(int alignment); 1083 BufferOffset nopAlign(int alignment); 1084 BufferOffset as_nop() { return as_andi(zero, zero, 0); } 1085 1086 // Branch and jump instructions 1087 BufferOffset as_b(JOffImm26 off); 1088 BufferOffset as_bl(JOffImm26 off); 1089 BufferOffset as_jirl(Register rd, Register rj, BOffImm16 off); 1090 1091 InstImm getBranchCode(JumpOrCall jumpOrCall); // b, bl 1092 InstImm getBranchCode(Register rd, Register rj, 1093 Condition c); // beq, bne, bge, bgeu, blt, bltu 1094 InstImm getBranchCode(Register rj, Condition c); // beqz, bnez 1095 InstImm getBranchCode(FPConditionBit cj); // bceqz, bcnez 1096 1097 // Arithmetic instructions 1098 BufferOffset as_add_w(Register rd, Register rj, Register rk); 1099 BufferOffset as_add_d(Register rd, Register rj, Register rk); 1100 BufferOffset as_sub_w(Register rd, Register rj, Register rk); 1101 BufferOffset as_sub_d(Register rd, Register rj, Register rk); 1102 1103 BufferOffset as_addi_w(Register rd, Register rj, int32_t si12); 1104 BufferOffset as_addi_d(Register rd, Register rj, int32_t si12); 1105 BufferOffset as_addu16i_d(Register rd, Register rj, int32_t si16); 1106 1107 BufferOffset as_alsl_w(Register rd, Register rj, Register rk, uint32_t sa2); 1108 BufferOffset as_alsl_wu(Register rd, Register rj, Register rk, uint32_t sa2); 1109 BufferOffset as_alsl_d(Register rd, Register rj, Register rk, uint32_t sa2); 1110 1111 BufferOffset as_lu12i_w(Register rd, int32_t si20); 1112 BufferOffset as_lu32i_d(Register rd, int32_t si20); 1113 BufferOffset as_lu52i_d(Register rd, Register rj, int32_t si12); 1114 1115 BufferOffset as_slt(Register rd, Register rj, Register rk); 1116 BufferOffset as_sltu(Register rd, Register rj, Register rk); 1117 BufferOffset as_slti(Register rd, Register rj, int32_t si12); 1118 BufferOffset as_sltui(Register rd, Register rj, int32_t si12); 1119 1120 BufferOffset as_pcaddi(Register rd, int32_t si20); 1121 BufferOffset as_pcaddu12i(Register rd, int32_t si20); 1122 BufferOffset as_pcaddu18i(Register rd, int32_t si20); 1123 BufferOffset as_pcalau12i(Register rd, int32_t si20); 1124 1125 BufferOffset as_mul_w(Register rd, Register rj, Register rk); 1126 BufferOffset as_mulh_w(Register rd, Register rj, Register rk); 1127 BufferOffset as_mulh_wu(Register rd, Register rj, Register rk); 1128 BufferOffset as_mul_d(Register rd, Register rj, Register rk); 1129 BufferOffset as_mulh_d(Register rd, Register rj, Register rk); 1130 BufferOffset as_mulh_du(Register rd, Register rj, Register rk); 1131 1132 BufferOffset as_mulw_d_w(Register rd, Register rj, Register rk); 1133 BufferOffset as_mulw_d_wu(Register rd, Register rj, Register rk); 1134 1135 BufferOffset as_div_w(Register rd, Register rj, Register rk); 1136 BufferOffset as_mod_w(Register rd, Register rj, Register rk); 1137 BufferOffset as_div_wu(Register rd, Register rj, Register rk); 1138 BufferOffset as_mod_wu(Register rd, Register rj, Register rk); 1139 BufferOffset as_div_d(Register rd, Register rj, Register rk); 1140 BufferOffset as_mod_d(Register rd, Register rj, Register rk); 1141 BufferOffset as_div_du(Register rd, Register rj, Register rk); 1142 BufferOffset as_mod_du(Register rd, Register rj, Register rk); 1143 1144 // Logical instructions 1145 BufferOffset as_and(Register rd, Register rj, Register rk); 1146 BufferOffset as_or(Register rd, Register rj, Register rk); 1147 BufferOffset as_xor(Register rd, Register rj, Register rk); 1148 BufferOffset as_nor(Register rd, Register rj, Register rk); 1149 BufferOffset as_andn(Register rd, Register rj, Register rk); 1150 BufferOffset as_orn(Register rd, Register rj, Register rk); 1151 1152 BufferOffset as_andi(Register rd, Register rj, int32_t ui12); 1153 BufferOffset as_ori(Register rd, Register rj, int32_t ui12); 1154 BufferOffset as_xori(Register rd, Register rj, int32_t ui12); 1155 1156 // Shift instructions 1157 BufferOffset as_sll_w(Register rd, Register rj, Register rk); 1158 BufferOffset as_srl_w(Register rd, Register rj, Register rk); 1159 BufferOffset as_sra_w(Register rd, Register rj, Register rk); 1160 BufferOffset as_rotr_w(Register rd, Register rj, Register rk); 1161 1162 BufferOffset as_slli_w(Register rd, Register rj, int32_t ui5); 1163 BufferOffset as_srli_w(Register rd, Register rj, int32_t ui5); 1164 BufferOffset as_srai_w(Register rd, Register rj, int32_t ui5); 1165 BufferOffset as_rotri_w(Register rd, Register rj, int32_t ui5); 1166 1167 BufferOffset as_sll_d(Register rd, Register rj, Register rk); 1168 BufferOffset as_srl_d(Register rd, Register rj, Register rk); 1169 BufferOffset as_sra_d(Register rd, Register rj, Register rk); 1170 BufferOffset as_rotr_d(Register rd, Register rj, Register rk); 1171 1172 BufferOffset as_slli_d(Register rd, Register rj, int32_t ui6); 1173 BufferOffset as_srli_d(Register rd, Register rj, int32_t ui6); 1174 BufferOffset as_srai_d(Register rd, Register rj, int32_t ui6); 1175 BufferOffset as_rotri_d(Register rd, Register rj, int32_t ui6); 1176 1177 // Bit operation instrucitons 1178 BufferOffset as_ext_w_b(Register rd, Register rj); 1179 BufferOffset as_ext_w_h(Register rd, Register rj); 1180 1181 BufferOffset as_clo_w(Register rd, Register rj); 1182 BufferOffset as_clz_w(Register rd, Register rj); 1183 BufferOffset as_cto_w(Register rd, Register rj); 1184 BufferOffset as_ctz_w(Register rd, Register rj); 1185 BufferOffset as_clo_d(Register rd, Register rj); 1186 BufferOffset as_clz_d(Register rd, Register rj); 1187 BufferOffset as_cto_d(Register rd, Register rj); 1188 BufferOffset as_ctz_d(Register rd, Register rj); 1189 1190 BufferOffset as_bytepick_w(Register rd, Register rj, Register rk, 1191 int32_t sa2); 1192 BufferOffset as_bytepick_d(Register rd, Register rj, Register rk, 1193 int32_t sa3); 1194 1195 BufferOffset as_revb_2h(Register rd, Register rj); 1196 BufferOffset as_revb_4h(Register rd, Register rj); 1197 BufferOffset as_revb_2w(Register rd, Register rj); 1198 BufferOffset as_revb_d(Register rd, Register rj); 1199 1200 BufferOffset as_revh_2w(Register rd, Register rj); 1201 BufferOffset as_revh_d(Register rd, Register rj); 1202 1203 BufferOffset as_bitrev_4b(Register rd, Register rj); 1204 BufferOffset as_bitrev_8b(Register rd, Register rj); 1205 1206 BufferOffset as_bitrev_w(Register rd, Register rj); 1207 BufferOffset as_bitrev_d(Register rd, Register rj); 1208 1209 BufferOffset as_bstrins_w(Register rd, Register rj, int32_t msbw, 1210 int32_t lsbw); 1211 BufferOffset as_bstrins_d(Register rd, Register rj, int32_t msbd, 1212 int32_t lsbd); 1213 BufferOffset as_bstrpick_w(Register rd, Register rj, int32_t msbw, 1214 int32_t lsbw); 1215 BufferOffset as_bstrpick_d(Register rd, Register rj, int32_t msbd, 1216 int32_t lsbd); 1217 1218 BufferOffset as_maskeqz(Register rd, Register rj, Register rk); 1219 BufferOffset as_masknez(Register rd, Register rj, Register rk); 1220 1221 // Load and store instructions 1222 BufferOffset as_ld_b(Register rd, Register rj, int32_t si12); 1223 BufferOffset as_ld_h(Register rd, Register rj, int32_t si12); 1224 BufferOffset as_ld_w(Register rd, Register rj, int32_t si12); 1225 BufferOffset as_ld_d(Register rd, Register rj, int32_t si12); 1226 BufferOffset as_ld_bu(Register rd, Register rj, int32_t si12); 1227 BufferOffset as_ld_hu(Register rd, Register rj, int32_t si12); 1228 BufferOffset as_ld_wu(Register rd, Register rj, int32_t si12); 1229 BufferOffset as_st_b(Register rd, Register rj, int32_t si12); 1230 BufferOffset as_st_h(Register rd, Register rj, int32_t si12); 1231 BufferOffset as_st_w(Register rd, Register rj, int32_t si12); 1232 BufferOffset as_st_d(Register rd, Register rj, int32_t si12); 1233 1234 BufferOffset as_ldx_b(Register rd, Register rj, Register rk); 1235 BufferOffset as_ldx_h(Register rd, Register rj, Register rk); 1236 BufferOffset as_ldx_w(Register rd, Register rj, Register rk); 1237 BufferOffset as_ldx_d(Register rd, Register rj, Register rk); 1238 BufferOffset as_ldx_bu(Register rd, Register rj, Register rk); 1239 BufferOffset as_ldx_hu(Register rd, Register rj, Register rk); 1240 BufferOffset as_ldx_wu(Register rd, Register rj, Register rk); 1241 BufferOffset as_stx_b(Register rd, Register rj, Register rk); 1242 BufferOffset as_stx_h(Register rd, Register rj, Register rk); 1243 BufferOffset as_stx_w(Register rd, Register rj, Register rk); 1244 BufferOffset as_stx_d(Register rd, Register rj, Register rk); 1245 1246 BufferOffset as_ldptr_w(Register rd, Register rj, int32_t si14); 1247 BufferOffset as_ldptr_d(Register rd, Register rj, int32_t si14); 1248 BufferOffset as_stptr_w(Register rd, Register rj, int32_t si14); 1249 BufferOffset as_stptr_d(Register rd, Register rj, int32_t si14); 1250 1251 BufferOffset as_preld(int32_t hint, Register rj, int32_t si12); 1252 1253 // Atomic instructions 1254 BufferOffset as_amswap_w(Register rd, Register rj, Register rk); 1255 BufferOffset as_amswap_d(Register rd, Register rj, Register rk); 1256 BufferOffset as_amadd_w(Register rd, Register rj, Register rk); 1257 BufferOffset as_amadd_d(Register rd, Register rj, Register rk); 1258 BufferOffset as_amand_w(Register rd, Register rj, Register rk); 1259 BufferOffset as_amand_d(Register rd, Register rj, Register rk); 1260 BufferOffset as_amor_w(Register rd, Register rj, Register rk); 1261 BufferOffset as_amor_d(Register rd, Register rj, Register rk); 1262 BufferOffset as_amxor_w(Register rd, Register rj, Register rk); 1263 BufferOffset as_amxor_d(Register rd, Register rj, Register rk); 1264 BufferOffset as_ammax_w(Register rd, Register rj, Register rk); 1265 BufferOffset as_ammax_d(Register rd, Register rj, Register rk); 1266 BufferOffset as_ammin_w(Register rd, Register rj, Register rk); 1267 BufferOffset as_ammin_d(Register rd, Register rj, Register rk); 1268 BufferOffset as_ammax_wu(Register rd, Register rj, Register rk); 1269 BufferOffset as_ammax_du(Register rd, Register rj, Register rk); 1270 BufferOffset as_ammin_wu(Register rd, Register rj, Register rk); 1271 BufferOffset as_ammin_du(Register rd, Register rj, Register rk); 1272 1273 BufferOffset as_amswap_db_w(Register rd, Register rj, Register rk); 1274 BufferOffset as_amswap_db_d(Register rd, Register rj, Register rk); 1275 BufferOffset as_amadd_db_w(Register rd, Register rj, Register rk); 1276 BufferOffset as_amadd_db_d(Register rd, Register rj, Register rk); 1277 BufferOffset as_amand_db_w(Register rd, Register rj, Register rk); 1278 BufferOffset as_amand_db_d(Register rd, Register rj, Register rk); 1279 BufferOffset as_amor_db_w(Register rd, Register rj, Register rk); 1280 BufferOffset as_amor_db_d(Register rd, Register rj, Register rk); 1281 BufferOffset as_amxor_db_w(Register rd, Register rj, Register rk); 1282 BufferOffset as_amxor_db_d(Register rd, Register rj, Register rk); 1283 BufferOffset as_ammax_db_w(Register rd, Register rj, Register rk); 1284 BufferOffset as_ammax_db_d(Register rd, Register rj, Register rk); 1285 BufferOffset as_ammin_db_w(Register rd, Register rj, Register rk); 1286 BufferOffset as_ammin_db_d(Register rd, Register rj, Register rk); 1287 BufferOffset as_ammax_db_wu(Register rd, Register rj, Register rk); 1288 BufferOffset as_ammax_db_du(Register rd, Register rj, Register rk); 1289 BufferOffset as_ammin_db_wu(Register rd, Register rj, Register rk); 1290 BufferOffset as_ammin_db_du(Register rd, Register rj, Register rk); 1291 1292 BufferOffset as_ll_w(Register rd, Register rj, int32_t si14); 1293 BufferOffset as_ll_d(Register rd, Register rj, int32_t si14); 1294 BufferOffset as_sc_w(Register rd, Register rj, int32_t si14); 1295 BufferOffset as_sc_d(Register rd, Register rj, int32_t si14); 1296 1297 // Barrier instructions 1298 BufferOffset as_dbar(int32_t hint); 1299 BufferOffset as_ibar(int32_t hint); 1300 1301 // FP Arithmetic instructions 1302 BufferOffset as_fadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1303 BufferOffset as_fadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1304 BufferOffset as_fsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1305 BufferOffset as_fsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1306 BufferOffset as_fmul_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1307 BufferOffset as_fmul_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1308 BufferOffset as_fdiv_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1309 BufferOffset as_fdiv_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1310 1311 BufferOffset as_fmadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1312 FloatRegister fa); 1313 BufferOffset as_fmadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1314 FloatRegister fa); 1315 BufferOffset as_fmsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1316 FloatRegister fa); 1317 BufferOffset as_fmsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1318 FloatRegister fa); 1319 BufferOffset as_fnmadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1320 FloatRegister fa); 1321 BufferOffset as_fnmadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1322 FloatRegister fa); 1323 BufferOffset as_fnmsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1324 FloatRegister fa); 1325 BufferOffset as_fnmsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1326 FloatRegister fa); 1327 1328 BufferOffset as_fmax_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1329 BufferOffset as_fmax_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1330 BufferOffset as_fmin_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1331 BufferOffset as_fmin_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1332 1333 BufferOffset as_fmaxa_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1334 BufferOffset as_fmaxa_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1335 BufferOffset as_fmina_s(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1336 BufferOffset as_fmina_d(FloatRegister fd, FloatRegister fj, FloatRegister fk); 1337 1338 BufferOffset as_fabs_s(FloatRegister fd, FloatRegister fj); 1339 BufferOffset as_fabs_d(FloatRegister fd, FloatRegister fj); 1340 BufferOffset as_fneg_s(FloatRegister fd, FloatRegister fj); 1341 BufferOffset as_fneg_d(FloatRegister fd, FloatRegister fj); 1342 1343 BufferOffset as_fsqrt_s(FloatRegister fd, FloatRegister fj); 1344 BufferOffset as_fsqrt_d(FloatRegister fd, FloatRegister fj); 1345 BufferOffset as_fcopysign_s(FloatRegister fd, FloatRegister fj, 1346 FloatRegister fk); 1347 BufferOffset as_fcopysign_d(FloatRegister fd, FloatRegister fj, 1348 FloatRegister fk); 1349 1350 // FP compare instructions (fcmp.cond.s fcmp.cond.d) 1351 BufferOffset as_fcmp_cor(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1352 FPConditionBit cd); 1353 BufferOffset as_fcmp_ceq(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1354 FPConditionBit cd); 1355 BufferOffset as_fcmp_cne(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1356 FPConditionBit cd); 1357 BufferOffset as_fcmp_cle(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1358 FPConditionBit cd); 1359 BufferOffset as_fcmp_clt(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1360 FPConditionBit cd); 1361 BufferOffset as_fcmp_cun(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1362 FPConditionBit cd); 1363 BufferOffset as_fcmp_cueq(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1364 FPConditionBit cd); 1365 BufferOffset as_fcmp_cune(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1366 FPConditionBit cd); 1367 BufferOffset as_fcmp_cule(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1368 FPConditionBit cd); 1369 BufferOffset as_fcmp_cult(FloatFormat fmt, FloatRegister fj, FloatRegister fk, 1370 FPConditionBit cd); 1371 1372 // FP conversion instructions 1373 BufferOffset as_fcvt_s_d(FloatRegister fd, FloatRegister fj); 1374 BufferOffset as_fcvt_d_s(FloatRegister fd, FloatRegister fj); 1375 1376 BufferOffset as_ffint_s_w(FloatRegister fd, FloatRegister fj); 1377 BufferOffset as_ffint_s_l(FloatRegister fd, FloatRegister fj); 1378 BufferOffset as_ffint_d_w(FloatRegister fd, FloatRegister fj); 1379 BufferOffset as_ffint_d_l(FloatRegister fd, FloatRegister fj); 1380 BufferOffset as_ftint_w_s(FloatRegister fd, FloatRegister fj); 1381 BufferOffset as_ftint_w_d(FloatRegister fd, FloatRegister fj); 1382 BufferOffset as_ftint_l_s(FloatRegister fd, FloatRegister fj); 1383 BufferOffset as_ftint_l_d(FloatRegister fd, FloatRegister fj); 1384 1385 BufferOffset as_ftintrm_w_s(FloatRegister fd, FloatRegister fj); 1386 BufferOffset as_ftintrm_w_d(FloatRegister fd, FloatRegister fj); 1387 BufferOffset as_ftintrm_l_s(FloatRegister fd, FloatRegister fj); 1388 BufferOffset as_ftintrm_l_d(FloatRegister fd, FloatRegister fj); 1389 BufferOffset as_ftintrp_w_s(FloatRegister fd, FloatRegister fj); 1390 BufferOffset as_ftintrp_w_d(FloatRegister fd, FloatRegister fj); 1391 BufferOffset as_ftintrp_l_s(FloatRegister fd, FloatRegister fj); 1392 BufferOffset as_ftintrp_l_d(FloatRegister fd, FloatRegister fj); 1393 BufferOffset as_ftintrz_w_s(FloatRegister fd, FloatRegister fj); 1394 BufferOffset as_ftintrz_w_d(FloatRegister fd, FloatRegister fj); 1395 BufferOffset as_ftintrz_l_s(FloatRegister fd, FloatRegister fj); 1396 BufferOffset as_ftintrz_l_d(FloatRegister fd, FloatRegister fj); 1397 BufferOffset as_ftintrne_w_s(FloatRegister fd, FloatRegister fj); 1398 BufferOffset as_ftintrne_w_d(FloatRegister fd, FloatRegister fj); 1399 BufferOffset as_ftintrne_l_s(FloatRegister fd, FloatRegister fj); 1400 BufferOffset as_ftintrne_l_d(FloatRegister fd, FloatRegister fj); 1401 1402 BufferOffset as_frint_s(FloatRegister fd, FloatRegister fj); 1403 BufferOffset as_frint_d(FloatRegister fd, FloatRegister fj); 1404 1405 // FP mov instructions 1406 BufferOffset as_fmov_s(FloatRegister fd, FloatRegister fj); 1407 BufferOffset as_fmov_d(FloatRegister fd, FloatRegister fj); 1408 1409 BufferOffset as_fsel(FloatRegister fd, FloatRegister fj, FloatRegister fk, 1410 FPConditionBit ca); 1411 1412 BufferOffset as_movgr2fr_w(FloatRegister fd, Register rj); 1413 BufferOffset as_movgr2fr_d(FloatRegister fd, Register rj); 1414 BufferOffset as_movgr2frh_w(FloatRegister fd, Register rj); 1415 1416 BufferOffset as_movfr2gr_s(Register rd, FloatRegister fj); 1417 BufferOffset as_movfr2gr_d(Register rd, FloatRegister fj); 1418 BufferOffset as_movfrh2gr_s(Register rd, FloatRegister fj); 1419 1420 BufferOffset as_movgr2fcsr(Register rj); 1421 BufferOffset as_movfcsr2gr(Register rd); 1422 1423 BufferOffset as_movfr2cf(FPConditionBit cd, FloatRegister fj); 1424 BufferOffset as_movcf2fr(FloatRegister fd, FPConditionBit cj); 1425 1426 BufferOffset as_movgr2cf(FPConditionBit cd, Register rj); 1427 BufferOffset as_movcf2gr(Register rd, FPConditionBit cj); 1428 1429 // FP load/store instructions 1430 BufferOffset as_fld_s(FloatRegister fd, Register rj, int32_t si12); 1431 BufferOffset as_fld_d(FloatRegister fd, Register rj, int32_t si12); 1432 BufferOffset as_fst_s(FloatRegister fd, Register rj, int32_t si12); 1433 BufferOffset as_fst_d(FloatRegister fd, Register rj, int32_t si12); 1434 1435 BufferOffset as_fldx_s(FloatRegister fd, Register rj, Register rk); 1436 BufferOffset as_fldx_d(FloatRegister fd, Register rj, Register rk); 1437 BufferOffset as_fstx_s(FloatRegister fd, Register rj, Register rk); 1438 BufferOffset as_fstx_d(FloatRegister fd, Register rj, Register rk); 1439 1440 // label operations 1441 void bind(Label* label, BufferOffset boff = BufferOffset()); 1442 virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0; 1443 void bind(CodeLabel* label) { label->target()->bind(currentOffset()); } 1444 uint32_t currentOffset() { return nextOffset().getOffset(); } 1445 void retarget(Label* label, Label* target); 1446 1447 void call(Label* label); 1448 void call(void* target); 1449 1450 void as_break(uint32_t code); 1451 1452 public: 1453 static bool SupportsFloatingPoint() { 1454 #if defined(__loongarch_hard_float) || defined(JS_SIMULATOR_LOONG64) 1455 return true; 1456 #else 1457 return false; 1458 #endif 1459 } 1460 static bool SupportsUnalignedAccesses() { return true; } 1461 static bool SupportsFastUnalignedFPAccesses() { return true; } 1462 static bool SupportsFloat64To16() { return false; } 1463 static bool SupportsFloat32To16() { return false; } 1464 1465 static bool HasRoundInstruction(RoundingMode mode) { return false; } 1466 1467 protected: 1468 InstImm invertBranch(InstImm branch, BOffImm16 skipOffset); 1469 void addPendingJump(BufferOffset src, ImmPtr target, RelocationKind kind) { 1470 enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); 1471 if (kind == RelocationKind::JITCODE) { 1472 jumpRelocations_.writeUnsigned(src.getOffset()); 1473 } 1474 } 1475 1476 void addLongJump(BufferOffset src, BufferOffset dst) { 1477 CodeLabel cl; 1478 cl.patchAt()->bind(src.getOffset()); 1479 cl.target()->bind(dst.getOffset()); 1480 cl.setLinkMode(CodeLabel::JumpImmediate); 1481 addCodeLabel(std::move(cl)); 1482 } 1483 1484 public: 1485 void flushBuffer() {} 1486 1487 void comment(const char* msg) { spew("; %s", msg); } 1488 1489 static uint32_t NopSize() { return 4; } 1490 1491 static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm); 1492 1493 static uint8_t* NextInstruction(uint8_t* instruction, 1494 uint32_t* count = nullptr); 1495 1496 static void ToggleToJmp(CodeLocationLabel inst_); 1497 static void ToggleToCmp(CodeLocationLabel inst_); 1498 1499 void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end, 1500 const Disassembler::HeapAccess& heapAccess) { 1501 // Implement this if we implement a disassembler. 1502 } 1503 1504 private: 1505 GeneralRegisterSet scratch_register_list_; 1506 1507 public: 1508 GeneralRegisterSet* GetScratchRegisterList() { 1509 return &scratch_register_list_; 1510 } 1511 }; // AssemblerLOONG64 1512 1513 // andi r0, r0, 0 1514 const uint32_t NopInst = 0x03400000; 1515 1516 // An Instruction is a structure for both encoding and decoding any and all 1517 // LoongArch instructions. 1518 class Instruction { 1519 public: 1520 uint32_t data; 1521 1522 protected: 1523 // Standard constructor 1524 explicit Instruction(uint32_t data_) : data(data_) {} 1525 // You should never create an instruction directly. You should create a 1526 // more specific instruction which will eventually call one of these 1527 // constructors for you. 1528 1529 public: 1530 uint32_t encode() const { return data; } 1531 1532 void makeNop() { data = NopInst; } 1533 1534 void setData(uint32_t data) { this->data = data; } 1535 1536 const Instruction& operator=(const Instruction& src) { 1537 data = src.data; 1538 return *this; 1539 } 1540 1541 // Extract the one particular bit. 1542 uint32_t extractBit(uint32_t bit) { return (encode() >> bit) & 1; } 1543 // Extract a bit field out of the instruction 1544 uint32_t extractBitField(uint32_t hi, uint32_t lo) { 1545 return (encode() >> lo) & ((2 << (hi - lo)) - 1); 1546 } 1547 1548 // Get the next instruction in the instruction stream. 1549 // This does neat things like ignoreconstant pools and their guards. 1550 Instruction* next(); 1551 1552 // Sometimes, an api wants a uint32_t (or a pointer to it) rather than 1553 // an instruction. raw() just coerces this into a pointer to a uint32_t 1554 const uint32_t* raw() const { return &data; } 1555 uint32_t size() const { return 4; } 1556 }; // Instruction 1557 1558 // make sure that it is the right size 1559 static_assert(sizeof(Instruction) == 4, 1560 "Size of Instruction class has to be 4 bytes."); 1561 1562 class InstNOP : public Instruction { 1563 public: 1564 InstNOP() : Instruction(NopInst) {} 1565 }; 1566 1567 // Class for register type instructions. 1568 class InstReg : public Instruction { 1569 public: 1570 InstReg(OpcodeField op, Register rj, Register rd) 1571 : Instruction(op | RJ(rj) | RD(rd)) {} 1572 InstReg(OpcodeField op, Register rk, Register rj, Register rd) 1573 : Instruction(op | RK(rk) | RJ(rj) | RD(rd)) {} 1574 InstReg(OpcodeField op, uint32_t sa, Register rk, Register rj, Register rd, 1575 uint32_t sa_bit) 1576 : Instruction(sa_bit == 2 ? op | SA2(sa) | RK(rk) | RJ(rj) | RD(rd) 1577 : op | SA3(sa) | RK(rk) | RJ(rj) | RD(rd)) { 1578 MOZ_ASSERT(sa_bit == 2 || sa_bit == 3); 1579 } 1580 InstReg(OpcodeField op, Register rj, Register rd, bool HasRd) 1581 : Instruction(HasRd ? op | RJ(rj) | RD(rd) : op | RK(rj) | RJ(rd)) {} 1582 1583 // For floating-point 1584 InstReg(OpcodeField op, Register rj, FloatRegister fd) 1585 : Instruction(op | RJ(rj) | FD(fd)) {} 1586 InstReg(OpcodeField op, FloatRegister fj, FloatRegister fd) 1587 : Instruction(op | FJ(fj) | FD(fd)) {} 1588 InstReg(OpcodeField op, FloatRegister fk, FloatRegister fj, FloatRegister fd) 1589 : Instruction(op | FK(fk) | FJ(fj) | FD(fd)) {} 1590 InstReg(OpcodeField op, Register rk, Register rj, FloatRegister fd) 1591 : Instruction(op | RK(rk) | RJ(rj) | FD(fd)) {} 1592 InstReg(OpcodeField op, FloatRegister fa, FloatRegister fk, FloatRegister fj, 1593 FloatRegister fd) 1594 : Instruction(op | FA(fa) | FK(fk) | FJ(fj) | FD(fd)) {} 1595 InstReg(OpcodeField op, AssemblerLOONG64::FPConditionBit ca, FloatRegister fk, 1596 FloatRegister fj, FloatRegister fd) 1597 : Instruction(op | ca << CAShift | FK(fk) | FJ(fj) | FD(fd)) { 1598 MOZ_ASSERT(op == op_fsel); 1599 } 1600 InstReg(OpcodeField op, FloatRegister fj, Register rd) 1601 : Instruction(op | FJ(fj) | RD(rd)) { 1602 MOZ_ASSERT((op == op_movfr2gr_s) || (op == op_movfr2gr_d) || 1603 (op == op_movfrh2gr_s)); 1604 } 1605 InstReg(OpcodeField op, Register rj, uint32_t fd) 1606 : Instruction(op | RJ(rj) | fd) { 1607 MOZ_ASSERT(op == op_movgr2fcsr); 1608 } 1609 InstReg(OpcodeField op, uint32_t fj, Register rd) 1610 : Instruction(op | (fj << FJShift) | RD(rd)) { 1611 MOZ_ASSERT(op == op_movfcsr2gr); 1612 } 1613 InstReg(OpcodeField op, FloatRegister fj, AssemblerLOONG64::FPConditionBit cd) 1614 : Instruction(op | FJ(fj) | cd) { 1615 MOZ_ASSERT(op == op_movfr2cf); 1616 } 1617 InstReg(OpcodeField op, AssemblerLOONG64::FPConditionBit cj, FloatRegister fd) 1618 : Instruction(op | (cj << CJShift) | FD(fd)) { 1619 MOZ_ASSERT(op == op_movcf2fr); 1620 } 1621 InstReg(OpcodeField op, Register rj, AssemblerLOONG64::FPConditionBit cd) 1622 : Instruction(op | RJ(rj) | cd) { 1623 MOZ_ASSERT(op == op_movgr2cf); 1624 } 1625 InstReg(OpcodeField op, AssemblerLOONG64::FPConditionBit cj, Register rd) 1626 : Instruction(op | (cj << CJShift) | RD(rd)) { 1627 MOZ_ASSERT(op == op_movcf2gr); 1628 } 1629 InstReg(OpcodeField op, int32_t cond, FloatRegister fk, FloatRegister fj, 1630 AssemblerLOONG64::FPConditionBit cd) 1631 : Instruction(op | (cond & CONDMask) << CONDShift | FK(fk) | FJ(fj) | 1632 (cd & CDMask)) { 1633 MOZ_ASSERT(is_uintN(cond, 5)); 1634 } 1635 1636 uint32_t extractRK() { 1637 return extractBitField(RKShift + RKBits - 1, RKShift); 1638 } 1639 uint32_t extractRJ() { 1640 return extractBitField(RJShift + RJBits - 1, RJShift); 1641 } 1642 uint32_t extractRD() { 1643 return extractBitField(RDShift + RDBits - 1, RDShift); 1644 } 1645 uint32_t extractSA2() { 1646 return extractBitField(SAShift + SA2Bits - 1, SAShift); 1647 } 1648 uint32_t extractSA3() { 1649 return extractBitField(SAShift + SA3Bits - 1, SAShift); 1650 } 1651 }; 1652 1653 // Class for branch, load and store instructions with immediate offset. 1654 class InstImm : public Instruction { 1655 public: 1656 void extractImm16(BOffImm16* dest); 1657 uint32_t genImm(int32_t value, uint32_t value_bits) { 1658 uint32_t imm = value & Imm5Mask; 1659 if (value_bits == 6) { 1660 imm = value & Imm6Mask; 1661 } else if (value_bits == 12) { 1662 imm = value & Imm12Mask; 1663 } else if (value_bits == 14) { 1664 imm = value & Imm14Mask; 1665 } 1666 1667 return imm; 1668 } 1669 1670 InstImm(OpcodeField op, int32_t value, Register rj, Register rd, 1671 uint32_t value_bits) 1672 : Instruction(op | genImm(value, value_bits) << RKShift | RJ(rj) | 1673 RD(rd)) { 1674 MOZ_ASSERT(value_bits == 5 || value_bits == 6 || value_bits == 12 || 1675 value_bits == 14); 1676 } 1677 InstImm(OpcodeField op, BOffImm16 off, Register rj, Register rd) 1678 : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift | RJ(rj) | 1679 RD(rd)) {} 1680 InstImm(OpcodeField op, int32_t si21, Register rj, bool NotHasRd) 1681 : Instruction(NotHasRd ? op | (si21 & Imm16Mask) << RKShift | RJ(rj) | 1682 (si21 & Imm21Mask) >> 16 1683 : op | (si21 & Imm20Mask) << Imm20Shift | RD(rj)) { 1684 if (NotHasRd) { 1685 MOZ_ASSERT(op == op_beqz || op == op_bnez); 1686 MOZ_ASSERT(is_intN(si21, 21)); 1687 } else { 1688 MOZ_ASSERT(op == op_lu12i_w || op == op_lu32i_d || op == op_pcaddi || 1689 op == op_pcaddu12i || op == op_pcaddu18i || 1690 op == op_pcalau12i); 1691 // si20 1692 MOZ_ASSERT(is_intN(si21, 20) || is_uintN(si21, 20)); 1693 } 1694 } 1695 InstImm(OpcodeField op, int32_t si21, AssemblerLOONG64::FPConditionBit cj, 1696 bool isNotEqual) 1697 : Instruction(isNotEqual 1698 ? op | (si21 & Imm16Mask) << RKShift | 1699 (cj + 8) << CJShift | (si21 & Imm21Mask) >> 16 1700 : op | (si21 & Imm16Mask) << RKShift | cj << CJShift | 1701 (si21 & Imm21Mask) >> 16) { 1702 MOZ_ASSERT(is_intN(si21, 21)); 1703 MOZ_ASSERT(op == op_bcz); 1704 MOZ_ASSERT(cj >= 0 && cj <= 7); 1705 } 1706 InstImm(OpcodeField op, Imm16 off, Register rj, Register rd) 1707 : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift | RJ(rj) | 1708 RD(rd)) {} 1709 InstImm(OpcodeField op, int32_t bit15) 1710 : Instruction(op | (bit15 & Imm15Mask)) { 1711 MOZ_ASSERT(is_uintN(bit15, 15)); 1712 } 1713 1714 InstImm(OpcodeField op, int32_t bit26, bool jump) 1715 : Instruction(op | (bit26 & Imm16Mask) << Imm16Shift | 1716 (bit26 & Imm26Mask) >> 16) { 1717 MOZ_ASSERT(is_intN(bit26, 26)); 1718 } 1719 InstImm(OpcodeField op, int32_t si12, Register rj, int32_t hint) 1720 : Instruction(op | (si12 & Imm12Mask) << Imm12Shift | RJ(rj) | 1721 (hint & HINTMask)) { 1722 MOZ_ASSERT(op == op_preld); 1723 } 1724 InstImm(OpcodeField op, int32_t msb, int32_t lsb, Register rj, Register rd, 1725 uint32_t sb_bits) 1726 : Instruction((sb_bits == 5) 1727 ? op | (msb & MSBWMask) << MSBWShift | 1728 (lsb & LSBWMask) << LSBWShift | RJ(rj) | RD(rd) 1729 : op | (msb & MSBDMask) << MSBDShift | 1730 (lsb & LSBDMask) << LSBDShift | RJ(rj) | RD(rd)) { 1731 MOZ_ASSERT(sb_bits == 5 || sb_bits == 6); 1732 MOZ_ASSERT(op == op_bstr_w || op == op_bstrins_d || op == op_bstrpick_d); 1733 } 1734 InstImm(OpcodeField op, int32_t msb, int32_t lsb, Register rj, Register rd) 1735 : Instruction(op | (msb & MSBWMask) << MSBWShift | 1736 ((lsb + 0x20) & LSBDMask) << LSBWShift | RJ(rj) | RD(rd)) { 1737 MOZ_ASSERT(op == op_bstr_w); 1738 } 1739 1740 // For floating-point loads and stores. 1741 InstImm(OpcodeField op, int32_t si12, Register rj, FloatRegister fd) 1742 : Instruction(op | (si12 & Imm12Mask) << Imm12Shift | RJ(rj) | FD(fd)) { 1743 MOZ_ASSERT(is_intN(si12, 12)); 1744 } 1745 1746 void setOpcode(OpcodeField op, uint32_t opBits) { 1747 // opBits not greater than 24. 1748 MOZ_ASSERT(opBits < 25); 1749 uint32_t OpcodeShift = 32 - opBits; 1750 uint32_t OpcodeMask = ((1 << opBits) - 1) << OpcodeShift; 1751 data = (data & ~OpcodeMask) | op; 1752 } 1753 uint32_t extractRK() { 1754 return extractBitField(RKShift + RKBits - 1, RKShift); 1755 } 1756 uint32_t extractRJ() { 1757 return extractBitField(RJShift + RJBits - 1, RJShift); 1758 } 1759 void setRJ(uint32_t rj) { 1760 data = (data & ~(RJMask << RJShift)) | (rj << RJShift); 1761 } 1762 uint32_t extractRD() { 1763 return extractBitField(RDShift + RDBits - 1, RDShift); 1764 } 1765 uint32_t extractImm16Value() { 1766 return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift); 1767 } 1768 void setBOffImm16(BOffImm16 off) { 1769 // Reset immediate field and replace it 1770 data = (data & ~BOffImm16Mask) | (off.encode() << Imm16Shift); 1771 } 1772 void setImm21(int32_t off) { 1773 // Reset immediate field and replace it 1774 uint32_t low16 = (off >> 2) & Imm16Mask; 1775 int32_t high5 = (off >> 18) & Imm5Mask; 1776 uint32_t fcc_info = (data >> 5) & 0x1F; 1777 data = (data & ~BOffImm26Mask) | (low16 << Imm16Shift) | high5 | 1778 (fcc_info << 5); 1779 } 1780 }; 1781 1782 // Class for Jump type instructions. 1783 class InstJump : public Instruction { 1784 public: 1785 InstJump(OpcodeField op, JOffImm26 off) 1786 : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift | 1787 (off.encode() & Imm26Mask) >> 16) { 1788 MOZ_ASSERT(op == op_b || op == op_bl); 1789 } 1790 1791 void setJOffImm26(JOffImm26 off) { 1792 // Reset immediate field and replace it 1793 data = (data & ~BOffImm26Mask) | 1794 ((off.encode() & Imm16Mask) << Imm16Shift) | 1795 ((off.encode() >> 16) & 0x3ff); 1796 } 1797 uint32_t extractImm26Value() { 1798 return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift); 1799 } 1800 }; 1801 1802 class ABIArgGenerator : public ABIArgGeneratorShared { 1803 public: 1804 explicit ABIArgGenerator(ABIKind kind) 1805 : ABIArgGeneratorShared(kind), 1806 intRegIndex_(0), 1807 floatRegIndex_(0), 1808 current_() {} 1809 1810 ABIArg next(MIRType argType); 1811 ABIArg& current() { return current_; } 1812 1813 protected: 1814 unsigned intRegIndex_; 1815 unsigned floatRegIndex_; 1816 ABIArg current_; 1817 }; 1818 1819 class Assembler : public AssemblerLOONG64 { 1820 public: 1821 Assembler() : AssemblerLOONG64() {} 1822 1823 static uintptr_t GetPointer(uint8_t*); 1824 1825 using AssemblerLOONG64::bind; 1826 1827 static void Bind(uint8_t* rawCode, const CodeLabel& label); 1828 1829 void processCodeLabels(uint8_t* rawCode); 1830 1831 static void TraceJumpRelocations(JSTracer* trc, JitCode* code, 1832 CompactBufferReader& reader); 1833 static void TraceDataRelocations(JSTracer* trc, JitCode* code, 1834 CompactBufferReader& reader); 1835 1836 void bind(InstImm* inst, uintptr_t branch, uintptr_t target); 1837 1838 // Copy the assembly code to the given buffer, and perform any pending 1839 // relocations relying on the target address. 1840 void executableCopy(uint8_t* buffer); 1841 1842 static uint32_t PatchWrite_NearCallSize(); 1843 1844 static uint64_t ExtractLoad64Value(Instruction* inst0); 1845 static void UpdateLoad64Value(Instruction* inst0, uint64_t value); 1846 static void WriteLoad64Instructions(Instruction* inst0, Register reg, 1847 uint64_t value); 1848 1849 static void PatchWrite_NearCall(CodeLocationLabel start, 1850 CodeLocationLabel toCall); 1851 static void PatchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, 1852 ImmPtr expectedValue); 1853 static void PatchDataWithValueCheck(CodeLocationLabel label, 1854 PatchedImmPtr newValue, 1855 PatchedImmPtr expectedValue); 1856 1857 static uint64_t ExtractInstructionImmediate(uint8_t* code); 1858 1859 static void ToggleCall(CodeLocationLabel inst_, bool enabled); 1860 }; // Assembler 1861 1862 static const uint32_t NumIntArgRegs = 8; 1863 static const uint32_t NumFloatArgRegs = 8; 1864 1865 static inline bool GetIntArgReg(uint32_t usedIntArgs, Register* out) { 1866 if (usedIntArgs < NumIntArgRegs) { 1867 *out = Register::FromCode(a0.code() + usedIntArgs); 1868 return true; 1869 } 1870 return false; 1871 } 1872 1873 static inline bool GetFloatArgReg(uint32_t usedFloatArgs, FloatRegister* out) { 1874 if (usedFloatArgs < NumFloatArgRegs) { 1875 *out = FloatRegister::FromCode(f0.code() + usedFloatArgs); 1876 return true; 1877 } 1878 return false; 1879 } 1880 1881 // Get a register in which we plan to put a quantity that will be used as an 1882 // integer argument. This differs from GetIntArgReg in that if we have no more 1883 // actual argument registers to use we will fall back on using whatever 1884 // CallTempReg* don't overlap the argument registers, and only fail once those 1885 // run out too. 1886 static inline bool GetTempRegForIntArg(uint32_t usedIntArgs, 1887 uint32_t usedFloatArgs, Register* out) { 1888 // NOTE: We can't properly determine which regs are used if there are 1889 // float arguments. If this is needed, we will have to guess. 1890 MOZ_ASSERT(usedFloatArgs == 0); 1891 1892 if (GetIntArgReg(usedIntArgs, out)) { 1893 return true; 1894 } 1895 // Unfortunately, we have to assume things about the point at which 1896 // GetIntArgReg returns false, because we need to know how many registers it 1897 // can allocate. 1898 usedIntArgs -= NumIntArgRegs; 1899 if (usedIntArgs >= NumCallTempNonArgRegs) { 1900 return false; 1901 } 1902 *out = CallTempNonArgRegs[usedIntArgs]; 1903 return true; 1904 } 1905 1906 } // namespace jit 1907 } // namespace js 1908 1909 #endif /* jit_loong64_Assembler_loong64_h */