1// Copyright 2017 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef V8_WASM_BASELINE_MIPS_LIFTOFF_ASSEMBLER_MIPS_H_ 6#define V8_WASM_BASELINE_MIPS_LIFTOFF_ASSEMBLER_MIPS_H_ 7 8#include "src/base/platform/wrappers.h" 9#include "src/heap/memory-chunk.h" 10#include "src/wasm/baseline/liftoff-assembler.h" 11#include "src/wasm/wasm-objects.h" 12 13namespace v8 { 14namespace internal { 15namespace wasm { 16 17namespace liftoff { 18 19inline constexpr Condition ToCondition(LiftoffCondition liftoff_cond) { 20 switch (liftoff_cond) { 21 case kEqual: 22 return eq; 23 case kUnequal: 24 return ne; 25 case kSignedLessThan: 26 return lt; 27 case kSignedLessEqual: 28 return le; 29 case kSignedGreaterThan: 30 return gt; 31 case kSignedGreaterEqual: 32 return ge; 33 case kUnsignedLessThan: 34 return ult; 35 case kUnsignedLessEqual: 36 return ule; 37 case kUnsignedGreaterThan: 38 return ugt; 39 case kUnsignedGreaterEqual: 40 return uge; 41 } 42} 43 44// half 45// slot Frame 46// -----+--------------------+--------------------------- 47// n+3 | parameter n | 48// ... | ... | 49// 4 | parameter 1 | or parameter 2 50// 3 | parameter 0 | or parameter 1 51// 2 | (result address) | or parameter 0 52// -----+--------------------+--------------------------- 53// 1 | return addr (ra) | 54// 0 | previous frame (fp)| 55// -----+--------------------+ <-- frame ptr (fp) 56// -1 | StackFrame::WASM | 57// -2 | instance | 58// -3 | feedback vector | 59// -4 | tiering budget | 60// -----+--------------------+--------------------------- 61// -5 | slot 0 (high) | ^ 62// -6 | slot 0 (low) | | 63// -7 | slot 1 (high) | Frame slots 64// -8 | slot 1 (low) | | 65// | | v 66// -----+--------------------+ <-- stack ptr (sp) 67// 68#if defined(V8_TARGET_BIG_ENDIAN) 69constexpr int32_t kLowWordOffset = 4; 70constexpr int32_t kHighWordOffset = 0; 71#else 72constexpr int32_t kLowWordOffset = 0; 73constexpr int32_t kHighWordOffset = 4; 74#endif 75 76constexpr int kInstanceOffset = 2 * kSystemPointerSize; 77constexpr int kFeedbackVectorOffset = 3 * kSystemPointerSize; 78constexpr int kTierupBudgetOffset = 4 * kSystemPointerSize; 79 80inline MemOperand GetStackSlot(int offset) { return MemOperand(fp, -offset); } 81 82inline MemOperand GetHalfStackSlot(int offset, RegPairHalf half) { 83 int32_t half_offset = 84 half == kLowWord ? 0 : LiftoffAssembler::kStackSlotSize / 2; 85 return MemOperand(offset > 0 ? fp : sp, -offset + half_offset); 86} 87 88inline MemOperand GetInstanceOperand() { return GetStackSlot(kInstanceOffset); } 89 90inline void Load(LiftoffAssembler* assm, LiftoffRegister dst, Register base, 91 int32_t offset, ValueKind kind) { 92 MemOperand src(base, offset); 93 switch (kind) { 94 case kI32: 95 case kRef: 96 case kOptRef: 97 case kRtt: 98 assm->lw(dst.gp(), src); 99 break; 100 case kI64: 101 assm->lw(dst.low_gp(), 102 MemOperand(base, offset + liftoff::kLowWordOffset)); 103 assm->lw(dst.high_gp(), 104 MemOperand(base, offset + liftoff::kHighWordOffset)); 105 break; 106 case kF32: 107 assm->lwc1(dst.fp(), src); 108 break; 109 case kF64: 110 assm->Ldc1(dst.fp(), src); 111 break; 112 default: 113 UNREACHABLE(); 114 } 115} 116 117inline void Store(LiftoffAssembler* assm, Register base, int32_t offset, 118 LiftoffRegister src, ValueKind kind) { 119 MemOperand dst(base, offset); 120 switch (kind) { 121 case kI32: 122 case kOptRef: 123 case kRef: 124 case kRtt: 125 assm->Usw(src.gp(), dst); 126 break; 127 case kI64: 128 assm->Usw(src.low_gp(), 129 MemOperand(base, offset + liftoff::kLowWordOffset)); 130 assm->Usw(src.high_gp(), 131 MemOperand(base, offset + liftoff::kHighWordOffset)); 132 break; 133 case kF32: 134 assm->Uswc1(src.fp(), dst, t8); 135 break; 136 case kF64: 137 assm->Usdc1(src.fp(), dst, t8); 138 break; 139 default: 140 UNREACHABLE(); 141 } 142} 143 144inline void push(LiftoffAssembler* assm, LiftoffRegister reg, ValueKind kind) { 145 switch (kind) { 146 case kI32: 147 case kOptRef: 148 case kRef: 149 case kRtt: 150 assm->push(reg.gp()); 151 break; 152 case kI64: 153 assm->Push(reg.high_gp(), reg.low_gp()); 154 break; 155 case kF32: 156 assm->addiu(sp, sp, -sizeof(float)); 157 assm->swc1(reg.fp(), MemOperand(sp, 0)); 158 break; 159 case kF64: 160 assm->addiu(sp, sp, -sizeof(double)); 161 assm->Sdc1(reg.fp(), MemOperand(sp, 0)); 162 break; 163 default: 164 UNREACHABLE(); 165 } 166} 167 168inline Register EnsureNoAlias(Assembler* assm, Register reg, 169 LiftoffRegister must_not_alias, 170 UseScratchRegisterScope* temps) { 171 if (reg != must_not_alias.low_gp() && reg != must_not_alias.high_gp()) 172 return reg; 173 Register tmp = temps->Acquire(); 174 DCHECK_NE(must_not_alias.low_gp(), tmp); 175 DCHECK_NE(must_not_alias.high_gp(), tmp); 176 assm->movz(tmp, reg, zero_reg); 177 return tmp; 178} 179 180#if defined(V8_TARGET_BIG_ENDIAN) 181inline void ChangeEndiannessLoad(LiftoffAssembler* assm, LiftoffRegister dst, 182 LoadType type, LiftoffRegList pinned) { 183 bool is_float = false; 184 LiftoffRegister tmp = dst; 185 switch (type.value()) { 186 case LoadType::kI64Load8U: 187 case LoadType::kI64Load8S: 188 case LoadType::kI32Load8U: 189 case LoadType::kI32Load8S: 190 // No need to change endianness for byte size. 191 return; 192 case LoadType::kF32Load: 193 is_float = true; 194 tmp = assm->GetUnusedRegister(kGpReg, pinned); 195 assm->emit_type_conversion(kExprI32ReinterpretF32, tmp, dst); 196 V8_FALLTHROUGH; 197 case LoadType::kI32Load: 198 assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4); 199 break; 200 case LoadType::kI32Load16S: 201 assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 2); 202 break; 203 case LoadType::kI32Load16U: 204 assm->TurboAssembler::ByteSwapUnsigned(tmp.gp(), tmp.gp(), 2); 205 break; 206 case LoadType::kF64Load: 207 is_float = true; 208 tmp = assm->GetUnusedRegister(kGpRegPair, pinned); 209 assm->emit_type_conversion(kExprI64ReinterpretF64, tmp, dst); 210 V8_FALLTHROUGH; 211 case LoadType::kI64Load: 212 assm->TurboAssembler::Move(kScratchReg, tmp.low_gp()); 213 assm->TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.high_gp(), 4); 214 assm->TurboAssembler::ByteSwapSigned(tmp.high_gp(), kScratchReg, 4); 215 break; 216 case LoadType::kI64Load16U: 217 assm->TurboAssembler::ByteSwapUnsigned(tmp.low_gp(), tmp.low_gp(), 2); 218 assm->TurboAssembler::Move(tmp.high_gp(), zero_reg); 219 break; 220 case LoadType::kI64Load16S: 221 assm->TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.low_gp(), 2); 222 assm->sra(tmp.high_gp(), tmp.low_gp(), 31); 223 break; 224 case LoadType::kI64Load32U: 225 assm->TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.low_gp(), 4); 226 assm->TurboAssembler::Move(tmp.high_gp(), zero_reg); 227 break; 228 case LoadType::kI64Load32S: 229 assm->TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.low_gp(), 4); 230 assm->sra(tmp.high_gp(), tmp.low_gp(), 31); 231 break; 232 default: 233 UNREACHABLE(); 234 } 235 236 if (is_float) { 237 switch (type.value()) { 238 case LoadType::kF32Load: 239 assm->emit_type_conversion(kExprF32ReinterpretI32, dst, tmp); 240 break; 241 case LoadType::kF64Load: 242 assm->emit_type_conversion(kExprF64ReinterpretI64, dst, tmp); 243 break; 244 default: 245 UNREACHABLE(); 246 } 247 } 248} 249 250inline void ChangeEndiannessStore(LiftoffAssembler* assm, LiftoffRegister src, 251 StoreType type, LiftoffRegList pinned) { 252 bool is_float = false; 253 LiftoffRegister tmp = src; 254 switch (type.value()) { 255 case StoreType::kI64Store8: 256 case StoreType::kI32Store8: 257 // No need to change endianness for byte size. 258 return; 259 case StoreType::kF32Store: 260 is_float = true; 261 tmp = assm->GetUnusedRegister(kGpReg, pinned); 262 assm->emit_type_conversion(kExprI32ReinterpretF32, tmp, src); 263 V8_FALLTHROUGH; 264 case StoreType::kI32Store: 265 assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 4); 266 break; 267 case StoreType::kI32Store16: 268 assm->TurboAssembler::ByteSwapSigned(tmp.gp(), tmp.gp(), 2); 269 break; 270 case StoreType::kF64Store: 271 is_float = true; 272 tmp = assm->GetUnusedRegister(kGpRegPair, pinned); 273 assm->emit_type_conversion(kExprI64ReinterpretF64, tmp, src); 274 V8_FALLTHROUGH; 275 case StoreType::kI64Store: 276 assm->TurboAssembler::Move(kScratchReg, tmp.low_gp()); 277 assm->TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.high_gp(), 4); 278 assm->TurboAssembler::ByteSwapSigned(tmp.high_gp(), kScratchReg, 4); 279 break; 280 case StoreType::kI64Store32: 281 assm->TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.low_gp(), 4); 282 break; 283 case StoreType::kI64Store16: 284 assm->TurboAssembler::ByteSwapSigned(tmp.low_gp(), tmp.low_gp(), 2); 285 break; 286 default: 287 UNREACHABLE(); 288 } 289 290 if (is_float) { 291 switch (type.value()) { 292 case StoreType::kF32Store: 293 assm->emit_type_conversion(kExprF32ReinterpretI32, src, tmp); 294 break; 295 case StoreType::kF64Store: 296 assm->emit_type_conversion(kExprF64ReinterpretI64, src, tmp); 297 break; 298 default: 299 UNREACHABLE(); 300 } 301 } 302} 303#endif // V8_TARGET_BIG_ENDIAN 304 305} // namespace liftoff 306 307int LiftoffAssembler::PrepareStackFrame() { 308 int offset = pc_offset(); 309 // When the frame size is bigger than 4KB, we need seven instructions for 310 // stack checking, so we reserve space for this case. 311 addiu(sp, sp, 0); 312 nop(); 313 nop(); 314 nop(); 315 nop(); 316 nop(); 317 nop(); 318 return offset; 319} 320 321void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params, 322 int stack_param_delta) { 323 UseScratchRegisterScope temps(this); 324 Register scratch = temps.Acquire(); 325 326 // Push the return address and frame pointer to complete the stack frame. 327 Lw(scratch, MemOperand(fp, 4)); 328 Push(scratch); 329 Lw(scratch, MemOperand(fp, 0)); 330 Push(scratch); 331 332 // Shift the whole frame upwards. 333 int slot_count = num_callee_stack_params + 2; 334 for (int i = slot_count - 1; i >= 0; --i) { 335 Lw(scratch, MemOperand(sp, i * 4)); 336 Sw(scratch, MemOperand(fp, (i - stack_param_delta) * 4)); 337 } 338 339 // Set the new stack and frame pointer. 340 addiu(sp, fp, -stack_param_delta * 4); 341 Pop(ra, fp); 342} 343 344void LiftoffAssembler::AlignFrameSize() {} 345 346void LiftoffAssembler::PatchPrepareStackFrame( 347 int offset, SafepointTableBuilder* safepoint_table_builder) { 348 // The frame_size includes the frame marker and the instance slot. Both are 349 // pushed as part of frame construction, so we don't need to allocate memory 350 // for them anymore. 351 int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize; 352 353 // We can't run out of space, just pass anything big enough to not cause the 354 // assembler to try to grow the buffer. 355 constexpr int kAvailableSpace = 256; 356 TurboAssembler patching_assembler( 357 nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, 358 ExternalAssemblerBuffer(buffer_start_ + offset, kAvailableSpace)); 359 360 if (V8_LIKELY(frame_size < 4 * KB)) { 361 // This is the standard case for small frames: just subtract from SP and be 362 // done with it. 363 patching_assembler.Addu(sp, sp, Operand(-frame_size)); 364 return; 365 } 366 367 // The frame size is bigger than 4KB, so we might overflow the available stack 368 // space if we first allocate the frame and then do the stack check (we will 369 // need some remaining stack space for throwing the exception). That's why we 370 // check the available stack space before we allocate the frame. To do this we 371 // replace the {__ Addu(sp, sp, -framesize)} with a jump to OOL code that does 372 // this "extended stack check". 373 // 374 // The OOL code can simply be generated here with the normal assembler, 375 // because all other code generation, including OOL code, has already finished 376 // when {PatchPrepareStackFrame} is called. The function prologue then jumps 377 // to the current {pc_offset()} to execute the OOL code for allocating the 378 // large frame. 379 // Emit the unconditional branch in the function prologue (from {offset} to 380 // {pc_offset()}). 381 382 int imm32 = pc_offset() - offset - 3 * kInstrSize; 383 patching_assembler.BranchLong(imm32); 384 385 // If the frame is bigger than the stack, we throw the stack overflow 386 // exception unconditionally. Thereby we can avoid the integer overflow 387 // check in the condition code. 388 RecordComment("OOL: stack check for large frame"); 389 Label continuation; 390 if (frame_size < FLAG_stack_size * 1024) { 391 Register stack_limit = kScratchReg; 392 Lw(stack_limit, 393 FieldMemOperand(kWasmInstanceRegister, 394 WasmInstanceObject::kRealStackLimitAddressOffset)); 395 Lw(stack_limit, MemOperand(stack_limit)); 396 Addu(stack_limit, stack_limit, Operand(frame_size)); 397 Branch(&continuation, uge, sp, Operand(stack_limit)); 398 } 399 400 Call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL); 401 // The call will not return; just define an empty safepoint. 402 safepoint_table_builder->DefineSafepoint(this); 403 if (FLAG_debug_code) stop(); 404 405 bind(&continuation); 406 407 // Now allocate the stack space. Note that this might do more than just 408 // decrementing the SP; 409 Addu(sp, sp, Operand(-frame_size)); 410 411 // Jump back to the start of the function, from {pc_offset()} to 412 // right after the reserved space for the {__ Addu(sp, sp, -framesize)} (which 413 // is a jump now). 414 int func_start_offset = offset + 7 * kInstrSize; 415 imm32 = func_start_offset - pc_offset() - 3 * kInstrSize; 416 BranchLong(imm32); 417} 418 419void LiftoffAssembler::FinishCode() {} 420 421void LiftoffAssembler::AbortCompilation() {} 422 423// static 424constexpr int LiftoffAssembler::StaticStackFrameSize() { 425 return liftoff::kTierupBudgetOffset; 426} 427 428int LiftoffAssembler::SlotSizeForType(ValueKind kind) { 429 switch (kind) { 430 case kS128: 431 return value_kind_size(kind); 432 default: 433 return kStackSlotSize; 434 } 435} 436 437bool LiftoffAssembler::NeedsAlignment(ValueKind kind) { 438 return kind == kS128 || is_reference(kind); 439} 440 441void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value, 442 RelocInfo::Mode rmode) { 443 switch (value.type().kind()) { 444 case kI32: 445 TurboAssembler::li(reg.gp(), Operand(value.to_i32(), rmode)); 446 break; 447 case kI64: { 448 DCHECK(RelocInfo::IsNoInfo(rmode)); 449 int32_t low_word = value.to_i64(); 450 int32_t high_word = value.to_i64() >> 32; 451 TurboAssembler::li(reg.low_gp(), Operand(low_word)); 452 TurboAssembler::li(reg.high_gp(), Operand(high_word)); 453 break; 454 } 455 case kF32: 456 TurboAssembler::Move(reg.fp(), value.to_f32_boxed().get_bits()); 457 break; 458 case kF64: 459 TurboAssembler::Move(reg.fp(), value.to_f64_boxed().get_bits()); 460 break; 461 default: 462 UNREACHABLE(); 463 } 464} 465 466void LiftoffAssembler::LoadInstanceFromFrame(Register dst) { 467 lw(dst, liftoff::GetInstanceOperand()); 468} 469 470void LiftoffAssembler::LoadFromInstance(Register dst, Register instance, 471 int32_t offset, int size) { 472 DCHECK_LE(0, offset); 473 switch (size) { 474 case 1: 475 lb(dst, MemOperand(instance, offset)); 476 break; 477 case 4: 478 lw(dst, MemOperand(instance, offset)); 479 break; 480 default: 481 UNIMPLEMENTED(); 482 } 483} 484 485void LiftoffAssembler::LoadTaggedPointerFromInstance(Register dst, 486 Register instance, 487 int32_t offset) { 488 STATIC_ASSERT(kTaggedSize == kSystemPointerSize); 489 lw(dst, MemOperand(instance, offset)); 490} 491 492void LiftoffAssembler::SpillInstance(Register instance) { 493 sw(instance, liftoff::GetInstanceOperand()); 494} 495 496void LiftoffAssembler::ResetOSRTarget() {} 497 498void LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr, 499 Register offset_reg, 500 int32_t offset_imm, 501 LiftoffRegList pinned) { 502 STATIC_ASSERT(kTaggedSize == kInt32Size); 503 Load(LiftoffRegister(dst), src_addr, offset_reg, 504 static_cast<uint32_t>(offset_imm), LoadType::kI32Load, pinned); 505} 506 507void LiftoffAssembler::LoadFullPointer(Register dst, Register src_addr, 508 int32_t offset_imm) { 509 MemOperand src_op = MemOperand(src_addr, offset_imm); 510 lw(dst, src_op); 511} 512 513void LiftoffAssembler::StoreTaggedPointer(Register dst_addr, 514 Register offset_reg, 515 int32_t offset_imm, 516 LiftoffRegister src, 517 LiftoffRegList pinned, 518 SkipWriteBarrier skip_write_barrier) { 519 STATIC_ASSERT(kTaggedSize == kInt32Size); 520 Register dst = no_reg; 521 if (offset_reg != no_reg) { 522 dst = pinned.set(GetUnusedRegister(kGpReg, pinned)).gp(); 523 emit_ptrsize_add(dst, dst_addr, offset_reg); 524 } 525 MemOperand dst_op = (offset_reg != no_reg) ? MemOperand(dst, offset_imm) 526 : MemOperand(dst_addr, offset_imm); 527 Sw(src.gp(), dst_op); 528 529 if (skip_write_barrier || FLAG_disable_write_barriers) return; 530 531 // The write barrier. 532 Label write_barrier; 533 Label exit; 534 Register scratch = pinned.set(GetUnusedRegister(kGpReg, pinned)).gp(); 535 CheckPageFlag(dst_addr, scratch, 536 MemoryChunk::kPointersFromHereAreInterestingMask, ne, 537 &write_barrier); 538 Branch(&exit); 539 bind(&write_barrier); 540 JumpIfSmi(src.gp(), &exit); 541 CheckPageFlag(src.gp(), scratch, 542 MemoryChunk::kPointersToHereAreInterestingMask, eq, &exit); 543 Addu(scratch, dst_op.rm(), dst_op.offset()); 544 CallRecordWriteStubSaveRegisters( 545 dst_addr, scratch, RememberedSetAction::kEmit, SaveFPRegsMode::kSave, 546 StubCallMode::kCallWasmRuntimeStub); 547 bind(&exit); 548} 549 550void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr, 551 Register offset_reg, uint32_t offset_imm, 552 LoadType type, LiftoffRegList pinned, 553 uint32_t* protected_load_pc, bool is_load_mem, 554 bool i64_offset) { 555 Register src = no_reg; 556 if (offset_reg != no_reg) { 557 src = GetUnusedRegister(kGpReg, pinned).gp(); 558 emit_ptrsize_add(src, src_addr, offset_reg); 559 } 560 MemOperand src_op = (offset_reg != no_reg) ? MemOperand(src, offset_imm) 561 : MemOperand(src_addr, offset_imm); 562 563 if (protected_load_pc) *protected_load_pc = pc_offset(); 564 switch (type.value()) { 565 case LoadType::kI32Load8U: 566 lbu(dst.gp(), src_op); 567 break; 568 case LoadType::kI64Load8U: 569 lbu(dst.low_gp(), src_op); 570 xor_(dst.high_gp(), dst.high_gp(), dst.high_gp()); 571 break; 572 case LoadType::kI32Load8S: 573 lb(dst.gp(), src_op); 574 break; 575 case LoadType::kI64Load8S: 576 lb(dst.low_gp(), src_op); 577 TurboAssembler::Move(dst.high_gp(), dst.low_gp()); 578 sra(dst.high_gp(), dst.high_gp(), 31); 579 break; 580 case LoadType::kI32Load16U: 581 TurboAssembler::Ulhu(dst.gp(), src_op); 582 break; 583 case LoadType::kI64Load16U: 584 TurboAssembler::Ulhu(dst.low_gp(), src_op); 585 xor_(dst.high_gp(), dst.high_gp(), dst.high_gp()); 586 break; 587 case LoadType::kI32Load16S: 588 TurboAssembler::Ulh(dst.gp(), src_op); 589 break; 590 case LoadType::kI64Load16S: 591 TurboAssembler::Ulh(dst.low_gp(), src_op); 592 TurboAssembler::Move(dst.high_gp(), dst.low_gp()); 593 sra(dst.high_gp(), dst.high_gp(), 31); 594 break; 595 case LoadType::kI32Load: 596 TurboAssembler::Ulw(dst.gp(), src_op); 597 break; 598 case LoadType::kI64Load32U: 599 TurboAssembler::Ulw(dst.low_gp(), src_op); 600 xor_(dst.high_gp(), dst.high_gp(), dst.high_gp()); 601 break; 602 case LoadType::kI64Load32S: 603 TurboAssembler::Ulw(dst.low_gp(), src_op); 604 TurboAssembler::Move(dst.high_gp(), dst.low_gp()); 605 sra(dst.high_gp(), dst.high_gp(), 31); 606 break; 607 case LoadType::kI64Load: { 608 MemOperand src_op = 609 (offset_reg != no_reg) 610 ? MemOperand(src, offset_imm + liftoff::kLowWordOffset) 611 : MemOperand(src_addr, offset_imm + liftoff::kLowWordOffset); 612 MemOperand src_op_upper = 613 (offset_reg != no_reg) 614 ? MemOperand(src, offset_imm + liftoff::kHighWordOffset) 615 : MemOperand(src_addr, offset_imm + liftoff::kHighWordOffset); 616 { 617 UseScratchRegisterScope temps(this); 618 Register temp = dst.low_gp(); 619 if (dst.low_gp() == src_op_upper.rm()) temp = temps.Acquire(); 620 TurboAssembler::Ulw(temp, src_op); 621 TurboAssembler::Ulw(dst.high_gp(), src_op_upper); 622 if (dst.low_gp() == src_op_upper.rm()) mov(dst.low_gp(), temp); 623 } 624 break; 625 } 626 case LoadType::kF32Load: 627 TurboAssembler::Ulwc1(dst.fp(), src_op, t8); 628 break; 629 case LoadType::kF64Load: 630 TurboAssembler::Uldc1(dst.fp(), src_op, t8); 631 break; 632 default: 633 UNREACHABLE(); 634 } 635 636#if defined(V8_TARGET_BIG_ENDIAN) 637 if (is_load_mem) { 638 pinned.set(src_op.rm()); 639 liftoff::ChangeEndiannessLoad(this, dst, type, pinned); 640 } 641#endif 642} 643 644void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, 645 uint32_t offset_imm, LiftoffRegister src, 646 StoreType type, LiftoffRegList pinned, 647 uint32_t* protected_store_pc, bool is_store_mem) { 648 Register dst = no_reg; 649 MemOperand dst_op = MemOperand(dst_addr, offset_imm); 650 if (offset_reg != no_reg) { 651 if (is_store_mem) { 652 pinned.set(src); 653 } 654 dst = GetUnusedRegister(kGpReg, pinned).gp(); 655 emit_ptrsize_add(dst, dst_addr, offset_reg); 656 dst_op = MemOperand(dst, offset_imm); 657 } 658 659#if defined(V8_TARGET_BIG_ENDIAN) 660 if (is_store_mem) { 661 pinned = pinned | LiftoffRegList{dst_op.rm(), src}; 662 LiftoffRegister tmp = GetUnusedRegister(src.reg_class(), pinned); 663 // Save original value. 664 Move(tmp, src, type.value_type()); 665 666 src = tmp; 667 pinned.set(tmp); 668 liftoff::ChangeEndiannessStore(this, src, type, pinned); 669 } 670#endif 671 672 if (protected_store_pc) *protected_store_pc = pc_offset(); 673 switch (type.value()) { 674 case StoreType::kI64Store8: 675 src = src.low(); 676 V8_FALLTHROUGH; 677 case StoreType::kI32Store8: 678 sb(src.gp(), dst_op); 679 break; 680 case StoreType::kI64Store16: 681 src = src.low(); 682 V8_FALLTHROUGH; 683 case StoreType::kI32Store16: 684 TurboAssembler::Ush(src.gp(), dst_op, t8); 685 break; 686 case StoreType::kI64Store32: 687 src = src.low(); 688 V8_FALLTHROUGH; 689 case StoreType::kI32Store: 690 TurboAssembler::Usw(src.gp(), dst_op); 691 break; 692 case StoreType::kI64Store: { 693 MemOperand dst_op_lower(dst_op.rm(), 694 offset_imm + liftoff::kLowWordOffset); 695 MemOperand dst_op_upper(dst_op.rm(), 696 offset_imm + liftoff::kHighWordOffset); 697 TurboAssembler::Usw(src.low_gp(), dst_op_lower); 698 TurboAssembler::Usw(src.high_gp(), dst_op_upper); 699 break; 700 } 701 case StoreType::kF32Store: 702 TurboAssembler::Uswc1(src.fp(), dst_op, t8); 703 break; 704 case StoreType::kF64Store: 705 TurboAssembler::Usdc1(src.fp(), dst_op, t8); 706 break; 707 default: 708 UNREACHABLE(); 709 } 710} 711 712void LiftoffAssembler::AtomicLoad(LiftoffRegister dst, Register src_addr, 713 Register offset_reg, uint32_t offset_imm, 714 LoadType type, LiftoffRegList pinned) { 715 bailout(kAtomics, "AtomicLoad"); 716} 717 718void LiftoffAssembler::AtomicStore(Register dst_addr, Register offset_reg, 719 uint32_t offset_imm, LiftoffRegister src, 720 StoreType type, LiftoffRegList pinned) { 721 bailout(kAtomics, "AtomicStore"); 722} 723 724void LiftoffAssembler::AtomicAdd(Register dst_addr, Register offset_reg, 725 uint32_t offset_imm, LiftoffRegister value, 726 LiftoffRegister result, StoreType type) { 727 bailout(kAtomics, "AtomicAdd"); 728} 729 730void LiftoffAssembler::AtomicSub(Register dst_addr, Register offset_reg, 731 uint32_t offset_imm, LiftoffRegister value, 732 LiftoffRegister result, StoreType type) { 733 bailout(kAtomics, "AtomicSub"); 734} 735 736void LiftoffAssembler::AtomicAnd(Register dst_addr, Register offset_reg, 737 uint32_t offset_imm, LiftoffRegister value, 738 LiftoffRegister result, StoreType type) { 739 bailout(kAtomics, "AtomicAnd"); 740} 741 742void LiftoffAssembler::AtomicOr(Register dst_addr, Register offset_reg, 743 uint32_t offset_imm, LiftoffRegister value, 744 LiftoffRegister result, StoreType type) { 745 bailout(kAtomics, "AtomicOr"); 746} 747 748void LiftoffAssembler::AtomicXor(Register dst_addr, Register offset_reg, 749 uint32_t offset_imm, LiftoffRegister value, 750 LiftoffRegister result, StoreType type) { 751 bailout(kAtomics, "AtomicXor"); 752} 753 754void LiftoffAssembler::AtomicExchange(Register dst_addr, Register offset_reg, 755 uint32_t offset_imm, 756 LiftoffRegister value, 757 LiftoffRegister result, StoreType type) { 758 bailout(kAtomics, "AtomicExchange"); 759} 760 761void LiftoffAssembler::AtomicCompareExchange( 762 Register dst_addr, Register offset_reg, uint32_t offset_imm, 763 LiftoffRegister expected, LiftoffRegister new_value, LiftoffRegister result, 764 StoreType type) { 765 bailout(kAtomics, "AtomicCompareExchange"); 766} 767 768void LiftoffAssembler::AtomicFence() { sync(); } 769 770void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst, 771 uint32_t caller_slot_idx, 772 ValueKind kind) { 773 int32_t offset = kSystemPointerSize * (caller_slot_idx + 1); 774 liftoff::Load(this, dst, fp, offset, kind); 775} 776 777void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src, 778 uint32_t caller_slot_idx, 779 ValueKind kind) { 780 int32_t offset = kSystemPointerSize * (caller_slot_idx + 1); 781 liftoff::Store(this, fp, offset, src, kind); 782} 783 784void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister dst, int offset, 785 ValueKind kind) { 786 liftoff::Load(this, dst, sp, offset, kind); 787} 788 789void LiftoffAssembler::MoveStackValue(uint32_t dst_offset, uint32_t src_offset, 790 ValueKind kind) { 791 DCHECK_NE(dst_offset, src_offset); 792 LiftoffRegister reg = GetUnusedRegister(reg_class_for(kind), {}); 793 Fill(reg, src_offset, kind); 794 Spill(dst_offset, reg, kind); 795} 796 797void LiftoffAssembler::Move(Register dst, Register src, ValueKind kind) { 798 DCHECK_NE(dst, src); 799 TurboAssembler::mov(dst, src); 800} 801 802void LiftoffAssembler::Move(DoubleRegister dst, DoubleRegister src, 803 ValueKind kind) { 804 DCHECK_NE(dst, src); 805 TurboAssembler::Move(dst, src); 806} 807 808void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueKind kind) { 809 RecordUsedSpillOffset(offset); 810 MemOperand dst = liftoff::GetStackSlot(offset); 811 switch (kind) { 812 case kI32: 813 case kRef: 814 case kOptRef: 815 case kRtt: 816 sw(reg.gp(), dst); 817 break; 818 case kI64: 819 sw(reg.low_gp(), liftoff::GetHalfStackSlot(offset, kLowWord)); 820 sw(reg.high_gp(), liftoff::GetHalfStackSlot(offset, kHighWord)); 821 break; 822 case kF32: 823 swc1(reg.fp(), dst); 824 break; 825 case kF64: 826 TurboAssembler::Sdc1(reg.fp(), dst); 827 break; 828 default: 829 UNREACHABLE(); 830 } 831} 832 833void LiftoffAssembler::Spill(int offset, WasmValue value) { 834 RecordUsedSpillOffset(offset); 835 MemOperand dst = liftoff::GetStackSlot(offset); 836 switch (value.type().kind()) { 837 case kI32: 838 case kRef: 839 case kOptRef: { 840 LiftoffRegister tmp = GetUnusedRegister(kGpReg, {}); 841 TurboAssembler::li(tmp.gp(), Operand(value.to_i32())); 842 sw(tmp.gp(), dst); 843 break; 844 } 845 case kI64: { 846 LiftoffRegister tmp = GetUnusedRegister(kGpRegPair, {}); 847 848 int32_t low_word = value.to_i64(); 849 int32_t high_word = value.to_i64() >> 32; 850 TurboAssembler::li(tmp.low_gp(), Operand(low_word)); 851 TurboAssembler::li(tmp.high_gp(), Operand(high_word)); 852 853 sw(tmp.low_gp(), liftoff::GetHalfStackSlot(offset, kLowWord)); 854 sw(tmp.high_gp(), liftoff::GetHalfStackSlot(offset, kHighWord)); 855 break; 856 } 857 default: 858 // kWasmF32 and kWasmF64 are unreachable, since those 859 // constants are not tracked. 860 UNREACHABLE(); 861 } 862} 863 864void LiftoffAssembler::Fill(LiftoffRegister reg, int offset, ValueKind kind) { 865 MemOperand src = liftoff::GetStackSlot(offset); 866 switch (kind) { 867 case kI32: 868 case kRef: 869 case kOptRef: 870 lw(reg.gp(), src); 871 break; 872 case kI64: 873 lw(reg.low_gp(), liftoff::GetHalfStackSlot(offset, kLowWord)); 874 lw(reg.high_gp(), liftoff::GetHalfStackSlot(offset, kHighWord)); 875 break; 876 case kF32: 877 lwc1(reg.fp(), src); 878 break; 879 case kF64: 880 TurboAssembler::Ldc1(reg.fp(), src); 881 break; 882 default: 883 UNREACHABLE(); 884 } 885} 886 887void LiftoffAssembler::FillI64Half(Register reg, int offset, RegPairHalf half) { 888 lw(reg, liftoff::GetHalfStackSlot(offset, half)); 889} 890 891void LiftoffAssembler::FillStackSlotsWithZero(int start, int size) { 892 DCHECK_LT(0, size); 893 DCHECK_EQ(0, size % 4); 894 RecordUsedSpillOffset(start + size); 895 896 if (size <= 48) { 897 // Special straight-line code for up to 12 words. Generates one 898 // instruction per word (<=12 instructions total). 899 for (int offset = 4; offset <= size; offset += 4) { 900 Sw(zero_reg, liftoff::GetStackSlot(start + offset)); 901 } 902 } else { 903 // General case for bigger counts (12 instructions). 904 // Use a0 for start address (inclusive), a1 for end address (exclusive). 905 Push(a1, a0); 906 Addu(a0, fp, Operand(-start - size)); 907 Addu(a1, fp, Operand(-start)); 908 909 Label loop; 910 bind(&loop); 911 Sw(zero_reg, MemOperand(a0)); 912 addiu(a0, a0, kSystemPointerSize); 913 BranchShort(&loop, ne, a0, Operand(a1)); 914 915 Pop(a1, a0); 916 } 917} 918 919void LiftoffAssembler::emit_i32_mul(Register dst, Register lhs, Register rhs) { 920 TurboAssembler::Mul(dst, lhs, rhs); 921} 922 923void LiftoffAssembler::emit_i32_divs(Register dst, Register lhs, Register rhs, 924 Label* trap_div_by_zero, 925 Label* trap_div_unrepresentable) { 926 TurboAssembler::Branch(trap_div_by_zero, eq, rhs, Operand(zero_reg)); 927 928 // Check if lhs == kMinInt and rhs == -1, since this case is unrepresentable. 929 TurboAssembler::li(kScratchReg, 1); 930 TurboAssembler::li(kScratchReg2, 1); 931 TurboAssembler::LoadZeroOnCondition(kScratchReg, lhs, Operand(kMinInt), eq); 932 TurboAssembler::LoadZeroOnCondition(kScratchReg2, rhs, Operand(-1), eq); 933 addu(kScratchReg, kScratchReg, kScratchReg2); 934 TurboAssembler::Branch(trap_div_unrepresentable, eq, kScratchReg, 935 Operand(zero_reg)); 936 937 TurboAssembler::Div(dst, lhs, rhs); 938} 939 940void LiftoffAssembler::emit_i32_divu(Register dst, Register lhs, Register rhs, 941 Label* trap_div_by_zero) { 942 TurboAssembler::Branch(trap_div_by_zero, eq, rhs, Operand(zero_reg)); 943 TurboAssembler::Divu(dst, lhs, rhs); 944} 945 946void LiftoffAssembler::emit_i32_rems(Register dst, Register lhs, Register rhs, 947 Label* trap_div_by_zero) { 948 TurboAssembler::Branch(trap_div_by_zero, eq, rhs, Operand(zero_reg)); 949 TurboAssembler::Mod(dst, lhs, rhs); 950} 951 952void LiftoffAssembler::emit_i32_remu(Register dst, Register lhs, Register rhs, 953 Label* trap_div_by_zero) { 954 TurboAssembler::Branch(trap_div_by_zero, eq, rhs, Operand(zero_reg)); 955 TurboAssembler::Modu(dst, lhs, rhs); 956} 957 958#define I32_BINOP(name, instruction) \ 959 void LiftoffAssembler::emit_i32_##name(Register dst, Register lhs, \ 960 Register rhs) { \ 961 instruction(dst, lhs, rhs); \ 962 } 963 964// clang-format off 965I32_BINOP(add, addu) 966I32_BINOP(sub, subu) 967I32_BINOP(and, and_) 968I32_BINOP(or, or_) 969I32_BINOP(xor, xor_) 970// clang-format on 971 972#undef I32_BINOP 973 974#define I32_BINOP_I(name, instruction) \ 975 void LiftoffAssembler::emit_i32_##name##i(Register dst, Register lhs, \ 976 int32_t imm) { \ 977 instruction(dst, lhs, Operand(imm)); \ 978 } 979 980// clang-format off 981I32_BINOP_I(add, Addu) 982I32_BINOP_I(sub, Subu) 983I32_BINOP_I(and, And) 984I32_BINOP_I(or, Or) 985I32_BINOP_I(xor, Xor) 986// clang-format on 987 988#undef I32_BINOP_I 989 990void LiftoffAssembler::emit_i32_clz(Register dst, Register src) { 991 TurboAssembler::Clz(dst, src); 992} 993 994void LiftoffAssembler::emit_i32_ctz(Register dst, Register src) { 995 TurboAssembler::Ctz(dst, src); 996} 997 998bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) { 999 TurboAssembler::Popcnt(dst, src); 1000 return true; 1001} 1002 1003#define I32_SHIFTOP(name, instruction) \ 1004 void LiftoffAssembler::emit_i32_##name(Register dst, Register src, \ 1005 Register amount) { \ 1006 instruction(dst, src, amount); \ 1007 } 1008#define I32_SHIFTOP_I(name, instruction) \ 1009 I32_SHIFTOP(name, instruction##v) \ 1010 void LiftoffAssembler::emit_i32_##name##i(Register dst, Register src, \ 1011 int amount) { \ 1012 DCHECK(is_uint5(amount)); \ 1013 instruction(dst, src, amount); \ 1014 } 1015 1016I32_SHIFTOP_I(shl, sll) 1017I32_SHIFTOP_I(sar, sra) 1018I32_SHIFTOP_I(shr, srl) 1019 1020#undef I32_SHIFTOP 1021#undef I32_SHIFTOP_I 1022 1023void LiftoffAssembler::emit_i64_addi(LiftoffRegister dst, LiftoffRegister lhs, 1024 int64_t imm) { 1025 LiftoffRegister imm_reg = 1026 GetUnusedRegister(kGpRegPair, LiftoffRegList{dst, lhs}); 1027 int32_t imm_low_word = static_cast<int32_t>(imm); 1028 int32_t imm_high_word = static_cast<int32_t>(imm >> 32); 1029 TurboAssembler::li(imm_reg.low_gp(), imm_low_word); 1030 TurboAssembler::li(imm_reg.high_gp(), imm_high_word); 1031 TurboAssembler::AddPair(dst.low_gp(), dst.high_gp(), lhs.low_gp(), 1032 lhs.high_gp(), imm_reg.low_gp(), imm_reg.high_gp(), 1033 kScratchReg, kScratchReg2); 1034} 1035 1036void LiftoffAssembler::emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs, 1037 LiftoffRegister rhs) { 1038 TurboAssembler::MulPair(dst.low_gp(), dst.high_gp(), lhs.low_gp(), 1039 lhs.high_gp(), rhs.low_gp(), rhs.high_gp(), 1040 kScratchReg, kScratchReg2); 1041} 1042 1043bool LiftoffAssembler::emit_i64_divs(LiftoffRegister dst, LiftoffRegister lhs, 1044 LiftoffRegister rhs, 1045 Label* trap_div_by_zero, 1046 Label* trap_div_unrepresentable) { 1047 return false; 1048} 1049 1050bool LiftoffAssembler::emit_i64_divu(LiftoffRegister dst, LiftoffRegister lhs, 1051 LiftoffRegister rhs, 1052 Label* trap_div_by_zero) { 1053 return false; 1054} 1055 1056bool LiftoffAssembler::emit_i64_rems(LiftoffRegister dst, LiftoffRegister lhs, 1057 LiftoffRegister rhs, 1058 Label* trap_div_by_zero) { 1059 return false; 1060} 1061 1062bool LiftoffAssembler::emit_i64_remu(LiftoffRegister dst, LiftoffRegister lhs, 1063 LiftoffRegister rhs, 1064 Label* trap_div_by_zero) { 1065 return false; 1066} 1067 1068void LiftoffAssembler::emit_i64_add(LiftoffRegister dst, LiftoffRegister lhs, 1069 LiftoffRegister rhs) { 1070 TurboAssembler::AddPair(dst.low_gp(), dst.high_gp(), lhs.low_gp(), 1071 lhs.high_gp(), rhs.low_gp(), rhs.high_gp(), 1072 kScratchReg, kScratchReg2); 1073} 1074 1075void LiftoffAssembler::emit_i64_sub(LiftoffRegister dst, LiftoffRegister lhs, 1076 LiftoffRegister rhs) { 1077 TurboAssembler::SubPair(dst.low_gp(), dst.high_gp(), lhs.low_gp(), 1078 lhs.high_gp(), rhs.low_gp(), rhs.high_gp(), 1079 kScratchReg, kScratchReg2); 1080} 1081 1082namespace liftoff { 1083 1084inline bool IsRegInRegPair(LiftoffRegister pair, Register reg) { 1085 DCHECK(pair.is_gp_pair()); 1086 return pair.low_gp() == reg || pair.high_gp() == reg; 1087} 1088 1089inline void Emit64BitShiftOperation( 1090 LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister src, 1091 Register amount, 1092 void (TurboAssembler::*emit_shift)(Register, Register, Register, Register, 1093 Register, Register, Register)) { 1094 Label move, done; 1095 LiftoffRegList pinned = {dst, src, amount}; 1096 1097 // If some of destination registers are in use, get another, unused pair. 1098 // That way we prevent overwriting some input registers while shifting. 1099 // Do this before any branch so that the cache state will be correct for 1100 // all conditions. 1101 LiftoffRegister tmp = assm->GetUnusedRegister(kGpRegPair, pinned); 1102 1103 // If shift amount is 0, don't do the shifting. 1104 assm->TurboAssembler::Branch(&move, eq, amount, Operand(zero_reg)); 1105 1106 if (liftoff::IsRegInRegPair(dst, amount) || dst.overlaps(src)) { 1107 // Do the actual shift. 1108 (assm->*emit_shift)(tmp.low_gp(), tmp.high_gp(), src.low_gp(), 1109 src.high_gp(), amount, kScratchReg, kScratchReg2); 1110 1111 // Place result in destination register. 1112 assm->TurboAssembler::Move(dst.high_gp(), tmp.high_gp()); 1113 assm->TurboAssembler::Move(dst.low_gp(), tmp.low_gp()); 1114 } else { 1115 (assm->*emit_shift)(dst.low_gp(), dst.high_gp(), src.low_gp(), 1116 src.high_gp(), amount, kScratchReg, kScratchReg2); 1117 } 1118 assm->TurboAssembler::Branch(&done); 1119 1120 // If shift amount is 0, move src to dst. 1121 assm->bind(&move); 1122 assm->TurboAssembler::Move(dst.high_gp(), src.high_gp()); 1123 assm->TurboAssembler::Move(dst.low_gp(), src.low_gp()); 1124 1125 assm->bind(&done); 1126} 1127} // namespace liftoff 1128 1129void LiftoffAssembler::emit_i64_shl(LiftoffRegister dst, LiftoffRegister src, 1130 Register amount) { 1131 liftoff::Emit64BitShiftOperation(this, dst, src, amount, 1132 &TurboAssembler::ShlPair); 1133} 1134 1135void LiftoffAssembler::emit_i64_shli(LiftoffRegister dst, LiftoffRegister src, 1136 int32_t amount) { 1137 UseScratchRegisterScope temps(this); 1138 // {src.low_gp()} will still be needed after writing {dst.high_gp()} and 1139 // {dst.low_gp()}. 1140 Register src_low = liftoff::EnsureNoAlias(this, src.low_gp(), dst, &temps); 1141 Register src_high = src.high_gp(); 1142 // {src.high_gp()} will still be needed after writing {dst.high_gp()}. 1143 if (src_high == dst.high_gp()) { 1144 mov(kScratchReg, src_high); 1145 src_high = kScratchReg; 1146 } 1147 DCHECK_NE(dst.low_gp(), kScratchReg); 1148 DCHECK_NE(dst.high_gp(), kScratchReg); 1149 1150 ShlPair(dst.low_gp(), dst.high_gp(), src_low, src_high, amount, kScratchReg); 1151} 1152 1153void LiftoffAssembler::emit_i64_sar(LiftoffRegister dst, LiftoffRegister src, 1154 Register amount) { 1155 liftoff::Emit64BitShiftOperation(this, dst, src, amount, 1156 &TurboAssembler::SarPair); 1157} 1158 1159void LiftoffAssembler::emit_i64_sari(LiftoffRegister dst, LiftoffRegister src, 1160 int32_t amount) { 1161 UseScratchRegisterScope temps(this); 1162 // {src.high_gp()} will still be needed after writing {dst.high_gp()} and 1163 // {dst.low_gp()}. 1164 Register src_high = liftoff::EnsureNoAlias(this, src.high_gp(), dst, &temps); 1165 DCHECK_NE(dst.low_gp(), kScratchReg); 1166 DCHECK_NE(dst.high_gp(), kScratchReg); 1167 1168 SarPair(dst.low_gp(), dst.high_gp(), src.low_gp(), src_high, amount, 1169 kScratchReg); 1170} 1171 1172void LiftoffAssembler::emit_i64_shr(LiftoffRegister dst, LiftoffRegister src, 1173 Register amount) { 1174 liftoff::Emit64BitShiftOperation(this, dst, src, amount, 1175 &TurboAssembler::ShrPair); 1176} 1177 1178void LiftoffAssembler::emit_i64_shri(LiftoffRegister dst, LiftoffRegister src, 1179 int32_t amount) { 1180 UseScratchRegisterScope temps(this); 1181 // {src.high_gp()} will still be needed after writing {dst.high_gp()} and 1182 // {dst.low_gp()}. 1183 Register src_high = liftoff::EnsureNoAlias(this, src.high_gp(), dst, &temps); 1184 DCHECK_NE(dst.low_gp(), kScratchReg); 1185 DCHECK_NE(dst.high_gp(), kScratchReg); 1186 1187 ShrPair(dst.low_gp(), dst.high_gp(), src.low_gp(), src_high, amount, 1188 kScratchReg); 1189} 1190 1191void LiftoffAssembler::emit_i64_clz(LiftoffRegister dst, LiftoffRegister src) { 1192 // return high == 0 ? 32 + CLZ32(low) : CLZ32(high); 1193 Label done; 1194 Label high_is_zero; 1195 Branch(&high_is_zero, eq, src.high_gp(), Operand(zero_reg)); 1196 1197 clz(dst.low_gp(), src.high_gp()); 1198 jmp(&done); 1199 1200 bind(&high_is_zero); 1201 clz(dst.low_gp(), src.low_gp()); 1202 Addu(dst.low_gp(), dst.low_gp(), Operand(32)); 1203 1204 bind(&done); 1205 mov(dst.high_gp(), zero_reg); // High word of result is always 0. 1206} 1207 1208void LiftoffAssembler::emit_i64_ctz(LiftoffRegister dst, LiftoffRegister src) { 1209 // return low == 0 ? 32 + CTZ32(high) : CTZ32(low); 1210 Label done; 1211 Label low_is_zero; 1212 Branch(&low_is_zero, eq, src.low_gp(), Operand(zero_reg)); 1213 1214 Ctz(dst.low_gp(), src.low_gp()); 1215 jmp(&done); 1216 1217 bind(&low_is_zero); 1218 Ctz(dst.low_gp(), src.high_gp()); 1219 Addu(dst.low_gp(), dst.low_gp(), Operand(32)); 1220 1221 bind(&done); 1222 mov(dst.high_gp(), zero_reg); // High word of result is always 0. 1223} 1224 1225bool LiftoffAssembler::emit_i64_popcnt(LiftoffRegister dst, 1226 LiftoffRegister src) { 1227 // Produce partial popcnts in the two dst registers. 1228 Register src1 = src.high_gp() == dst.low_gp() ? src.high_gp() : src.low_gp(); 1229 Register src2 = src.high_gp() == dst.low_gp() ? src.low_gp() : src.high_gp(); 1230 TurboAssembler::Popcnt(dst.low_gp(), src1); 1231 TurboAssembler::Popcnt(dst.high_gp(), src2); 1232 // Now add the two into the lower dst reg and clear the higher dst reg. 1233 addu(dst.low_gp(), dst.low_gp(), dst.high_gp()); 1234 mov(dst.high_gp(), zero_reg); 1235 return true; 1236} 1237 1238void LiftoffAssembler::IncrementSmi(LiftoffRegister dst, int offset) { 1239 UseScratchRegisterScope temps(this); 1240 Register scratch = temps.Acquire(); 1241 lw(scratch, MemOperand(dst.gp(), offset)); 1242 Addu(scratch, scratch, Operand(Smi::FromInt(1))); 1243 sw(scratch, MemOperand(dst.gp(), offset)); 1244} 1245 1246void LiftoffAssembler::emit_f32_neg(DoubleRegister dst, DoubleRegister src) { 1247 TurboAssembler::Neg_s(dst, src); 1248} 1249 1250void LiftoffAssembler::emit_f64_neg(DoubleRegister dst, DoubleRegister src) { 1251 TurboAssembler::Neg_d(dst, src); 1252} 1253 1254void LiftoffAssembler::emit_f32_min(DoubleRegister dst, DoubleRegister lhs, 1255 DoubleRegister rhs) { 1256 Label ool, done; 1257 TurboAssembler::Float32Min(dst, lhs, rhs, &ool); 1258 Branch(&done); 1259 1260 bind(&ool); 1261 TurboAssembler::Float32MinOutOfLine(dst, lhs, rhs); 1262 bind(&done); 1263} 1264 1265void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs, 1266 DoubleRegister rhs) { 1267 Label ool, done; 1268 TurboAssembler::Float32Max(dst, lhs, rhs, &ool); 1269 Branch(&done); 1270 1271 bind(&ool); 1272 TurboAssembler::Float32MaxOutOfLine(dst, lhs, rhs); 1273 bind(&done); 1274} 1275 1276void LiftoffAssembler::emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs, 1277 DoubleRegister rhs) { 1278 bailout(kComplexOperation, "f32_copysign"); 1279} 1280 1281void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs, 1282 DoubleRegister rhs) { 1283 Label ool, done; 1284 TurboAssembler::Float64Min(dst, lhs, rhs, &ool); 1285 Branch(&done); 1286 1287 bind(&ool); 1288 TurboAssembler::Float64MinOutOfLine(dst, lhs, rhs); 1289 bind(&done); 1290} 1291 1292void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs, 1293 DoubleRegister rhs) { 1294 Label ool, done; 1295 TurboAssembler::Float64Max(dst, lhs, rhs, &ool); 1296 Branch(&done); 1297 1298 bind(&ool); 1299 TurboAssembler::Float64MaxOutOfLine(dst, lhs, rhs); 1300 bind(&done); 1301} 1302 1303void LiftoffAssembler::emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs, 1304 DoubleRegister rhs) { 1305 bailout(kComplexOperation, "f64_copysign"); 1306} 1307 1308#define FP_BINOP(name, instruction) \ 1309 void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \ 1310 DoubleRegister rhs) { \ 1311 instruction(dst, lhs, rhs); \ 1312 } 1313#define FP_UNOP(name, instruction) \ 1314 void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \ 1315 instruction(dst, src); \ 1316 } 1317#define FP_UNOP_RETURN_TRUE(name, instruction) \ 1318 bool LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister src) { \ 1319 instruction(dst, src); \ 1320 return true; \ 1321 } 1322 1323FP_BINOP(f32_add, add_s) 1324FP_BINOP(f32_sub, sub_s) 1325FP_BINOP(f32_mul, mul_s) 1326FP_BINOP(f32_div, div_s) 1327FP_UNOP(f32_abs, abs_s) 1328FP_UNOP_RETURN_TRUE(f32_ceil, Ceil_s_s) 1329FP_UNOP_RETURN_TRUE(f32_floor, Floor_s_s) 1330FP_UNOP_RETURN_TRUE(f32_trunc, Trunc_s_s) 1331FP_UNOP_RETURN_TRUE(f32_nearest_int, Round_s_s) 1332FP_UNOP(f32_sqrt, sqrt_s) 1333FP_BINOP(f64_add, add_d) 1334FP_BINOP(f64_sub, sub_d) 1335FP_BINOP(f64_mul, mul_d) 1336FP_BINOP(f64_div, div_d) 1337FP_UNOP(f64_abs, abs_d) 1338FP_UNOP(f64_sqrt, sqrt_d) 1339 1340#undef FP_BINOP 1341#undef FP_UNOP 1342 1343bool LiftoffAssembler::emit_f64_ceil(DoubleRegister dst, DoubleRegister src) { 1344 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) && 1345 IsFp64Mode()) { 1346 Ceil_d_d(dst, src); 1347 return true; 1348 } 1349 return false; 1350} 1351 1352bool LiftoffAssembler::emit_f64_floor(DoubleRegister dst, DoubleRegister src) { 1353 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) && 1354 IsFp64Mode()) { 1355 Floor_d_d(dst, src); 1356 return true; 1357 } 1358 return false; 1359} 1360 1361bool LiftoffAssembler::emit_f64_trunc(DoubleRegister dst, DoubleRegister src) { 1362 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) && 1363 IsFp64Mode()) { 1364 Trunc_d_d(dst, src); 1365 return true; 1366 } 1367 return false; 1368} 1369 1370bool LiftoffAssembler::emit_f64_nearest_int(DoubleRegister dst, 1371 DoubleRegister src) { 1372 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) && 1373 IsFp64Mode()) { 1374 Round_d_d(dst, src); 1375 return true; 1376 } 1377 return false; 1378} 1379 1380bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode, 1381 LiftoffRegister dst, 1382 LiftoffRegister src, Label* trap) { 1383 switch (opcode) { 1384 case kExprI32ConvertI64: 1385 TurboAssembler::Move(dst.gp(), src.low_gp()); 1386 return true; 1387 case kExprI32SConvertF32: { 1388 LiftoffRegister rounded = GetUnusedRegister(kFpReg, LiftoffRegList{src}); 1389 LiftoffRegister converted_back = 1390 GetUnusedRegister(kFpReg, LiftoffRegList{src, rounded}); 1391 1392 // Real conversion. 1393 TurboAssembler::Trunc_s_s(rounded.fp(), src.fp()); 1394 trunc_w_s(kScratchDoubleReg, rounded.fp()); 1395 mfc1(dst.gp(), kScratchDoubleReg); 1396 // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead, 1397 // because INT32_MIN allows easier out-of-bounds detection. 1398 TurboAssembler::Addu(kScratchReg, dst.gp(), 1); 1399 TurboAssembler::Slt(kScratchReg2, kScratchReg, dst.gp()); 1400 TurboAssembler::Movn(dst.gp(), kScratchReg, kScratchReg2); 1401 1402 // Checking if trap. 1403 mtc1(dst.gp(), kScratchDoubleReg); 1404 cvt_s_w(converted_back.fp(), kScratchDoubleReg); 1405 TurboAssembler::CompareF32(EQ, rounded.fp(), converted_back.fp()); 1406 TurboAssembler::BranchFalseF(trap); 1407 return true; 1408 } 1409 case kExprI32UConvertF32: { 1410 LiftoffRegister rounded = GetUnusedRegister(kFpReg, LiftoffRegList{src}); 1411 LiftoffRegister converted_back = 1412 GetUnusedRegister(kFpReg, LiftoffRegList{src, rounded}); 1413 1414 // Real conversion. 1415 TurboAssembler::Trunc_s_s(rounded.fp(), src.fp()); 1416 TurboAssembler::Trunc_uw_s(dst.gp(), rounded.fp(), kScratchDoubleReg); 1417 // Avoid UINT32_MAX as an overflow indicator and use 0 instead, 1418 // because 0 allows easier out-of-bounds detection. 1419 TurboAssembler::Addu(kScratchReg, dst.gp(), 1); 1420 TurboAssembler::Movz(dst.gp(), zero_reg, kScratchReg); 1421 1422 // Checking if trap. 1423 TurboAssembler::Cvt_d_uw(converted_back.fp(), dst.gp(), 1424 kScratchDoubleReg); 1425 cvt_s_d(converted_back.fp(), converted_back.fp()); 1426 TurboAssembler::CompareF32(EQ, rounded.fp(), converted_back.fp()); 1427 TurboAssembler::BranchFalseF(trap); 1428 return true; 1429 } 1430 case kExprI32SConvertF64: { 1431 LiftoffRegister scratch = GetUnusedRegister(kGpReg, LiftoffRegList{dst}); 1432 1433 // Try a conversion to a signed integer. 1434 trunc_w_d(kScratchDoubleReg, src.fp()); 1435 mfc1(dst.gp(), kScratchDoubleReg); 1436 // Retrieve the FCSR. 1437 cfc1(scratch.gp(), FCSR); 1438 // Check for overflow and NaNs. 1439 And(scratch.gp(), scratch.gp(), 1440 kFCSROverflowCauseMask | kFCSRUnderflowCauseMask | 1441 kFCSRInvalidOpCauseMask); 1442 // If we had exceptions we are trap. 1443 Branch(trap, ne, scratch.gp(), Operand(zero_reg)); 1444 return true; 1445 } 1446 case kExprI32UConvertF64: { 1447 if ((IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) && 1448 IsFp64Mode()) { 1449 LiftoffRegister rounded = 1450 GetUnusedRegister(kFpReg, LiftoffRegList{src}); 1451 LiftoffRegister converted_back = 1452 GetUnusedRegister(kFpReg, LiftoffRegList{src, rounded}); 1453 1454 // Real conversion. 1455 TurboAssembler::Trunc_d_d(rounded.fp(), src.fp()); 1456 TurboAssembler::Trunc_uw_d(dst.gp(), rounded.fp(), kScratchDoubleReg); 1457 1458 // Checking if trap. 1459 TurboAssembler::Cvt_d_uw(converted_back.fp(), dst.gp(), 1460 kScratchDoubleReg); 1461 TurboAssembler::CompareF64(EQ, rounded.fp(), converted_back.fp()); 1462 TurboAssembler::BranchFalseF(trap); 1463 return true; 1464 } 1465 bailout(kUnsupportedArchitecture, "kExprI32UConvertF64"); 1466 return true; 1467 } 1468 case kExprI32SConvertSatF32: 1469 bailout(kNonTrappingFloatToInt, "kExprI32SConvertSatF32"); 1470 return true; 1471 case kExprI32UConvertSatF32: 1472 bailout(kNonTrappingFloatToInt, "kExprI32UConvertSatF32"); 1473 return true; 1474 case kExprI32SConvertSatF64: 1475 bailout(kNonTrappingFloatToInt, "kExprI32SConvertSatF64"); 1476 return true; 1477 case kExprI32UConvertSatF64: 1478 bailout(kNonTrappingFloatToInt, "kExprI32UConvertSatF64"); 1479 return true; 1480 case kExprI64SConvertSatF32: 1481 bailout(kNonTrappingFloatToInt, "kExprI64SConvertSatF32"); 1482 return true; 1483 case kExprI64UConvertSatF32: 1484 bailout(kNonTrappingFloatToInt, "kExprI64UConvertSatF32"); 1485 return true; 1486 case kExprI64SConvertSatF64: 1487 bailout(kNonTrappingFloatToInt, "kExprI64SConvertSatF64"); 1488 return true; 1489 case kExprI64UConvertSatF64: 1490 bailout(kNonTrappingFloatToInt, "kExprI64UConvertSatF64"); 1491 return true; 1492 case kExprI32ReinterpretF32: 1493 mfc1(dst.gp(), src.fp()); 1494 return true; 1495 case kExprI64SConvertI32: 1496 TurboAssembler::Move(dst.low_gp(), src.gp()); 1497 TurboAssembler::Move(dst.high_gp(), src.gp()); 1498 sra(dst.high_gp(), dst.high_gp(), 31); 1499 return true; 1500 case kExprI64UConvertI32: 1501 TurboAssembler::Move(dst.low_gp(), src.gp()); 1502 TurboAssembler::Move(dst.high_gp(), zero_reg); 1503 return true; 1504 case kExprI64ReinterpretF64: 1505 mfc1(dst.low_gp(), src.fp()); 1506 TurboAssembler::Mfhc1(dst.high_gp(), src.fp()); 1507 return true; 1508 case kExprF32SConvertI32: { 1509 LiftoffRegister scratch = GetUnusedRegister(kFpReg, LiftoffRegList{dst}); 1510 mtc1(src.gp(), scratch.fp()); 1511 cvt_s_w(dst.fp(), scratch.fp()); 1512 return true; 1513 } 1514 case kExprF32UConvertI32: { 1515 LiftoffRegister scratch = GetUnusedRegister(kFpReg, LiftoffRegList{dst}); 1516 TurboAssembler::Cvt_d_uw(dst.fp(), src.gp(), scratch.fp()); 1517 cvt_s_d(dst.fp(), dst.fp()); 1518 return true; 1519 } 1520 case kExprF32ConvertF64: 1521 cvt_s_d(dst.fp(), src.fp()); 1522 return true; 1523 case kExprF32ReinterpretI32: 1524 TurboAssembler::FmoveLow(dst.fp(), src.gp()); 1525 return true; 1526 case kExprF64SConvertI32: { 1527 LiftoffRegister scratch = GetUnusedRegister(kFpReg, LiftoffRegList{dst}); 1528 mtc1(src.gp(), scratch.fp()); 1529 cvt_d_w(dst.fp(), scratch.fp()); 1530 return true; 1531 } 1532 case kExprF64UConvertI32: { 1533 LiftoffRegister scratch = GetUnusedRegister(kFpReg, LiftoffRegList{dst}); 1534 TurboAssembler::Cvt_d_uw(dst.fp(), src.gp(), scratch.fp()); 1535 return true; 1536 } 1537 case kExprF64ConvertF32: 1538 cvt_d_s(dst.fp(), src.fp()); 1539 return true; 1540 case kExprF64ReinterpretI64: 1541 mtc1(src.low_gp(), dst.fp()); 1542 TurboAssembler::Mthc1(src.high_gp(), dst.fp()); 1543 return true; 1544 default: 1545 return false; 1546 } 1547} 1548 1549void LiftoffAssembler::emit_i32_signextend_i8(Register dst, Register src) { 1550 bailout(kComplexOperation, "i32_signextend_i8"); 1551} 1552 1553void LiftoffAssembler::emit_i32_signextend_i16(Register dst, Register src) { 1554 bailout(kComplexOperation, "i32_signextend_i16"); 1555} 1556 1557void LiftoffAssembler::emit_i64_signextend_i8(LiftoffRegister dst, 1558 LiftoffRegister src) { 1559 bailout(kComplexOperation, "i64_signextend_i8"); 1560} 1561 1562void LiftoffAssembler::emit_i64_signextend_i16(LiftoffRegister dst, 1563 LiftoffRegister src) { 1564 bailout(kComplexOperation, "i64_signextend_i16"); 1565} 1566 1567void LiftoffAssembler::emit_i64_signextend_i32(LiftoffRegister dst, 1568 LiftoffRegister src) { 1569 bailout(kComplexOperation, "i64_signextend_i32"); 1570} 1571 1572void LiftoffAssembler::emit_jump(Label* label) { 1573 TurboAssembler::Branch(label); 1574} 1575 1576void LiftoffAssembler::emit_jump(Register target) { 1577 TurboAssembler::Jump(target); 1578} 1579 1580void LiftoffAssembler::emit_cond_jump(LiftoffCondition liftoff_cond, 1581 Label* label, ValueKind kind, 1582 Register lhs, Register rhs) { 1583 Condition cond = liftoff::ToCondition(liftoff_cond); 1584 if (rhs == no_reg) { 1585 DCHECK_EQ(kind, kI32); 1586 TurboAssembler::Branch(label, cond, lhs, Operand(zero_reg)); 1587 } else { 1588 DCHECK(kind == kI32 || (is_reference(kind) && (liftoff_cond == kEqual || 1589 liftoff_cond == kUnequal))); 1590 TurboAssembler::Branch(label, cond, lhs, Operand(rhs)); 1591 } 1592} 1593 1594void LiftoffAssembler::emit_i32_cond_jumpi(LiftoffCondition liftoff_cond, 1595 Label* label, Register lhs, 1596 int32_t imm) { 1597 Condition cond = liftoff::ToCondition(liftoff_cond); 1598 TurboAssembler::Branch(label, cond, lhs, Operand(imm)); 1599} 1600 1601void LiftoffAssembler::emit_i32_subi_jump_negative(Register value, 1602 int subtrahend, 1603 Label* result_negative) { 1604 TurboAssembler::Subu(value, value, Operand(subtrahend)); 1605 TurboAssembler::Branch(result_negative, less, value, Operand(zero_reg)); 1606} 1607 1608void LiftoffAssembler::emit_i32_eqz(Register dst, Register src) { 1609 sltiu(dst, src, 1); 1610} 1611 1612void LiftoffAssembler::emit_i32_set_cond(LiftoffCondition liftoff_cond, 1613 Register dst, Register lhs, 1614 Register rhs) { 1615 Condition cond = liftoff::ToCondition(liftoff_cond); 1616 Register tmp = dst; 1617 if (dst == lhs || dst == rhs) { 1618 tmp = GetUnusedRegister(kGpReg, LiftoffRegList{lhs, rhs}).gp(); 1619 } 1620 // Write 1 as result. 1621 TurboAssembler::li(tmp, 1); 1622 1623 // If negative condition is true, write 0 as result. 1624 Condition neg_cond = NegateCondition(cond); 1625 TurboAssembler::LoadZeroOnCondition(tmp, lhs, Operand(rhs), neg_cond); 1626 1627 // If tmp != dst, result will be moved. 1628 TurboAssembler::Move(dst, tmp); 1629} 1630 1631void LiftoffAssembler::emit_i64_eqz(Register dst, LiftoffRegister src) { 1632 Register tmp = GetUnusedRegister(kGpReg, LiftoffRegList{src, dst}).gp(); 1633 sltiu(tmp, src.low_gp(), 1); 1634 sltiu(dst, src.high_gp(), 1); 1635 and_(dst, dst, tmp); 1636} 1637 1638namespace liftoff { 1639inline LiftoffCondition cond_make_unsigned(LiftoffCondition cond) { 1640 switch (cond) { 1641 case kSignedLessThan: 1642 return kUnsignedLessThan; 1643 case kSignedLessEqual: 1644 return kUnsignedLessEqual; 1645 case kSignedGreaterThan: 1646 return kUnsignedGreaterThan; 1647 case kSignedGreaterEqual: 1648 return kUnsignedGreaterEqual; 1649 default: 1650 return cond; 1651 } 1652} 1653} // namespace liftoff 1654 1655void LiftoffAssembler::emit_i64_set_cond(LiftoffCondition liftoff_cond, 1656 Register dst, LiftoffRegister lhs, 1657 LiftoffRegister rhs) { 1658 Condition cond = liftoff::ToCondition(liftoff_cond); 1659 Label low, cont; 1660 1661 // For signed i64 comparisons, we still need to use unsigned comparison for 1662 // the low word (the only bit carrying signedness information is the MSB in 1663 // the high word). 1664 Condition unsigned_cond = 1665 liftoff::ToCondition(liftoff::cond_make_unsigned(liftoff_cond)); 1666 1667 Register tmp = dst; 1668 if (liftoff::IsRegInRegPair(lhs, dst) || liftoff::IsRegInRegPair(rhs, dst)) { 1669 tmp = GetUnusedRegister(kGpReg, LiftoffRegList{dst, lhs, rhs}).gp(); 1670 } 1671 1672 // Write 1 initially in tmp register. 1673 TurboAssembler::li(tmp, 1); 1674 1675 // If high words are equal, then compare low words, else compare high. 1676 Branch(&low, eq, lhs.high_gp(), Operand(rhs.high_gp())); 1677 1678 TurboAssembler::LoadZeroOnCondition( 1679 tmp, lhs.high_gp(), Operand(rhs.high_gp()), NegateCondition(cond)); 1680 Branch(&cont); 1681 1682 bind(&low); 1683 TurboAssembler::LoadZeroOnCondition(tmp, lhs.low_gp(), Operand(rhs.low_gp()), 1684 NegateCondition(unsigned_cond)); 1685 1686 bind(&cont); 1687 // Move result to dst register if needed. 1688 TurboAssembler::Move(dst, tmp); 1689} 1690 1691namespace liftoff { 1692 1693inline FPUCondition ConditionToConditionCmpFPU(LiftoffCondition condition, 1694 bool* predicate) { 1695 switch (condition) { 1696 case kEqual: 1697 *predicate = true; 1698 return EQ; 1699 case kUnequal: 1700 *predicate = false; 1701 return EQ; 1702 case kUnsignedLessThan: 1703 *predicate = true; 1704 return OLT; 1705 case kUnsignedGreaterEqual: 1706 *predicate = false; 1707 return OLT; 1708 case kUnsignedLessEqual: 1709 *predicate = true; 1710 return OLE; 1711 case kUnsignedGreaterThan: 1712 *predicate = false; 1713 return OLE; 1714 default: 1715 *predicate = true; 1716 break; 1717 } 1718 UNREACHABLE(); 1719} 1720 1721} // namespace liftoff 1722 1723void LiftoffAssembler::emit_f32_set_cond(LiftoffCondition liftoff_cond, 1724 Register dst, DoubleRegister lhs, 1725 DoubleRegister rhs) { 1726 Condition cond = liftoff::ToCondition(liftoff_cond); 1727 Label not_nan, cont; 1728 TurboAssembler::CompareIsNanF32(lhs, rhs); 1729 TurboAssembler::BranchFalseF(¬_nan); 1730 // If one of the operands is NaN, return 1 for f32.ne, else 0. 1731 if (cond == ne) { 1732 TurboAssembler::li(dst, 1); 1733 } else { 1734 TurboAssembler::Move(dst, zero_reg); 1735 } 1736 TurboAssembler::Branch(&cont); 1737 1738 bind(¬_nan); 1739 1740 TurboAssembler::li(dst, 1); 1741 bool predicate; 1742 FPUCondition fcond = 1743 liftoff::ConditionToConditionCmpFPU(liftoff_cond, &predicate); 1744 TurboAssembler::CompareF32(fcond, lhs, rhs); 1745 if (predicate) { 1746 TurboAssembler::LoadZeroIfNotFPUCondition(dst); 1747 } else { 1748 TurboAssembler::LoadZeroIfFPUCondition(dst); 1749 } 1750 1751 bind(&cont); 1752} 1753 1754void LiftoffAssembler::emit_f64_set_cond(LiftoffCondition liftoff_cond, 1755 Register dst, DoubleRegister lhs, 1756 DoubleRegister rhs) { 1757 Condition cond = liftoff::ToCondition(liftoff_cond); 1758 Label not_nan, cont; 1759 TurboAssembler::CompareIsNanF64(lhs, rhs); 1760 TurboAssembler::BranchFalseF(¬_nan); 1761 // If one of the operands is NaN, return 1 for f64.ne, else 0. 1762 if (cond == ne) { 1763 TurboAssembler::li(dst, 1); 1764 } else { 1765 TurboAssembler::Move(dst, zero_reg); 1766 } 1767 TurboAssembler::Branch(&cont); 1768 1769 bind(¬_nan); 1770 1771 TurboAssembler::li(dst, 1); 1772 bool predicate; 1773 FPUCondition fcond = 1774 liftoff::ConditionToConditionCmpFPU(liftoff_cond, &predicate); 1775 TurboAssembler::CompareF64(fcond, lhs, rhs); 1776 if (predicate) { 1777 TurboAssembler::LoadZeroIfNotFPUCondition(dst); 1778 } else { 1779 TurboAssembler::LoadZeroIfFPUCondition(dst); 1780 } 1781 1782 bind(&cont); 1783} 1784 1785bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition, 1786 LiftoffRegister true_value, 1787 LiftoffRegister false_value, 1788 ValueKind kind) { 1789 return false; 1790} 1791 1792void LiftoffAssembler::emit_smi_check(Register obj, Label* target, 1793 SmiCheckMode mode) { 1794 UseScratchRegisterScope temps(this); 1795 Register scratch = temps.Acquire(); 1796 And(scratch, obj, Operand(kSmiTagMask)); 1797 Condition condition = mode == kJumpOnSmi ? eq : ne; 1798 Branch(target, condition, scratch, Operand(zero_reg)); 1799} 1800 1801void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr, 1802 Register offset_reg, uintptr_t offset_imm, 1803 LoadType type, 1804 LoadTransformationKind transform, 1805 uint32_t* protected_load_pc) { 1806 bailout(kSimd, "load extend and load splat unimplemented"); 1807} 1808 1809void LiftoffAssembler::StoreLane(Register dst, Register offset, 1810 uintptr_t offset_imm, LiftoffRegister src, 1811 StoreType type, uint8_t lane, 1812 uint32_t* protected_store_pc) { 1813 bailout(kSimd, "storelane"); 1814} 1815 1816void LiftoffAssembler::LoadLane(LiftoffRegister dst, LiftoffRegister src, 1817 Register addr, Register offset_reg, 1818 uintptr_t offset_imm, LoadType type, 1819 uint8_t laneidx, uint32_t* protected_load_pc) { 1820 bailout(kSimd, "loadlane"); 1821} 1822 1823void LiftoffAssembler::emit_i8x16_shuffle(LiftoffRegister dst, 1824 LiftoffRegister lhs, 1825 LiftoffRegister rhs, 1826 const uint8_t shuffle[16], 1827 bool is_swizzle) { 1828 bailout(kSimd, "emit_i8x16_shuffle"); 1829} 1830 1831void LiftoffAssembler::emit_i8x16_swizzle(LiftoffRegister dst, 1832 LiftoffRegister lhs, 1833 LiftoffRegister rhs) { 1834 bailout(kSimd, "emit_i8x16_swizzle"); 1835} 1836 1837void LiftoffAssembler::emit_i8x16_splat(LiftoffRegister dst, 1838 LiftoffRegister src) { 1839 bailout(kSimd, "emit_i8x16_splat"); 1840} 1841 1842void LiftoffAssembler::emit_i16x8_splat(LiftoffRegister dst, 1843 LiftoffRegister src) { 1844 bailout(kSimd, "emit_i16x8_splat"); 1845} 1846 1847void LiftoffAssembler::emit_i32x4_splat(LiftoffRegister dst, 1848 LiftoffRegister src) { 1849 bailout(kSimd, "emit_i32x4_splat"); 1850} 1851 1852void LiftoffAssembler::emit_i64x2_splat(LiftoffRegister dst, 1853 LiftoffRegister src) { 1854 bailout(kSimd, "emit_i64x2_splat"); 1855} 1856 1857void LiftoffAssembler::emit_f32x4_splat(LiftoffRegister dst, 1858 LiftoffRegister src) { 1859 bailout(kSimd, "emit_f32x4_splat"); 1860} 1861 1862void LiftoffAssembler::emit_f64x2_splat(LiftoffRegister dst, 1863 LiftoffRegister src) { 1864 bailout(kSimd, "emit_f64x2_splat"); 1865} 1866 1867#define SIMD_BINOP(name, ilv_instr, dotp_instr) \ 1868 void LiftoffAssembler::emit_##name( \ 1869 LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2) { \ 1870 MSARegister dst_msa = MSARegister::from_code(dst.liftoff_code()); \ 1871 MSARegister src1_msa = MSARegister::from_code(src1.liftoff_code()); \ 1872 MSARegister src2_msa = MSARegister::from_code(src2.liftoff_code()); \ 1873 xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero); \ 1874 ilv_instr(kSimd128ScratchReg, kSimd128RegZero, src1_msa); \ 1875 ilv_instr(kSimd128RegZero, kSimd128RegZero, src2_msa); \ 1876 dotp_instr(dst_msa, kSimd128ScratchReg, kSimd128RegZero); \ 1877 } 1878 1879SIMD_BINOP(i16x8_extmul_low_i8x16_s, ilvr_b, dotp_s_h) 1880SIMD_BINOP(i16x8_extmul_high_i8x16_s, ilvl_b, dotp_s_h) 1881SIMD_BINOP(i16x8_extmul_low_i8x16_u, ilvr_b, dotp_u_h) 1882SIMD_BINOP(i16x8_extmul_high_i8x16_u, ilvl_b, dotp_u_h) 1883 1884SIMD_BINOP(i32x4_extmul_low_i16x8_s, ilvr_h, dotp_s_w) 1885SIMD_BINOP(i32x4_extmul_high_i16x8_s, ilvl_h, dotp_s_w) 1886SIMD_BINOP(i32x4_extmul_low_i16x8_u, ilvr_h, dotp_u_w) 1887SIMD_BINOP(i32x4_extmul_high_i16x8_u, ilvl_h, dotp_u_w) 1888 1889SIMD_BINOP(i64x2_extmul_low_i32x4_s, ilvr_w, dotp_s_d) 1890SIMD_BINOP(i64x2_extmul_high_i32x4_s, ilvl_w, dotp_s_d) 1891SIMD_BINOP(i64x2_extmul_low_i32x4_u, ilvr_w, dotp_u_d) 1892SIMD_BINOP(i64x2_extmul_high_i32x4_u, ilvl_w, dotp_u_d) 1893 1894#undef SIMD_BINOP 1895 1896void LiftoffAssembler::emit_i16x8_q15mulr_sat_s(LiftoffRegister dst, 1897 LiftoffRegister src1, 1898 LiftoffRegister src2) { 1899 bailout(kSimd, "i16x8_q15mulr_sat_s"); 1900} 1901 1902void LiftoffAssembler::emit_i8x16_eq(LiftoffRegister dst, LiftoffRegister lhs, 1903 LiftoffRegister rhs) { 1904 bailout(kSimd, "emit_i8x16_eq"); 1905} 1906 1907void LiftoffAssembler::emit_i8x16_ne(LiftoffRegister dst, LiftoffRegister lhs, 1908 LiftoffRegister rhs) { 1909 bailout(kSimd, "emit_i8x16_ne"); 1910} 1911 1912void LiftoffAssembler::emit_i8x16_gt_s(LiftoffRegister dst, LiftoffRegister lhs, 1913 LiftoffRegister rhs) { 1914 bailout(kSimd, "emit_i8x16_gt_s"); 1915} 1916 1917void LiftoffAssembler::emit_i8x16_gt_u(LiftoffRegister dst, LiftoffRegister lhs, 1918 LiftoffRegister rhs) { 1919 bailout(kSimd, "emit_i8x16_gt_u"); 1920} 1921 1922void LiftoffAssembler::emit_i8x16_ge_s(LiftoffRegister dst, LiftoffRegister lhs, 1923 LiftoffRegister rhs) { 1924 bailout(kSimd, "emit_i8x16_ge_s"); 1925} 1926 1927void LiftoffAssembler::emit_i8x16_ge_u(LiftoffRegister dst, LiftoffRegister lhs, 1928 LiftoffRegister rhs) { 1929 bailout(kSimd, "emit_i8x16_ge_u"); 1930} 1931 1932void LiftoffAssembler::emit_i16x8_eq(LiftoffRegister dst, LiftoffRegister lhs, 1933 LiftoffRegister rhs) { 1934 bailout(kSimd, "emit_i16x8_eq"); 1935} 1936 1937void LiftoffAssembler::emit_i16x8_ne(LiftoffRegister dst, LiftoffRegister lhs, 1938 LiftoffRegister rhs) { 1939 bailout(kSimd, "emit_i16x8_ne"); 1940} 1941 1942void LiftoffAssembler::emit_i16x8_gt_s(LiftoffRegister dst, LiftoffRegister lhs, 1943 LiftoffRegister rhs) { 1944 bailout(kSimd, "emit_i16x8_gt_s"); 1945} 1946 1947void LiftoffAssembler::emit_i16x8_gt_u(LiftoffRegister dst, LiftoffRegister lhs, 1948 LiftoffRegister rhs) { 1949 bailout(kSimd, "emit_i16x8_gt_u"); 1950} 1951 1952void LiftoffAssembler::emit_i16x8_ge_s(LiftoffRegister dst, LiftoffRegister lhs, 1953 LiftoffRegister rhs) { 1954 bailout(kSimd, "emit_i16x8_ge_s"); 1955} 1956 1957void LiftoffAssembler::emit_i16x8_ge_u(LiftoffRegister dst, LiftoffRegister lhs, 1958 LiftoffRegister rhs) { 1959 bailout(kSimd, "emit_i16x8_ge_u"); 1960} 1961 1962void LiftoffAssembler::emit_i32x4_eq(LiftoffRegister dst, LiftoffRegister lhs, 1963 LiftoffRegister rhs) { 1964 bailout(kSimd, "emit_i32x4_eq"); 1965} 1966 1967void LiftoffAssembler::emit_i32x4_ne(LiftoffRegister dst, LiftoffRegister lhs, 1968 LiftoffRegister rhs) { 1969 bailout(kSimd, "emit_i32x4_ne"); 1970} 1971 1972void LiftoffAssembler::emit_i32x4_gt_s(LiftoffRegister dst, LiftoffRegister lhs, 1973 LiftoffRegister rhs) { 1974 bailout(kSimd, "emit_i32x4_gt_s"); 1975} 1976 1977void LiftoffAssembler::emit_i32x4_gt_u(LiftoffRegister dst, LiftoffRegister lhs, 1978 LiftoffRegister rhs) { 1979 bailout(kSimd, "emit_i32x4_gt_u"); 1980} 1981 1982void LiftoffAssembler::emit_i32x4_ge_s(LiftoffRegister dst, LiftoffRegister lhs, 1983 LiftoffRegister rhs) { 1984 bailout(kSimd, "emit_i32x4_ge_s"); 1985} 1986 1987void LiftoffAssembler::emit_i32x4_ge_u(LiftoffRegister dst, LiftoffRegister lhs, 1988 LiftoffRegister rhs) { 1989 bailout(kSimd, "emit_i32x4_ge_u"); 1990} 1991 1992void LiftoffAssembler::emit_f32x4_eq(LiftoffRegister dst, LiftoffRegister lhs, 1993 LiftoffRegister rhs) { 1994 bailout(kSimd, "emit_f32x4_eq"); 1995} 1996 1997void LiftoffAssembler::emit_f32x4_ne(LiftoffRegister dst, LiftoffRegister lhs, 1998 LiftoffRegister rhs) { 1999 bailout(kSimd, "emit_f32x4_ne"); 2000} 2001 2002void LiftoffAssembler::emit_f32x4_lt(LiftoffRegister dst, LiftoffRegister lhs, 2003 LiftoffRegister rhs) { 2004 bailout(kSimd, "emit_f32x4_lt"); 2005} 2006 2007void LiftoffAssembler::emit_f32x4_le(LiftoffRegister dst, LiftoffRegister lhs, 2008 LiftoffRegister rhs) { 2009 bailout(kSimd, "emit_f32x4_le"); 2010} 2011 2012void LiftoffAssembler::emit_i64x2_eq(LiftoffRegister dst, LiftoffRegister lhs, 2013 LiftoffRegister rhs) { 2014 bailout(kSimd, "emit_i64x2_eq"); 2015} 2016 2017void LiftoffAssembler::emit_i64x2_ne(LiftoffRegister dst, LiftoffRegister lhs, 2018 LiftoffRegister rhs) { 2019 bailout(kSimd, "emit_i64x2_ne"); 2020} 2021 2022void LiftoffAssembler::emit_i64x2_abs(LiftoffRegister dst, 2023 LiftoffRegister src) { 2024 bailout(kSimd, "emit_i64x2_abs"); 2025} 2026 2027void LiftoffAssembler::emit_f64x2_eq(LiftoffRegister dst, LiftoffRegister lhs, 2028 LiftoffRegister rhs) { 2029 bailout(kSimd, "emit_f64x2_eq"); 2030} 2031 2032void LiftoffAssembler::emit_f64x2_ne(LiftoffRegister dst, LiftoffRegister lhs, 2033 LiftoffRegister rhs) { 2034 bailout(kSimd, "emit_f64x2_ne"); 2035} 2036 2037void LiftoffAssembler::emit_f64x2_lt(LiftoffRegister dst, LiftoffRegister lhs, 2038 LiftoffRegister rhs) { 2039 bailout(kSimd, "emit_f64x2_lt"); 2040} 2041 2042void LiftoffAssembler::emit_f64x2_le(LiftoffRegister dst, LiftoffRegister lhs, 2043 LiftoffRegister rhs) { 2044 bailout(kSimd, "emit_f64x2_le"); 2045} 2046 2047void LiftoffAssembler::emit_s128_const(LiftoffRegister dst, 2048 const uint8_t imms[16]) { 2049 bailout(kSimd, "emit_s128_const"); 2050} 2051 2052void LiftoffAssembler::emit_s128_not(LiftoffRegister dst, LiftoffRegister src) { 2053 bailout(kSimd, "emit_s128_not"); 2054} 2055 2056void LiftoffAssembler::emit_s128_and(LiftoffRegister dst, LiftoffRegister lhs, 2057 LiftoffRegister rhs) { 2058 bailout(kSimd, "emit_s128_and"); 2059} 2060 2061void LiftoffAssembler::emit_s128_or(LiftoffRegister dst, LiftoffRegister lhs, 2062 LiftoffRegister rhs) { 2063 bailout(kSimd, "emit_s128_or"); 2064} 2065 2066void LiftoffAssembler::emit_s128_xor(LiftoffRegister dst, LiftoffRegister lhs, 2067 LiftoffRegister rhs) { 2068 bailout(kSimd, "emit_s128_xor"); 2069} 2070 2071void LiftoffAssembler::emit_s128_and_not(LiftoffRegister dst, 2072 LiftoffRegister lhs, 2073 LiftoffRegister rhs) { 2074 bailout(kSimd, "emit_s128_and_not"); 2075} 2076 2077void LiftoffAssembler::emit_s128_select(LiftoffRegister dst, 2078 LiftoffRegister src1, 2079 LiftoffRegister src2, 2080 LiftoffRegister mask) { 2081 bailout(kSimd, "emit_s128_select"); 2082} 2083 2084void LiftoffAssembler::emit_i8x16_neg(LiftoffRegister dst, 2085 LiftoffRegister src) { 2086 bailout(kSimd, "emit_i8x16_neg"); 2087} 2088 2089void LiftoffAssembler::emit_v128_anytrue(LiftoffRegister dst, 2090 LiftoffRegister src) { 2091 bailout(kSimd, "emit_v128_anytrue"); 2092} 2093 2094void LiftoffAssembler::emit_i8x16_alltrue(LiftoffRegister dst, 2095 LiftoffRegister src) { 2096 bailout(kSimd, "emit_i8x16_alltrue"); 2097} 2098 2099void LiftoffAssembler::emit_i8x16_bitmask(LiftoffRegister dst, 2100 LiftoffRegister src) { 2101 bailout(kSimd, "emit_i8x16_bitmask"); 2102} 2103 2104void LiftoffAssembler::emit_i8x16_shl(LiftoffRegister dst, LiftoffRegister lhs, 2105 LiftoffRegister rhs) { 2106 bailout(kSimd, "emit_i8x16_shl"); 2107} 2108 2109void LiftoffAssembler::emit_i8x16_shli(LiftoffRegister dst, LiftoffRegister lhs, 2110 int32_t rhs) { 2111 bailout(kSimd, "emit_i8x16_shli"); 2112} 2113 2114void LiftoffAssembler::emit_i8x16_shr_s(LiftoffRegister dst, 2115 LiftoffRegister lhs, 2116 LiftoffRegister rhs) { 2117 bailout(kSimd, "emit_i8x16_shr_s"); 2118} 2119 2120void LiftoffAssembler::emit_i8x16_shri_s(LiftoffRegister dst, 2121 LiftoffRegister lhs, int32_t rhs) { 2122 bailout(kSimd, "emit_i8x16_shri_s"); 2123} 2124 2125void LiftoffAssembler::emit_i8x16_shr_u(LiftoffRegister dst, 2126 LiftoffRegister lhs, 2127 LiftoffRegister rhs) { 2128 bailout(kSimd, "emit_i8x16_shr_u"); 2129} 2130 2131void LiftoffAssembler::emit_i8x16_shri_u(LiftoffRegister dst, 2132 LiftoffRegister lhs, int32_t rhs) { 2133 bailout(kSimd, "emit_i8x16_shri_u"); 2134} 2135 2136void LiftoffAssembler::emit_i8x16_add(LiftoffRegister dst, LiftoffRegister lhs, 2137 LiftoffRegister rhs) { 2138 bailout(kSimd, "emit_i8x16_add"); 2139} 2140 2141void LiftoffAssembler::emit_i8x16_add_sat_s(LiftoffRegister dst, 2142 LiftoffRegister lhs, 2143 LiftoffRegister rhs) { 2144 bailout(kSimd, "emit_i8x16_add_sat_s"); 2145} 2146 2147void LiftoffAssembler::emit_i8x16_add_sat_u(LiftoffRegister dst, 2148 LiftoffRegister lhs, 2149 LiftoffRegister rhs) { 2150 bailout(kSimd, "emit_i8x16_add_sat_u"); 2151} 2152 2153void LiftoffAssembler::emit_i8x16_sub(LiftoffRegister dst, LiftoffRegister lhs, 2154 LiftoffRegister rhs) { 2155 bailout(kSimd, "emit_i8x16_sub"); 2156} 2157 2158void LiftoffAssembler::emit_i8x16_sub_sat_s(LiftoffRegister dst, 2159 LiftoffRegister lhs, 2160 LiftoffRegister rhs) { 2161 bailout(kSimd, "emit_i8x16_sub_sat_s"); 2162} 2163 2164void LiftoffAssembler::emit_i8x16_sub_sat_u(LiftoffRegister dst, 2165 LiftoffRegister lhs, 2166 LiftoffRegister rhs) { 2167 bailout(kSimd, "emit_i8x16_sub_sat_u"); 2168} 2169 2170void LiftoffAssembler::emit_i8x16_min_s(LiftoffRegister dst, 2171 LiftoffRegister lhs, 2172 LiftoffRegister rhs) { 2173 bailout(kSimd, "emit_i8x16_min_s"); 2174} 2175 2176void LiftoffAssembler::emit_i8x16_min_u(LiftoffRegister dst, 2177 LiftoffRegister lhs, 2178 LiftoffRegister rhs) { 2179 bailout(kSimd, "emit_i8x16_min_u"); 2180} 2181 2182void LiftoffAssembler::emit_i8x16_max_s(LiftoffRegister dst, 2183 LiftoffRegister lhs, 2184 LiftoffRegister rhs) { 2185 bailout(kSimd, "emit_i8x16_max_s"); 2186} 2187 2188void LiftoffAssembler::emit_i8x16_max_u(LiftoffRegister dst, 2189 LiftoffRegister lhs, 2190 LiftoffRegister rhs) { 2191 bailout(kSimd, "emit_i8x16_max_u"); 2192} 2193 2194void LiftoffAssembler::emit_i8x16_popcnt(LiftoffRegister dst, 2195 LiftoffRegister src) { 2196 bailout(kSimd, "emit_i8x16_popcnt"); 2197} 2198 2199void LiftoffAssembler::emit_i16x8_neg(LiftoffRegister dst, 2200 LiftoffRegister src) { 2201 bailout(kSimd, "emit_i16x8_neg"); 2202} 2203 2204void LiftoffAssembler::emit_i16x8_alltrue(LiftoffRegister dst, 2205 LiftoffRegister src) { 2206 bailout(kSimd, "emit_i16x8_alltrue"); 2207} 2208 2209void LiftoffAssembler::emit_i16x8_bitmask(LiftoffRegister dst, 2210 LiftoffRegister src) { 2211 bailout(kSimd, "emit_i16x8_bitmask"); 2212} 2213 2214void LiftoffAssembler::emit_i16x8_shl(LiftoffRegister dst, LiftoffRegister lhs, 2215 LiftoffRegister rhs) { 2216 bailout(kSimd, "emit_i16x8_shl"); 2217} 2218 2219void LiftoffAssembler::emit_i16x8_shli(LiftoffRegister dst, LiftoffRegister lhs, 2220 int32_t rhs) { 2221 bailout(kSimd, "emit_i16x8_shli"); 2222} 2223 2224void LiftoffAssembler::emit_i16x8_shr_s(LiftoffRegister dst, 2225 LiftoffRegister lhs, 2226 LiftoffRegister rhs) { 2227 bailout(kSimd, "emit_i16x8_shr_s"); 2228} 2229 2230void LiftoffAssembler::emit_i16x8_shri_s(LiftoffRegister dst, 2231 LiftoffRegister lhs, int32_t rhs) { 2232 bailout(kSimd, "emit_i16x8_shri_s"); 2233} 2234 2235void LiftoffAssembler::emit_i16x8_shr_u(LiftoffRegister dst, 2236 LiftoffRegister lhs, 2237 LiftoffRegister rhs) { 2238 bailout(kSimd, "emit_i16x8_shr_u"); 2239} 2240 2241void LiftoffAssembler::emit_i16x8_shri_u(LiftoffRegister dst, 2242 LiftoffRegister lhs, int32_t rhs) { 2243 bailout(kSimd, "emit_i16x8_shri_u"); 2244} 2245 2246void LiftoffAssembler::emit_i16x8_add(LiftoffRegister dst, LiftoffRegister lhs, 2247 LiftoffRegister rhs) { 2248 bailout(kSimd, "emit_i16x8_add"); 2249} 2250 2251void LiftoffAssembler::emit_i16x8_add_sat_s(LiftoffRegister dst, 2252 LiftoffRegister lhs, 2253 LiftoffRegister rhs) { 2254 bailout(kSimd, "emit_i16x8_add_sat_s"); 2255} 2256 2257void LiftoffAssembler::emit_i16x8_add_sat_u(LiftoffRegister dst, 2258 LiftoffRegister lhs, 2259 LiftoffRegister rhs) { 2260 bailout(kSimd, "emit_i16x8_add_sat_u"); 2261} 2262 2263void LiftoffAssembler::emit_i16x8_sub(LiftoffRegister dst, LiftoffRegister lhs, 2264 LiftoffRegister rhs) { 2265 bailout(kSimd, "emit_i16x8_sub"); 2266} 2267 2268void LiftoffAssembler::emit_i16x8_sub_sat_s(LiftoffRegister dst, 2269 LiftoffRegister lhs, 2270 LiftoffRegister rhs) { 2271 bailout(kSimd, "emit_i16x8_sub_sat_s"); 2272} 2273 2274void LiftoffAssembler::emit_i16x8_sub_sat_u(LiftoffRegister dst, 2275 LiftoffRegister lhs, 2276 LiftoffRegister rhs) { 2277 bailout(kSimd, "emit_i16x8_sub_sat_u"); 2278} 2279 2280void LiftoffAssembler::emit_i16x8_mul(LiftoffRegister dst, LiftoffRegister lhs, 2281 LiftoffRegister rhs) { 2282 bailout(kSimd, "emit_i16x8_mul"); 2283} 2284 2285void LiftoffAssembler::emit_i16x8_min_s(LiftoffRegister dst, 2286 LiftoffRegister lhs, 2287 LiftoffRegister rhs) { 2288 bailout(kSimd, "emit_i16x8_min_s"); 2289} 2290 2291void LiftoffAssembler::emit_i16x8_min_u(LiftoffRegister dst, 2292 LiftoffRegister lhs, 2293 LiftoffRegister rhs) { 2294 bailout(kSimd, "emit_i16x8_min_u"); 2295} 2296 2297void LiftoffAssembler::emit_i16x8_max_s(LiftoffRegister dst, 2298 LiftoffRegister lhs, 2299 LiftoffRegister rhs) { 2300 bailout(kSimd, "emit_i16x8_max_s"); 2301} 2302 2303void LiftoffAssembler::emit_i16x8_max_u(LiftoffRegister dst, 2304 LiftoffRegister lhs, 2305 LiftoffRegister rhs) { 2306 bailout(kSimd, "emit_i16x8_max_u"); 2307} 2308 2309void LiftoffAssembler::emit_i16x8_extadd_pairwise_i8x16_s(LiftoffRegister dst, 2310 LiftoffRegister src) { 2311 bailout(kSimd, "emit_i16x8_extadd_pairwise_i8x16_s"); 2312} 2313 2314void LiftoffAssembler::emit_i16x8_extadd_pairwise_i8x16_u(LiftoffRegister dst, 2315 LiftoffRegister src) { 2316 bailout(kSimd, "emit_i16x8_extadd_pairwise_i8x16_u"); 2317} 2318 2319void LiftoffAssembler::emit_i32x4_neg(LiftoffRegister dst, 2320 LiftoffRegister src) { 2321 bailout(kSimd, "emit_i32x4_neg"); 2322} 2323 2324void LiftoffAssembler::emit_i32x4_alltrue(LiftoffRegister dst, 2325 LiftoffRegister src) { 2326 bailout(kSimd, "emit_i32x4_alltrue"); 2327} 2328 2329void LiftoffAssembler::emit_i32x4_bitmask(LiftoffRegister dst, 2330 LiftoffRegister src) { 2331 bailout(kSimd, "emit_i32x4_bitmask"); 2332} 2333 2334void LiftoffAssembler::emit_i32x4_shl(LiftoffRegister dst, LiftoffRegister lhs, 2335 LiftoffRegister rhs) { 2336 bailout(kSimd, "emit_i32x4_shl"); 2337} 2338 2339void LiftoffAssembler::emit_i32x4_shli(LiftoffRegister dst, LiftoffRegister lhs, 2340 int32_t rhs) { 2341 bailout(kSimd, "emit_i32x4_shli"); 2342} 2343 2344void LiftoffAssembler::emit_i32x4_shr_s(LiftoffRegister dst, 2345 LiftoffRegister lhs, 2346 LiftoffRegister rhs) { 2347 bailout(kSimd, "emit_i32x4_shr_s"); 2348} 2349 2350void LiftoffAssembler::emit_i32x4_shri_s(LiftoffRegister dst, 2351 LiftoffRegister lhs, int32_t rhs) { 2352 bailout(kSimd, "emit_i32x4_shri_s"); 2353} 2354 2355void LiftoffAssembler::emit_i32x4_shr_u(LiftoffRegister dst, 2356 LiftoffRegister lhs, 2357 LiftoffRegister rhs) { 2358 bailout(kSimd, "emit_i32x4_shr_u"); 2359} 2360 2361void LiftoffAssembler::emit_i32x4_shri_u(LiftoffRegister dst, 2362 LiftoffRegister lhs, int32_t rhs) { 2363 bailout(kSimd, "emit_i32x4_shri_u"); 2364} 2365 2366void LiftoffAssembler::emit_i32x4_add(LiftoffRegister dst, LiftoffRegister lhs, 2367 LiftoffRegister rhs) { 2368 bailout(kSimd, "emit_i32x4_add"); 2369} 2370 2371void LiftoffAssembler::emit_i32x4_sub(LiftoffRegister dst, LiftoffRegister lhs, 2372 LiftoffRegister rhs) { 2373 bailout(kSimd, "emit_i32x4_sub"); 2374} 2375 2376void LiftoffAssembler::emit_i32x4_mul(LiftoffRegister dst, LiftoffRegister lhs, 2377 LiftoffRegister rhs) { 2378 bailout(kSimd, "emit_i32x4_mul"); 2379} 2380 2381void LiftoffAssembler::emit_i32x4_min_s(LiftoffRegister dst, 2382 LiftoffRegister lhs, 2383 LiftoffRegister rhs) { 2384 bailout(kSimd, "emit_i32x4_min_s"); 2385} 2386 2387void LiftoffAssembler::emit_i32x4_min_u(LiftoffRegister dst, 2388 LiftoffRegister lhs, 2389 LiftoffRegister rhs) { 2390 bailout(kSimd, "emit_i32x4_min_u"); 2391} 2392 2393void LiftoffAssembler::emit_i32x4_max_s(LiftoffRegister dst, 2394 LiftoffRegister lhs, 2395 LiftoffRegister rhs) { 2396 bailout(kSimd, "emit_i32x4_max_s"); 2397} 2398 2399void LiftoffAssembler::emit_i32x4_max_u(LiftoffRegister dst, 2400 LiftoffRegister lhs, 2401 LiftoffRegister rhs) { 2402 bailout(kSimd, "emit_i32x4_max_u"); 2403} 2404 2405void LiftoffAssembler::emit_i32x4_dot_i16x8_s(LiftoffRegister dst, 2406 LiftoffRegister lhs, 2407 LiftoffRegister rhs) { 2408 bailout(kSimd, "emit_i32x4_dot_i16x8_s"); 2409} 2410 2411void LiftoffAssembler::emit_i32x4_extadd_pairwise_i16x8_s(LiftoffRegister dst, 2412 LiftoffRegister src) { 2413 bailout(kSimd, "emit_i32x4_extadd_pairwise_i16x8_s"); 2414} 2415 2416void LiftoffAssembler::emit_i32x4_extadd_pairwise_i16x8_u(LiftoffRegister dst, 2417 LiftoffRegister src) { 2418 bailout(kSimd, "emit_i32x4_extadd_pairwise_i16x8_u"); 2419} 2420 2421void LiftoffAssembler::emit_i64x2_neg(LiftoffRegister dst, 2422 LiftoffRegister src) { 2423 bailout(kSimd, "emit_i64x2_neg"); 2424} 2425 2426void LiftoffAssembler::emit_i64x2_alltrue(LiftoffRegister dst, 2427 LiftoffRegister src) { 2428 bailout(kSimd, "emit_i64x2_alltrue"); 2429} 2430 2431void LiftoffAssembler::emit_i64x2_bitmask(LiftoffRegister dst, 2432 LiftoffRegister src) { 2433 bailout(kSimd, "emit_i64x2_bitmask"); 2434} 2435 2436void LiftoffAssembler::emit_i64x2_shl(LiftoffRegister dst, LiftoffRegister lhs, 2437 LiftoffRegister rhs) { 2438 bailout(kSimd, "emit_i64x2_shl"); 2439} 2440 2441void LiftoffAssembler::emit_i64x2_shli(LiftoffRegister dst, LiftoffRegister lhs, 2442 int32_t rhs) { 2443 bailout(kSimd, "emit_i64x2_shli"); 2444} 2445 2446void LiftoffAssembler::emit_i64x2_shr_s(LiftoffRegister dst, 2447 LiftoffRegister lhs, 2448 LiftoffRegister rhs) { 2449 bailout(kSimd, "emit_i64x2_shr_s"); 2450} 2451 2452void LiftoffAssembler::emit_i64x2_shri_s(LiftoffRegister dst, 2453 LiftoffRegister lhs, int32_t rhs) { 2454 bailout(kSimd, "emit_i64x2_shri_s"); 2455} 2456 2457void LiftoffAssembler::emit_i64x2_shr_u(LiftoffRegister dst, 2458 LiftoffRegister lhs, 2459 LiftoffRegister rhs) { 2460 bailout(kSimd, "emit_i64x2_shr_u"); 2461} 2462 2463void LiftoffAssembler::emit_i64x2_shri_u(LiftoffRegister dst, 2464 LiftoffRegister lhs, int32_t rhs) { 2465 bailout(kSimd, "emit_i64x2_shri_u"); 2466} 2467 2468void LiftoffAssembler::emit_i64x2_add(LiftoffRegister dst, LiftoffRegister lhs, 2469 LiftoffRegister rhs) { 2470 bailout(kSimd, "emit_i64x2_add"); 2471} 2472 2473void LiftoffAssembler::emit_i64x2_sub(LiftoffRegister dst, LiftoffRegister lhs, 2474 LiftoffRegister rhs) { 2475 bailout(kSimd, "emit_i64x2_sub"); 2476} 2477 2478void LiftoffAssembler::emit_i64x2_mul(LiftoffRegister dst, LiftoffRegister lhs, 2479 LiftoffRegister rhs) { 2480 bailout(kSimd, "emit_i64x2_mul"); 2481} 2482 2483void LiftoffAssembler::emit_i64x2_gt_s(LiftoffRegister dst, LiftoffRegister lhs, 2484 LiftoffRegister rhs) { 2485 bailout(kSimd, "emit_i64x2_gt_s"); 2486} 2487 2488void LiftoffAssembler::emit_i64x2_ge_s(LiftoffRegister dst, LiftoffRegister lhs, 2489 LiftoffRegister rhs) { 2490 bailout(kSimd, "emit_i64x2_ge_s"); 2491} 2492 2493void LiftoffAssembler::emit_f32x4_abs(LiftoffRegister dst, 2494 LiftoffRegister src) { 2495 bailout(kSimd, "emit_f32x4_abs"); 2496} 2497 2498void LiftoffAssembler::emit_f32x4_neg(LiftoffRegister dst, 2499 LiftoffRegister src) { 2500 bailout(kSimd, "emit_f32x4_neg"); 2501} 2502 2503void LiftoffAssembler::emit_f32x4_sqrt(LiftoffRegister dst, 2504 LiftoffRegister src) { 2505 bailout(kSimd, "emit_f32x4_sqrt"); 2506} 2507 2508bool LiftoffAssembler::emit_f32x4_ceil(LiftoffRegister dst, 2509 LiftoffRegister src) { 2510 return false; 2511} 2512 2513bool LiftoffAssembler::emit_f32x4_floor(LiftoffRegister dst, 2514 LiftoffRegister src) { 2515 return false; 2516} 2517 2518bool LiftoffAssembler::emit_f32x4_trunc(LiftoffRegister dst, 2519 LiftoffRegister src) { 2520 return false; 2521} 2522 2523bool LiftoffAssembler::emit_f32x4_nearest_int(LiftoffRegister dst, 2524 LiftoffRegister src) { 2525 return false; 2526} 2527 2528void LiftoffAssembler::emit_f32x4_add(LiftoffRegister dst, LiftoffRegister lhs, 2529 LiftoffRegister rhs) { 2530 bailout(kSimd, "emit_f32x4_add"); 2531} 2532 2533void LiftoffAssembler::emit_f32x4_sub(LiftoffRegister dst, LiftoffRegister lhs, 2534 LiftoffRegister rhs) { 2535 bailout(kSimd, "emit_f32x4_sub"); 2536} 2537 2538void LiftoffAssembler::emit_f32x4_mul(LiftoffRegister dst, LiftoffRegister lhs, 2539 LiftoffRegister rhs) { 2540 bailout(kSimd, "emit_f32x4_mul"); 2541} 2542 2543void LiftoffAssembler::emit_f32x4_div(LiftoffRegister dst, LiftoffRegister lhs, 2544 LiftoffRegister rhs) { 2545 bailout(kSimd, "emit_f32x4_div"); 2546} 2547 2548void LiftoffAssembler::emit_f32x4_min(LiftoffRegister dst, LiftoffRegister lhs, 2549 LiftoffRegister rhs) { 2550 bailout(kSimd, "emit_f32x4_min"); 2551} 2552 2553void LiftoffAssembler::emit_f32x4_max(LiftoffRegister dst, LiftoffRegister lhs, 2554 LiftoffRegister rhs) { 2555 bailout(kSimd, "emit_f32x4_max"); 2556} 2557 2558void LiftoffAssembler::emit_f32x4_pmin(LiftoffRegister dst, LiftoffRegister lhs, 2559 LiftoffRegister rhs) { 2560 bailout(kSimd, "emit_f32x4_pmin"); 2561} 2562 2563void LiftoffAssembler::emit_f32x4_pmax(LiftoffRegister dst, LiftoffRegister lhs, 2564 LiftoffRegister rhs) { 2565 bailout(kSimd, "emit_f32x4_pmax"); 2566} 2567 2568void LiftoffAssembler::emit_f64x2_abs(LiftoffRegister dst, 2569 LiftoffRegister src) { 2570 bailout(kSimd, "emit_f64x2_abs"); 2571} 2572 2573void LiftoffAssembler::emit_f64x2_neg(LiftoffRegister dst, 2574 LiftoffRegister src) { 2575 bailout(kSimd, "emit_f64x2_neg"); 2576} 2577 2578void LiftoffAssembler::emit_f64x2_sqrt(LiftoffRegister dst, 2579 LiftoffRegister src) { 2580 bailout(kSimd, "emit_f64x2_sqrt"); 2581} 2582 2583bool LiftoffAssembler::emit_f64x2_ceil(LiftoffRegister dst, 2584 LiftoffRegister src) { 2585 return false; 2586} 2587 2588bool LiftoffAssembler::emit_f64x2_floor(LiftoffRegister dst, 2589 LiftoffRegister src) { 2590 return false; 2591} 2592 2593bool LiftoffAssembler::emit_f64x2_trunc(LiftoffRegister dst, 2594 LiftoffRegister src) { 2595 return false; 2596} 2597 2598bool LiftoffAssembler::emit_f64x2_nearest_int(LiftoffRegister dst, 2599 LiftoffRegister src) { 2600 return false; 2601} 2602 2603void LiftoffAssembler::emit_f64x2_add(LiftoffRegister dst, LiftoffRegister lhs, 2604 LiftoffRegister rhs) { 2605 bailout(kSimd, "emit_f64x2_add"); 2606} 2607 2608void LiftoffAssembler::emit_f64x2_sub(LiftoffRegister dst, LiftoffRegister lhs, 2609 LiftoffRegister rhs) { 2610 bailout(kSimd, "emit_f64x2_sub"); 2611} 2612 2613void LiftoffAssembler::emit_f64x2_mul(LiftoffRegister dst, LiftoffRegister lhs, 2614 LiftoffRegister rhs) { 2615 bailout(kSimd, "emit_f64x2_mul"); 2616} 2617 2618void LiftoffAssembler::emit_f64x2_div(LiftoffRegister dst, LiftoffRegister lhs, 2619 LiftoffRegister rhs) { 2620 bailout(kSimd, "emit_f64x2_div"); 2621} 2622 2623void LiftoffAssembler::emit_f64x2_min(LiftoffRegister dst, LiftoffRegister lhs, 2624 LiftoffRegister rhs) { 2625 bailout(kSimd, "emit_f64x2_min"); 2626} 2627 2628void LiftoffAssembler::emit_f64x2_max(LiftoffRegister dst, LiftoffRegister lhs, 2629 LiftoffRegister rhs) { 2630 bailout(kSimd, "emit_f64x2_max"); 2631} 2632 2633void LiftoffAssembler::emit_f64x2_pmin(LiftoffRegister dst, LiftoffRegister lhs, 2634 LiftoffRegister rhs) { 2635 bailout(kSimd, "emit_f64x2_pmin"); 2636} 2637 2638void LiftoffAssembler::emit_f64x2_pmax(LiftoffRegister dst, LiftoffRegister lhs, 2639 LiftoffRegister rhs) { 2640 bailout(kSimd, "emit_f64x2_pmax"); 2641} 2642 2643void LiftoffAssembler::emit_f64x2_convert_low_i32x4_s(LiftoffRegister dst, 2644 LiftoffRegister src) { 2645 bailout(kSimd, "emit_f64x2_convert_low_i32x4_s"); 2646} 2647 2648void LiftoffAssembler::emit_f64x2_convert_low_i32x4_u(LiftoffRegister dst, 2649 LiftoffRegister src) { 2650 bailout(kSimd, "emit_f64x2_convert_low_i32x4_u"); 2651} 2652 2653void LiftoffAssembler::emit_f64x2_promote_low_f32x4(LiftoffRegister dst, 2654 LiftoffRegister src) { 2655 bailout(kSimd, "emit_f64x2_promote_low_f32x4"); 2656} 2657 2658void LiftoffAssembler::emit_i32x4_sconvert_f32x4(LiftoffRegister dst, 2659 LiftoffRegister src) { 2660 bailout(kSimd, "emit_i32x4_sconvert_f32x4"); 2661} 2662 2663void LiftoffAssembler::emit_i32x4_uconvert_f32x4(LiftoffRegister dst, 2664 LiftoffRegister src) { 2665 bailout(kSimd, "emit_i32x4_uconvert_f32x4"); 2666} 2667 2668void LiftoffAssembler::emit_i32x4_trunc_sat_f64x2_s_zero(LiftoffRegister dst, 2669 LiftoffRegister src) { 2670 bailout(kSimd, "emit_i32x4_trunc_sat_f64x2_s_zero"); 2671} 2672 2673void LiftoffAssembler::emit_i32x4_trunc_sat_f64x2_u_zero(LiftoffRegister dst, 2674 LiftoffRegister src) { 2675 bailout(kSimd, "emit_i32x4_trunc_sat_f64x2_u_zero"); 2676} 2677 2678void LiftoffAssembler::emit_f32x4_sconvert_i32x4(LiftoffRegister dst, 2679 LiftoffRegister src) { 2680 bailout(kSimd, "emit_f32x4_sconvert_i32x4"); 2681} 2682 2683void LiftoffAssembler::emit_f32x4_uconvert_i32x4(LiftoffRegister dst, 2684 LiftoffRegister src) { 2685 bailout(kSimd, "emit_f32x4_uconvert_i32x4"); 2686} 2687 2688void LiftoffAssembler::emit_f32x4_demote_f64x2_zero(LiftoffRegister dst, 2689 LiftoffRegister src) { 2690 bailout(kSimd, "emit_f32x4_demote_f64x2_zero"); 2691} 2692 2693void LiftoffAssembler::emit_i8x16_sconvert_i16x8(LiftoffRegister dst, 2694 LiftoffRegister lhs, 2695 LiftoffRegister rhs) { 2696 bailout(kSimd, "emit_i8x16_sconvert_i16x8"); 2697} 2698 2699void LiftoffAssembler::emit_i8x16_uconvert_i16x8(LiftoffRegister dst, 2700 LiftoffRegister lhs, 2701 LiftoffRegister rhs) { 2702 bailout(kSimd, "emit_i8x16_uconvert_i16x8"); 2703} 2704 2705void LiftoffAssembler::emit_i16x8_sconvert_i32x4(LiftoffRegister dst, 2706 LiftoffRegister lhs, 2707 LiftoffRegister rhs) { 2708 bailout(kSimd, "emit_i16x8_sconvert_i32x4"); 2709} 2710 2711void LiftoffAssembler::emit_i16x8_uconvert_i32x4(LiftoffRegister dst, 2712 LiftoffRegister lhs, 2713 LiftoffRegister rhs) { 2714 bailout(kSimd, "emit_i16x8_uconvert_i32x4"); 2715} 2716 2717void LiftoffAssembler::emit_i16x8_sconvert_i8x16_low(LiftoffRegister dst, 2718 LiftoffRegister src) { 2719 bailout(kSimd, "emit_i16x8_sconvert_i8x16_low"); 2720} 2721 2722void LiftoffAssembler::emit_i16x8_sconvert_i8x16_high(LiftoffRegister dst, 2723 LiftoffRegister src) { 2724 bailout(kSimd, "emit_i16x8_sconvert_i8x16_high"); 2725} 2726 2727void LiftoffAssembler::emit_i16x8_uconvert_i8x16_low(LiftoffRegister dst, 2728 LiftoffRegister src) { 2729 bailout(kSimd, "emit_i16x8_uconvert_i8x16_low"); 2730} 2731 2732void LiftoffAssembler::emit_i16x8_uconvert_i8x16_high(LiftoffRegister dst, 2733 LiftoffRegister src) { 2734 bailout(kSimd, "emit_i16x8_uconvert_i8x16_high"); 2735} 2736 2737void LiftoffAssembler::emit_i32x4_sconvert_i16x8_low(LiftoffRegister dst, 2738 LiftoffRegister src) { 2739 bailout(kSimd, "emit_i32x4_sconvert_i16x8_low"); 2740} 2741 2742void LiftoffAssembler::emit_i32x4_sconvert_i16x8_high(LiftoffRegister dst, 2743 LiftoffRegister src) { 2744 bailout(kSimd, "emit_i32x4_sconvert_i16x8_high"); 2745} 2746 2747void LiftoffAssembler::emit_i32x4_uconvert_i16x8_low(LiftoffRegister dst, 2748 LiftoffRegister src) { 2749 bailout(kSimd, "emit_i32x4_uconvert_i16x8_low"); 2750} 2751 2752void LiftoffAssembler::emit_i32x4_uconvert_i16x8_high(LiftoffRegister dst, 2753 LiftoffRegister src) { 2754 bailout(kSimd, "emit_i32x4_uconvert_i16x8_high"); 2755} 2756 2757void LiftoffAssembler::emit_i64x2_sconvert_i32x4_low(LiftoffRegister dst, 2758 LiftoffRegister src) { 2759 bailout(kSimd, "emit_i64x2_sconvert_i32x4_low"); 2760} 2761 2762void LiftoffAssembler::emit_i64x2_sconvert_i32x4_high(LiftoffRegister dst, 2763 LiftoffRegister src) { 2764 bailout(kSimd, "emit_i64x2_sconvert_i32x4_high"); 2765} 2766 2767void LiftoffAssembler::emit_i64x2_uconvert_i32x4_low(LiftoffRegister dst, 2768 LiftoffRegister src) { 2769 bailout(kSimd, "emit_i64x2_uconvert_i32x4_low"); 2770} 2771 2772void LiftoffAssembler::emit_i64x2_uconvert_i32x4_high(LiftoffRegister dst, 2773 LiftoffRegister src) { 2774 bailout(kSimd, "emit_i64x2_uconvert_i32x4_high"); 2775} 2776 2777void LiftoffAssembler::emit_i8x16_rounding_average_u(LiftoffRegister dst, 2778 LiftoffRegister lhs, 2779 LiftoffRegister rhs) { 2780 bailout(kSimd, "emit_i8x16_rounding_average_u"); 2781} 2782 2783void LiftoffAssembler::emit_i16x8_rounding_average_u(LiftoffRegister dst, 2784 LiftoffRegister lhs, 2785 LiftoffRegister rhs) { 2786 bailout(kSimd, "emit_i16x8_rounding_average_u"); 2787} 2788 2789void LiftoffAssembler::emit_i8x16_abs(LiftoffRegister dst, 2790 LiftoffRegister src) { 2791 bailout(kSimd, "emit_i8x16_abs"); 2792} 2793 2794void LiftoffAssembler::emit_i16x8_abs(LiftoffRegister dst, 2795 LiftoffRegister src) { 2796 bailout(kSimd, "emit_i16x8_abs"); 2797} 2798 2799void LiftoffAssembler::emit_i32x4_abs(LiftoffRegister dst, 2800 LiftoffRegister src) { 2801 bailout(kSimd, "emit_i32x4_abs"); 2802} 2803 2804void LiftoffAssembler::emit_i8x16_extract_lane_s(LiftoffRegister dst, 2805 LiftoffRegister lhs, 2806 uint8_t imm_lane_idx) { 2807 bailout(kSimd, "emit_i8x16_extract_lane_s"); 2808} 2809 2810void LiftoffAssembler::emit_i8x16_extract_lane_u(LiftoffRegister dst, 2811 LiftoffRegister lhs, 2812 uint8_t imm_lane_idx) { 2813 bailout(kSimd, "emit_i8x16_extract_lane_u"); 2814} 2815 2816void LiftoffAssembler::emit_i16x8_extract_lane_s(LiftoffRegister dst, 2817 LiftoffRegister lhs, 2818 uint8_t imm_lane_idx) { 2819 bailout(kSimd, "emit_i16x8_extract_lane_s"); 2820} 2821 2822void LiftoffAssembler::emit_i16x8_extract_lane_u(LiftoffRegister dst, 2823 LiftoffRegister lhs, 2824 uint8_t imm_lane_idx) { 2825 bailout(kSimd, "emit_i16x8_extract_lane_u"); 2826} 2827 2828void LiftoffAssembler::emit_i32x4_extract_lane(LiftoffRegister dst, 2829 LiftoffRegister lhs, 2830 uint8_t imm_lane_idx) { 2831 bailout(kSimd, "emit_i32x4_extract_lane"); 2832} 2833 2834void LiftoffAssembler::emit_i64x2_extract_lane(LiftoffRegister dst, 2835 LiftoffRegister lhs, 2836 uint8_t imm_lane_idx) { 2837 bailout(kSimd, "emit_i64x2_extract_lane"); 2838} 2839 2840void LiftoffAssembler::emit_f32x4_extract_lane(LiftoffRegister dst, 2841 LiftoffRegister lhs, 2842 uint8_t imm_lane_idx) { 2843 bailout(kSimd, "emit_f32x4_extract_lane"); 2844} 2845 2846void LiftoffAssembler::emit_f64x2_extract_lane(LiftoffRegister dst, 2847 LiftoffRegister lhs, 2848 uint8_t imm_lane_idx) { 2849 bailout(kSimd, "emit_f64x2_extract_lane"); 2850} 2851 2852void LiftoffAssembler::emit_i8x16_replace_lane(LiftoffRegister dst, 2853 LiftoffRegister src1, 2854 LiftoffRegister src2, 2855 uint8_t imm_lane_idx) { 2856 bailout(kSimd, "emit_i8x16_replace_lane"); 2857} 2858 2859void LiftoffAssembler::emit_i16x8_replace_lane(LiftoffRegister dst, 2860 LiftoffRegister src1, 2861 LiftoffRegister src2, 2862 uint8_t imm_lane_idx) { 2863 bailout(kSimd, "emit_i16x8_replace_lane"); 2864} 2865 2866void LiftoffAssembler::emit_i32x4_replace_lane(LiftoffRegister dst, 2867 LiftoffRegister src1, 2868 LiftoffRegister src2, 2869 uint8_t imm_lane_idx) { 2870 bailout(kSimd, "emit_i32x4_replace_lane"); 2871} 2872 2873void LiftoffAssembler::emit_i64x2_replace_lane(LiftoffRegister dst, 2874 LiftoffRegister src1, 2875 LiftoffRegister src2, 2876 uint8_t imm_lane_idx) { 2877 bailout(kSimd, "emit_i64x2_replace_lane"); 2878} 2879 2880void LiftoffAssembler::emit_f32x4_replace_lane(LiftoffRegister dst, 2881 LiftoffRegister src1, 2882 LiftoffRegister src2, 2883 uint8_t imm_lane_idx) { 2884 bailout(kSimd, "emit_f32x4_replace_lane"); 2885} 2886 2887void LiftoffAssembler::emit_f64x2_replace_lane(LiftoffRegister dst, 2888 LiftoffRegister src1, 2889 LiftoffRegister src2, 2890 uint8_t imm_lane_idx) { 2891 bailout(kSimd, "emit_f64x2_replace_lane"); 2892} 2893 2894void LiftoffAssembler::StackCheck(Label* ool_code, Register limit_address) { 2895 TurboAssembler::Ulw(limit_address, MemOperand(limit_address)); 2896 TurboAssembler::Branch(ool_code, ule, sp, Operand(limit_address)); 2897} 2898 2899void LiftoffAssembler::CallTrapCallbackForTesting() { 2900 PrepareCallCFunction(0, GetUnusedRegister(kGpReg, {}).gp()); 2901 CallCFunction(ExternalReference::wasm_call_trap_callback_for_testing(), 0); 2902} 2903 2904void LiftoffAssembler::AssertUnreachable(AbortReason reason) { 2905 if (FLAG_debug_code) Abort(reason); 2906} 2907 2908void LiftoffAssembler::PushRegisters(LiftoffRegList regs) { 2909 LiftoffRegList gp_regs = regs & kGpCacheRegList; 2910 unsigned num_gp_regs = gp_regs.GetNumRegsSet(); 2911 if (num_gp_regs) { 2912 unsigned offset = num_gp_regs * kSystemPointerSize; 2913 addiu(sp, sp, -offset); 2914 while (!gp_regs.is_empty()) { 2915 LiftoffRegister reg = gp_regs.GetFirstRegSet(); 2916 offset -= kSystemPointerSize; 2917 sw(reg.gp(), MemOperand(sp, offset)); 2918 gp_regs.clear(reg); 2919 } 2920 DCHECK_EQ(offset, 0); 2921 } 2922 LiftoffRegList fp_regs = regs & kFpCacheRegList; 2923 unsigned num_fp_regs = fp_regs.GetNumRegsSet(); 2924 if (num_fp_regs) { 2925 addiu(sp, sp, -(num_fp_regs * kStackSlotSize)); 2926 unsigned offset = 0; 2927 while (!fp_regs.is_empty()) { 2928 LiftoffRegister reg = fp_regs.GetFirstRegSet(); 2929 TurboAssembler::Sdc1(reg.fp(), MemOperand(sp, offset)); 2930 fp_regs.clear(reg); 2931 offset += sizeof(double); 2932 } 2933 DCHECK_EQ(offset, num_fp_regs * sizeof(double)); 2934 } 2935} 2936 2937void LiftoffAssembler::PopRegisters(LiftoffRegList regs) { 2938 LiftoffRegList fp_regs = regs & kFpCacheRegList; 2939 unsigned fp_offset = 0; 2940 while (!fp_regs.is_empty()) { 2941 LiftoffRegister reg = fp_regs.GetFirstRegSet(); 2942 TurboAssembler::Ldc1(reg.fp(), MemOperand(sp, fp_offset)); 2943 fp_regs.clear(reg); 2944 fp_offset += sizeof(double); 2945 } 2946 if (fp_offset) addiu(sp, sp, fp_offset); 2947 LiftoffRegList gp_regs = regs & kGpCacheRegList; 2948 unsigned gp_offset = 0; 2949 while (!gp_regs.is_empty()) { 2950 LiftoffRegister reg = gp_regs.GetLastRegSet(); 2951 lw(reg.gp(), MemOperand(sp, gp_offset)); 2952 gp_regs.clear(reg); 2953 gp_offset += kSystemPointerSize; 2954 } 2955 addiu(sp, sp, gp_offset); 2956} 2957 2958void LiftoffAssembler::RecordSpillsInSafepoint( 2959 SafepointTableBuilder::Safepoint& safepoint, LiftoffRegList all_spills, 2960 LiftoffRegList ref_spills, int spill_offset) { 2961 int spill_space_size = 0; 2962 while (!all_spills.is_empty()) { 2963 LiftoffRegister reg = all_spills.GetFirstRegSet(); 2964 if (ref_spills.has(reg)) { 2965 safepoint.DefineTaggedStackSlot(spill_offset); 2966 } 2967 all_spills.clear(reg); 2968 ++spill_offset; 2969 spill_space_size += kSystemPointerSize; 2970 } 2971 // Record the number of additional spill slots. 2972 RecordOolSpillSpaceSize(spill_space_size); 2973} 2974 2975void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) { 2976 DCHECK_LT(num_stack_slots, 2977 (1 << 16) / kSystemPointerSize); // 16 bit immediate 2978 TurboAssembler::DropAndRet(static_cast<int>(num_stack_slots)); 2979} 2980 2981void LiftoffAssembler::CallC(const ValueKindSig* sig, 2982 const LiftoffRegister* args, 2983 const LiftoffRegister* rets, 2984 ValueKind out_argument_kind, int stack_bytes, 2985 ExternalReference ext_ref) { 2986 addiu(sp, sp, -stack_bytes); 2987 2988 int arg_bytes = 0; 2989 for (ValueKind param_kind : sig->parameters()) { 2990 liftoff::Store(this, sp, arg_bytes, *args++, param_kind); 2991 arg_bytes += value_kind_size(param_kind); 2992 } 2993 DCHECK_LE(arg_bytes, stack_bytes); 2994 2995 // Pass a pointer to the buffer with the arguments to the C function. 2996 // On mips, the first argument is passed in {a0}. 2997 constexpr Register kFirstArgReg = a0; 2998 mov(kFirstArgReg, sp); 2999 3000 // Now call the C function. 3001 constexpr int kNumCCallArgs = 1; 3002 PrepareCallCFunction(kNumCCallArgs, kScratchReg); 3003 CallCFunction(ext_ref, kNumCCallArgs); 3004 3005 // Move return value to the right register. 3006 const LiftoffRegister* next_result_reg = rets; 3007 if (sig->return_count() > 0) { 3008 DCHECK_EQ(1, sig->return_count()); 3009 constexpr Register kReturnReg = v0; 3010 if (kReturnReg != next_result_reg->gp()) { 3011 Move(*next_result_reg, LiftoffRegister(kReturnReg), sig->GetReturn(0)); 3012 } 3013 ++next_result_reg; 3014 } 3015 3016 // Load potential output value from the buffer on the stack. 3017 if (out_argument_kind != kVoid) { 3018 liftoff::Load(this, *next_result_reg, sp, 0, out_argument_kind); 3019 } 3020 3021 addiu(sp, sp, stack_bytes); 3022} 3023 3024void LiftoffAssembler::CallNativeWasmCode(Address addr) { 3025 Call(addr, RelocInfo::WASM_CALL); 3026} 3027 3028void LiftoffAssembler::TailCallNativeWasmCode(Address addr) { 3029 Jump(addr, RelocInfo::WASM_CALL); 3030} 3031 3032void LiftoffAssembler::CallIndirect(const ValueKindSig* sig, 3033 compiler::CallDescriptor* call_descriptor, 3034 Register target) { 3035 if (target == no_reg) { 3036 pop(kScratchReg); 3037 Call(kScratchReg); 3038 } else { 3039 Call(target); 3040 } 3041} 3042 3043void LiftoffAssembler::TailCallIndirect(Register target) { 3044 if (target == no_reg) { 3045 Pop(kScratchReg); 3046 Jump(kScratchReg); 3047 } else { 3048 Jump(target); 3049 } 3050} 3051 3052void LiftoffAssembler::CallRuntimeStub(WasmCode::RuntimeStubId sid) { 3053 // A direct call to a wasm runtime stub defined in this module. 3054 // Just encode the stub index. This will be patched at relocation. 3055 Call(static_cast<Address>(sid), RelocInfo::WASM_STUB_CALL); 3056} 3057 3058void LiftoffAssembler::AllocateStackSlot(Register addr, uint32_t size) { 3059 addiu(sp, sp, -size); 3060 TurboAssembler::Move(addr, sp); 3061} 3062 3063void LiftoffAssembler::DeallocateStackSlot(uint32_t size) { 3064 addiu(sp, sp, size); 3065} 3066 3067void LiftoffAssembler::MaybeOSR() {} 3068 3069void LiftoffAssembler::emit_set_if_nan(Register dst, FPURegister src, 3070 ValueKind kind) { 3071 UseScratchRegisterScope temps(this); 3072 Register scratch = temps.Acquire(); 3073 Label not_nan; 3074 if (kind == kF32) { 3075 CompareIsNanF32(src, src); 3076 } else { 3077 DCHECK_EQ(kind, kF64); 3078 CompareIsNanF64(src, src); 3079 } 3080 BranchFalseShortF(¬_nan, USE_DELAY_SLOT); 3081 li(scratch, 1); 3082 sw(scratch, MemOperand(dst)); 3083 bind(¬_nan); 3084} 3085 3086void LiftoffAssembler::emit_s128_set_if_nan(Register dst, LiftoffRegister src, 3087 Register tmp_gp, 3088 LiftoffRegister tmp_s128, 3089 ValueKind lane_kind) { 3090 UNIMPLEMENTED(); 3091} 3092 3093void LiftoffStackSlots::Construct(int param_slots) { 3094 DCHECK_LT(0, slots_.size()); 3095 SortInPushOrder(); 3096 int last_stack_slot = param_slots; 3097 for (auto& slot : slots_) { 3098 const int stack_slot = slot.dst_slot_; 3099 int stack_decrement = (last_stack_slot - stack_slot) * kSystemPointerSize; 3100 DCHECK_LT(0, stack_decrement); 3101 last_stack_slot = stack_slot; 3102 const LiftoffAssembler::VarState& src = slot.src_; 3103 switch (src.loc()) { 3104 case LiftoffAssembler::VarState::kStack: { 3105 if (src.kind() == kF64) { 3106 asm_->AllocateStackSpace(stack_decrement - kDoubleSize); 3107 DCHECK_EQ(kLowWord, slot.half_); 3108 asm_->lw(kScratchReg, 3109 liftoff::GetHalfStackSlot(slot.src_offset_, kHighWord)); 3110 asm_->push(kScratchReg); 3111 } else { 3112 asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); 3113 } 3114 asm_->lw(kScratchReg, 3115 liftoff::GetHalfStackSlot(slot.src_offset_, slot.half_)); 3116 asm_->push(kScratchReg); 3117 break; 3118 } 3119 case LiftoffAssembler::VarState::kRegister: { 3120 int pushed_bytes = SlotSizeInBytes(slot); 3121 asm_->AllocateStackSpace(stack_decrement - pushed_bytes); 3122 if (src.kind() == kI64) { 3123 liftoff::push( 3124 asm_, slot.half_ == kLowWord ? src.reg().low() : src.reg().high(), 3125 kI32); 3126 } else { 3127 liftoff::push(asm_, src.reg(), src.kind()); 3128 } 3129 break; 3130 } 3131 case LiftoffAssembler::VarState::kIntConst: { 3132 // The high word is the sign extension of the low word. 3133 asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize); 3134 asm_->li(kScratchReg, 3135 Operand(slot.half_ == kLowWord ? src.i32_const() 3136 : src.i32_const() >> 31)); 3137 asm_->push(kScratchReg); 3138 break; 3139 } 3140 } 3141 } 3142} 3143 3144} // namespace wasm 3145} // namespace internal 3146} // namespace v8 3147 3148#endif // V8_WASM_BASELINE_MIPS_LIFTOFF_ASSEMBLER_MIPS_H_ 3149