Assembler-loong64.cpp (96942B)
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 #include "jit/loong64/Assembler-loong64.h" 8 9 #include "mozilla/DebugOnly.h" 10 #include "mozilla/Maybe.h" 11 12 #include "gc/Marking.h" 13 #include "jit/AutoWritableJitCode.h" 14 #include "jit/ExecutableAllocator.h" 15 #include "vm/Realm.h" 16 #include "wasm/WasmFrame.h" 17 18 using mozilla::DebugOnly; 19 20 using namespace js; 21 using namespace js::jit; 22 23 ABIArg ABIArgGenerator::next(MIRType type) { 24 switch (type) { 25 case MIRType::Int32: 26 case MIRType::Int64: 27 case MIRType::Pointer: 28 case MIRType::WasmAnyRef: 29 case MIRType::WasmArrayData: 30 case MIRType::StackResults: { 31 if (intRegIndex_ == NumIntArgRegs) { 32 current_ = ABIArg(stackOffset_); 33 stackOffset_ += sizeof(uintptr_t); 34 break; 35 } 36 current_ = ABIArg(Register::FromCode(intRegIndex_ + a0.encoding())); 37 intRegIndex_++; 38 break; 39 } 40 case MIRType::Float32: 41 case MIRType::Double: { 42 if (floatRegIndex_ == NumFloatArgRegs) { 43 // LoongArch floating-point parameters calling convention: 44 // The first 8 floating-point parameters should be passed in f0-f7, 45 // and the rest will be passed like integer parameters. 46 if (kind_ == ABIKind::System && intRegIndex_ != NumIntArgRegs) { 47 current_ = ABIArg(Register::FromCode(intRegIndex_ + a0.encoding())); 48 intRegIndex_++; 49 break; 50 } 51 current_ = ABIArg(stackOffset_); 52 stackOffset_ += sizeof(double); 53 break; 54 } 55 current_ = ABIArg(FloatRegister( 56 FloatRegisters::Encoding(floatRegIndex_ + f0.encoding()), 57 type == MIRType::Double ? FloatRegisters::Double 58 : FloatRegisters::Single)); 59 floatRegIndex_++; 60 break; 61 } 62 case MIRType::Simd128: { 63 MOZ_CRASH("LoongArch does not support simd yet."); 64 break; 65 } 66 default: 67 MOZ_CRASH("Unexpected argument type"); 68 } 69 return current_; 70 } 71 72 // Encode a standard register when it is being used as rd, the rj, and 73 // an extra register(rk). These should never be called with an InvalidReg. 74 uint32_t js::jit::RJ(Register r) { 75 MOZ_ASSERT(r != InvalidReg); 76 return r.encoding() << RJShift; 77 } 78 79 uint32_t js::jit::RK(Register r) { 80 MOZ_ASSERT(r != InvalidReg); 81 return r.encoding() << RKShift; 82 } 83 84 uint32_t js::jit::RD(Register r) { 85 MOZ_ASSERT(r != InvalidReg); 86 return r.encoding() << RDShift; 87 } 88 89 uint32_t js::jit::FJ(FloatRegister r) { return r.encoding() << RJShift; } 90 91 uint32_t js::jit::FK(FloatRegister r) { return r.encoding() << RKShift; } 92 93 uint32_t js::jit::FD(FloatRegister r) { return r.encoding() << RDShift; } 94 95 uint32_t js::jit::FA(FloatRegister r) { return r.encoding() << FAShift; } 96 97 uint32_t js::jit::SA2(uint32_t value) { 98 MOZ_ASSERT(value < 4); 99 return (value & SA2Mask) << SAShift; 100 } 101 102 uint32_t js::jit::SA3(uint32_t value) { 103 MOZ_ASSERT(value < 8); 104 return (value & SA3Mask) << SAShift; 105 } 106 107 Register js::jit::toRK(Instruction& i) { 108 return Register::FromCode(((i.encode() >> RKShift) & RKMask)); 109 } 110 111 Register js::jit::toRJ(Instruction& i) { 112 return Register::FromCode(((i.encode() >> RJShift) & RJMask)); 113 } 114 115 Register js::jit::toRD(Instruction& i) { 116 return Register::FromCode(((i.encode() >> RDShift) & RDMask)); 117 } 118 119 Register js::jit::toR(Instruction& i) { 120 return Register::FromCode(i.encode() & RegMask); 121 } 122 123 void InstImm::extractImm16(BOffImm16* dest) { *dest = BOffImm16(*this); } 124 125 void AssemblerLOONG64::finish() { 126 MOZ_ASSERT(!isFinished); 127 isFinished = true; 128 } 129 130 bool AssemblerLOONG64::appendRawCode(const uint8_t* code, size_t numBytes) { 131 return m_buffer.appendRawCode(code, numBytes); 132 } 133 134 bool AssemblerLOONG64::reserve(size_t size) { 135 // This buffer uses fixed-size chunks so there's no point in reserving 136 // now vs. on-demand. 137 return !oom(); 138 } 139 140 bool AssemblerLOONG64::swapBuffer(wasm::Bytes& bytes) { 141 // For now, specialize to the one use case. As long as wasm::Bytes is a 142 // Vector, not a linked-list of chunks, there's not much we can do other 143 // than copy. 144 MOZ_ASSERT(bytes.empty()); 145 if (!bytes.resize(bytesNeeded())) { 146 return false; 147 } 148 m_buffer.executableCopy(bytes.begin()); 149 return true; 150 } 151 152 void AssemblerLOONG64::copyJumpRelocationTable(uint8_t* dest) { 153 if (jumpRelocations_.length()) { 154 memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length()); 155 } 156 } 157 158 void AssemblerLOONG64::copyDataRelocationTable(uint8_t* dest) { 159 if (dataRelocations_.length()) { 160 memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length()); 161 } 162 } 163 164 AssemblerLOONG64::Condition AssemblerLOONG64::InvertCondition(Condition cond) { 165 switch (cond) { 166 case Equal: 167 return NotEqual; 168 case NotEqual: 169 return Equal; 170 case Zero: 171 return NonZero; 172 case NonZero: 173 return Zero; 174 case LessThan: 175 return GreaterThanOrEqual; 176 case LessThanOrEqual: 177 return GreaterThan; 178 case GreaterThan: 179 return LessThanOrEqual; 180 case GreaterThanOrEqual: 181 return LessThan; 182 case Above: 183 return BelowOrEqual; 184 case AboveOrEqual: 185 return Below; 186 case Below: 187 return AboveOrEqual; 188 case BelowOrEqual: 189 return Above; 190 case Signed: 191 return NotSigned; 192 case NotSigned: 193 return Signed; 194 default: 195 MOZ_CRASH("unexpected condition"); 196 } 197 } 198 199 AssemblerLOONG64::DoubleCondition AssemblerLOONG64::InvertCondition( 200 DoubleCondition cond) { 201 switch (cond) { 202 case DoubleOrdered: 203 return DoubleUnordered; 204 case DoubleEqual: 205 return DoubleNotEqualOrUnordered; 206 case DoubleNotEqual: 207 return DoubleEqualOrUnordered; 208 case DoubleGreaterThan: 209 return DoubleLessThanOrEqualOrUnordered; 210 case DoubleGreaterThanOrEqual: 211 return DoubleLessThanOrUnordered; 212 case DoubleLessThan: 213 return DoubleGreaterThanOrEqualOrUnordered; 214 case DoubleLessThanOrEqual: 215 return DoubleGreaterThanOrUnordered; 216 case DoubleUnordered: 217 return DoubleOrdered; 218 case DoubleEqualOrUnordered: 219 return DoubleNotEqual; 220 case DoubleNotEqualOrUnordered: 221 return DoubleEqual; 222 case DoubleGreaterThanOrUnordered: 223 return DoubleLessThanOrEqual; 224 case DoubleGreaterThanOrEqualOrUnordered: 225 return DoubleLessThan; 226 case DoubleLessThanOrUnordered: 227 return DoubleGreaterThanOrEqual; 228 case DoubleLessThanOrEqualOrUnordered: 229 return DoubleGreaterThan; 230 default: 231 MOZ_CRASH("unexpected condition"); 232 } 233 } 234 235 AssemblerLOONG64::Condition AssemblerLOONG64::SwapCmpOperandsCondition( 236 Condition cond) { 237 switch (cond) { 238 case Equal: 239 case NotEqual: 240 return cond; 241 case LessThan: 242 return GreaterThan; 243 case LessThanOrEqual: 244 return GreaterThanOrEqual; 245 case GreaterThan: 246 return LessThan; 247 case GreaterThanOrEqual: 248 return LessThanOrEqual; 249 case Above: 250 return Below; 251 case AboveOrEqual: 252 return BelowOrEqual; 253 case Below: 254 return Above; 255 case BelowOrEqual: 256 return AboveOrEqual; 257 default: 258 MOZ_CRASH("no meaningful swapped-operand condition"); 259 } 260 } 261 262 BOffImm16::BOffImm16(InstImm inst) 263 : data((inst.encode() >> Imm16Shift) & Imm16Mask) {} 264 265 Instruction* BOffImm16::getDest(Instruction* src) const { 266 return &src[(((int32_t)data << 16) >> 16) + 1]; 267 } 268 269 bool AssemblerLOONG64::oom() const { 270 return AssemblerShared::oom() || m_buffer.oom() || jumpRelocations_.oom() || 271 dataRelocations_.oom(); 272 } 273 274 // Size of the instruction stream, in bytes. 275 size_t AssemblerLOONG64::size() const { return m_buffer.size(); } 276 277 // Size of the relocation table, in bytes. 278 size_t AssemblerLOONG64::jumpRelocationTableBytes() const { 279 return jumpRelocations_.length(); 280 } 281 282 size_t AssemblerLOONG64::dataRelocationTableBytes() const { 283 return dataRelocations_.length(); 284 } 285 286 // Size of the data table, in bytes. 287 size_t AssemblerLOONG64::bytesNeeded() const { 288 return size() + jumpRelocationTableBytes() + dataRelocationTableBytes(); 289 } 290 291 // write a blob of binary into the instruction stream 292 BufferOffset AssemblerLOONG64::writeInst(uint32_t x, uint32_t* dest) { 293 MOZ_ASSERT(hasCreator()); 294 if (dest == nullptr) { 295 return m_buffer.putInt(x); 296 } 297 298 WriteInstStatic(x, dest); 299 return BufferOffset(); 300 } 301 302 void AssemblerLOONG64::WriteInstStatic(uint32_t x, uint32_t* dest) { 303 MOZ_ASSERT(dest != nullptr); 304 *dest = x; 305 } 306 307 BufferOffset AssemblerLOONG64::haltingAlign(int alignment) { 308 // TODO(loong64): Implement a proper halting align. 309 return nopAlign(alignment); 310 } 311 312 BufferOffset AssemblerLOONG64::nopAlign(int alignment) { 313 BufferOffset ret; 314 MOZ_ASSERT(m_buffer.isAligned(4)); 315 if (alignment == 8) { 316 if (!m_buffer.isAligned(alignment)) { 317 BufferOffset tmp = as_nop(); 318 if (!ret.assigned()) { 319 ret = tmp; 320 } 321 } 322 } else { 323 MOZ_ASSERT((alignment & (alignment - 1)) == 0); 324 while (size() & (alignment - 1)) { 325 BufferOffset tmp = as_nop(); 326 if (!ret.assigned()) { 327 ret = tmp; 328 } 329 } 330 } 331 return ret; 332 } 333 334 // Logical operations. 335 BufferOffset AssemblerLOONG64::as_and(Register rd, Register rj, Register rk) { 336 spew("and %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 337 return writeInst(InstReg(op_and, rk, rj, rd).encode()); 338 } 339 340 BufferOffset AssemblerLOONG64::as_or(Register rd, Register rj, Register rk) { 341 spew("or %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 342 return writeInst(InstReg(op_or, rk, rj, rd).encode()); 343 } 344 345 BufferOffset AssemblerLOONG64::as_xor(Register rd, Register rj, Register rk) { 346 spew("xor %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 347 return writeInst(InstReg(op_xor, rk, rj, rd).encode()); 348 } 349 350 BufferOffset AssemblerLOONG64::as_nor(Register rd, Register rj, Register rk) { 351 spew("nor %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 352 return writeInst(InstReg(op_nor, rk, rj, rd).encode()); 353 } 354 355 BufferOffset AssemblerLOONG64::as_andn(Register rd, Register rj, Register rk) { 356 spew("andn %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 357 return writeInst(InstReg(op_andn, rk, rj, rd).encode()); 358 } 359 360 BufferOffset AssemblerLOONG64::as_orn(Register rd, Register rj, Register rk) { 361 spew("orn %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 362 return writeInst(InstReg(op_orn, rk, rj, rd).encode()); 363 } 364 365 BufferOffset AssemblerLOONG64::as_andi(Register rd, Register rj, int32_t ui12) { 366 MOZ_ASSERT(is_uintN(ui12, 12)); 367 spew("andi %3s,%3s,0x%x", rd.name(), rj.name(), ui12); 368 return writeInst(InstImm(op_andi, ui12, rj, rd, 12).encode()); 369 } 370 371 BufferOffset AssemblerLOONG64::as_ori(Register rd, Register rj, int32_t ui12) { 372 MOZ_ASSERT(is_uintN(ui12, 12)); 373 spew("ori %3s,%3s,0x%x", rd.name(), rj.name(), ui12); 374 return writeInst(InstImm(op_ori, ui12, rj, rd, 12).encode()); 375 } 376 377 BufferOffset AssemblerLOONG64::as_xori(Register rd, Register rj, int32_t ui12) { 378 MOZ_ASSERT(is_uintN(ui12, 12)); 379 spew("xori %3s,%3s,0x%x", rd.name(), rj.name(), ui12); 380 return writeInst(InstImm(op_xori, ui12, rj, rd, 12).encode()); 381 } 382 383 // Branch and jump instructions 384 BufferOffset AssemblerLOONG64::as_b(JOffImm26 off) { 385 spew("b %d", off.decode()); 386 return writeInst(InstJump(op_b, off).encode()); 387 } 388 389 BufferOffset AssemblerLOONG64::as_bl(JOffImm26 off) { 390 spew("bl %d", off.decode()); 391 return writeInst(InstJump(op_bl, off).encode()); 392 } 393 394 BufferOffset AssemblerLOONG64::as_jirl(Register rd, Register rj, 395 BOffImm16 off) { 396 spew("jirl %3s, %3s, %d", rd.name(), rj.name(), off.decode()); 397 return writeInst(InstImm(op_jirl, off, rj, rd).encode()); 398 } 399 400 InstImm AssemblerLOONG64::getBranchCode(JumpOrCall jumpOrCall) { 401 // jirl or beq 402 if (jumpOrCall == BranchIsCall) { 403 return InstImm(op_jirl, BOffImm16(0), zero, ra); 404 } 405 406 return InstImm(op_beq, BOffImm16(0), zero, zero); 407 } 408 409 InstImm AssemblerLOONG64::getBranchCode(Register rj, Register rd, Condition c) { 410 // beq, bne 411 MOZ_ASSERT(c == AssemblerLOONG64::Equal || c == AssemblerLOONG64::NotEqual); 412 return InstImm(c == AssemblerLOONG64::Equal ? op_beq : op_bne, BOffImm16(0), 413 rj, rd); 414 } 415 416 InstImm AssemblerLOONG64::getBranchCode(Register rj, Condition c) { 417 // beq, bne, blt, bge 418 switch (c) { 419 case AssemblerLOONG64::Equal: 420 case AssemblerLOONG64::Zero: 421 case AssemblerLOONG64::BelowOrEqual: 422 return InstImm(op_beq, BOffImm16(0), rj, zero); 423 case AssemblerLOONG64::NotEqual: 424 case AssemblerLOONG64::NonZero: 425 case AssemblerLOONG64::Above: 426 return InstImm(op_bne, BOffImm16(0), rj, zero); 427 case AssemblerLOONG64::GreaterThan: 428 return InstImm(op_blt, BOffImm16(0), zero, rj); 429 case AssemblerLOONG64::GreaterThanOrEqual: 430 case AssemblerLOONG64::NotSigned: 431 return InstImm(op_bge, BOffImm16(0), rj, zero); 432 case AssemblerLOONG64::LessThan: 433 case AssemblerLOONG64::Signed: 434 return InstImm(op_blt, BOffImm16(0), rj, zero); 435 case AssemblerLOONG64::LessThanOrEqual: 436 return InstImm(op_bge, BOffImm16(0), zero, rj); 437 default: 438 MOZ_CRASH("Condition not supported."); 439 } 440 } 441 442 // Code semantics must conform to compareFloatingpoint 443 InstImm AssemblerLOONG64::getBranchCode(FPConditionBit cj) { 444 return InstImm(op_bcz, 0, cj, true); // bcnez 445 } 446 447 // Arithmetic instructions 448 BufferOffset AssemblerLOONG64::as_add_w(Register rd, Register rj, Register rk) { 449 spew("add_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 450 return writeInst(InstReg(op_add_w, rk, rj, rd).encode()); 451 } 452 453 BufferOffset AssemblerLOONG64::as_add_d(Register rd, Register rj, Register rk) { 454 spew("add_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 455 return writeInst(InstReg(op_add_d, rk, rj, rd).encode()); 456 } 457 458 BufferOffset AssemblerLOONG64::as_sub_w(Register rd, Register rj, Register rk) { 459 spew("sub_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 460 return writeInst(InstReg(op_sub_w, rk, rj, rd).encode()); 461 } 462 463 BufferOffset AssemblerLOONG64::as_sub_d(Register rd, Register rj, Register rk) { 464 spew("sub_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 465 return writeInst(InstReg(op_sub_d, rk, rj, rd).encode()); 466 } 467 468 BufferOffset AssemblerLOONG64::as_addi_w(Register rd, Register rj, 469 int32_t si12) { 470 MOZ_ASSERT(is_intN(si12, 12)); 471 spew("addi_w %3s,%3s,0x%x", rd.name(), rj.name(), si12); 472 return writeInst(InstImm(op_addi_w, si12, rj, rd, 12).encode()); 473 } 474 475 BufferOffset AssemblerLOONG64::as_addi_d(Register rd, Register rj, 476 int32_t si12) { 477 MOZ_ASSERT(is_intN(si12, 12)); 478 spew("addi_d %3s,%3s,0x%x", rd.name(), rj.name(), si12); 479 return writeInst(InstImm(op_addi_d, si12, rj, rd, 12).encode()); 480 } 481 482 BufferOffset AssemblerLOONG64::as_addu16i_d(Register rd, Register rj, 483 int32_t si16) { 484 MOZ_ASSERT(Imm16::IsInSignedRange(si16)); 485 spew("addu16i_d %3s,%3s,0x%x", rd.name(), rj.name(), si16); 486 return writeInst(InstImm(op_addu16i_d, Imm16(si16), rj, rd).encode()); 487 } 488 489 BufferOffset AssemblerLOONG64::as_alsl_w(Register rd, Register rj, Register rk, 490 uint32_t sa2) { 491 MOZ_ASSERT(sa2 < 4); 492 spew("alsl_w %3s,%3s,0x%x", rd.name(), rj.name(), sa2); 493 return writeInst(InstReg(op_alsl_w, sa2, rk, rj, rd, 2).encode()); 494 } 495 496 BufferOffset AssemblerLOONG64::as_alsl_wu(Register rd, Register rj, Register rk, 497 uint32_t sa2) { 498 MOZ_ASSERT(sa2 < 4); 499 spew("alsl_wu %3s,%3s,0x%x", rd.name(), rj.name(), sa2); 500 return writeInst(InstReg(op_alsl_wu, sa2, rk, rj, rd, 2).encode()); 501 } 502 503 BufferOffset AssemblerLOONG64::as_alsl_d(Register rd, Register rj, Register rk, 504 uint32_t sa2) { 505 MOZ_ASSERT(sa2 < 4); 506 spew("alsl_d %3s,%3s,%3s,0x%x", rd.name(), rj.name(), rk.name(), sa2); 507 return writeInst(InstReg(op_alsl_d, sa2, rk, rj, rd, 2).encode()); 508 } 509 510 BufferOffset AssemblerLOONG64::as_lu12i_w(Register rd, int32_t si20) { 511 spew("lu12i_w %3s,0x%x", rd.name(), si20); 512 return writeInst(InstImm(op_lu12i_w, si20, rd, false).encode()); 513 } 514 515 BufferOffset AssemblerLOONG64::as_lu32i_d(Register rd, int32_t si20) { 516 spew("lu32i_d %3s,0x%x", rd.name(), si20); 517 return writeInst(InstImm(op_lu32i_d, si20, rd, false).encode()); 518 } 519 520 BufferOffset AssemblerLOONG64::as_lu52i_d(Register rd, Register rj, 521 int32_t si12) { 522 MOZ_ASSERT(is_uintN(si12, 12)); 523 spew("lu52i_d %3s,%3s,0x%x", rd.name(), rj.name(), si12); 524 return writeInst(InstImm(op_lu52i_d, si12, rj, rd, 12).encode()); 525 } 526 527 BufferOffset AssemblerLOONG64::as_slt(Register rd, Register rj, Register rk) { 528 spew("slt %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 529 return writeInst(InstReg(op_slt, rk, rj, rd).encode()); 530 } 531 532 BufferOffset AssemblerLOONG64::as_sltu(Register rd, Register rj, Register rk) { 533 spew("sltu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 534 return writeInst(InstReg(op_sltu, rk, rj, rd).encode()); 535 } 536 537 BufferOffset AssemblerLOONG64::as_slti(Register rd, Register rj, int32_t si12) { 538 MOZ_ASSERT(is_intN(si12, 12)); 539 spew("slti %3s,%3s,0x%x", rd.name(), rj.name(), si12); 540 return writeInst(InstImm(op_slti, si12, rj, rd, 12).encode()); 541 } 542 543 BufferOffset AssemblerLOONG64::as_sltui(Register rd, Register rj, 544 int32_t si12) { 545 MOZ_ASSERT(is_intN(si12, 12)); 546 spew("sltui %3s,%3s,0x%x", rd.name(), rj.name(), si12); 547 return writeInst(InstImm(op_sltui, si12, rj, rd, 12).encode()); 548 } 549 550 BufferOffset AssemblerLOONG64::as_pcaddi(Register rd, int32_t si20) { 551 spew("pcaddi %3s,0x%x", rd.name(), si20); 552 return writeInst(InstImm(op_pcaddi, si20, rd, false).encode()); 553 } 554 555 BufferOffset AssemblerLOONG64::as_pcaddu12i(Register rd, int32_t si20) { 556 spew("pcaddu12i %3s,0x%x", rd.name(), si20); 557 return writeInst(InstImm(op_pcaddu12i, si20, rd, false).encode()); 558 } 559 560 BufferOffset AssemblerLOONG64::as_pcaddu18i(Register rd, int32_t si20) { 561 spew("pcaddu18i %3s,0x%x", rd.name(), si20); 562 return writeInst(InstImm(op_pcaddu18i, si20, rd, false).encode()); 563 } 564 565 BufferOffset AssemblerLOONG64::as_pcalau12i(Register rd, int32_t si20) { 566 spew("pcalau12i %3s,0x%x", rd.name(), si20); 567 return writeInst(InstImm(op_pcalau12i, si20, rd, false).encode()); 568 } 569 570 BufferOffset AssemblerLOONG64::as_mul_w(Register rd, Register rj, Register rk) { 571 spew("mul_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 572 return writeInst(InstReg(op_mul_w, rk, rj, rd).encode()); 573 } 574 575 BufferOffset AssemblerLOONG64::as_mulh_w(Register rd, Register rj, 576 Register rk) { 577 spew("mulh_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 578 return writeInst(InstReg(op_mulh_w, rk, rj, rd).encode()); 579 } 580 581 BufferOffset AssemblerLOONG64::as_mulh_wu(Register rd, Register rj, 582 Register rk) { 583 spew("mulh_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 584 return writeInst(InstReg(op_mulh_wu, rk, rj, rd).encode()); 585 } 586 587 BufferOffset AssemblerLOONG64::as_mul_d(Register rd, Register rj, Register rk) { 588 spew("mul_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 589 return writeInst(InstReg(op_mul_d, rk, rj, rd).encode()); 590 } 591 592 BufferOffset AssemblerLOONG64::as_mulh_d(Register rd, Register rj, 593 Register rk) { 594 spew("mulh_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 595 return writeInst(InstReg(op_mulh_d, rk, rj, rd).encode()); 596 } 597 598 BufferOffset AssemblerLOONG64::as_mulh_du(Register rd, Register rj, 599 Register rk) { 600 spew("mulh_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 601 return writeInst(InstReg(op_mulh_du, rk, rj, rd).encode()); 602 } 603 604 BufferOffset AssemblerLOONG64::as_mulw_d_w(Register rd, Register rj, 605 Register rk) { 606 spew("mulw_d_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 607 return writeInst(InstReg(op_mulw_d_w, rk, rj, rd).encode()); 608 } 609 610 BufferOffset AssemblerLOONG64::as_mulw_d_wu(Register rd, Register rj, 611 Register rk) { 612 spew("mulw_d_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 613 return writeInst(InstReg(op_mulw_d_wu, rk, rj, rd).encode()); 614 } 615 616 BufferOffset AssemblerLOONG64::as_div_w(Register rd, Register rj, Register rk) { 617 spew("div_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 618 return writeInst(InstReg(op_div_w, rk, rj, rd).encode()); 619 } 620 621 BufferOffset AssemblerLOONG64::as_mod_w(Register rd, Register rj, Register rk) { 622 spew("mod_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 623 return writeInst(InstReg(op_mod_w, rk, rj, rd).encode()); 624 } 625 626 BufferOffset AssemblerLOONG64::as_div_wu(Register rd, Register rj, 627 Register rk) { 628 spew("div_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 629 return writeInst(InstReg(op_div_wu, rk, rj, rd).encode()); 630 } 631 632 BufferOffset AssemblerLOONG64::as_mod_wu(Register rd, Register rj, 633 Register rk) { 634 spew("mod_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 635 return writeInst(InstReg(op_mod_wu, rk, rj, rd).encode()); 636 } 637 638 BufferOffset AssemblerLOONG64::as_div_d(Register rd, Register rj, Register rk) { 639 spew("div_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 640 return writeInst(InstReg(op_div_d, rk, rj, rd).encode()); 641 } 642 643 BufferOffset AssemblerLOONG64::as_mod_d(Register rd, Register rj, Register rk) { 644 spew("mod_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 645 return writeInst(InstReg(op_mod_d, rk, rj, rd).encode()); 646 } 647 648 BufferOffset AssemblerLOONG64::as_div_du(Register rd, Register rj, 649 Register rk) { 650 spew("div_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 651 return writeInst(InstReg(op_div_du, rk, rj, rd).encode()); 652 } 653 654 BufferOffset AssemblerLOONG64::as_mod_du(Register rd, Register rj, 655 Register rk) { 656 spew("mod_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 657 return writeInst(InstReg(op_mod_du, rk, rj, rd).encode()); 658 } 659 660 // Shift instructions 661 BufferOffset AssemblerLOONG64::as_sll_w(Register rd, Register rj, Register rk) { 662 spew("sll_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 663 return writeInst(InstReg(op_sll_w, rk, rj, rd).encode()); 664 } 665 666 BufferOffset AssemblerLOONG64::as_srl_w(Register rd, Register rj, Register rk) { 667 spew("srl_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 668 return writeInst(InstReg(op_srl_w, rk, rj, rd).encode()); 669 } 670 671 BufferOffset AssemblerLOONG64::as_sra_w(Register rd, Register rj, Register rk) { 672 spew("sra_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 673 return writeInst(InstReg(op_sra_w, rk, rj, rd).encode()); 674 } 675 676 BufferOffset AssemblerLOONG64::as_rotr_w(Register rd, Register rj, 677 Register rk) { 678 spew("rotr_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 679 return writeInst(InstReg(op_rotr_w, rk, rj, rd).encode()); 680 } 681 682 BufferOffset AssemblerLOONG64::as_slli_w(Register rd, Register rj, 683 int32_t ui5) { 684 MOZ_ASSERT(is_uintN(ui5, 5)); 685 spew("slli_w %3s,%3s,0x%x", rd.name(), rj.name(), ui5); 686 return writeInst(InstImm(op_slli_w, ui5, rj, rd, 5).encode()); 687 } 688 689 BufferOffset AssemblerLOONG64::as_srli_w(Register rd, Register rj, 690 int32_t ui5) { 691 MOZ_ASSERT(is_uintN(ui5, 5)); 692 spew("srli_w %3s,%3s,0x%x", rd.name(), rj.name(), ui5); 693 return writeInst(InstImm(op_srli_w, ui5, rj, rd, 5).encode()); 694 } 695 696 BufferOffset AssemblerLOONG64::as_srai_w(Register rd, Register rj, 697 int32_t ui5) { 698 MOZ_ASSERT(is_uintN(ui5, 5)); 699 spew("srai_w %3s,%3s,0x%x", rd.name(), rj.name(), ui5); 700 return writeInst(InstImm(op_srai_w, ui5, rj, rd, 5).encode()); 701 } 702 703 BufferOffset AssemblerLOONG64::as_rotri_w(Register rd, Register rj, 704 int32_t ui5) { 705 MOZ_ASSERT(is_uintN(ui5, 5)); 706 spew("rotri_w %3s,%3s,0x%x", rd.name(), rj.name(), ui5); 707 return writeInst(InstImm(op_rotri_w, ui5, rj, rd, 5).encode()); 708 } 709 710 BufferOffset AssemblerLOONG64::as_sll_d(Register rd, Register rj, Register rk) { 711 spew("sll_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 712 return writeInst(InstReg(op_sll_d, rk, rj, rd).encode()); 713 } 714 715 BufferOffset AssemblerLOONG64::as_srl_d(Register rd, Register rj, Register rk) { 716 spew("srl_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 717 return writeInst(InstReg(op_srl_d, rk, rj, rd).encode()); 718 } 719 720 BufferOffset AssemblerLOONG64::as_sra_d(Register rd, Register rj, Register rk) { 721 spew("sra_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 722 return writeInst(InstReg(op_sra_d, rk, rj, rd).encode()); 723 } 724 725 BufferOffset AssemblerLOONG64::as_rotr_d(Register rd, Register rj, 726 Register rk) { 727 spew("rotr_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 728 return writeInst(InstReg(op_rotr_d, rk, rj, rd).encode()); 729 } 730 731 BufferOffset AssemblerLOONG64::as_slli_d(Register rd, Register rj, 732 int32_t ui6) { 733 MOZ_ASSERT(is_uintN(ui6, 6)); 734 spew("slli_d %3s,%3s,0x%x", rd.name(), rj.name(), ui6); 735 return writeInst(InstImm(op_slli_d, ui6, rj, rd, 6).encode()); 736 } 737 738 BufferOffset AssemblerLOONG64::as_srli_d(Register rd, Register rj, 739 int32_t ui6) { 740 MOZ_ASSERT(is_uintN(ui6, 6)); 741 spew("srli_d %3s,%3s,0x%x", rd.name(), rj.name(), ui6); 742 return writeInst(InstImm(op_srli_d, ui6, rj, rd, 6).encode()); 743 } 744 745 BufferOffset AssemblerLOONG64::as_srai_d(Register rd, Register rj, 746 int32_t ui6) { 747 MOZ_ASSERT(is_uintN(ui6, 6)); 748 spew("srai_d %3s,%3s,0x%x", rd.name(), rj.name(), ui6); 749 return writeInst(InstImm(op_srai_d, ui6, rj, rd, 6).encode()); 750 } 751 752 BufferOffset AssemblerLOONG64::as_rotri_d(Register rd, Register rj, 753 int32_t ui6) { 754 MOZ_ASSERT(is_uintN(ui6, 6)); 755 spew("rotri_d %3s,%3s,0x%x", rd.name(), rj.name(), ui6); 756 return writeInst(InstImm(op_rotri_d, ui6, rj, rd, 6).encode()); 757 } 758 759 // Bit operation instrucitons 760 BufferOffset AssemblerLOONG64::as_ext_w_b(Register rd, Register rj) { 761 spew("ext_w_b %3s,%3s", rd.name(), rj.name()); 762 return writeInst(InstReg(op_ext_w_b, rj, rd).encode()); 763 } 764 765 BufferOffset AssemblerLOONG64::as_ext_w_h(Register rd, Register rj) { 766 spew("ext_w_h %3s,%3s", rd.name(), rj.name()); 767 return writeInst(InstReg(op_ext_w_h, rj, rd).encode()); 768 } 769 770 BufferOffset AssemblerLOONG64::as_clo_w(Register rd, Register rj) { 771 spew("clo_w %3s,%3s", rd.name(), rj.name()); 772 return writeInst(InstReg(op_clo_w, rj, rd).encode()); 773 } 774 775 BufferOffset AssemblerLOONG64::as_clz_w(Register rd, Register rj) { 776 spew("clz_w %3s,%3s", rd.name(), rj.name()); 777 return writeInst(InstReg(op_clz_w, rj, rd).encode()); 778 } 779 780 BufferOffset AssemblerLOONG64::as_cto_w(Register rd, Register rj) { 781 spew("cto_w %3s,%3s", rd.name(), rj.name()); 782 return writeInst(InstReg(op_cto_w, rj, rd).encode()); 783 } 784 785 BufferOffset AssemblerLOONG64::as_ctz_w(Register rd, Register rj) { 786 spew("ctz_w %3s,%3s", rd.name(), rj.name()); 787 return writeInst(InstReg(op_ctz_w, rj, rd).encode()); 788 } 789 790 BufferOffset AssemblerLOONG64::as_clo_d(Register rd, Register rj) { 791 spew("clo_d %3s,%3s", rd.name(), rj.name()); 792 return writeInst(InstReg(op_clo_d, rj, rd).encode()); 793 } 794 795 BufferOffset AssemblerLOONG64::as_clz_d(Register rd, Register rj) { 796 spew("clz_d %3s,%3s", rd.name(), rj.name()); 797 return writeInst(InstReg(op_clz_d, rj, rd).encode()); 798 } 799 800 BufferOffset AssemblerLOONG64::as_cto_d(Register rd, Register rj) { 801 spew("cto_d %3s,%3s", rd.name(), rj.name()); 802 return writeInst(InstReg(op_cto_d, rj, rd).encode()); 803 } 804 805 BufferOffset AssemblerLOONG64::as_ctz_d(Register rd, Register rj) { 806 spew("ctz_d %3s,%3s", rd.name(), rj.name()); 807 return writeInst(InstReg(op_ctz_d, rj, rd).encode()); 808 } 809 810 BufferOffset AssemblerLOONG64::as_bytepick_w(Register rd, Register rj, 811 Register rk, int32_t sa2) { 812 MOZ_ASSERT(sa2 < 4); 813 spew("bytepick_w %3s,%3s,%3s, 0x%x", rd.name(), rj.name(), rk.name(), sa2); 814 return writeInst(InstReg(op_bytepick_w, sa2, rk, rj, rd, 2).encode()); 815 } 816 817 BufferOffset AssemblerLOONG64::as_bytepick_d(Register rd, Register rj, 818 Register rk, int32_t sa3) { 819 MOZ_ASSERT(sa3 < 8); 820 spew("bytepick_d %3s,%3s,%3s, 0x%x", rd.name(), rj.name(), rk.name(), sa3); 821 return writeInst(InstReg(op_bytepick_d, sa3, rk, rj, rd, 3).encode()); 822 } 823 824 BufferOffset AssemblerLOONG64::as_revb_2h(Register rd, Register rj) { 825 spew("revb_2h %3s,%3s", rd.name(), rj.name()); 826 return writeInst(InstReg(op_revb_2h, rj, rd).encode()); 827 } 828 829 BufferOffset AssemblerLOONG64::as_revb_4h(Register rd, Register rj) { 830 spew("revb_4h %3s,%3s", rd.name(), rj.name()); 831 return writeInst(InstReg(op_revb_4h, rj, rd).encode()); 832 } 833 834 BufferOffset AssemblerLOONG64::as_revb_2w(Register rd, Register rj) { 835 spew("revb_2w %3s,%3s", rd.name(), rj.name()); 836 return writeInst(InstReg(op_revb_2w, rj, rd).encode()); 837 } 838 839 BufferOffset AssemblerLOONG64::as_revb_d(Register rd, Register rj) { 840 spew("revb_d %3s,%3s", rd.name(), rj.name()); 841 return writeInst(InstReg(op_revb_d, rj, rd).encode()); 842 } 843 844 BufferOffset AssemblerLOONG64::as_revh_2w(Register rd, Register rj) { 845 spew("revh_2w %3s,%3s", rd.name(), rj.name()); 846 return writeInst(InstReg(op_revh_2w, rj, rd).encode()); 847 } 848 849 BufferOffset AssemblerLOONG64::as_revh_d(Register rd, Register rj) { 850 spew("revh_d %3s,%3s", rd.name(), rj.name()); 851 return writeInst(InstReg(op_revh_d, rj, rd).encode()); 852 } 853 854 BufferOffset AssemblerLOONG64::as_bitrev_4b(Register rd, Register rj) { 855 spew("bitrev_4b %3s,%3s", rd.name(), rj.name()); 856 return writeInst(InstReg(op_bitrev_4b, rj, rd).encode()); 857 } 858 859 BufferOffset AssemblerLOONG64::as_bitrev_8b(Register rd, Register rj) { 860 spew("bitrev_8b %3s,%3s", rd.name(), rj.name()); 861 return writeInst(InstReg(op_bitrev_8b, rj, rd).encode()); 862 } 863 864 BufferOffset AssemblerLOONG64::as_bitrev_w(Register rd, Register rj) { 865 spew("bitrev_w %3s,%3s", rd.name(), rj.name()); 866 return writeInst(InstReg(op_bitrev_w, rj, rd).encode()); 867 } 868 869 BufferOffset AssemblerLOONG64::as_bitrev_d(Register rd, Register rj) { 870 spew("bitrev_d %3s,%3s", rd.name(), rj.name()); 871 return writeInst(InstReg(op_bitrev_d, rj, rd).encode()); 872 } 873 874 BufferOffset AssemblerLOONG64::as_bstrins_w(Register rd, Register rj, 875 int32_t msbw, int32_t lsbw) { 876 MOZ_ASSERT(lsbw <= msbw); 877 spew("bstrins_w %3s,%3s,0x%x,0x%x", rd.name(), rj.name(), msbw, lsbw); 878 return writeInst(InstImm(op_bstr_w, msbw, lsbw, rj, rd, 5).encode()); 879 } 880 881 BufferOffset AssemblerLOONG64::as_bstrins_d(Register rd, Register rj, 882 int32_t msbd, int32_t lsbd) { 883 MOZ_ASSERT(lsbd <= msbd); 884 spew("bstrins_d %3s,%3s,0x%x,0x%x", rd.name(), rj.name(), msbd, lsbd); 885 return writeInst(InstImm(op_bstrins_d, msbd, lsbd, rj, rd, 6).encode()); 886 } 887 888 BufferOffset AssemblerLOONG64::as_bstrpick_w(Register rd, Register rj, 889 int32_t msbw, int32_t lsbw) { 890 MOZ_ASSERT(lsbw <= msbw); 891 spew("bstrpick_w %3s,%3s,0x%x,0x%x", rd.name(), rj.name(), msbw, lsbw); 892 return writeInst(InstImm(op_bstr_w, msbw, lsbw, rj, rd).encode()); 893 } 894 895 BufferOffset AssemblerLOONG64::as_bstrpick_d(Register rd, Register rj, 896 int32_t msbd, int32_t lsbd) { 897 MOZ_ASSERT(lsbd <= msbd); 898 spew("bstrpick_d %3s,%3s,0x%x,0x%x", rd.name(), rj.name(), msbd, lsbd); 899 return writeInst(InstImm(op_bstrpick_d, msbd, lsbd, rj, rd, 6).encode()); 900 } 901 902 BufferOffset AssemblerLOONG64::as_maskeqz(Register rd, Register rj, 903 Register rk) { 904 spew("maskeqz %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 905 return writeInst(InstReg(op_maskeqz, rk, rj, rd).encode()); 906 } 907 908 BufferOffset AssemblerLOONG64::as_masknez(Register rd, Register rj, 909 Register rk) { 910 spew("masknez %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 911 return writeInst(InstReg(op_masknez, rk, rj, rd).encode()); 912 } 913 914 // Load and store instructions 915 BufferOffset AssemblerLOONG64::as_ld_b(Register rd, Register rj, int32_t si12) { 916 MOZ_ASSERT(is_intN(si12, 12)); 917 spew("ld_b %3s,%3s,0x%x", rd.name(), rj.name(), si12); 918 return writeInst(InstImm(op_ld_b, si12, rj, rd, 12).encode()); 919 } 920 921 BufferOffset AssemblerLOONG64::as_ld_h(Register rd, Register rj, int32_t si12) { 922 MOZ_ASSERT(is_intN(si12, 12)); 923 spew("ld_h %3s,%3s,0x%x", rd.name(), rj.name(), si12); 924 return writeInst(InstImm(op_ld_h, si12, rj, rd, 12).encode()); 925 } 926 927 BufferOffset AssemblerLOONG64::as_ld_w(Register rd, Register rj, int32_t si12) { 928 MOZ_ASSERT(is_intN(si12, 12)); 929 spew("ld_w %3s,%3s,0x%x", rd.name(), rj.name(), si12); 930 return writeInst(InstImm(op_ld_w, si12, rj, rd, 12).encode()); 931 } 932 933 BufferOffset AssemblerLOONG64::as_ld_d(Register rd, Register rj, int32_t si12) { 934 MOZ_ASSERT(is_intN(si12, 12)); 935 spew("ld_d %3s,%3s,0x%x", rd.name(), rj.name(), si12); 936 return writeInst(InstImm(op_ld_d, si12, rj, rd, 12).encode()); 937 } 938 939 BufferOffset AssemblerLOONG64::as_ld_bu(Register rd, Register rj, 940 int32_t si12) { 941 MOZ_ASSERT(is_intN(si12, 12)); 942 spew("ld_bu %3s,%3s,0x%x", rd.name(), rj.name(), si12); 943 return writeInst(InstImm(op_ld_bu, si12, rj, rd, 12).encode()); 944 } 945 946 BufferOffset AssemblerLOONG64::as_ld_hu(Register rd, Register rj, 947 int32_t si12) { 948 MOZ_ASSERT(is_intN(si12, 12)); 949 spew("ld_hu %3s,%3s,0x%x", rd.name(), rj.name(), si12); 950 return writeInst(InstImm(op_ld_hu, si12, rj, rd, 12).encode()); 951 } 952 953 BufferOffset AssemblerLOONG64::as_ld_wu(Register rd, Register rj, 954 int32_t si12) { 955 MOZ_ASSERT(is_intN(si12, 12)); 956 spew("ld_wu %3s,%3s,0x%x", rd.name(), rj.name(), si12); 957 return writeInst(InstImm(op_ld_wu, si12, rj, rd, 12).encode()); 958 } 959 960 BufferOffset AssemblerLOONG64::as_st_b(Register rd, Register rj, int32_t si12) { 961 MOZ_ASSERT(is_intN(si12, 12)); 962 spew("st_b %3s,%3s,0x%x", rd.name(), rj.name(), si12); 963 return writeInst(InstImm(op_st_b, si12, rj, rd, 12).encode()); 964 } 965 966 BufferOffset AssemblerLOONG64::as_st_h(Register rd, Register rj, int32_t si12) { 967 MOZ_ASSERT(is_intN(si12, 12)); 968 spew("st_h %3s,%3s,0x%x", rd.name(), rj.name(), si12); 969 return writeInst(InstImm(op_st_h, si12, rj, rd, 12).encode()); 970 } 971 972 BufferOffset AssemblerLOONG64::as_st_w(Register rd, Register rj, int32_t si12) { 973 MOZ_ASSERT(is_intN(si12, 12)); 974 spew("st_w %3s,%3s,0x%x", rd.name(), rj.name(), si12); 975 return writeInst(InstImm(op_st_w, si12, rj, rd, 12).encode()); 976 } 977 978 BufferOffset AssemblerLOONG64::as_st_d(Register rd, Register rj, int32_t si12) { 979 MOZ_ASSERT(is_intN(si12, 12)); 980 spew("st_d %3s,%3s,0x%x", rd.name(), rj.name(), si12); 981 return writeInst(InstImm(op_st_d, si12, rj, rd, 12).encode()); 982 } 983 984 BufferOffset AssemblerLOONG64::as_ldx_b(Register rd, Register rj, Register rk) { 985 spew("ldx_b %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 986 return writeInst(InstReg(op_ldx_b, rk, rj, rd).encode()); 987 } 988 989 BufferOffset AssemblerLOONG64::as_ldx_h(Register rd, Register rj, Register rk) { 990 spew("ldx_h %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 991 return writeInst(InstReg(op_ldx_h, rk, rj, rd).encode()); 992 } 993 994 BufferOffset AssemblerLOONG64::as_ldx_w(Register rd, Register rj, Register rk) { 995 spew("ldx_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 996 return writeInst(InstReg(op_ldx_w, rk, rj, rd).encode()); 997 } 998 999 BufferOffset AssemblerLOONG64::as_ldx_d(Register rd, Register rj, Register rk) { 1000 spew("ldx_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1001 return writeInst(InstReg(op_ldx_d, rk, rj, rd).encode()); 1002 } 1003 1004 BufferOffset AssemblerLOONG64::as_ldx_bu(Register rd, Register rj, 1005 Register rk) { 1006 spew("ldx_bu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1007 return writeInst(InstReg(op_ldx_bu, rk, rj, rd).encode()); 1008 } 1009 1010 BufferOffset AssemblerLOONG64::as_ldx_hu(Register rd, Register rj, 1011 Register rk) { 1012 spew("ldx_hu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1013 return writeInst(InstReg(op_ldx_hu, rk, rj, rd).encode()); 1014 } 1015 1016 BufferOffset AssemblerLOONG64::as_ldx_wu(Register rd, Register rj, 1017 Register rk) { 1018 spew("ldx_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1019 return writeInst(InstReg(op_ldx_wu, rk, rj, rd).encode()); 1020 } 1021 1022 BufferOffset AssemblerLOONG64::as_stx_b(Register rd, Register rj, Register rk) { 1023 spew("stx_b %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1024 return writeInst(InstReg(op_stx_b, rk, rj, rd).encode()); 1025 } 1026 1027 BufferOffset AssemblerLOONG64::as_stx_h(Register rd, Register rj, Register rk) { 1028 spew("stx_h %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1029 return writeInst(InstReg(op_stx_h, rk, rj, rd).encode()); 1030 } 1031 1032 BufferOffset AssemblerLOONG64::as_stx_w(Register rd, Register rj, Register rk) { 1033 spew("stx_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1034 return writeInst(InstReg(op_stx_w, rk, rj, rd).encode()); 1035 } 1036 1037 BufferOffset AssemblerLOONG64::as_stx_d(Register rd, Register rj, Register rk) { 1038 spew("stx_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1039 return writeInst(InstReg(op_stx_d, rk, rj, rd).encode()); 1040 } 1041 1042 BufferOffset AssemblerLOONG64::as_ldptr_w(Register rd, Register rj, 1043 int32_t si14) { 1044 MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); 1045 spew("ldptr_w %3s,%3s,0x%x", rd.name(), rj.name(), si14); 1046 return writeInst(InstImm(op_ldptr_w, si14 >> 2, rj, rd, 14).encode()); 1047 } 1048 1049 BufferOffset AssemblerLOONG64::as_ldptr_d(Register rd, Register rj, 1050 int32_t si14) { 1051 MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); 1052 spew("ldptr_d %3s,%3s,0x%x", rd.name(), rj.name(), si14); 1053 return writeInst(InstImm(op_ldptr_d, si14 >> 2, rj, rd, 14).encode()); 1054 } 1055 1056 BufferOffset AssemblerLOONG64::as_stptr_w(Register rd, Register rj, 1057 int32_t si14) { 1058 MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); 1059 spew("stptr_w %3s,%3s,0x%x", rd.name(), rj.name(), si14); 1060 return writeInst(InstImm(op_stptr_w, si14 >> 2, rj, rd, 14).encode()); 1061 } 1062 1063 BufferOffset AssemblerLOONG64::as_stptr_d(Register rd, Register rj, 1064 int32_t si14) { 1065 MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); 1066 spew("stptr_d %3s,%3s,0x%x", rd.name(), rj.name(), si14); 1067 return writeInst(InstImm(op_stptr_d, si14 >> 2, rj, rd, 14).encode()); 1068 } 1069 1070 BufferOffset AssemblerLOONG64::as_preld(int32_t hint, Register rj, 1071 int32_t si12) { 1072 MOZ_ASSERT(is_intN(si12, 12)); 1073 spew("preld 0x%x,%3s,0x%x", hint, rj.name(), si12); 1074 return writeInst(InstImm(op_preld, si12, rj, hint).encode()); 1075 } 1076 1077 // Atomic instructions 1078 BufferOffset AssemblerLOONG64::as_amswap_w(Register rd, Register rj, 1079 Register rk) { 1080 spew("amswap_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1081 return writeInst(InstReg(op_amswap_w, rk, rj, rd).encode()); 1082 } 1083 1084 BufferOffset AssemblerLOONG64::as_amswap_d(Register rd, Register rj, 1085 Register rk) { 1086 spew("amswap_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1087 return writeInst(InstReg(op_amswap_d, rk, rj, rd).encode()); 1088 } 1089 1090 BufferOffset AssemblerLOONG64::as_amadd_w(Register rd, Register rj, 1091 Register rk) { 1092 spew("amadd_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1093 return writeInst(InstReg(op_amadd_w, rk, rj, rd).encode()); 1094 } 1095 1096 BufferOffset AssemblerLOONG64::as_amadd_d(Register rd, Register rj, 1097 Register rk) { 1098 spew("amadd_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1099 return writeInst(InstReg(op_amadd_d, rk, rj, rd).encode()); 1100 } 1101 1102 BufferOffset AssemblerLOONG64::as_amand_w(Register rd, Register rj, 1103 Register rk) { 1104 spew("amand_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1105 return writeInst(InstReg(op_amand_w, rk, rj, rd).encode()); 1106 } 1107 1108 BufferOffset AssemblerLOONG64::as_amand_d(Register rd, Register rj, 1109 Register rk) { 1110 spew("amand_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1111 return writeInst(InstReg(op_amand_d, rk, rj, rd).encode()); 1112 } 1113 1114 BufferOffset AssemblerLOONG64::as_amor_w(Register rd, Register rj, 1115 Register rk) { 1116 spew("amor_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1117 return writeInst(InstReg(op_amor_w, rk, rj, rd).encode()); 1118 } 1119 1120 BufferOffset AssemblerLOONG64::as_amor_d(Register rd, Register rj, 1121 Register rk) { 1122 spew("amor_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1123 return writeInst(InstReg(op_amor_d, rk, rj, rd).encode()); 1124 } 1125 1126 BufferOffset AssemblerLOONG64::as_amxor_w(Register rd, Register rj, 1127 Register rk) { 1128 spew("amxor_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1129 return writeInst(InstReg(op_amxor_w, rk, rj, rd).encode()); 1130 } 1131 1132 BufferOffset AssemblerLOONG64::as_amxor_d(Register rd, Register rj, 1133 Register rk) { 1134 spew("amxor_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1135 return writeInst(InstReg(op_amxor_d, rk, rj, rd).encode()); 1136 } 1137 1138 BufferOffset AssemblerLOONG64::as_ammax_w(Register rd, Register rj, 1139 Register rk) { 1140 spew("ammax_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1141 return writeInst(InstReg(op_ammax_w, rk, rj, rd).encode()); 1142 } 1143 1144 BufferOffset AssemblerLOONG64::as_ammax_d(Register rd, Register rj, 1145 Register rk) { 1146 spew("ammax_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1147 return writeInst(InstReg(op_ammax_d, rk, rj, rd).encode()); 1148 } 1149 1150 BufferOffset AssemblerLOONG64::as_ammin_w(Register rd, Register rj, 1151 Register rk) { 1152 spew("ammin_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1153 return writeInst(InstReg(op_ammin_w, rk, rj, rd).encode()); 1154 } 1155 1156 BufferOffset AssemblerLOONG64::as_ammin_d(Register rd, Register rj, 1157 Register rk) { 1158 spew("ammin_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1159 return writeInst(InstReg(op_ammin_d, rk, rj, rd).encode()); 1160 } 1161 1162 BufferOffset AssemblerLOONG64::as_ammax_wu(Register rd, Register rj, 1163 Register rk) { 1164 spew("ammax_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1165 return writeInst(InstReg(op_ammax_wu, rk, rj, rd).encode()); 1166 } 1167 1168 BufferOffset AssemblerLOONG64::as_ammax_du(Register rd, Register rj, 1169 Register rk) { 1170 spew("ammax_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1171 return writeInst(InstReg(op_ammax_du, rk, rj, rd).encode()); 1172 } 1173 1174 BufferOffset AssemblerLOONG64::as_ammin_wu(Register rd, Register rj, 1175 Register rk) { 1176 spew("ammin_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1177 return writeInst(InstReg(op_ammin_wu, rk, rj, rd).encode()); 1178 } 1179 1180 BufferOffset AssemblerLOONG64::as_ammin_du(Register rd, Register rj, 1181 Register rk) { 1182 spew("ammin_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1183 return writeInst(InstReg(op_ammin_du, rk, rj, rd).encode()); 1184 } 1185 1186 BufferOffset AssemblerLOONG64::as_amswap_db_w(Register rd, Register rj, 1187 Register rk) { 1188 spew("amswap_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1189 return writeInst(InstReg(op_amswap_db_w, rk, rj, rd).encode()); 1190 } 1191 1192 BufferOffset AssemblerLOONG64::as_amswap_db_d(Register rd, Register rj, 1193 Register rk) { 1194 spew("amswap_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1195 return writeInst(InstReg(op_amswap_db_d, rk, rj, rd).encode()); 1196 } 1197 1198 BufferOffset AssemblerLOONG64::as_amadd_db_w(Register rd, Register rj, 1199 Register rk) { 1200 spew("amadd_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1201 return writeInst(InstReg(op_amadd_db_w, rk, rj, rd).encode()); 1202 } 1203 1204 BufferOffset AssemblerLOONG64::as_amadd_db_d(Register rd, Register rj, 1205 Register rk) { 1206 spew("amadd_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1207 return writeInst(InstReg(op_amadd_db_d, rk, rj, rd).encode()); 1208 } 1209 1210 BufferOffset AssemblerLOONG64::as_amand_db_w(Register rd, Register rj, 1211 Register rk) { 1212 spew("amand_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1213 return writeInst(InstReg(op_amand_db_w, rk, rj, rd).encode()); 1214 } 1215 1216 BufferOffset AssemblerLOONG64::as_amand_db_d(Register rd, Register rj, 1217 Register rk) { 1218 spew("amand_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1219 return writeInst(InstReg(op_amand_db_d, rk, rj, rd).encode()); 1220 } 1221 1222 BufferOffset AssemblerLOONG64::as_amor_db_w(Register rd, Register rj, 1223 Register rk) { 1224 spew("amor_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1225 return writeInst(InstReg(op_amor_db_w, rk, rj, rd).encode()); 1226 } 1227 1228 BufferOffset AssemblerLOONG64::as_amor_db_d(Register rd, Register rj, 1229 Register rk) { 1230 spew("amor_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1231 return writeInst(InstReg(op_amor_db_d, rk, rj, rd).encode()); 1232 } 1233 1234 BufferOffset AssemblerLOONG64::as_amxor_db_w(Register rd, Register rj, 1235 Register rk) { 1236 spew("amxor_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1237 return writeInst(InstReg(op_amxor_db_w, rk, rj, rd).encode()); 1238 } 1239 1240 BufferOffset AssemblerLOONG64::as_amxor_db_d(Register rd, Register rj, 1241 Register rk) { 1242 spew("amxor_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1243 return writeInst(InstReg(op_amxor_db_d, rk, rj, rd).encode()); 1244 } 1245 1246 BufferOffset AssemblerLOONG64::as_ammax_db_w(Register rd, Register rj, 1247 Register rk) { 1248 spew("ammax_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1249 return writeInst(InstReg(op_ammax_db_w, rk, rj, rd).encode()); 1250 } 1251 1252 BufferOffset AssemblerLOONG64::as_ammax_db_d(Register rd, Register rj, 1253 Register rk) { 1254 spew("ammax_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1255 return writeInst(InstReg(op_ammax_db_d, rk, rj, rd).encode()); 1256 } 1257 1258 BufferOffset AssemblerLOONG64::as_ammin_db_w(Register rd, Register rj, 1259 Register rk) { 1260 spew("ammin_db_w %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1261 return writeInst(InstReg(op_ammin_db_w, rk, rj, rd).encode()); 1262 } 1263 1264 BufferOffset AssemblerLOONG64::as_ammin_db_d(Register rd, Register rj, 1265 Register rk) { 1266 spew("ammin_db_d %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1267 return writeInst(InstReg(op_ammin_db_d, rk, rj, rd).encode()); 1268 } 1269 1270 BufferOffset AssemblerLOONG64::as_ammax_db_wu(Register rd, Register rj, 1271 Register rk) { 1272 spew("ammax_db_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1273 return writeInst(InstReg(op_ammax_db_wu, rk, rj, rd).encode()); 1274 } 1275 1276 BufferOffset AssemblerLOONG64::as_ammax_db_du(Register rd, Register rj, 1277 Register rk) { 1278 spew("ammax_db_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1279 return writeInst(InstReg(op_ammax_db_du, rk, rj, rd).encode()); 1280 } 1281 1282 BufferOffset AssemblerLOONG64::as_ammin_db_wu(Register rd, Register rj, 1283 Register rk) { 1284 spew("ammin_db_wu %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1285 return writeInst(InstReg(op_ammin_db_wu, rk, rj, rd).encode()); 1286 } 1287 1288 BufferOffset AssemblerLOONG64::as_ammin_db_du(Register rd, Register rj, 1289 Register rk) { 1290 spew("ammin_db_du %3s,%3s,%3s", rd.name(), rj.name(), rk.name()); 1291 return writeInst(InstReg(op_ammin_db_du, rk, rj, rd).encode()); 1292 } 1293 1294 BufferOffset AssemblerLOONG64::as_ll_w(Register rd, Register rj, int32_t si14) { 1295 spew("ll_w %3s,%3s,0x%x", rd.name(), rj.name(), si14); 1296 MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); 1297 return writeInst(InstImm(op_ll_w, si14 >> 2, rj, rd, 14).encode()); 1298 } 1299 1300 BufferOffset AssemblerLOONG64::as_ll_d(Register rd, Register rj, int32_t si14) { 1301 spew("ll_d %3s,%3s,0x%x", rd.name(), rj.name(), si14); 1302 MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); 1303 return writeInst(InstImm(op_ll_d, si14 >> 2, rj, rd, 14).encode()); 1304 } 1305 1306 BufferOffset AssemblerLOONG64::as_sc_w(Register rd, Register rj, int32_t si14) { 1307 spew("sc_w %3s,%3s,0x%x", rd.name(), rj.name(), si14); 1308 MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); 1309 return writeInst(InstImm(op_sc_w, si14 >> 2, rj, rd, 14).encode()); 1310 } 1311 1312 BufferOffset AssemblerLOONG64::as_sc_d(Register rd, Register rj, int32_t si14) { 1313 spew("sc_d %3s,%3s,0x%x", rd.name(), rj.name(), si14); 1314 MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0)); 1315 return writeInst(InstImm(op_sc_d, si14 >> 2, rj, rd, 14).encode()); 1316 } 1317 1318 // Barrier instructions 1319 BufferOffset AssemblerLOONG64::as_dbar(int32_t hint) { 1320 MOZ_ASSERT(is_uintN(hint, 15)); 1321 spew("dbar 0x%x", hint); 1322 return writeInst(InstImm(op_dbar, hint).encode()); 1323 } 1324 1325 BufferOffset AssemblerLOONG64::as_ibar(int32_t hint) { 1326 MOZ_ASSERT(is_uintN(hint, 15)); 1327 spew("ibar 0x%x", hint); 1328 return writeInst(InstImm(op_ibar, hint).encode()); 1329 } 1330 1331 /* =============================================================== */ 1332 1333 // FP Arithmetic instructions 1334 BufferOffset AssemblerLOONG64::as_fadd_s(FloatRegister fd, FloatRegister fj, 1335 FloatRegister fk) { 1336 spew("fadd_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1337 return writeInst(InstReg(op_fadd_s, fk, fj, fd).encode()); 1338 } 1339 1340 BufferOffset AssemblerLOONG64::as_fadd_d(FloatRegister fd, FloatRegister fj, 1341 FloatRegister fk) { 1342 spew("fadd_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1343 return writeInst(InstReg(op_fadd_d, fk, fj, fd).encode()); 1344 } 1345 1346 BufferOffset AssemblerLOONG64::as_fsub_s(FloatRegister fd, FloatRegister fj, 1347 FloatRegister fk) { 1348 spew("fsub_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1349 return writeInst(InstReg(op_fsub_s, fk, fj, fd).encode()); 1350 } 1351 1352 BufferOffset AssemblerLOONG64::as_fsub_d(FloatRegister fd, FloatRegister fj, 1353 FloatRegister fk) { 1354 spew("fsub_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1355 return writeInst(InstReg(op_fsub_d, fk, fj, fd).encode()); 1356 } 1357 1358 BufferOffset AssemblerLOONG64::as_fmul_s(FloatRegister fd, FloatRegister fj, 1359 FloatRegister fk) { 1360 spew("fmul_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1361 return writeInst(InstReg(op_fmul_s, fk, fj, fd).encode()); 1362 } 1363 1364 BufferOffset AssemblerLOONG64::as_fmul_d(FloatRegister fd, FloatRegister fj, 1365 FloatRegister fk) { 1366 spew("fmul_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1367 return writeInst(InstReg(op_fmul_d, fk, fj, fd).encode()); 1368 } 1369 1370 BufferOffset AssemblerLOONG64::as_fdiv_s(FloatRegister fd, FloatRegister fj, 1371 FloatRegister fk) { 1372 spew("fdiv_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1373 return writeInst(InstReg(op_fdiv_s, fk, fj, fd).encode()); 1374 } 1375 1376 BufferOffset AssemblerLOONG64::as_fdiv_d(FloatRegister fd, FloatRegister fj, 1377 FloatRegister fk) { 1378 spew("fdiv_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1379 return writeInst(InstReg(op_fdiv_d, fk, fj, fd).encode()); 1380 } 1381 1382 BufferOffset AssemblerLOONG64::as_fmadd_s(FloatRegister fd, FloatRegister fj, 1383 FloatRegister fk, FloatRegister fa) { 1384 spew("fmadd_s %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), 1385 fa.name()); 1386 return writeInst(InstReg(op_fmadd_s, fa, fk, fj, fd).encode()); 1387 } 1388 1389 BufferOffset AssemblerLOONG64::as_fmadd_d(FloatRegister fd, FloatRegister fj, 1390 FloatRegister fk, FloatRegister fa) { 1391 spew("fmadd_d %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), 1392 fa.name()); 1393 return writeInst(InstReg(op_fmadd_d, fa, fk, fj, fd).encode()); 1394 } 1395 1396 BufferOffset AssemblerLOONG64::as_fmsub_s(FloatRegister fd, FloatRegister fj, 1397 FloatRegister fk, FloatRegister fa) { 1398 spew("fmsub_s %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), 1399 fa.name()); 1400 return writeInst(InstReg(op_fmsub_s, fa, fk, fj, fd).encode()); 1401 } 1402 1403 BufferOffset AssemblerLOONG64::as_fmsub_d(FloatRegister fd, FloatRegister fj, 1404 FloatRegister fk, FloatRegister fa) { 1405 spew("fmsub_d %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), 1406 fa.name()); 1407 return writeInst(InstReg(op_fmsub_d, fa, fk, fj, fd).encode()); 1408 } 1409 1410 BufferOffset AssemblerLOONG64::as_fnmadd_s(FloatRegister fd, FloatRegister fj, 1411 FloatRegister fk, FloatRegister fa) { 1412 spew("fnmadd_s %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), 1413 fa.name()); 1414 return writeInst(InstReg(op_fnmadd_s, fa, fk, fj, fd).encode()); 1415 } 1416 1417 BufferOffset AssemblerLOONG64::as_fnmadd_d(FloatRegister fd, FloatRegister fj, 1418 FloatRegister fk, FloatRegister fa) { 1419 spew("fnmadd_d %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), 1420 fa.name()); 1421 return writeInst(InstReg(op_fnmadd_d, fa, fk, fj, fd).encode()); 1422 } 1423 1424 BufferOffset AssemblerLOONG64::as_fnmsub_s(FloatRegister fd, FloatRegister fj, 1425 FloatRegister fk, FloatRegister fa) { 1426 spew("fnmsub_s %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), 1427 fa.name()); 1428 return writeInst(InstReg(op_fnmsub_s, fa, fk, fj, fd).encode()); 1429 } 1430 1431 BufferOffset AssemblerLOONG64::as_fnmsub_d(FloatRegister fd, FloatRegister fj, 1432 FloatRegister fk, FloatRegister fa) { 1433 spew("fnmsub_d %3s,%3s,%3s,%3s", fd.name(), fj.name(), fk.name(), 1434 fa.name()); 1435 return writeInst(InstReg(op_fnmsub_d, fa, fk, fj, fd).encode()); 1436 } 1437 1438 BufferOffset AssemblerLOONG64::as_fmax_s(FloatRegister fd, FloatRegister fj, 1439 FloatRegister fk) { 1440 spew("fmax_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1441 return writeInst(InstReg(op_fmax_s, fk, fj, fd).encode()); 1442 } 1443 1444 BufferOffset AssemblerLOONG64::as_fmax_d(FloatRegister fd, FloatRegister fj, 1445 FloatRegister fk) { 1446 spew("fmax_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1447 return writeInst(InstReg(op_fmax_d, fk, fj, fd).encode()); 1448 } 1449 1450 BufferOffset AssemblerLOONG64::as_fmin_s(FloatRegister fd, FloatRegister fj, 1451 FloatRegister fk) { 1452 spew("fmin_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1453 return writeInst(InstReg(op_fmin_s, fk, fj, fd).encode()); 1454 } 1455 1456 BufferOffset AssemblerLOONG64::as_fmin_d(FloatRegister fd, FloatRegister fj, 1457 FloatRegister fk) { 1458 spew("fmin_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1459 return writeInst(InstReg(op_fmin_d, fk, fj, fd).encode()); 1460 } 1461 1462 BufferOffset AssemblerLOONG64::as_fmaxa_s(FloatRegister fd, FloatRegister fj, 1463 FloatRegister fk) { 1464 spew("fmaxa_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1465 return writeInst(InstReg(op_fmaxa_s, fk, fj, fd).encode()); 1466 } 1467 1468 BufferOffset AssemblerLOONG64::as_fmaxa_d(FloatRegister fd, FloatRegister fj, 1469 FloatRegister fk) { 1470 spew("fmaxa_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1471 return writeInst(InstReg(op_fmaxa_d, fk, fj, fd).encode()); 1472 } 1473 1474 BufferOffset AssemblerLOONG64::as_fmina_s(FloatRegister fd, FloatRegister fj, 1475 FloatRegister fk) { 1476 spew("fmina_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1477 return writeInst(InstReg(op_fmina_s, fk, fj, fd).encode()); 1478 } 1479 1480 BufferOffset AssemblerLOONG64::as_fmina_d(FloatRegister fd, FloatRegister fj, 1481 FloatRegister fk) { 1482 spew("fmina_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1483 return writeInst(InstReg(op_fmina_d, fk, fj, fd).encode()); 1484 } 1485 1486 BufferOffset AssemblerLOONG64::as_fabs_s(FloatRegister fd, FloatRegister fj) { 1487 spew("fabs_s %3s,%3s", fd.name(), fj.name()); 1488 return writeInst(InstReg(op_fabs_s, fj, fd).encode()); 1489 } 1490 1491 BufferOffset AssemblerLOONG64::as_fabs_d(FloatRegister fd, FloatRegister fj) { 1492 spew("fabs_d %3s,%3s", fd.name(), fj.name()); 1493 return writeInst(InstReg(op_fabs_d, fj, fd).encode()); 1494 } 1495 1496 BufferOffset AssemblerLOONG64::as_fneg_s(FloatRegister fd, FloatRegister fj) { 1497 spew("fneg_s %3s,%3s", fd.name(), fj.name()); 1498 return writeInst(InstReg(op_fneg_s, fj, fd).encode()); 1499 } 1500 1501 BufferOffset AssemblerLOONG64::as_fneg_d(FloatRegister fd, FloatRegister fj) { 1502 spew("fneg_d %3s,%3s", fd.name(), fj.name()); 1503 return writeInst(InstReg(op_fneg_d, fj, fd).encode()); 1504 } 1505 1506 BufferOffset AssemblerLOONG64::as_fsqrt_s(FloatRegister fd, FloatRegister fj) { 1507 spew("fsqrt_s %3s,%3s", fd.name(), fj.name()); 1508 return writeInst(InstReg(op_fsqrt_s, fj, fd).encode()); 1509 } 1510 1511 BufferOffset AssemblerLOONG64::as_fsqrt_d(FloatRegister fd, FloatRegister fj) { 1512 spew("fsqrt_d %3s,%3s", fd.name(), fj.name()); 1513 return writeInst(InstReg(op_fsqrt_d, fj, fd).encode()); 1514 } 1515 1516 BufferOffset AssemblerLOONG64::as_fcopysign_s(FloatRegister fd, 1517 FloatRegister fj, 1518 FloatRegister fk) { 1519 spew("fcopysign_s %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1520 return writeInst(InstReg(op_fcopysign_s, fk, fj, fd).encode()); 1521 } 1522 1523 BufferOffset AssemblerLOONG64::as_fcopysign_d(FloatRegister fd, 1524 FloatRegister fj, 1525 FloatRegister fk) { 1526 spew("fcopysign_d %3s,%3s,%3s", fd.name(), fj.name(), fk.name()); 1527 return writeInst(InstReg(op_fcopysign_d, fk, fj, fd).encode()); 1528 } 1529 1530 // FP compare instructions 1531 // fcmp.cond.s and fcmp.cond.d instructions 1532 BufferOffset AssemblerLOONG64::as_fcmp_cor(FloatFormat fmt, FloatRegister fj, 1533 FloatRegister fk, 1534 FPConditionBit cd) { 1535 if (fmt == DoubleFloat) { 1536 spew("fcmp_cor_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1537 return writeInst(InstReg(op_fcmp_cond_d, COR, fk, fj, cd).encode()); 1538 } else { 1539 spew("fcmp_cor_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1540 return writeInst(InstReg(op_fcmp_cond_s, COR, fk, fj, cd).encode()); 1541 } 1542 } 1543 1544 BufferOffset AssemblerLOONG64::as_fcmp_ceq(FloatFormat fmt, FloatRegister fj, 1545 FloatRegister fk, 1546 FPConditionBit cd) { 1547 if (fmt == DoubleFloat) { 1548 spew("fcmp_ceq_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1549 return writeInst(InstReg(op_fcmp_cond_d, CEQ, fk, fj, cd).encode()); 1550 } else { 1551 spew("fcmp_ceq_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1552 return writeInst(InstReg(op_fcmp_cond_s, CEQ, fk, fj, cd).encode()); 1553 } 1554 } 1555 1556 BufferOffset AssemblerLOONG64::as_fcmp_cne(FloatFormat fmt, FloatRegister fj, 1557 FloatRegister fk, 1558 FPConditionBit cd) { 1559 if (fmt == DoubleFloat) { 1560 spew("fcmp_cne_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1561 return writeInst(InstReg(op_fcmp_cond_d, CNE, fk, fj, cd).encode()); 1562 } else { 1563 spew("fcmp_cne_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1564 return writeInst(InstReg(op_fcmp_cond_s, CNE, fk, fj, cd).encode()); 1565 } 1566 } 1567 1568 BufferOffset AssemblerLOONG64::as_fcmp_cle(FloatFormat fmt, FloatRegister fj, 1569 FloatRegister fk, 1570 FPConditionBit cd) { 1571 if (fmt == DoubleFloat) { 1572 spew("fcmp_cle_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1573 return writeInst(InstReg(op_fcmp_cond_d, CLE, fk, fj, cd).encode()); 1574 } else { 1575 spew("fcmp_cle_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1576 return writeInst(InstReg(op_fcmp_cond_s, CLE, fk, fj, cd).encode()); 1577 } 1578 } 1579 1580 BufferOffset AssemblerLOONG64::as_fcmp_clt(FloatFormat fmt, FloatRegister fj, 1581 FloatRegister fk, 1582 FPConditionBit cd) { 1583 if (fmt == DoubleFloat) { 1584 spew("fcmp_clt_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1585 return writeInst(InstReg(op_fcmp_cond_d, CLT, fk, fj, cd).encode()); 1586 } else { 1587 spew("fcmp_clt_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1588 return writeInst(InstReg(op_fcmp_cond_s, CLT, fk, fj, cd).encode()); 1589 } 1590 } 1591 1592 BufferOffset AssemblerLOONG64::as_fcmp_cun(FloatFormat fmt, FloatRegister fj, 1593 FloatRegister fk, 1594 FPConditionBit cd) { 1595 if (fmt == DoubleFloat) { 1596 spew("fcmp_cun_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1597 return writeInst(InstReg(op_fcmp_cond_d, CUN, fk, fj, cd).encode()); 1598 } else { 1599 spew("fcmp_cun_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1600 return writeInst(InstReg(op_fcmp_cond_s, CUN, fk, fj, cd).encode()); 1601 } 1602 } 1603 1604 BufferOffset AssemblerLOONG64::as_fcmp_cueq(FloatFormat fmt, FloatRegister fj, 1605 FloatRegister fk, 1606 FPConditionBit cd) { 1607 if (fmt == DoubleFloat) { 1608 spew("fcmp_cueq_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1609 return writeInst(InstReg(op_fcmp_cond_d, CUEQ, fk, fj, cd).encode()); 1610 } else { 1611 spew("fcmp_cueq_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1612 return writeInst(InstReg(op_fcmp_cond_s, CUEQ, fk, fj, cd).encode()); 1613 } 1614 } 1615 1616 BufferOffset AssemblerLOONG64::as_fcmp_cune(FloatFormat fmt, FloatRegister fj, 1617 FloatRegister fk, 1618 FPConditionBit cd) { 1619 if (fmt == DoubleFloat) { 1620 spew("fcmp_cune_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1621 return writeInst(InstReg(op_fcmp_cond_d, CUNE, fk, fj, cd).encode()); 1622 } else { 1623 spew("fcmp_cune_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1624 return writeInst(InstReg(op_fcmp_cond_s, CUNE, fk, fj, cd).encode()); 1625 } 1626 } 1627 1628 BufferOffset AssemblerLOONG64::as_fcmp_cule(FloatFormat fmt, FloatRegister fj, 1629 FloatRegister fk, 1630 FPConditionBit cd) { 1631 if (fmt == DoubleFloat) { 1632 spew("fcmp_cule_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1633 return writeInst(InstReg(op_fcmp_cond_d, CULE, fk, fj, cd).encode()); 1634 } else { 1635 spew("fcmp_cule_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1636 return writeInst(InstReg(op_fcmp_cond_s, CULE, fk, fj, cd).encode()); 1637 } 1638 } 1639 1640 BufferOffset AssemblerLOONG64::as_fcmp_cult(FloatFormat fmt, FloatRegister fj, 1641 FloatRegister fk, 1642 FPConditionBit cd) { 1643 if (fmt == DoubleFloat) { 1644 spew("fcmp_cult_d FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1645 return writeInst(InstReg(op_fcmp_cond_d, CULT, fk, fj, cd).encode()); 1646 } else { 1647 spew("fcmp_cult_s FCC%d,%3s,%3s", cd, fj.name(), fk.name()); 1648 return writeInst(InstReg(op_fcmp_cond_s, CULT, fk, fj, cd).encode()); 1649 } 1650 } 1651 1652 // FP conversion instructions 1653 BufferOffset AssemblerLOONG64::as_fcvt_s_d(FloatRegister fd, FloatRegister fj) { 1654 spew("fcvt_s_d %3s,%3s", fd.name(), fj.name()); 1655 return writeInst(InstReg(op_fcvt_s_d, fj, fd).encode()); 1656 } 1657 1658 BufferOffset AssemblerLOONG64::as_fcvt_d_s(FloatRegister fd, FloatRegister fj) { 1659 spew("fcvt_d_s %3s,%3s", fd.name(), fj.name()); 1660 return writeInst(InstReg(op_fcvt_d_s, fj, fd).encode()); 1661 } 1662 1663 BufferOffset AssemblerLOONG64::as_ffint_s_w(FloatRegister fd, 1664 FloatRegister fj) { 1665 spew("ffint_s_w %3s,%3s", fd.name(), fj.name()); 1666 return writeInst(InstReg(op_ffint_s_w, fj, fd).encode()); 1667 } 1668 1669 BufferOffset AssemblerLOONG64::as_ffint_s_l(FloatRegister fd, 1670 FloatRegister fj) { 1671 spew("ffint_s_l %3s,%3s", fd.name(), fj.name()); 1672 return writeInst(InstReg(op_ffint_s_l, fj, fd).encode()); 1673 } 1674 1675 BufferOffset AssemblerLOONG64::as_ffint_d_w(FloatRegister fd, 1676 FloatRegister fj) { 1677 spew("ffint_d_w %3s,%3s", fd.name(), fj.name()); 1678 return writeInst(InstReg(op_ffint_d_w, fj, fd).encode()); 1679 } 1680 1681 BufferOffset AssemblerLOONG64::as_ffint_d_l(FloatRegister fd, 1682 FloatRegister fj) { 1683 spew("ffint_d_l %3s,%3s", fd.name(), fj.name()); 1684 return writeInst(InstReg(op_ffint_d_l, fj, fd).encode()); 1685 } 1686 1687 BufferOffset AssemblerLOONG64::as_ftint_w_s(FloatRegister fd, 1688 FloatRegister fj) { 1689 spew("ftint_w_s %3s,%3s", fd.name(), fj.name()); 1690 return writeInst(InstReg(op_ftint_w_s, fj, fd).encode()); 1691 } 1692 1693 BufferOffset AssemblerLOONG64::as_ftint_w_d(FloatRegister fd, 1694 FloatRegister fj) { 1695 spew("ftint_w_d %3s,%3s", fd.name(), fj.name()); 1696 return writeInst(InstReg(op_ftint_w_d, fj, fd).encode()); 1697 } 1698 1699 BufferOffset AssemblerLOONG64::as_ftint_l_s(FloatRegister fd, 1700 FloatRegister fj) { 1701 spew("ftint_l_s %3s,%3s", fd.name(), fj.name()); 1702 return writeInst(InstReg(op_ftint_l_s, fj, fd).encode()); 1703 } 1704 1705 BufferOffset AssemblerLOONG64::as_ftint_l_d(FloatRegister fd, 1706 FloatRegister fj) { 1707 spew("ftint_l_d %3s,%3s", fd.name(), fj.name()); 1708 return writeInst(InstReg(op_ftint_l_d, fj, fd).encode()); 1709 } 1710 1711 BufferOffset AssemblerLOONG64::as_ftintrm_w_s(FloatRegister fd, 1712 FloatRegister fj) { 1713 spew("ftintrm_w_s %3s,%3s", fd.name(), fj.name()); 1714 return writeInst(InstReg(op_ftintrm_w_s, fj, fd).encode()); 1715 } 1716 1717 BufferOffset AssemblerLOONG64::as_ftintrm_w_d(FloatRegister fd, 1718 FloatRegister fj) { 1719 spew("ftintrm_w_d %3s,%3s", fd.name(), fj.name()); 1720 return writeInst(InstReg(op_ftintrm_w_d, fj, fd).encode()); 1721 } 1722 1723 BufferOffset AssemblerLOONG64::as_ftintrm_l_s(FloatRegister fd, 1724 FloatRegister fj) { 1725 spew("ftintrm_l_s %3s,%3s", fd.name(), fj.name()); 1726 return writeInst(InstReg(op_ftintrm_l_s, fj, fd).encode()); 1727 } 1728 1729 BufferOffset AssemblerLOONG64::as_ftintrm_l_d(FloatRegister fd, 1730 FloatRegister fj) { 1731 spew("ftintrm_l_d %3s,%3s", fd.name(), fj.name()); 1732 return writeInst(InstReg(op_ftintrm_l_d, fj, fd).encode()); 1733 } 1734 1735 BufferOffset AssemblerLOONG64::as_ftintrp_w_s(FloatRegister fd, 1736 FloatRegister fj) { 1737 spew("ftintrp_w_s %3s,%3s", fd.name(), fj.name()); 1738 return writeInst(InstReg(op_ftintrp_w_s, fj, fd).encode()); 1739 } 1740 1741 BufferOffset AssemblerLOONG64::as_ftintrp_w_d(FloatRegister fd, 1742 FloatRegister fj) { 1743 spew("ftintrp_w_d %3s,%3s", fd.name(), fj.name()); 1744 return writeInst(InstReg(op_ftintrp_w_d, fj, fd).encode()); 1745 } 1746 1747 BufferOffset AssemblerLOONG64::as_ftintrp_l_s(FloatRegister fd, 1748 FloatRegister fj) { 1749 spew("ftintrp_l_s %3s,%3s", fd.name(), fj.name()); 1750 return writeInst(InstReg(op_ftintrp_l_s, fj, fd).encode()); 1751 } 1752 1753 BufferOffset AssemblerLOONG64::as_ftintrp_l_d(FloatRegister fd, 1754 FloatRegister fj) { 1755 spew("ftintrp_l_d %3s,%3s", fd.name(), fj.name()); 1756 return writeInst(InstReg(op_ftintrp_l_d, fj, fd).encode()); 1757 } 1758 1759 BufferOffset AssemblerLOONG64::as_ftintrz_w_s(FloatRegister fd, 1760 FloatRegister fj) { 1761 spew("ftintrz_w_s %3s,%3s", fd.name(), fj.name()); 1762 return writeInst(InstReg(op_ftintrz_w_s, fj, fd).encode()); 1763 } 1764 1765 BufferOffset AssemblerLOONG64::as_ftintrz_w_d(FloatRegister fd, 1766 FloatRegister fj) { 1767 spew("ftintrz_w_d %3s,%3s", fd.name(), fj.name()); 1768 return writeInst(InstReg(op_ftintrz_w_d, fj, fd).encode()); 1769 } 1770 1771 BufferOffset AssemblerLOONG64::as_ftintrz_l_s(FloatRegister fd, 1772 FloatRegister fj) { 1773 spew("ftintrz_l_s %3s,%3s", fd.name(), fj.name()); 1774 return writeInst(InstReg(op_ftintrz_l_s, fj, fd).encode()); 1775 } 1776 1777 BufferOffset AssemblerLOONG64::as_ftintrz_l_d(FloatRegister fd, 1778 FloatRegister fj) { 1779 spew("ftintrz_l_d %3s,%3s", fd.name(), fj.name()); 1780 return writeInst(InstReg(op_ftintrz_l_d, fj, fd).encode()); 1781 } 1782 BufferOffset AssemblerLOONG64::as_ftintrne_w_s(FloatRegister fd, 1783 FloatRegister fj) { 1784 spew("ftintrne_w_s %3s,%3s", fd.name(), fj.name()); 1785 return writeInst(InstReg(op_ftintrne_w_s, fj, fd).encode()); 1786 } 1787 1788 BufferOffset AssemblerLOONG64::as_ftintrne_w_d(FloatRegister fd, 1789 FloatRegister fj) { 1790 spew("ftintrne_w_d %3s,%3s", fd.name(), fj.name()); 1791 return writeInst(InstReg(op_ftintrne_w_d, fj, fd).encode()); 1792 } 1793 1794 BufferOffset AssemblerLOONG64::as_ftintrne_l_s(FloatRegister fd, 1795 FloatRegister fj) { 1796 spew("ftintrne_l_s %3s,%3s", fd.name(), fj.name()); 1797 return writeInst(InstReg(op_ftintrne_l_s, fj, fd).encode()); 1798 } 1799 1800 BufferOffset AssemblerLOONG64::as_ftintrne_l_d(FloatRegister fd, 1801 FloatRegister fj) { 1802 spew("ftintrne_l_d %3s,%3s", fd.name(), fj.name()); 1803 return writeInst(InstReg(op_ftintrne_l_d, fj, fd).encode()); 1804 } 1805 1806 BufferOffset AssemblerLOONG64::as_frint_s(FloatRegister fd, FloatRegister fj) { 1807 spew("frint_s %3s,%3s", fd.name(), fj.name()); 1808 return writeInst(InstReg(op_frint_s, fj, fd).encode()); 1809 } 1810 1811 BufferOffset AssemblerLOONG64::as_frint_d(FloatRegister fd, FloatRegister fj) { 1812 spew("frint_d %3s,%3s", fd.name(), fj.name()); 1813 return writeInst(InstReg(op_frint_d, fj, fd).encode()); 1814 } 1815 1816 // FP mov instructions 1817 BufferOffset AssemblerLOONG64::as_fmov_s(FloatRegister fd, FloatRegister fj) { 1818 spew("fmov_s %3s,%3s", fd.name(), fj.name()); 1819 return writeInst(InstReg(op_fmov_s, fj, fd).encode()); 1820 } 1821 1822 BufferOffset AssemblerLOONG64::as_fmov_d(FloatRegister fd, FloatRegister fj) { 1823 spew("fmov_d %3s,%3s", fd.name(), fj.name()); 1824 return writeInst(InstReg(op_fmov_d, fj, fd).encode()); 1825 } 1826 1827 BufferOffset AssemblerLOONG64::as_fsel(FloatRegister fd, FloatRegister fj, 1828 FloatRegister fk, FPConditionBit ca) { 1829 spew("fsel %3s,%3s,%3s,%d", fd.name(), fj.name(), fk.name(), ca); 1830 return writeInst(InstReg(op_fsel, ca, fk, fj, fd).encode()); 1831 } 1832 1833 BufferOffset AssemblerLOONG64::as_movgr2fr_w(FloatRegister fd, Register rj) { 1834 spew("movgr2fr_w %3s,%3s", fd.name(), rj.name()); 1835 return writeInst(InstReg(op_movgr2fr_w, rj, fd).encode()); 1836 } 1837 1838 BufferOffset AssemblerLOONG64::as_movgr2fr_d(FloatRegister fd, Register rj) { 1839 spew("movgr2fr_d %3s,%3s", fd.name(), rj.name()); 1840 return writeInst(InstReg(op_movgr2fr_d, rj, fd).encode()); 1841 } 1842 1843 BufferOffset AssemblerLOONG64::as_movgr2frh_w(FloatRegister fd, Register rj) { 1844 spew("movgr2frh_w %3s,%3s", fd.name(), rj.name()); 1845 return writeInst(InstReg(op_movgr2frh_w, rj, fd).encode()); 1846 } 1847 1848 BufferOffset AssemblerLOONG64::as_movfr2gr_s(Register rd, FloatRegister fj) { 1849 spew("movfr2gr_s %3s,%3s", rd.name(), fj.name()); 1850 return writeInst(InstReg(op_movfr2gr_s, fj, rd).encode()); 1851 } 1852 1853 BufferOffset AssemblerLOONG64::as_movfr2gr_d(Register rd, FloatRegister fj) { 1854 spew("movfr2gr_d %3s,%3s", rd.name(), fj.name()); 1855 return writeInst(InstReg(op_movfr2gr_d, fj, rd).encode()); 1856 } 1857 1858 BufferOffset AssemblerLOONG64::as_movfrh2gr_s(Register rd, FloatRegister fj) { 1859 spew("movfrh2gr_s %3s,%3s", rd.name(), fj.name()); 1860 return writeInst(InstReg(op_movfrh2gr_s, fj, rd).encode()); 1861 } 1862 1863 BufferOffset AssemblerLOONG64::as_movgr2fcsr(Register rj) { 1864 spew("movgr2fcsr %3s", rj.name()); 1865 return writeInst(InstReg(op_movgr2fcsr, rj, FCSR).encode()); 1866 } 1867 1868 BufferOffset AssemblerLOONG64::as_movfcsr2gr(Register rd) { 1869 spew("movfcsr2gr %3s", rd.name()); 1870 return writeInst(InstReg(op_movfcsr2gr, FCSR, rd).encode()); 1871 } 1872 1873 BufferOffset AssemblerLOONG64::as_movfr2cf(FPConditionBit cd, 1874 FloatRegister fj) { 1875 spew("movfr2cf %d,%3s", cd, fj.name()); 1876 return writeInst(InstReg(op_movfr2cf, fj, cd).encode()); 1877 } 1878 1879 BufferOffset AssemblerLOONG64::as_movcf2fr(FloatRegister fd, 1880 FPConditionBit cj) { 1881 spew("movcf2fr %3s,%d", fd.name(), cj); 1882 return writeInst(InstReg(op_movcf2fr, cj, fd).encode()); 1883 } 1884 1885 BufferOffset AssemblerLOONG64::as_movgr2cf(FPConditionBit cd, Register rj) { 1886 spew("movgr2cf %d,%3s", cd, rj.name()); 1887 return writeInst(InstReg(op_movgr2cf, rj, cd).encode()); 1888 } 1889 1890 BufferOffset AssemblerLOONG64::as_movcf2gr(Register rd, FPConditionBit cj) { 1891 spew("movcf2gr %3s,%d", rd.name(), cj); 1892 return writeInst(InstReg(op_movcf2gr, cj, rd).encode()); 1893 } 1894 1895 // FP load/store instructions 1896 BufferOffset AssemblerLOONG64::as_fld_s(FloatRegister fd, Register rj, 1897 int32_t si12) { 1898 MOZ_ASSERT(is_intN(si12, 12)); 1899 spew("fld_s %3s,%3s,0x%x", fd.name(), rj.name(), si12); 1900 return writeInst(InstImm(op_fld_s, si12, rj, fd).encode()); 1901 } 1902 1903 BufferOffset AssemblerLOONG64::as_fld_d(FloatRegister fd, Register rj, 1904 int32_t si12) { 1905 MOZ_ASSERT(is_intN(si12, 12)); 1906 spew("fld_d %3s,%3s,0x%x", fd.name(), rj.name(), si12); 1907 return writeInst(InstImm(op_fld_d, si12, rj, fd).encode()); 1908 } 1909 1910 BufferOffset AssemblerLOONG64::as_fst_s(FloatRegister fd, Register rj, 1911 int32_t si12) { 1912 MOZ_ASSERT(is_intN(si12, 12)); 1913 spew("fst_s %3s,%3s,0x%x", fd.name(), rj.name(), si12); 1914 return writeInst(InstImm(op_fst_s, si12, rj, fd).encode()); 1915 } 1916 1917 BufferOffset AssemblerLOONG64::as_fst_d(FloatRegister fd, Register rj, 1918 int32_t si12) { 1919 MOZ_ASSERT(is_intN(si12, 12)); 1920 spew("fst_d %3s,%3s,0x%x", fd.name(), rj.name(), si12); 1921 return writeInst(InstImm(op_fst_d, si12, rj, fd).encode()); 1922 } 1923 1924 BufferOffset AssemblerLOONG64::as_fldx_s(FloatRegister fd, Register rj, 1925 Register rk) { 1926 spew("fldx_s %3s,%3s,%3s", fd.name(), rj.name(), rk.name()); 1927 return writeInst(InstReg(op_fldx_s, rk, rj, fd).encode()); 1928 } 1929 1930 BufferOffset AssemblerLOONG64::as_fldx_d(FloatRegister fd, Register rj, 1931 Register rk) { 1932 spew("fldx_d %3s,%3s,%3s", fd.name(), rj.name(), rk.name()); 1933 return writeInst(InstReg(op_fldx_d, rk, rj, fd).encode()); 1934 } 1935 1936 BufferOffset AssemblerLOONG64::as_fstx_s(FloatRegister fd, Register rj, 1937 Register rk) { 1938 spew("fstx_s %3s,%3s,%3s", fd.name(), rj.name(), rk.name()); 1939 return writeInst(InstReg(op_fstx_s, rk, rj, fd).encode()); 1940 } 1941 1942 BufferOffset AssemblerLOONG64::as_fstx_d(FloatRegister fd, Register rj, 1943 Register rk) { 1944 spew("fstx_d %3s,%3s,%3s", fd.name(), rj.name(), rk.name()); 1945 return writeInst(InstReg(op_fstx_d, rk, rj, fd).encode()); 1946 } 1947 1948 /* ========================================================================= */ 1949 1950 void AssemblerLOONG64::bind(Label* label, BufferOffset boff) { 1951 spew(".set Llabel %p", label); 1952 // If our caller didn't give us an explicit target to bind to 1953 // then we want to bind to the location of the next instruction 1954 BufferOffset dest = boff.assigned() ? boff : nextOffset(); 1955 if (label->used()) { 1956 int32_t next; 1957 1958 // A used label holds a link to branch that uses it. 1959 BufferOffset b(label); 1960 do { 1961 // Even a 0 offset may be invalid if we're out of memory. 1962 if (oom()) { 1963 return; 1964 } 1965 1966 Instruction* inst = editSrc(b); 1967 1968 // Second word holds a pointer to the next branch in label's chain. 1969 next = inst[1].encode(); 1970 bind(reinterpret_cast<InstImm*>(inst), b.getOffset(), dest.getOffset()); 1971 1972 b = BufferOffset(next); 1973 } while (next != LabelBase::INVALID_OFFSET); 1974 } 1975 label->bind(dest.getOffset()); 1976 } 1977 1978 void AssemblerLOONG64::retarget(Label* label, Label* target) { 1979 spew("retarget %p -> %p", label, target); 1980 if (label->used() && !oom()) { 1981 if (target->bound()) { 1982 bind(label, BufferOffset(target)); 1983 } else if (target->used()) { 1984 // The target is not bound but used. Prepend label's branch list 1985 // onto target's. 1986 int32_t next; 1987 BufferOffset labelBranchOffset(label); 1988 1989 // Find the head of the use chain for label. 1990 do { 1991 Instruction* inst = editSrc(labelBranchOffset); 1992 1993 // Second word holds a pointer to the next branch in chain. 1994 next = inst[1].encode(); 1995 labelBranchOffset = BufferOffset(next); 1996 } while (next != LabelBase::INVALID_OFFSET); 1997 1998 // Then patch the head of label's use chain to the tail of 1999 // target's use chain, prepending the entire use chain of target. 2000 Instruction* inst = editSrc(labelBranchOffset); 2001 int32_t prev = target->offset(); 2002 target->use(label->offset()); 2003 inst[1].setData(prev); 2004 } else { 2005 // The target is unbound and unused. We can just take the head of 2006 // the list hanging off of label, and dump that into target. 2007 target->use(label->offset()); 2008 } 2009 } 2010 label->reset(); 2011 } 2012 2013 void dbg_break() {} 2014 2015 void AssemblerLOONG64::as_break(uint32_t code) { 2016 MOZ_ASSERT(code <= MAX_BREAK_CODE); 2017 spew("break %d", code); 2018 writeInst(InstImm(op_break, code).encode()); 2019 } 2020 2021 // This just stomps over memory with 32 bits of raw data. Its purpose is to 2022 // overwrite the call of JITed code with 32 bits worth of an offset. This will 2023 // is only meant to function on code that has been invalidated, so it should 2024 // be totally safe. Since that instruction will never be executed again, a 2025 // ICache flush should not be necessary 2026 void AssemblerLOONG64::PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm) { 2027 // Raw is going to be the return address. 2028 uint32_t* raw = (uint32_t*)label.raw(); 2029 // Overwrite the 4 bytes before the return address, which will 2030 // end up being the call instruction. 2031 *(raw - 1) = imm.value; 2032 } 2033 2034 uint8_t* AssemblerLOONG64::NextInstruction(uint8_t* inst_, uint32_t* count) { 2035 Instruction* inst = reinterpret_cast<Instruction*>(inst_); 2036 if (count != nullptr) { 2037 *count += sizeof(Instruction); 2038 } 2039 return reinterpret_cast<uint8_t*>(inst->next()); 2040 } 2041 2042 void AssemblerLOONG64::ToggleToJmp(CodeLocationLabel inst_) { 2043 InstImm* inst = (InstImm*)inst_.raw(); 2044 2045 MOZ_ASSERT(inst->extractBitField(31, 26) == (uint32_t)op_addu16i_d >> 26); 2046 // We converted beq to addu16i_d, so now we restore it. 2047 inst->setOpcode(op_beq, 6); 2048 } 2049 2050 void AssemblerLOONG64::ToggleToCmp(CodeLocationLabel inst_) { 2051 InstImm* inst = (InstImm*)inst_.raw(); 2052 2053 // toggledJump is allways used for short jumps. 2054 MOZ_ASSERT(inst->extractBitField(31, 26) == (uint32_t)op_beq >> 26); 2055 // Replace "beq $zero, $zero, offset" with "addu16i_d $zero, $zero, offset" 2056 inst->setOpcode(op_addu16i_d, 6); 2057 } 2058 2059 // Since there are no pools in LoongArch64 implementation, this should be 2060 // simple. 2061 Instruction* Instruction::next() { return this + 1; } 2062 2063 InstImm AssemblerLOONG64::invertBranch(InstImm branch, BOffImm16 skipOffset) { 2064 uint32_t rj = 0; 2065 OpcodeField opcode = (OpcodeField)((branch.extractBitField(31, 26)) << 26); 2066 switch (opcode) { 2067 case op_beq: 2068 branch.setBOffImm16(skipOffset); 2069 branch.setOpcode(op_bne, 6); 2070 return branch; 2071 case op_bne: 2072 branch.setBOffImm16(skipOffset); 2073 branch.setOpcode(op_beq, 6); 2074 return branch; 2075 case op_bge: 2076 branch.setBOffImm16(skipOffset); 2077 branch.setOpcode(op_blt, 6); 2078 return branch; 2079 case op_bgeu: 2080 branch.setBOffImm16(skipOffset); 2081 branch.setOpcode(op_bltu, 6); 2082 return branch; 2083 case op_blt: 2084 branch.setBOffImm16(skipOffset); 2085 branch.setOpcode(op_bge, 6); 2086 return branch; 2087 case op_bltu: 2088 branch.setBOffImm16(skipOffset); 2089 branch.setOpcode(op_bgeu, 6); 2090 return branch; 2091 case op_beqz: 2092 branch.setBOffImm16(skipOffset); 2093 branch.setOpcode(op_bnez, 6); 2094 return branch; 2095 case op_bnez: 2096 branch.setBOffImm16(skipOffset); 2097 branch.setOpcode(op_beqz, 6); 2098 return branch; 2099 case op_bcz: 2100 branch.setBOffImm16(skipOffset); 2101 rj = branch.extractRJ(); 2102 if (rj & 0x8) { 2103 branch.setRJ(rj & 0x17); 2104 } else { 2105 branch.setRJ(rj | 0x8); 2106 } 2107 return branch; 2108 default: 2109 MOZ_CRASH("Error creating long branch."); 2110 } 2111 } 2112 2113 #ifdef JS_JITSPEW 2114 void AssemblerLOONG64::decodeBranchInstAndSpew(InstImm branch) { 2115 OpcodeField opcode = (OpcodeField)((branch.extractBitField(31, 26)) << 26); 2116 uint32_t rd_id; 2117 uint32_t rj_id; 2118 uint32_t cj_id; 2119 uint32_t immi = branch.extractImm16Value(); 2120 switch (opcode) { 2121 case op_beq: 2122 rd_id = branch.extractRD(); 2123 rj_id = branch.extractRJ(); 2124 spew("beq 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, 2125 Registers::GetName(rj_id), Registers::GetName(rd_id)); 2126 break; 2127 case op_bne: 2128 rd_id = branch.extractRD(); 2129 rj_id = branch.extractRJ(); 2130 spew("bne 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, 2131 Registers::GetName(rj_id), Registers::GetName(rd_id)); 2132 break; 2133 case op_bge: 2134 rd_id = branch.extractRD(); 2135 rj_id = branch.extractRJ(); 2136 spew("bge 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, 2137 Registers::GetName(rj_id), Registers::GetName(rd_id)); 2138 break; 2139 case op_bgeu: 2140 rd_id = branch.extractRD(); 2141 rj_id = branch.extractRJ(); 2142 spew("bgeu 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, 2143 Registers::GetName(rj_id), Registers::GetName(rd_id)); 2144 break; 2145 case op_blt: 2146 rd_id = branch.extractRD(); 2147 rj_id = branch.extractRJ(); 2148 spew("blt 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, 2149 Registers::GetName(rj_id), Registers::GetName(rd_id)); 2150 break; 2151 case op_bltu: 2152 rd_id = branch.extractRD(); 2153 rj_id = branch.extractRJ(); 2154 spew("bltu 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, 2155 Registers::GetName(rj_id), Registers::GetName(rd_id)); 2156 break; 2157 case op_beqz: 2158 rd_id = branch.extractRD(); 2159 rj_id = branch.extractRJ(); 2160 spew("beqz 0x%x,%3s,0x%x", (int32_t(immi << 18) >> 16) + 4, 2161 Registers::GetName(rj_id), rd_id); 2162 break; 2163 case op_bnez: 2164 rd_id = branch.extractRD(); 2165 rj_id = branch.extractRJ(); 2166 spew("bnez 0x%x,%3s,0x%x", (int32_t(immi << 18) >> 16) + 4, 2167 Registers::GetName(rj_id), rd_id); 2168 break; 2169 case op_bcz: 2170 rd_id = branch.extractRD(); 2171 rj_id = branch.extractRJ(); 2172 cj_id = branch.extractBitField(CJShift + CJBits - 1, CJShift); 2173 if (rj_id & 0x8) { 2174 spew("bcnez 0x%x,FCC%d,0x%x", (int32_t(immi << 18) >> 16) + 4, cj_id, 2175 rd_id); 2176 } else { 2177 spew("bceqz 0x%x,FCC%d,0x%x", (int32_t(immi << 18) >> 16) + 4, cj_id, 2178 rd_id); 2179 } 2180 break; 2181 case op_jirl: 2182 rd_id = branch.extractRD(); 2183 rj_id = branch.extractRJ(); 2184 spew("beqz 0x%x,%3s,%3s", (int32_t(immi << 18) >> 16) + 4, 2185 Registers::GetName(rj_id), Registers::GetName(rd_id)); 2186 break; 2187 default: 2188 MOZ_CRASH("Error disassemble branch."); 2189 } 2190 } 2191 #endif 2192 2193 void Assembler::executableCopy(uint8_t* buffer) { 2194 MOZ_ASSERT(isFinished); 2195 m_buffer.executableCopy(buffer); 2196 } 2197 2198 uintptr_t Assembler::GetPointer(uint8_t* instPtr) { 2199 Instruction* inst = (Instruction*)instPtr; 2200 return Assembler::ExtractLoad64Value(inst); 2201 } 2202 2203 static JitCode* CodeFromJump(Instruction* jump) { 2204 uint8_t* target = (uint8_t*)Assembler::ExtractLoad64Value(jump); 2205 return JitCode::FromExecutable(target); 2206 } 2207 2208 void Assembler::TraceJumpRelocations(JSTracer* trc, JitCode* code, 2209 CompactBufferReader& reader) { 2210 while (reader.more()) { 2211 JitCode* child = 2212 CodeFromJump((Instruction*)(code->raw() + reader.readUnsigned())); 2213 TraceManuallyBarrieredEdge(trc, &child, "rel32"); 2214 } 2215 } 2216 2217 static void TraceOneDataRelocation(JSTracer* trc, 2218 mozilla::Maybe<AutoWritableJitCode>& awjc, 2219 JitCode* code, Instruction* inst) { 2220 void* ptr = (void*)Assembler::ExtractLoad64Value(inst); 2221 void* prior = ptr; 2222 2223 // Data relocations can be for Values or for raw pointers. If a Value is 2224 // zero-tagged, we can trace it as if it were a raw pointer. If a Value 2225 // is not zero-tagged, we have to interpret it as a Value to ensure that the 2226 // tag bits are masked off to recover the actual pointer. 2227 uintptr_t word = reinterpret_cast<uintptr_t>(ptr); 2228 if (word >> JSVAL_TAG_SHIFT) { 2229 // This relocation is a Value with a non-zero tag. 2230 Value v = Value::fromRawBits(word); 2231 TraceManuallyBarrieredEdge(trc, &v, "jit-masm-value"); 2232 ptr = (void*)v.bitsAsPunboxPointer(); 2233 } else { 2234 // This relocation is a raw pointer or a Value with a zero tag. 2235 // No barrier needed since these are constants. 2236 TraceManuallyBarrieredGenericPointerEdge( 2237 trc, reinterpret_cast<gc::Cell**>(&ptr), "jit-masm-ptr"); 2238 } 2239 2240 if (ptr != prior) { 2241 if (awjc.isNothing()) { 2242 awjc.emplace(code); 2243 } 2244 Assembler::UpdateLoad64Value(inst, uint64_t(ptr)); 2245 } 2246 } 2247 2248 /* static */ 2249 void Assembler::TraceDataRelocations(JSTracer* trc, JitCode* code, 2250 CompactBufferReader& reader) { 2251 mozilla::Maybe<AutoWritableJitCode> awjc; 2252 while (reader.more()) { 2253 size_t offset = reader.readUnsigned(); 2254 Instruction* inst = (Instruction*)(code->raw() + offset); 2255 TraceOneDataRelocation(trc, awjc, code, inst); 2256 } 2257 } 2258 2259 void Assembler::Bind(uint8_t* rawCode, const CodeLabel& label) { 2260 if (label.patchAt().bound()) { 2261 auto mode = label.linkMode(); 2262 intptr_t offset = label.patchAt().offset(); 2263 intptr_t target = label.target().offset(); 2264 2265 if (mode == CodeLabel::RawPointer) { 2266 *reinterpret_cast<const void**>(rawCode + offset) = rawCode + target; 2267 } else { 2268 MOZ_ASSERT(mode == CodeLabel::MoveImmediate || 2269 mode == CodeLabel::JumpImmediate); 2270 Instruction* inst = (Instruction*)(rawCode + offset); 2271 Assembler::UpdateLoad64Value(inst, (uint64_t)(rawCode + target)); 2272 } 2273 } 2274 } 2275 2276 void Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target) { 2277 int64_t offset = target - branch; 2278 InstImm inst_jirl = InstImm(op_jirl, BOffImm16(0), zero, ra); 2279 InstImm inst_beq = InstImm(op_beq, BOffImm16(0), zero, zero); 2280 2281 // If encoded offset is 4, then the jump must be short 2282 if (BOffImm16(inst[0]).decode() == 4) { 2283 MOZ_ASSERT(BOffImm16::IsInRange(offset)); 2284 inst[0].setBOffImm16(BOffImm16(offset)); 2285 inst[1].makeNop(); // because before set INVALID_OFFSET 2286 return; 2287 } 2288 2289 UseScratchRegisterScope temps(*this); 2290 2291 // Generate the long jump for calls because return address has to be the 2292 // address after the reserved block. 2293 if (inst[0].encode() == inst_jirl.encode()) { 2294 Register scratch = temps.Acquire(); 2295 addLongJump(BufferOffset(branch), BufferOffset(target)); 2296 Assembler::WriteLoad64Instructions(inst, scratch, 2297 LabelBase::INVALID_OFFSET); 2298 inst[3].makeNop(); // There are 1 nop. 2299 inst[4] = InstImm(op_jirl, BOffImm16(0), scratch, ra); 2300 return; 2301 } 2302 2303 if (BOffImm16::IsInRange(offset)) { 2304 // Skip trailing nops . 2305 bool skipNops = (inst[0].encode() != inst_jirl.encode() && 2306 inst[0].encode() != inst_beq.encode()); 2307 2308 inst[0].setBOffImm16(BOffImm16(offset)); 2309 inst[1].makeNop(); 2310 2311 if (skipNops) { 2312 inst[2] = InstImm(op_bge, BOffImm16(3 * sizeof(uint32_t)), zero, zero); 2313 // There are 2 nops after this 2314 } 2315 return; 2316 } 2317 2318 if (inst[0].encode() == inst_beq.encode()) { 2319 // Handle long unconditional jump. Only four 4 instruction. 2320 addLongJump(BufferOffset(branch), BufferOffset(target)); 2321 Register scratch = temps.Acquire(); 2322 Assembler::WriteLoad64Instructions(inst, scratch, 2323 LabelBase::INVALID_OFFSET); 2324 inst[3] = InstImm(op_jirl, BOffImm16(0), scratch, zero); 2325 } else { 2326 // Handle long conditional jump. 2327 inst[0] = invertBranch(inst[0], BOffImm16(5 * sizeof(uint32_t))); 2328 // No need for a "nop" here because we can clobber scratch. 2329 addLongJump(BufferOffset(branch + sizeof(uint32_t)), BufferOffset(target)); 2330 Register scratch = temps.Acquire(); 2331 Assembler::WriteLoad64Instructions(&inst[1], scratch, 2332 LabelBase::INVALID_OFFSET); 2333 inst[4] = InstImm(op_jirl, BOffImm16(0), scratch, zero); 2334 } 2335 } 2336 2337 void Assembler::processCodeLabels(uint8_t* rawCode) { 2338 for (const CodeLabel& label : codeLabels_) { 2339 Bind(rawCode, label); 2340 } 2341 } 2342 2343 uint32_t Assembler::PatchWrite_NearCallSize() { 2344 // Load an address needs 3 instructions, and a jump. 2345 return (3 + 1) * sizeof(uint32_t); 2346 } 2347 2348 void Assembler::PatchWrite_NearCall(CodeLocationLabel start, 2349 CodeLocationLabel toCall) { 2350 Instruction* inst = (Instruction*)start.raw(); 2351 uint8_t* dest = toCall.raw(); 2352 2353 // Overwrite whatever instruction used to be here with a call. 2354 // Always use long jump for two reasons: 2355 // - Jump has to be the same size because of PatchWrite_NearCallSize. 2356 // - Return address has to be at the end of replaced block. 2357 // Short jump wouldn't be more efficient. 2358 Assembler::WriteLoad64Instructions(inst, SavedScratchRegister, 2359 (uint64_t)dest); 2360 inst[3] = InstImm(op_jirl, BOffImm16(0), SavedScratchRegister, ra); 2361 } 2362 2363 uint64_t Assembler::ExtractLoad64Value(Instruction* inst0) { 2364 InstImm* i0 = (InstImm*)inst0; 2365 InstImm* i1 = (InstImm*)i0->next(); 2366 InstImm* i2 = (InstImm*)i1->next(); 2367 InstImm* i3 = (InstImm*)i2->next(); 2368 2369 MOZ_ASSERT((i0->extractBitField(31, 25)) == ((uint32_t)op_lu12i_w >> 25)); 2370 MOZ_ASSERT((i1->extractBitField(31, 22)) == ((uint32_t)op_ori >> 22)); 2371 MOZ_ASSERT((i2->extractBitField(31, 25)) == ((uint32_t)op_lu32i_d >> 25)); 2372 2373 if ((i3->extractBitField(31, 22)) == ((uint32_t)op_lu52i_d >> 22)) { 2374 // Li64 2375 uint64_t value = 2376 (uint64_t(i0->extractBitField(Imm20Bits + Imm20Shift - 1, Imm20Shift)) 2377 << 12) | 2378 (uint64_t( 2379 i1->extractBitField(Imm12Bits + Imm12Shift - 1, Imm12Shift))) | 2380 (uint64_t(i2->extractBitField(Imm20Bits + Imm20Shift - 1, Imm20Shift)) 2381 << 32) | 2382 (uint64_t(i3->extractBitField(Imm12Bits + Imm12Shift - 1, Imm12Shift)) 2383 << 52); 2384 return value; 2385 } else { 2386 // Li48 2387 uint64_t value = 2388 (uint64_t(i0->extractBitField(Imm20Bits + Imm20Shift - 1, Imm20Shift)) 2389 << 12) | 2390 (uint64_t( 2391 i1->extractBitField(Imm12Bits + Imm12Shift - 1, Imm12Shift))) | 2392 (uint64_t(i2->extractBitField(Imm20Bits + Imm20Shift - 1, Imm20Shift)) 2393 << 32); 2394 2395 return uint64_t((int64_t(value) << 16) >> 16); 2396 } 2397 } 2398 2399 void Assembler::UpdateLoad64Value(Instruction* inst0, uint64_t value) { 2400 // Todo: with ma_liPatchable 2401 InstImm* i0 = (InstImm*)inst0; 2402 InstImm* i1 = (InstImm*)i0->next(); 2403 InstImm* i2 = (InstImm*)i1->next(); 2404 InstImm* i3 = (InstImm*)i2->next(); 2405 2406 MOZ_ASSERT((i0->extractBitField(31, 25)) == ((uint32_t)op_lu12i_w >> 25)); 2407 MOZ_ASSERT((i1->extractBitField(31, 22)) == ((uint32_t)op_ori >> 22)); 2408 MOZ_ASSERT((i2->extractBitField(31, 25)) == ((uint32_t)op_lu32i_d >> 25)); 2409 2410 if ((i3->extractBitField(31, 22)) == ((uint32_t)op_lu52i_d >> 22)) { 2411 // Li64 2412 *i0 = InstImm(op_lu12i_w, (int32_t)((value >> 12) & 0xfffff), 2413 Register::FromCode(i0->extractRD()), false); 2414 *i1 = InstImm(op_ori, (int32_t)(value & 0xfff), 2415 Register::FromCode(i1->extractRJ()), 2416 Register::FromCode(i1->extractRD()), 12); 2417 *i2 = InstImm(op_lu32i_d, (int32_t)((value >> 32) & 0xfffff), 2418 Register::FromCode(i2->extractRD()), false); 2419 *i3 = InstImm(op_lu52i_d, (int32_t)((value >> 52) & 0xfff), 2420 Register::FromCode(i3->extractRJ()), 2421 Register::FromCode(i3->extractRD()), 12); 2422 } else { 2423 // Li48 2424 *i0 = InstImm(op_lu12i_w, (int32_t)((value >> 12) & 0xfffff), 2425 Register::FromCode(i0->extractRD()), false); 2426 *i1 = InstImm(op_ori, (int32_t)(value & 0xfff), 2427 Register::FromCode(i1->extractRJ()), 2428 Register::FromCode(i1->extractRD()), 12); 2429 *i2 = InstImm(op_lu32i_d, (int32_t)((value >> 32) & 0xfffff), 2430 Register::FromCode(i2->extractRD()), false); 2431 } 2432 } 2433 2434 void Assembler::WriteLoad64Instructions(Instruction* inst0, Register reg, 2435 uint64_t value) { 2436 Instruction* inst1 = inst0->next(); 2437 Instruction* inst2 = inst1->next(); 2438 *inst0 = InstImm(op_lu12i_w, (int32_t)((value >> 12) & 0xfffff), reg, false); 2439 *inst1 = InstImm(op_ori, (int32_t)(value & 0xfff), reg, reg, 12); 2440 *inst2 = InstImm(op_lu32i_d, (int32_t)((value >> 32) & 0xfffff), reg, false); 2441 } 2442 2443 void Assembler::PatchDataWithValueCheck(CodeLocationLabel label, 2444 ImmPtr newValue, ImmPtr expectedValue) { 2445 PatchDataWithValueCheck(label, PatchedImmPtr(newValue.value), 2446 PatchedImmPtr(expectedValue.value)); 2447 } 2448 2449 void Assembler::PatchDataWithValueCheck(CodeLocationLabel label, 2450 PatchedImmPtr newValue, 2451 PatchedImmPtr expectedValue) { 2452 Instruction* inst = (Instruction*)label.raw(); 2453 2454 // Extract old Value 2455 DebugOnly<uint64_t> value = Assembler::ExtractLoad64Value(inst); 2456 MOZ_ASSERT(value == uint64_t(expectedValue.value)); 2457 2458 // Replace with new value 2459 Assembler::UpdateLoad64Value(inst, uint64_t(newValue.value)); 2460 } 2461 2462 uint64_t Assembler::ExtractInstructionImmediate(uint8_t* code) { 2463 InstImm* inst = (InstImm*)code; 2464 return Assembler::ExtractLoad64Value(inst); 2465 } 2466 2467 void Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled) { 2468 Instruction* inst = (Instruction*)inst_.raw(); 2469 InstImm* i0 = (InstImm*)inst; 2470 InstImm* i1 = (InstImm*)i0->next(); 2471 InstImm* i2 = (InstImm*)i1->next(); 2472 Instruction* i3 = (Instruction*)i2->next(); 2473 2474 MOZ_ASSERT((i0->extractBitField(31, 25)) == ((uint32_t)op_lu12i_w >> 25)); 2475 MOZ_ASSERT((i1->extractBitField(31, 22)) == ((uint32_t)op_ori >> 22)); 2476 MOZ_ASSERT((i2->extractBitField(31, 25)) == ((uint32_t)op_lu32i_d >> 25)); 2477 2478 if (enabled) { 2479 MOZ_ASSERT((i3->extractBitField(31, 25)) != ((uint32_t)op_lu12i_w >> 25)); 2480 InstImm jirl = 2481 InstImm(op_jirl, BOffImm16(0), Register::FromCode(i2->extractRD()), ra); 2482 *i3 = jirl; 2483 } else { 2484 InstNOP nop; 2485 *i3 = nop; 2486 } 2487 } 2488 2489 UseScratchRegisterScope::UseScratchRegisterScope(Assembler& assembler) 2490 : available_(assembler.GetScratchRegisterList()), 2491 old_available_(*available_) {} 2492 2493 UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler) 2494 : available_(assembler->GetScratchRegisterList()), 2495 old_available_(*available_) {} 2496 2497 UseScratchRegisterScope::~UseScratchRegisterScope() { 2498 *available_ = old_available_; 2499 } 2500 2501 Register UseScratchRegisterScope::Acquire() { 2502 MOZ_ASSERT(available_ != nullptr); 2503 MOZ_ASSERT(!available_->empty()); 2504 Register index = GeneralRegisterSet::FirstRegister(available_->bits()); 2505 available_->takeRegisterIndex(index); 2506 return index; 2507 } 2508 2509 void UseScratchRegisterScope::Release(const Register& reg) { 2510 MOZ_ASSERT(available_ != nullptr); 2511 MOZ_ASSERT(old_available_.hasRegisterIndex(reg)); 2512 MOZ_ASSERT(!available_->hasRegisterIndex(reg)); 2513 Include(GeneralRegisterSet(1 << reg.code())); 2514 } 2515 2516 bool UseScratchRegisterScope::hasAvailable() const { 2517 return (available_->size()) != 0; 2518 }