v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
liftoff-assembler-x64-inl.h
Go to the documentation of this file.
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_X64_LIFTOFF_ASSEMBLER_X64_INL_H_
6#define V8_WASM_BASELINE_X64_LIFTOFF_ASSEMBLER_X64_INL_H_
7
8#include <optional>
9
17#include "src/flags/flags.h"
26
27namespace v8::internal::wasm {
28
29#define RETURN_FALSE_IF_MISSING_CPU_FEATURE(name) \
30 if (!CpuFeatures::IsSupported(name)) return false; \
31 CpuFeatureScope feature(this, name);
32
33namespace liftoff {
34
36static_assert(kScratchRegister != kScratchRegister2, "collision");
37static_assert((kLiftoffAssemblerGpCacheRegs &
39 .is_empty(),
40 "scratch registers must not be used as cache registers");
41
42constexpr DoubleRegister kScratchDoubleReg2 = xmm14;
43static_assert(kScratchDoubleReg != kScratchDoubleReg2, "collision");
44static_assert((kLiftoffAssemblerFpCacheRegs &
46 .is_empty(),
47 "scratch registers must not be used as cache registers");
48
49inline constexpr Operand GetStackSlot(int offset) {
50 return Operand(rbp, -offset);
51}
52
55
56constexpr Operand kOSRTargetSlot = GetStackSlot(kOSRTargetOffset);
57
58// Note: The returned Operand might contain {kScratchRegister2}; make sure not
59// to clobber that until after the last use of the Operand.
61 Register offset_reg, uintptr_t offset_imm,
62 ScaleFactor scale_factor = times_1) {
63 if (is_uint31(offset_imm)) {
64 int32_t offset_imm32 = static_cast<int32_t>(offset_imm);
65 return offset_reg == no_reg
66 ? Operand(addr, offset_imm32)
67 : Operand(addr, offset_reg, scale_factor, offset_imm32);
68 }
69 // Offset immediate does not fit in 31 bits.
71 assm->MacroAssembler::Move(scratch, offset_imm);
72 if (offset_reg != no_reg) assm->addq(scratch, offset_reg);
73 return Operand(addr, scratch, scale_factor, 0);
74}
75
77 Operand src, ValueKind kind) {
78 switch (kind) {
79 case kI16:
80 assm->movw(dst.gp(), src);
81 break;
82 case kI32:
83 assm->movl(dst.gp(), src);
84 break;
85 case kI64:
86 case kRefNull:
87 case kRef:
88 // Stack slots are uncompressed even when heap pointers are compressed.
89 assm->movq(dst.gp(), src);
90 break;
91 case kF32:
92 assm->Movss(dst.fp(), src);
93 break;
94 case kF64:
95 assm->Movsd(dst.fp(), src);
96 break;
97 case kS128:
98 assm->Movdqu(dst.fp(), src);
99 break;
100 default:
101 UNREACHABLE();
102 }
103}
104
107 switch (kind) {
108 case kI16:
109 assm->movw(dst, src.gp());
110 break;
111 case kI32:
112 assm->movl(dst, src.gp());
113 break;
114 case kI64:
115 case kRefNull:
116 case kRef:
117 // Stack slots are uncompressed even when heap pointers are compressed.
118 assm->movq(dst, src.gp());
119 break;
120 case kF32:
121 assm->Movss(dst, src.fp());
122 break;
123 case kF64:
124 assm->Movsd(dst, src.fp());
125 break;
126 case kS128:
127 assm->Movdqu(dst, src.fp());
128 break;
129 default:
130 UNREACHABLE();
131 }
132}
133
135 const LiftoffAssembler::VarState& src) {
136 if (src.is_reg()) {
137 liftoff::StoreToMemory(assm, dst, src.reg(), src.kind());
138 } else if (src.is_const()) {
139 if (src.kind() == kI32) {
140 assm->movl(dst, Immediate(src.i32_const()));
141 } else {
142 assm->MacroAssembler::Move(dst, static_cast<int64_t>(src.i32_const()));
143 }
144 } else if (value_kind_size(src.kind()) == 4) {
145 DCHECK(src.is_stack());
146 assm->movl(kScratchRegister, liftoff::GetStackSlot(src.offset()));
147 assm->movl(dst, kScratchRegister);
148 } else {
149 DCHECK(src.is_stack());
150 DCHECK_EQ(8, value_kind_size(src.kind()));
151 assm->movq(kScratchRegister, liftoff::GetStackSlot(src.offset()));
152 assm->movq(dst, kScratchRegister);
153 }
154}
155
157 int padding = 0) {
158 switch (kind) {
159 case kI32:
160 case kI64:
161 case kRef:
162 case kRefNull:
163 assm->AllocateStackSpace(padding);
164 assm->pushq(reg.gp());
165 break;
166 case kF32:
167 assm->AllocateStackSpace(kSystemPointerSize + padding);
168 assm->Movss(Operand(rsp, 0), reg.fp());
169 break;
170 case kF64:
171 assm->AllocateStackSpace(kSystemPointerSize + padding);
172 assm->Movsd(Operand(rsp, 0), reg.fp());
173 break;
174 case kS128:
175 assm->AllocateStackSpace(kSystemPointerSize * 2 + padding);
176 assm->Movdqu(Operand(rsp, 0), reg.fp());
177 break;
178 default:
179 UNREACHABLE();
180 }
181}
182
183constexpr int kSubSpSize = 7; // 7 bytes for "subq rsp, <imm32>"
184
185} // namespace liftoff
186
188 int offset = pc_offset();
189 // Next we reserve the memory for the whole stack frame. We do not know yet
190 // how big the stack frame will be so we just emit a placeholder instruction.
191 // PatchPrepareStackFrame will patch this in order to increase the stack
192 // appropriately.
193 sub_sp_32(0);
195 return offset;
196}
197
199// The standard library used by gcc tryjobs does not consider `std::find` to be
200// `constexpr`, so wrap it in a `#ifdef __clang__` block.
201#ifdef __clang__
202 static_assert(std::find(std::begin(wasm::kGpParamRegisters),
203 std::end(wasm::kGpParamRegisters),
204 kLiftoffFrameSetupFunctionReg) ==
205 std::end(wasm::kGpParamRegisters));
206#endif
207
208 LoadConstant(LiftoffRegister(kLiftoffFrameSetupFunctionReg),
209 WasmValue(declared_function_index));
210 CallBuiltin(Builtin::kWasmLiftoffFrameSetup);
211}
212
213void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params,
214 int stack_param_delta) {
215 // Push the return address and frame pointer to complete the stack frame.
216 pushq(Operand(rbp, 8));
217 pushq(Operand(rbp, 0));
218
219 // Shift the whole frame upwards.
220 const int slot_count = num_callee_stack_params + 2;
221 for (int i = slot_count - 1; i >= 0; --i) {
222 movq(kScratchRegister, Operand(rsp, i * 8));
223 movq(Operand(rbp, (i - stack_param_delta) * 8), kScratchRegister);
224 }
225
226 // Set the new stack and frame pointer.
227 leaq(rsp, Operand(rbp, -stack_param_delta * 8));
228 popq(rbp);
229}
230
233}
234
236 int offset, SafepointTableBuilder* safepoint_table_builder,
237 bool feedback_vector_slot, size_t stack_param_slots) {
238 // The frame_size includes the frame marker and the instance slot. Both are
239 // pushed as part of frame construction, so we don't need to allocate memory
240 // for them anymore.
241 int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize;
242 // The frame setup builtin also pushes the feedback vector.
243 if (feedback_vector_slot) {
244 frame_size -= kSystemPointerSize;
245 }
246 DCHECK_EQ(0, frame_size % kSystemPointerSize);
247
248 // We can't run out of space when patching, just pass anything big enough to
249 // not cause the assembler to try to grow the buffer.
250 constexpr int kAvailableSpace = 64;
251 Assembler patching_assembler(
252 AssemblerOptions{},
253 ExternalAssemblerBuffer(buffer_start_ + offset, kAvailableSpace));
254
255 if (V8_LIKELY(frame_size < 4 * KB)) {
256 // This is the standard case for small frames: just subtract from SP and be
257 // done with it.
258 patching_assembler.sub_sp_32(frame_size);
259 DCHECK_EQ(liftoff::kSubSpSize, patching_assembler.pc_offset());
260 return;
261 }
262
263 // The frame size is bigger than 4KB, so we might overflow the available stack
264 // space if we first allocate the frame and then do the stack check (we will
265 // need some remaining stack space for throwing the exception). That's why we
266 // check the available stack space before we allocate the frame. To do this we
267 // replace the {__ sub(sp, framesize)} with a jump to OOL code that does this
268 // "extended stack check".
269 //
270 // The OOL code can simply be generated here with the normal assembler,
271 // because all other code generation, including OOL code, has already finished
272 // when {PatchPrepareStackFrame} is called. The function prologue then jumps
273 // to the current {pc_offset()} to execute the OOL code for allocating the
274 // large frame.
275
276 // Emit the unconditional branch in the function prologue (from {offset} to
277 // {pc_offset()}).
278 patching_assembler.jmp_rel(pc_offset() - offset);
279 DCHECK_GE(liftoff::kSubSpSize, patching_assembler.pc_offset());
280 patching_assembler.Nop(liftoff::kSubSpSize - patching_assembler.pc_offset());
281
282 // If the frame is bigger than the stack, we throw the stack overflow
283 // exception unconditionally. Thereby we can avoid the integer overflow
284 // check in the condition code.
285 RecordComment("OOL: stack check for large frame");
286 Label continuation;
287 if (frame_size < v8_flags.stack_size * 1024) {
290 addq(kScratchRegister, Immediate(frame_size));
291 cmpq(rsp, kScratchRegister);
293 }
294
295 if (v8_flags.experimental_wasm_growable_stacks) {
296 LiftoffRegList regs_to_save;
298 regs_to_save.set(WasmHandleStackOverflowDescriptor::FrameBaseRegister());
299 for (auto reg : kGpParamRegisters) regs_to_save.set(reg);
300 for (auto reg : kFpParamRegisters) regs_to_save.set(reg);
303 Immediate(frame_size));
304 movq(WasmHandleStackOverflowDescriptor::FrameBaseRegister(), rbp);
305 addq(WasmHandleStackOverflowDescriptor::FrameBaseRegister(),
306 Immediate(static_cast<int32_t>(
307 stack_param_slots * kStackSlotSize +
309 CallBuiltin(Builtin::kWasmHandleStackOverflow);
310 safepoint_table_builder->DefineSafepoint(this);
312 } else {
313 near_call(static_cast<intptr_t>(Builtin::kWasmStackOverflow),
315 // The call will not return; just define an empty safepoint.
316 safepoint_table_builder->DefineSafepoint(this);
317 AssertUnreachable(AbortReason::kUnexpectedReturnFromWasmTrap);
318 }
319
321
322 // Now allocate the stack space. Note that this might do more than just
323 // decrementing the SP; consult {MacroAssembler::AllocateStackSpace}.
324 AllocateStackSpace(frame_size);
325
326 // Jump back to the start of the function, from {pc_offset()} to
327 // right after the reserved space for the {__ sub(sp, sp, framesize)} (which
328 // is a branch now).
329 int func_start_offset = offset + liftoff::kSubSpSize;
330 jmp_rel(func_start_offset - pc_offset());
331}
332
334
336
337// static
339 return kOSRTargetOffset;
340}
341
344}
345
347 return is_reference(kind);
348}
349
350void LiftoffAssembler::CheckTierUp(int declared_func_index, int budget_used,
351 Label* ool_label,
352 const FreezeCacheState& frozen) {
354 if (instance_data == no_reg) {
357 }
358
359 Register budget_array = kScratchRegister; // Overwriting {instance_data}.
360 constexpr int kArrayOffset = wasm::ObjectAccess::ToTagged(
361 WasmTrustedInstanceData::kTieringBudgetArrayOffset);
362 movq(budget_array, Operand{instance_data, kArrayOffset});
363
364 int offset = kInt32Size * declared_func_index;
365 subl(Operand{budget_array, offset}, Immediate(budget_used));
366 j(negative, ool_label);
367}
368
370 if (!v8_flags.experimental_wasm_growable_stacks) {
371 return rbp;
372 }
373 Label done, call_runtime;
375 Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)));
376 j(equal, &call_runtime);
377 LiftoffRegister old_fp = GetUnusedRegister(RegClass::kGpReg, {});
378 movq(old_fp.gp(), rbp);
379 jmp(&done);
380
381 bind(&call_runtime);
382 LiftoffRegList regs_to_save = cache_state()->used_registers;
386 CallCFunction(ExternalReference::wasm_load_old_fp(), 1);
387 if (old_fp.gp() != kReturnRegister0) {
388 movq(old_fp.gp(), kReturnRegister0);
389 }
391
392 bind(&done);
393 return old_fp.gp();
394}
395
398 Immediate(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)));
399 Label done;
400 j(not_equal, &done);
401 LiftoffRegList regs_to_save;
402 for (auto reg : kGpReturnRegisters) regs_to_save.set(reg);
403 for (auto reg : kFpReturnRegisters) regs_to_save.set(reg);
407 CallCFunction(ExternalReference::wasm_shrink_stack(), 1);
408 // Restore old FP. We don't need to restore old SP explicitly, because
409 // it will be restored from FP in LeaveFrame before return.
412 bind(&done);
413}
414
415void LiftoffAssembler::LoadConstant(LiftoffRegister reg, WasmValue value) {
416 switch (value.type().kind()) {
417 case kI32:
418 if (value.to_i32() == 0) {
419 xorl(reg.gp(), reg.gp());
420 } else {
421 movl(reg.gp(), Immediate(value.to_i32()));
422 }
423 break;
424 case kI64:
425 MacroAssembler::Move(reg.gp(), value.to_i64());
426 break;
427 case kF32:
428 MacroAssembler::Move(reg.fp(), value.to_f32_boxed().get_bits());
429 break;
430 case kF64:
431 MacroAssembler::Move(reg.fp(), value.to_f64_boxed().get_bits());
432 break;
433 default:
434 UNREACHABLE();
435 }
436}
437
440}
441
442void LiftoffAssembler::LoadTrustedPointer(Register dst, Register src_addr,
443 int offset, IndirectPointerTag tag) {
444 LoadTrustedPointerField(dst, Operand{src_addr, offset}, tag,
446}
447
448void LiftoffAssembler::LoadFromInstance(Register dst, Register instance,
449 int offset, int size) {
450 DCHECK_LE(0, offset);
451 Operand src{instance, offset};
452 switch (size) {
453 case 1:
454 movzxbl(dst, src);
455 break;
456 case 4:
457 movl(dst, src);
458 break;
459 case 8:
460 movq(dst, src);
461 break;
462 default:
464 }
465}
466
468 Register instance,
469 int offset) {
470 DCHECK_LE(0, offset);
471 LoadTaggedField(dst, Operand(instance, offset));
472}
473
474void LiftoffAssembler::SpillInstanceData(Register instance) {
476}
477
479 movq(liftoff::kOSRTargetSlot, Immediate(0));
480}
481
482void LiftoffAssembler::LoadTaggedPointer(Register dst, Register src_addr,
483 Register offset_reg,
484 int32_t offset_imm,
485 uint32_t* protected_load_pc,
486 bool needs_shift) {
487 DCHECK_GE(offset_imm, 0);
488 if (offset_reg != no_reg) AssertZeroExtended(offset_reg);
489 ScaleFactor scale_factor = !needs_shift ? times_1
491 : times_8;
492 Operand src_op =
493 liftoff::GetMemOp(this, src_addr, offset_reg,
494 static_cast<uint32_t>(offset_imm), scale_factor);
495 if (protected_load_pc) *protected_load_pc = pc_offset();
496 LoadTaggedField(dst, src_op);
497}
498
499void LiftoffAssembler::LoadProtectedPointer(Register dst, Register src_addr,
500 int32_t offset_imm) {
501 DCHECK_LE(0, offset_imm);
502 LoadProtectedPointerField(dst, Operand{src_addr, offset_imm});
503}
504
505void LiftoffAssembler::LoadFullPointer(Register dst, Register src_addr,
506 int32_t offset_imm) {
507 Operand src_op = liftoff::GetMemOp(this, src_addr, no_reg,
508 static_cast<uint32_t>(offset_imm));
509 movq(dst, src_op);
510}
511
512#ifdef V8_ENABLE_SANDBOX
513void LiftoffAssembler::LoadCodeEntrypointViaCodePointer(Register dst,
514 Register src_addr,
515 int offset_imm) {
516 Operand src_op = liftoff::GetMemOp(this, src_addr, no_reg,
517 static_cast<uint32_t>(offset_imm));
518 MacroAssembler::LoadCodeEntrypointViaCodePointer(dst, src_op,
520}
521#endif
522
523void LiftoffAssembler::StoreTaggedPointer(Register dst_addr,
524 Register offset_reg,
525 int32_t offset_imm, Register src,
526 LiftoffRegList pinned,
527 uint32_t* protected_store_pc,
528 SkipWriteBarrier skip_write_barrier) {
529 DCHECK_GE(offset_imm, 0);
530 Operand dst_op = liftoff::GetMemOp(this, dst_addr, offset_reg,
531 static_cast<uint32_t>(offset_imm));
532 if (protected_store_pc) *protected_store_pc = pc_offset();
533 StoreTaggedField(dst_op, src);
534
535 if (skip_write_barrier || v8_flags.disable_write_barriers) return;
536
537 // None of the code below uses the {kScratchRegister} (in particular the
538 // {CallRecordWriteStubSaveRegisters} just emits a near call). Hence we can
539 // use it as scratch register here.
540 Label exit;
544 JumpIfSmi(src, &exit, Label::kNear);
548 leaq(kScratchRegister, dst_op);
549
552 StubCallMode::kCallWasmRuntimeStub);
553 bind(&exit);
554}
555
556void LiftoffAssembler::AtomicLoad(LiftoffRegister dst, Register src_addr,
557 Register offset_reg, uintptr_t offset_imm,
558 LoadType type, LiftoffRegList /* pinned */,
559 bool i64_offset) {
560 Load(dst, src_addr, offset_reg, offset_imm, type, nullptr, true, i64_offset);
561}
562
563void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr,
564 Register offset_reg, uintptr_t offset_imm,
565 LoadType type, uint32_t* protected_load_pc,
566 bool /* is_load_mem */, bool i64_offset,
567 bool needs_shift) {
568 if (offset_reg != no_reg && !i64_offset) AssertZeroExtended(offset_reg);
569 static_assert(times_4 == 2);
570 ScaleFactor scale_factor =
571 needs_shift ? static_cast<ScaleFactor>(type.size_log_2()) : times_1;
572 Operand src_op =
573 liftoff::GetMemOp(this, src_addr, offset_reg, offset_imm, scale_factor);
574 if (protected_load_pc) *protected_load_pc = pc_offset();
575 switch (type.value()) {
576 case LoadType::kI32Load8U:
577 case LoadType::kI64Load8U:
578 movzxbl(dst.gp(), src_op);
579 break;
580 case LoadType::kI32Load8S:
581 movsxbl(dst.gp(), src_op);
582 break;
583 case LoadType::kI64Load8S:
584 movsxbq(dst.gp(), src_op);
585 break;
586 case LoadType::kI32Load16U:
587 case LoadType::kI64Load16U:
588 movzxwl(dst.gp(), src_op);
589 break;
590 case LoadType::kI32Load16S:
591 movsxwl(dst.gp(), src_op);
592 break;
593 case LoadType::kI64Load16S:
594 movsxwq(dst.gp(), src_op);
595 break;
596 case LoadType::kI32Load:
597 case LoadType::kI64Load32U:
598 movl(dst.gp(), src_op);
599 break;
600 case LoadType::kI64Load32S:
601 movsxlq(dst.gp(), src_op);
602 break;
603 case LoadType::kI64Load:
604 movq(dst.gp(), src_op);
605 break;
606 case LoadType::kF32Load:
607 Movss(dst.fp(), src_op);
608 break;
609 case LoadType::kF32LoadF16: {
610 CpuFeatureScope f16c_scope(this, F16C);
611 CpuFeatureScope avx2_scope(this, AVX2);
612 vpbroadcastw(dst.fp(), src_op);
613 vcvtph2ps(dst.fp(), dst.fp());
614 break;
615 }
616 case LoadType::kF64Load:
617 Movsd(dst.fp(), src_op);
618 break;
619 case LoadType::kS128Load:
620 Movdqu(dst.fp(), src_op);
621 break;
622 }
623}
624
625void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
626 uintptr_t offset_imm, LiftoffRegister src,
627 StoreType type, LiftoffRegList /* pinned */,
628 uint32_t* protected_store_pc,
629 bool /* is_store_mem */, bool i64_offset) {
630 if (offset_reg != no_reg && !i64_offset) AssertZeroExtended(offset_reg);
631 Operand dst_op = liftoff::GetMemOp(this, dst_addr, offset_reg, offset_imm);
632 if (protected_store_pc) *protected_store_pc = pc_offset();
633 switch (type.value()) {
634 case StoreType::kI32Store8:
635 case StoreType::kI64Store8:
636 movb(dst_op, src.gp());
637 break;
638 case StoreType::kI32Store16:
639 case StoreType::kI64Store16:
640 movw(dst_op, src.gp());
641 break;
642 case StoreType::kI32Store:
643 case StoreType::kI64Store32:
644 movl(dst_op, src.gp());
645 break;
646 case StoreType::kI64Store:
647 movq(dst_op, src.gp());
648 break;
649 case StoreType::kF32Store:
650 Movss(dst_op, src.fp());
651 break;
652 case StoreType::kF32StoreF16: {
653 CpuFeatureScope fscope(this, F16C);
654 vcvtps2ph(kScratchDoubleReg, src.fp(), 0);
655 Pextrw(dst_op, kScratchDoubleReg, static_cast<uint8_t>(0));
656 break;
657 }
658 case StoreType::kF64Store:
659 Movsd(dst_op, src.fp());
660 break;
661 case StoreType::kS128Store:
662 Movdqu(dst_op, src.fp());
663 break;
664 }
665}
666
667void LiftoffAssembler::AtomicStore(Register dst_addr, Register offset_reg,
668 uintptr_t offset_imm, LiftoffRegister src,
669 StoreType type, LiftoffRegList /* pinned */,
670 bool i64_offset) {
671 if (offset_reg != no_reg && !i64_offset) AssertZeroExtended(offset_reg);
672 Operand dst_op = liftoff::GetMemOp(this, dst_addr, offset_reg, offset_imm);
673 Register src_reg = src.gp();
674 if (cache_state()->is_used(src)) {
675 movq(kScratchRegister, src_reg);
676 src_reg = kScratchRegister;
677 }
678 switch (type.value()) {
679 case StoreType::kI32Store8:
680 case StoreType::kI64Store8:
681 xchgb(src_reg, dst_op);
682 break;
683 case StoreType::kI32Store16:
684 case StoreType::kI64Store16:
685 xchgw(src_reg, dst_op);
686 break;
687 case StoreType::kI32Store:
688 case StoreType::kI64Store32:
689 xchgl(src_reg, dst_op);
690 break;
691 case StoreType::kI64Store:
692 xchgq(src_reg, dst_op);
693 break;
694 default:
695 UNREACHABLE();
696 }
697}
698
699void LiftoffAssembler::AtomicAdd(Register dst_addr, Register offset_reg,
700 uintptr_t offset_imm, LiftoffRegister value,
701 LiftoffRegister result, StoreType type,
702 bool i64_offset) {
703 if (offset_reg != no_reg && !i64_offset) AssertZeroExtended(offset_reg);
704 DCHECK(!cache_state()->is_used(result));
705 if (cache_state()->is_used(value)) {
706 // We cannot overwrite {value}, but the {value} register is changed in the
707 // code we generate. Therefore we copy {value} to {result} and use the
708 // {result} register in the code below.
709 movq(result.gp(), value.gp());
710 value = result;
711 }
712 Operand dst_op = liftoff::GetMemOp(this, dst_addr, offset_reg, offset_imm);
713 lock();
714 switch (type.value()) {
715 case StoreType::kI32Store8:
716 case StoreType::kI64Store8:
717 xaddb(dst_op, value.gp());
718 movzxbq(result.gp(), value.gp());
719 break;
720 case StoreType::kI32Store16:
721 case StoreType::kI64Store16:
722 xaddw(dst_op, value.gp());
723 movzxwq(result.gp(), value.gp());
724 break;
725 case StoreType::kI32Store:
726 case StoreType::kI64Store32:
727 xaddl(dst_op, value.gp());
728 if (value != result) {
729 movq(result.gp(), value.gp());
730 }
731 break;
732 case StoreType::kI64Store:
733 xaddq(dst_op, value.gp());
734 if (value != result) {
735 movq(result.gp(), value.gp());
736 }
737 break;
738 default:
739 UNREACHABLE();
740 }
741}
742
743void LiftoffAssembler::AtomicSub(Register dst_addr, Register offset_reg,
744 uintptr_t offset_imm, LiftoffRegister value,
745 LiftoffRegister result, StoreType type,
746 bool i64_offset) {
747 if (offset_reg != no_reg && !i64_offset) AssertZeroExtended(offset_reg);
748 LiftoffRegList dont_overwrite =
749 cache_state()->used_registers | LiftoffRegList{dst_addr};
750 if (offset_reg != no_reg) dont_overwrite.set(offset_reg);
751 DCHECK(!dont_overwrite.has(result));
752 if (dont_overwrite.has(value)) {
753 // We cannot overwrite {value}, but the {value} register is changed in the
754 // code we generate. Therefore we copy {value} to {result} and use the
755 // {result} register in the code below.
756 movq(result.gp(), value.gp());
757 value = result;
758 }
759 Operand dst_op = liftoff::GetMemOp(this, dst_addr, offset_reg, offset_imm);
760 switch (type.value()) {
761 case StoreType::kI32Store8:
762 case StoreType::kI64Store8:
763 negb(value.gp());
764 lock();
765 xaddb(dst_op, value.gp());
766 movzxbq(result.gp(), value.gp());
767 break;
768 case StoreType::kI32Store16:
769 case StoreType::kI64Store16:
770 negw(value.gp());
771 lock();
772 xaddw(dst_op, value.gp());
773 movzxwq(result.gp(), value.gp());
774 break;
775 case StoreType::kI32Store:
776 case StoreType::kI64Store32:
777 negl(value.gp());
778 lock();
779 xaddl(dst_op, value.gp());
780 if (value != result) {
781 movq(result.gp(), value.gp());
782 }
783 break;
784 case StoreType::kI64Store:
785 negq(value.gp());
786 lock();
787 xaddq(dst_op, value.gp());
788 if (value != result) {
789 movq(result.gp(), value.gp());
790 }
791 break;
792 default:
793 UNREACHABLE();
794 }
795}
796
797namespace liftoff {
798#define __ lasm->
799
801 void (Assembler::*opl)(Register, Register),
802 void (Assembler::*opq)(Register, Register),
803 Register dst_addr, Register offset_reg,
804 uintptr_t offset_imm, LiftoffRegister value,
806 bool i64_offset) {
807 if (offset_reg != no_reg && !i64_offset) __ AssertZeroExtended(offset_reg);
808 DCHECK(!__ cache_state()->is_used(result));
809 Register value_reg = value.gp();
810 // The cmpxchg instruction uses rax to store the old value of the
811 // compare-exchange primitive. Therefore we have to spill the register and
812 // move any use to another register.
813 LiftoffRegList pinned = LiftoffRegList{dst_addr, value_reg};
814 if (offset_reg != no_reg) pinned.set(offset_reg);
815 __ ClearRegister(rax, {&dst_addr, &offset_reg, &value_reg}, pinned);
816 Operand dst_op = liftoff::GetMemOp(lasm, dst_addr, offset_reg, offset_imm);
817
818 switch (type.value()) {
819 case StoreType::kI32Store8:
820 case StoreType::kI64Store8: {
821 Label binop;
822 __ xorq(rax, rax);
823 __ movb(rax, dst_op);
824 __ bind(&binop);
825 __ movl(kScratchRegister, rax);
826 (lasm->*opl)(kScratchRegister, value_reg);
827 __ lock();
828 __ cmpxchgb(dst_op, kScratchRegister);
829 __ j(not_equal, &binop);
830 break;
831 }
832 case StoreType::kI32Store16:
833 case StoreType::kI64Store16: {
834 Label binop;
835 __ xorq(rax, rax);
836 __ movw(rax, dst_op);
837 __ bind(&binop);
838 __ movl(kScratchRegister, rax);
839 (lasm->*opl)(kScratchRegister, value_reg);
840 __ lock();
841 __ cmpxchgw(dst_op, kScratchRegister);
842 __ j(not_equal, &binop);
843 break;
844 }
845 case StoreType::kI32Store:
846 case StoreType::kI64Store32: {
847 Label binop;
848 __ movl(rax, dst_op);
849 __ bind(&binop);
850 __ movl(kScratchRegister, rax);
851 (lasm->*opl)(kScratchRegister, value_reg);
852 __ lock();
853 __ cmpxchgl(dst_op, kScratchRegister);
854 __ j(not_equal, &binop);
855 break;
856 }
857 case StoreType::kI64Store: {
858 Label binop;
859 __ movq(rax, dst_op);
860 __ bind(&binop);
861 __ movq(kScratchRegister, rax);
862 (lasm->*opq)(kScratchRegister, value_reg);
863 __ lock();
864 __ cmpxchgq(dst_op, kScratchRegister);
865 __ j(not_equal, &binop);
866 break;
867 }
868 default:
869 UNREACHABLE();
870 }
871
872 if (result.gp() != rax) {
873 __ movq(result.gp(), rax);
874 }
875}
876#undef __
877} // namespace liftoff
878
879void LiftoffAssembler::AtomicAnd(Register dst_addr, Register offset_reg,
880 uintptr_t offset_imm, LiftoffRegister value,
881 LiftoffRegister result, StoreType type,
882 bool i64_offset) {
883 liftoff::AtomicBinop(this, &Assembler::andl, &Assembler::andq, dst_addr,
884 offset_reg, offset_imm, value, result, type, i64_offset);
885}
886
887void LiftoffAssembler::AtomicOr(Register dst_addr, Register offset_reg,
888 uintptr_t offset_imm, LiftoffRegister value,
889 LiftoffRegister result, StoreType type,
890 bool i64_offset) {
891 liftoff::AtomicBinop(this, &Assembler::orl, &Assembler::orq, dst_addr,
892 offset_reg, offset_imm, value, result, type, i64_offset);
893}
894
895void LiftoffAssembler::AtomicXor(Register dst_addr, Register offset_reg,
896 uintptr_t offset_imm, LiftoffRegister value,
897 LiftoffRegister result, StoreType type,
898 bool i64_offset) {
899 liftoff::AtomicBinop(this, &Assembler::xorl, &Assembler::xorq, dst_addr,
900 offset_reg, offset_imm, value, result, type, i64_offset);
901}
902
903void LiftoffAssembler::AtomicExchange(Register dst_addr, Register offset_reg,
904 uintptr_t offset_imm,
905 LiftoffRegister value,
906 LiftoffRegister result, StoreType type,
907 bool i64_offset) {
908 if (offset_reg != no_reg && !i64_offset) AssertZeroExtended(offset_reg);
909 DCHECK(!cache_state()->is_used(result));
910 if (cache_state()->is_used(value)) {
911 // We cannot overwrite {value}, but the {value} register is changed in the
912 // code we generate. Therefore we copy {value} to {result} and use the
913 // {result} register in the code below.
914 movq(result.gp(), value.gp());
915 value = result;
916 }
917 Operand dst_op = liftoff::GetMemOp(this, dst_addr, offset_reg, offset_imm);
918 switch (type.value()) {
919 case StoreType::kI32Store8:
920 case StoreType::kI64Store8:
921 xchgb(value.gp(), dst_op);
922 movzxbq(result.gp(), value.gp());
923 break;
924 case StoreType::kI32Store16:
925 case StoreType::kI64Store16:
926 xchgw(value.gp(), dst_op);
927 movzxwq(result.gp(), value.gp());
928 break;
929 case StoreType::kI32Store:
930 case StoreType::kI64Store32:
931 xchgl(value.gp(), dst_op);
932 if (value != result) {
933 movq(result.gp(), value.gp());
934 }
935 break;
936 case StoreType::kI64Store:
937 xchgq(value.gp(), dst_op);
938 if (value != result) {
939 movq(result.gp(), value.gp());
940 }
941 break;
942 default:
943 UNREACHABLE();
944 }
945}
946
948 Register dst_addr, Register offset_reg, uintptr_t offset_imm,
949 LiftoffRegister expected, LiftoffRegister new_value, LiftoffRegister result,
950 StoreType type, bool i64_offset) {
951 if (offset_reg != no_reg && !i64_offset) AssertZeroExtended(offset_reg);
952 Register value_reg = new_value.gp();
953 // The cmpxchg instruction uses rax to store the old value of the
954 // compare-exchange primitive. Therefore we have to spill the register and
955 // move any use to another register.
956 LiftoffRegList pinned = LiftoffRegList{dst_addr, expected, value_reg};
957 if (offset_reg != no_reg) pinned.set(offset_reg);
958 ClearRegister(rax, {&dst_addr, &offset_reg, &value_reg}, pinned);
959 if (expected.gp() != rax) {
960 movq(rax, expected.gp());
961 }
962
963 Operand dst_op = liftoff::GetMemOp(this, dst_addr, offset_reg, offset_imm);
964
965 lock();
966 switch (type.value()) {
967 case StoreType::kI32Store8:
968 case StoreType::kI64Store8: {
969 cmpxchgb(dst_op, value_reg);
970 movzxbq(result.gp(), rax);
971 break;
972 }
973 case StoreType::kI32Store16:
974 case StoreType::kI64Store16: {
975 cmpxchgw(dst_op, value_reg);
976 movzxwq(result.gp(), rax);
977 break;
978 }
979 case StoreType::kI32Store: {
980 cmpxchgl(dst_op, value_reg);
981 if (result.gp() != rax) {
982 movl(result.gp(), rax);
983 }
984 break;
985 }
986 case StoreType::kI64Store32: {
987 cmpxchgl(dst_op, value_reg);
988 // Zero extension.
989 movl(result.gp(), rax);
990 break;
991 }
992 case StoreType::kI64Store: {
993 cmpxchgq(dst_op, value_reg);
994 if (result.gp() != rax) {
995 movq(result.gp(), rax);
996 }
997 break;
998 }
999 default:
1000 UNREACHABLE();
1001 }
1002}
1003
1005
1006void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
1007 uint32_t caller_slot_idx,
1008 ValueKind kind) {
1009 Operand src(rbp, kSystemPointerSize * (caller_slot_idx + 1));
1010 liftoff::LoadFromStack(this, dst, src, kind);
1011}
1012
1013void LiftoffAssembler::StoreCallerFrameSlot(LiftoffRegister src,
1014 uint32_t caller_slot_idx,
1016 Register frame_pointer) {
1017 Operand dst(frame_pointer, kSystemPointerSize * (caller_slot_idx + 1));
1018 liftoff::StoreToMemory(this, dst, src, kind);
1019}
1020
1021void LiftoffAssembler::LoadReturnStackSlot(LiftoffRegister reg, int offset,
1022 ValueKind kind) {
1023 Operand src(rsp, offset);
1024 liftoff::LoadFromStack(this, reg, src, kind);
1025}
1026
1027void LiftoffAssembler::MoveStackValue(uint32_t dst_offset, uint32_t src_offset,
1028 ValueKind kind) {
1029 DCHECK_NE(dst_offset, src_offset);
1030 Operand dst = liftoff::GetStackSlot(dst_offset);
1031 Operand src = liftoff::GetStackSlot(src_offset);
1032 switch (SlotSizeForType(kind)) {
1033 case 4:
1034 movl(kScratchRegister, src);
1035 movl(dst, kScratchRegister);
1036 break;
1037 case 8:
1038 movq(kScratchRegister, src);
1039 movq(dst, kScratchRegister);
1040 break;
1041 case 16:
1042 Movdqu(kScratchDoubleReg, src);
1043 Movdqu(dst, kScratchDoubleReg);
1044 break;
1045 default:
1046 UNREACHABLE();
1047 }
1048}
1049
1050void LiftoffAssembler::Move(Register dst, Register src, ValueKind kind) {
1051 DCHECK_NE(dst, src);
1052 if (kind == kI32) {
1053 movl(dst, src);
1054 } else {
1056 movq(dst, src);
1057 }
1058}
1059
1061 ValueKind kind) {
1062 DCHECK_NE(dst, src);
1063 if (kind == kF32) {
1064 Movss(dst, src);
1065 } else if (kind == kF64) {
1066 Movsd(dst, src);
1067 } else {
1069 Movapd(dst, src);
1070 }
1071}
1072
1073void LiftoffAssembler::Spill(int offset, LiftoffRegister reg, ValueKind kind) {
1075 Operand dst = liftoff::GetStackSlot(offset);
1076 switch (kind) {
1077 case kI32:
1078 movl(dst, reg.gp());
1079 break;
1080 case kI64:
1081 case kRefNull:
1082 case kRef:
1083 movq(dst, reg.gp());
1084 break;
1085 case kF32:
1086 Movss(dst, reg.fp());
1087 break;
1088 case kF64:
1089 Movsd(dst, reg.fp());
1090 break;
1091 case kS128:
1092 Movdqu(dst, reg.fp());
1093 break;
1094 default:
1095 UNREACHABLE();
1096 }
1097}
1098
1099void LiftoffAssembler::Spill(int offset, WasmValue value) {
1101 Operand dst = liftoff::GetStackSlot(offset);
1102 switch (value.type().kind()) {
1103 case kI32:
1104 movl(dst, Immediate(value.to_i32()));
1105 break;
1106 case kI64: {
1107 if (is_int32(value.to_i64())) {
1108 // Sign extend low word.
1109 movq(dst, Immediate(static_cast<int32_t>(value.to_i64())));
1110 } else if (is_uint32(value.to_i64())) {
1111 // Zero extend low word.
1112 movl(kScratchRegister, Immediate(static_cast<int32_t>(value.to_i64())));
1113 movq(dst, kScratchRegister);
1114 } else {
1115 movq(kScratchRegister, value.to_i64());
1116 movq(dst, kScratchRegister);
1117 }
1118 break;
1119 }
1120 default:
1121 // We do not track f32 and f64 constants, hence they are unreachable.
1122 UNREACHABLE();
1123 }
1124}
1125
1126void LiftoffAssembler::Fill(LiftoffRegister reg, int offset, ValueKind kind) {
1128}
1129
1131 UNREACHABLE();
1132}
1133
1135 DCHECK_LT(0, size);
1137
1138 if (size <= 3 * kStackSlotSize) {
1139 // Special straight-line code for up to three slots
1140 // (7-10 bytes per slot: REX C7 <1-4 bytes op> <4 bytes imm>),
1141 // And a movd (6-9 byte) when size % 8 != 0;
1142 uint32_t remainder = size;
1144 movq(liftoff::GetStackSlot(start + remainder), Immediate(0));
1145 }
1146 DCHECK(remainder == 4 || remainder == 0);
1147 if (remainder) {
1148 movl(liftoff::GetStackSlot(start + remainder), Immediate(0));
1149 }
1150 } else {
1151 // General case for bigger counts.
1152 // This sequence takes 19-22 bytes (3 for pushes, 4-7 for lea, 2 for xor, 5
1153 // for mov, 2 for repstosl, 3 for pops).
1154 pushq(rax);
1155 pushq(rcx);
1156 pushq(rdi);
1157 leaq(rdi, liftoff::GetStackSlot(start + size));
1158 xorl(rax, rax);
1159 // Convert size (bytes) to doublewords (4-bytes).
1160 movl(rcx, Immediate(size / 4));
1161 repstosl();
1162 popq(rdi);
1163 popq(rcx);
1164 popq(rax);
1165 }
1166}
1167
1168void LiftoffAssembler::LoadSpillAddress(Register dst, int offset,
1169 ValueKind /* kind */) {
1170 leaq(dst, liftoff::GetStackSlot(offset));
1171}
1172
1176
1178 if (lhs != dst) {
1179 leal(dst, Operand(lhs, rhs, times_1, 0));
1180 } else {
1181 addl(dst, rhs);
1182 }
1183}
1184
1185void LiftoffAssembler::emit_i32_addi(Register dst, Register lhs, int32_t imm) {
1186 if (lhs != dst) {
1187 leal(dst, Operand(lhs, imm));
1188 } else {
1189 addl(dst, Immediate(imm));
1190 }
1191}
1192
1193void LiftoffAssembler::emit_i32_sub(Register dst, Register lhs, Register rhs) {
1194 if (dst != rhs) {
1195 // Default path.
1196 if (dst != lhs) movl(dst, lhs);
1197 subl(dst, rhs);
1198 } else if (lhs == rhs) {
1199 // Degenerate case.
1200 xorl(dst, dst);
1201 } else {
1202 // Emit {dst = lhs + -rhs} if dst == rhs.
1203 negl(dst);
1204 addl(dst, lhs);
1205 }
1206}
1207
1208void LiftoffAssembler::emit_i32_subi(Register dst, Register lhs, int32_t imm) {
1209 if (dst != lhs) {
1210 // We'll have to implement an UB-safe version if we need this corner case.
1211 DCHECK_NE(imm, kMinInt);
1212 leal(dst, Operand(lhs, -imm));
1213 } else {
1214 subl(dst, Immediate(imm));
1215 }
1216}
1217
1218namespace liftoff {
1219template <void (Assembler::*op)(Register, Register),
1220 void (Assembler::*mov)(Register, Register)>
1222 Register rhs) {
1223 if (dst == rhs) {
1224 (assm->*op)(dst, lhs);
1225 } else {
1226 if (dst != lhs) (assm->*mov)(dst, lhs);
1227 (assm->*op)(dst, rhs);
1228 }
1229}
1230
1231template <void (Assembler::*op)(Register, Immediate),
1232 void (Assembler::*mov)(Register, Register)>
1234 int32_t imm) {
1235 if (dst != lhs) (assm->*mov)(dst, lhs);
1236 (assm->*op)(dst, Immediate(imm));
1237}
1238
1239} // namespace liftoff
1240
1243 lhs, rhs);
1244}
1245
1246namespace liftoff {
1247enum class DivOrRem : uint8_t { kDiv, kRem };
1248template <typename type, DivOrRem div_or_rem>
1250 Register rhs, Label* trap_div_by_zero,
1251 Label* trap_div_unrepresentable) {
1252 constexpr bool needs_unrepresentable_check =
1253 std::is_signed<type>::value && div_or_rem == DivOrRem::kDiv;
1254 constexpr bool special_case_minus_1 =
1255 std::is_signed<type>::value && div_or_rem == DivOrRem::kRem;
1256 DCHECK_EQ(needs_unrepresentable_check, trap_div_unrepresentable != nullptr);
1257
1258#define iop(name, ...) \
1259 do { \
1260 if (sizeof(type) == 4) { \
1261 assm->name##l(__VA_ARGS__); \
1262 } else { \
1263 assm->name##q(__VA_ARGS__); \
1264 } \
1265 } while (false)
1266
1267 // For division, the lhs is always taken from {edx:eax}. Thus, make sure that
1268 // these registers are unused. If {rhs} is stored in one of them, move it to
1269 // another temporary register.
1270 // Do all this before any branch, such that the code is executed
1271 // unconditionally, as the cache state will also be modified unconditionally.
1272 assm->SpillRegisters(rdx, rax);
1273 if (rhs == rax || rhs == rdx) {
1274 iop(mov, kScratchRegister, rhs);
1275 rhs = kScratchRegister;
1276 }
1277
1278 // Check for division by zero.
1279 iop(test, rhs, rhs);
1280 assm->j(zero, trap_div_by_zero);
1281
1282 Label done;
1283 if (needs_unrepresentable_check) {
1284 // Check for {kMinInt / -1}. This is unrepresentable.
1285 Label do_div;
1286 iop(cmp, rhs, Immediate(-1));
1287 assm->j(not_equal, &do_div);
1288 // {lhs} is min int if {lhs - 1} overflows.
1289 iop(cmp, lhs, Immediate(1));
1290 assm->j(overflow, trap_div_unrepresentable);
1291 assm->bind(&do_div);
1292 } else if (special_case_minus_1) {
1293 // {lhs % -1} is always 0 (needs to be special cased because {kMinInt / -1}
1294 // cannot be computed).
1295 Label do_rem;
1296 iop(cmp, rhs, Immediate(-1));
1297 assm->j(not_equal, &do_rem);
1298 // clang-format off
1299 // (conflicts with presubmit checks because it is confused about "xor")
1300 iop(xor, dst, dst);
1301 // clang-format on
1302 assm->jmp(&done);
1303 assm->bind(&do_rem);
1304 }
1305
1306 // Now move {lhs} into {eax}, then zero-extend or sign-extend into {edx}, then
1307 // do the division.
1308 if (lhs != rax) iop(mov, rax, lhs);
1309 if (std::is_same<int32_t, type>::value) { // i32
1310 assm->cdq();
1311 assm->idivl(rhs);
1312 } else if (std::is_same<uint32_t, type>::value) { // u32
1313 assm->xorl(rdx, rdx);
1314 assm->divl(rhs);
1315 } else if (std::is_same<int64_t, type>::value) { // i64
1316 assm->cqo();
1317 assm->idivq(rhs);
1318 } else { // u64
1319 assm->xorq(rdx, rdx);
1320 assm->divq(rhs);
1321 }
1322
1323 // Move back the result (in {eax} or {edx}) into the {dst} register.
1324 constexpr Register kResultReg = div_or_rem == DivOrRem::kDiv ? rax : rdx;
1325 if (dst != kResultReg) {
1326 iop(mov, dst, kResultReg);
1327 }
1328 if (special_case_minus_1) assm->bind(&done);
1329}
1330} // namespace liftoff
1331
1333 Label* trap_div_by_zero,
1334 Label* trap_div_unrepresentable) {
1336 this, dst, lhs, rhs, trap_div_by_zero, trap_div_unrepresentable);
1337}
1338
1339void LiftoffAssembler::emit_i32_divu(Register dst, Register lhs, Register rhs,
1340 Label* trap_div_by_zero) {
1342 this, dst, lhs, rhs, trap_div_by_zero, nullptr);
1343}
1344
1345void LiftoffAssembler::emit_i32_rems(Register dst, Register lhs, Register rhs,
1346 Label* trap_div_by_zero) {
1348 this, dst, lhs, rhs, trap_div_by_zero, nullptr);
1349}
1350
1351void LiftoffAssembler::emit_i32_remu(Register dst, Register lhs, Register rhs,
1352 Label* trap_div_by_zero) {
1354 this, dst, lhs, rhs, trap_div_by_zero, nullptr);
1355}
1356
1357void LiftoffAssembler::emit_i32_and(Register dst, Register lhs, Register rhs) {
1359 lhs, rhs);
1360}
1361
1362void LiftoffAssembler::emit_i32_andi(Register dst, Register lhs, int32_t imm) {
1364 this, dst, lhs, imm);
1365}
1366
1367void LiftoffAssembler::emit_i32_or(Register dst, Register lhs, Register rhs) {
1369 lhs, rhs);
1370}
1371
1372void LiftoffAssembler::emit_i32_ori(Register dst, Register lhs, int32_t imm) {
1374 lhs, imm);
1375}
1376
1377void LiftoffAssembler::emit_i32_xor(Register dst, Register lhs, Register rhs) {
1379 lhs, rhs);
1380}
1381
1382void LiftoffAssembler::emit_i32_xori(Register dst, Register lhs, int32_t imm) {
1384 this, dst, lhs, imm);
1385}
1386
1387namespace liftoff {
1388template <ValueKind kind>
1390 Register src, Register amount,
1391 void (Assembler::*emit_shift)(Register)) {
1392 // If dst is rcx, compute into the scratch register first, then move to rcx.
1393 if (dst == rcx) {
1394 assm->Move(kScratchRegister, src, kind);
1395 if (amount != rcx) assm->Move(rcx, amount, kind);
1396 (assm->*emit_shift)(kScratchRegister);
1397 assm->Move(rcx, kScratchRegister, kind);
1398 return;
1399 }
1400
1401 // Move amount into rcx. If rcx is in use, move its content into the scratch
1402 // register. If src is rcx, src is now the scratch register.
1403 bool use_scratch = false;
1404 if (amount != rcx) {
1405 use_scratch =
1406 src == rcx || assm->cache_state()->is_used(LiftoffRegister(rcx));
1407 if (use_scratch) assm->movq(kScratchRegister, rcx);
1408 if (src == rcx) src = kScratchRegister;
1409 assm->Move(rcx, amount, kind);
1410 }
1411
1412 // Do the actual shift.
1413 if (dst != src) assm->Move(dst, src, kind);
1414 (assm->*emit_shift)(dst);
1415
1416 // Restore rcx if needed.
1417 if (use_scratch) assm->movq(rcx, kScratchRegister);
1418}
1419} // namespace liftoff
1420
1422 Register amount) {
1423 liftoff::EmitShiftOperation<kI32>(this, dst, src, amount,
1424 &Assembler::shll_cl);
1425}
1426
1427void LiftoffAssembler::emit_i32_shli(Register dst, Register src,
1428 int32_t amount) {
1429 if (dst != src) movl(dst, src);
1430 shll(dst, Immediate(amount & 31));
1431}
1432
1433void LiftoffAssembler::emit_i32_sar(Register dst, Register src,
1434 Register amount) {
1435 liftoff::EmitShiftOperation<kI32>(this, dst, src, amount,
1436 &Assembler::sarl_cl);
1437}
1438
1439void LiftoffAssembler::emit_i32_sari(Register dst, Register src,
1440 int32_t amount) {
1441 if (dst != src) movl(dst, src);
1442 sarl(dst, Immediate(amount & 31));
1443}
1444
1445void LiftoffAssembler::emit_i32_shr(Register dst, Register src,
1446 Register amount) {
1447 liftoff::EmitShiftOperation<kI32>(this, dst, src, amount,
1448 &Assembler::shrl_cl);
1449}
1450
1451void LiftoffAssembler::emit_i32_shri(Register dst, Register src,
1452 int32_t amount) {
1453 if (dst != src) movl(dst, src);
1454 shrl(dst, Immediate(amount & 31));
1455}
1456
1457void LiftoffAssembler::emit_i32_clz(Register dst, Register src) {
1458 Lzcntl(dst, src);
1459}
1460
1461void LiftoffAssembler::emit_i32_ctz(Register dst, Register src) {
1462 Tzcntl(dst, src);
1463}
1464
1465bool LiftoffAssembler::emit_i32_popcnt(Register dst, Register src) {
1466 if (!CpuFeatures::IsSupported(POPCNT)) return false;
1467 CpuFeatureScope scope(this, POPCNT);
1468 popcntl(dst, src);
1469 return true;
1470}
1471
1472void LiftoffAssembler::emit_i64_add(LiftoffRegister dst, LiftoffRegister lhs,
1473 LiftoffRegister rhs) {
1474 if (lhs.gp() != dst.gp()) {
1475 leaq(dst.gp(), Operand(lhs.gp(), rhs.gp(), times_1, 0));
1476 } else {
1477 addq(dst.gp(), rhs.gp());
1478 }
1479}
1480
1481void LiftoffAssembler::emit_i64_addi(LiftoffRegister dst, LiftoffRegister lhs,
1482 int64_t imm) {
1483 if (!is_int32(imm)) {
1485 if (lhs.gp() == dst.gp()) {
1486 addq(dst.gp(), kScratchRegister);
1487 } else {
1488 leaq(dst.gp(), Operand(lhs.gp(), kScratchRegister, times_1, 0));
1489 }
1490 } else if (lhs.gp() == dst.gp()) {
1491 addq(dst.gp(), Immediate(static_cast<int32_t>(imm)));
1492 } else {
1493 leaq(dst.gp(), Operand(lhs.gp(), static_cast<int32_t>(imm)));
1494 }
1495}
1496
1497void LiftoffAssembler::emit_i64_sub(LiftoffRegister dst, LiftoffRegister lhs,
1498 LiftoffRegister rhs) {
1499 if (lhs.gp() == rhs.gp()) {
1500 xorq(dst.gp(), dst.gp());
1501 } else if (dst.gp() == rhs.gp()) {
1502 negq(dst.gp());
1503 addq(dst.gp(), lhs.gp());
1504 } else {
1505 if (dst.gp() != lhs.gp()) movq(dst.gp(), lhs.gp());
1506 subq(dst.gp(), rhs.gp());
1507 }
1508}
1509
1510void LiftoffAssembler::emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs,
1511 LiftoffRegister rhs) {
1513 this, dst.gp(), lhs.gp(), rhs.gp());
1514}
1515
1516void LiftoffAssembler::emit_i64_muli(LiftoffRegister dst, LiftoffRegister lhs,
1517 int32_t imm) {
1518 if (base::bits::IsPowerOfTwo(imm)) {
1520 } else {
1521 imulq(dst.gp(), lhs.gp(), Immediate{imm});
1522 }
1523}
1524
1525bool LiftoffAssembler::emit_i64_divs(LiftoffRegister dst, LiftoffRegister lhs,
1526 LiftoffRegister rhs,
1527 Label* trap_div_by_zero,
1528 Label* trap_div_unrepresentable) {
1530 this, dst.gp(), lhs.gp(), rhs.gp(), trap_div_by_zero,
1531 trap_div_unrepresentable);
1532 return true;
1533}
1534
1535bool LiftoffAssembler::emit_i64_divu(LiftoffRegister dst, LiftoffRegister lhs,
1536 LiftoffRegister rhs,
1537 Label* trap_div_by_zero) {
1539 this, dst.gp(), lhs.gp(), rhs.gp(), trap_div_by_zero, nullptr);
1540 return true;
1541}
1542
1543bool LiftoffAssembler::emit_i64_rems(LiftoffRegister dst, LiftoffRegister lhs,
1544 LiftoffRegister rhs,
1545 Label* trap_div_by_zero) {
1547 this, dst.gp(), lhs.gp(), rhs.gp(), trap_div_by_zero, nullptr);
1548 return true;
1549}
1550
1551bool LiftoffAssembler::emit_i64_remu(LiftoffRegister dst, LiftoffRegister lhs,
1552 LiftoffRegister rhs,
1553 Label* trap_div_by_zero) {
1555 this, dst.gp(), lhs.gp(), rhs.gp(), trap_div_by_zero, nullptr);
1556 return true;
1557}
1558
1559void LiftoffAssembler::emit_i64_and(LiftoffRegister dst, LiftoffRegister lhs,
1560 LiftoffRegister rhs) {
1562 this, dst.gp(), lhs.gp(), rhs.gp());
1563}
1564
1565void LiftoffAssembler::emit_i64_andi(LiftoffRegister dst, LiftoffRegister lhs,
1566 int32_t imm) {
1568 this, dst.gp(), lhs.gp(), imm);
1569}
1570
1571void LiftoffAssembler::emit_i64_or(LiftoffRegister dst, LiftoffRegister lhs,
1572 LiftoffRegister rhs) {
1574 this, dst.gp(), lhs.gp(), rhs.gp());
1575}
1576
1577void LiftoffAssembler::emit_i64_ori(LiftoffRegister dst, LiftoffRegister lhs,
1578 int32_t imm) {
1580 this, dst.gp(), lhs.gp(), imm);
1581}
1582
1583void LiftoffAssembler::emit_i64_xor(LiftoffRegister dst, LiftoffRegister lhs,
1584 LiftoffRegister rhs) {
1586 this, dst.gp(), lhs.gp(), rhs.gp());
1587}
1588
1589void LiftoffAssembler::emit_i64_xori(LiftoffRegister dst, LiftoffRegister lhs,
1590 int32_t imm) {
1592 this, dst.gp(), lhs.gp(), imm);
1593}
1594
1595void LiftoffAssembler::emit_i64_shl(LiftoffRegister dst, LiftoffRegister src,
1596 Register amount) {
1597 liftoff::EmitShiftOperation<kI64>(this, dst.gp(), src.gp(), amount,
1598 &Assembler::shlq_cl);
1599}
1600
1601void LiftoffAssembler::emit_i64_shli(LiftoffRegister dst, LiftoffRegister src,
1602 int32_t amount) {
1603 if (dst.gp() != src.gp()) movq(dst.gp(), src.gp());
1604 shlq(dst.gp(), Immediate(amount & 63));
1605}
1606
1607void LiftoffAssembler::emit_i64_sar(LiftoffRegister dst, LiftoffRegister src,
1608 Register amount) {
1609 liftoff::EmitShiftOperation<kI64>(this, dst.gp(), src.gp(), amount,
1610 &Assembler::sarq_cl);
1611}
1612
1613void LiftoffAssembler::emit_i64_sari(LiftoffRegister dst, LiftoffRegister src,
1614 int32_t amount) {
1615 if (dst.gp() != src.gp()) movq(dst.gp(), src.gp());
1616 sarq(dst.gp(), Immediate(amount & 63));
1617}
1618
1619void LiftoffAssembler::emit_i64_shr(LiftoffRegister dst, LiftoffRegister src,
1620 Register amount) {
1621 liftoff::EmitShiftOperation<kI64>(this, dst.gp(), src.gp(), amount,
1622 &Assembler::shrq_cl);
1623}
1624
1625void LiftoffAssembler::emit_i64_shri(LiftoffRegister dst, LiftoffRegister src,
1626 int32_t amount) {
1627 if (dst != src) movq(dst.gp(), src.gp());
1628 shrq(dst.gp(), Immediate(amount & 63));
1629}
1630
1631void LiftoffAssembler::emit_i64_clz(LiftoffRegister dst, LiftoffRegister src) {
1632 Lzcntq(dst.gp(), src.gp());
1633}
1634
1635void LiftoffAssembler::emit_i64_ctz(LiftoffRegister dst, LiftoffRegister src) {
1636 Tzcntq(dst.gp(), src.gp());
1637}
1638
1639bool LiftoffAssembler::emit_i64_popcnt(LiftoffRegister dst,
1640 LiftoffRegister src) {
1641 if (!CpuFeatures::IsSupported(POPCNT)) return false;
1642 CpuFeatureScope scope(this, POPCNT);
1643 popcntq(dst.gp(), src.gp());
1644 return true;
1645}
1646
1647void LiftoffAssembler::IncrementSmi(LiftoffRegister dst, int offset) {
1648 SmiAddConstant(Operand(dst.gp(), offset), Smi::FromInt(1));
1649}
1650
1651void LiftoffAssembler::emit_u32_to_uintptr(Register dst, Register src) {
1652 AssertZeroExtended(src);
1653 if (dst != src) movl(dst, src);
1654}
1655
1656void LiftoffAssembler::clear_i32_upper_half(Register dst) { movl(dst, dst); }
1657
1659 DoubleRegister rhs) {
1660 if (CpuFeatures::IsSupported(AVX)) {
1661 CpuFeatureScope scope(this, AVX);
1662 vaddss(dst, lhs, rhs);
1663 } else if (dst == rhs) {
1664 addss(dst, lhs);
1665 } else {
1666 if (dst != lhs) movss(dst, lhs);
1667 addss(dst, rhs);
1668 }
1669}
1670
1672 DoubleRegister rhs) {
1673 if (CpuFeatures::IsSupported(AVX)) {
1674 CpuFeatureScope scope(this, AVX);
1675 vsubss(dst, lhs, rhs);
1676 } else if (dst == rhs) {
1678 movss(dst, lhs);
1680 } else {
1681 if (dst != lhs) movss(dst, lhs);
1682 subss(dst, rhs);
1683 }
1684}
1685
1687 DoubleRegister rhs) {
1688 if (CpuFeatures::IsSupported(AVX)) {
1689 CpuFeatureScope scope(this, AVX);
1690 vmulss(dst, lhs, rhs);
1691 } else if (dst == rhs) {
1692 mulss(dst, lhs);
1693 } else {
1694 if (dst != lhs) movss(dst, lhs);
1695 mulss(dst, rhs);
1696 }
1697}
1698
1700 DoubleRegister rhs) {
1701 if (CpuFeatures::IsSupported(AVX)) {
1702 CpuFeatureScope scope(this, AVX);
1703 vdivss(dst, lhs, rhs);
1704 } else if (dst == rhs) {
1706 movss(dst, lhs);
1708 } else {
1709 if (dst != lhs) movss(dst, lhs);
1710 divss(dst, rhs);
1711 }
1712}
1713
1714namespace liftoff {
1715enum class MinOrMax : uint8_t { kMin, kMax };
1716template <typename type>
1717inline void EmitFloatMinOrMax(LiftoffAssembler* assm, DoubleRegister dst,
1719 MinOrMax min_or_max) {
1720 Label is_nan;
1721 Label lhs_below_rhs;
1722 Label lhs_above_rhs;
1723 Label done;
1724
1725#define dop(name, ...) \
1726 do { \
1727 if (sizeof(type) == 4) { \
1728 assm->name##s(__VA_ARGS__); \
1729 } else { \
1730 assm->name##d(__VA_ARGS__); \
1731 } \
1732 } while (false)
1733
1734 // Check the easy cases first: nan (e.g. unordered), smaller and greater.
1735 // NaN has to be checked first, because PF=1 implies CF=1.
1736 dop(Ucomis, lhs, rhs);
1737 assm->j(parity_even, &is_nan, Label::kNear); // PF=1
1738 assm->j(below, &lhs_below_rhs, Label::kNear); // CF=1
1739 assm->j(above, &lhs_above_rhs, Label::kNear); // CF=0 && ZF=0
1740
1741 // If we get here, then either
1742 // a) {lhs == rhs},
1743 // b) {lhs == -0.0} and {rhs == 0.0}, or
1744 // c) {lhs == 0.0} and {rhs == -0.0}.
1745 // For a), it does not matter whether we return {lhs} or {rhs}. Check the sign
1746 // bit of {rhs} to differentiate b) and c).
1747 dop(Movmskp, kScratchRegister, rhs);
1748 assm->testl(kScratchRegister, Immediate(1));
1749 assm->j(zero, &lhs_below_rhs, Label::kNear);
1750 assm->jmp(&lhs_above_rhs, Label::kNear);
1751
1752 assm->bind(&is_nan);
1753 // Create a NaN output.
1754 dop(Xorp, dst, dst);
1755 dop(Divs, dst, dst);
1756 assm->jmp(&done, Label::kNear);
1757
1758 assm->bind(&lhs_below_rhs);
1759 DoubleRegister lhs_below_rhs_src = min_or_max == MinOrMax::kMin ? lhs : rhs;
1760 if (dst != lhs_below_rhs_src) dop(Movs, dst, lhs_below_rhs_src);
1761 assm->jmp(&done, Label::kNear);
1762
1763 assm->bind(&lhs_above_rhs);
1764 DoubleRegister lhs_above_rhs_src = min_or_max == MinOrMax::kMin ? rhs : lhs;
1765 if (dst != lhs_above_rhs_src) dop(Movs, dst, lhs_above_rhs_src);
1766
1767 assm->bind(&done);
1768}
1769} // namespace liftoff
1770
1772 DoubleRegister rhs) {
1773 liftoff::EmitFloatMinOrMax<float>(this, dst, lhs, rhs,
1775}
1776
1778 DoubleRegister rhs) {
1779 liftoff::EmitFloatMinOrMax<float>(this, dst, lhs, rhs,
1781}
1782
1784 DoubleRegister rhs) {
1785 static constexpr int kF32SignBit = 1 << 31;
1786 Movd(kScratchRegister, lhs);
1787 andl(kScratchRegister, Immediate(~kF32SignBit));
1788 Movd(liftoff::kScratchRegister2, rhs);
1789 andl(liftoff::kScratchRegister2, Immediate(kF32SignBit));
1791 Movd(dst, kScratchRegister);
1792}
1793
1795 static constexpr uint32_t kSignBit = uint32_t{1} << 31;
1796 if (dst == src) {
1798 Andps(dst, kScratchDoubleReg);
1799 } else {
1801 Andps(dst, src);
1802 }
1803}
1804
1806 static constexpr uint32_t kSignBit = uint32_t{1} << 31;
1807 if (dst == src) {
1809 Xorps(dst, kScratchDoubleReg);
1810 } else {
1812 Xorps(dst, src);
1813 }
1814}
1815
1818 Roundss(dst, src, kRoundUp);
1819 return true;
1820}
1821
1824 Roundss(dst, src, kRoundDown);
1825 return true;
1826}
1827
1830 Roundss(dst, src, kRoundToZero);
1831 return true;
1832}
1833
1835 DoubleRegister src) {
1837 Roundss(dst, src, kRoundToNearest);
1838 return true;
1839}
1840
1842 Sqrtss(dst, src);
1843}
1844
1846 DoubleRegister rhs) {
1847 if (CpuFeatures::IsSupported(AVX)) {
1848 CpuFeatureScope scope(this, AVX);
1849 vaddsd(dst, lhs, rhs);
1850 } else if (dst == rhs) {
1851 addsd(dst, lhs);
1852 } else {
1853 if (dst != lhs) movsd(dst, lhs);
1854 addsd(dst, rhs);
1855 }
1856}
1857
1859 DoubleRegister rhs) {
1860 if (CpuFeatures::IsSupported(AVX)) {
1861 CpuFeatureScope scope(this, AVX);
1862 vsubsd(dst, lhs, rhs);
1863 } else if (dst == rhs) {
1865 movsd(dst, lhs);
1866 subsd(dst, kScratchDoubleReg);
1867 } else {
1868 if (dst != lhs) movsd(dst, lhs);
1869 subsd(dst, rhs);
1870 }
1871}
1872
1874 DoubleRegister rhs) {
1875 if (CpuFeatures::IsSupported(AVX)) {
1876 CpuFeatureScope scope(this, AVX);
1877 vmulsd(dst, lhs, rhs);
1878 } else if (dst == rhs) {
1879 mulsd(dst, lhs);
1880 } else {
1881 if (dst != lhs) movsd(dst, lhs);
1882 mulsd(dst, rhs);
1883 }
1884}
1885
1887 DoubleRegister rhs) {
1888 if (CpuFeatures::IsSupported(AVX)) {
1889 CpuFeatureScope scope(this, AVX);
1890 vdivsd(dst, lhs, rhs);
1891 } else if (dst == rhs) {
1893 movsd(dst, lhs);
1894 divsd(dst, kScratchDoubleReg);
1895 } else {
1896 if (dst != lhs) movsd(dst, lhs);
1897 divsd(dst, rhs);
1898 }
1899}
1900
1902 DoubleRegister rhs) {
1903 liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs,
1905}
1906
1908 DoubleRegister rhs) {
1909 // Extract sign bit from {rhs} into {kScratchRegister2}.
1911 shrq(liftoff::kScratchRegister2, Immediate(63));
1912 shlq(liftoff::kScratchRegister2, Immediate(63));
1913 // Reset sign bit of {lhs} (in {kScratchRegister}).
1914 Movq(kScratchRegister, lhs);
1915 btrq(kScratchRegister, Immediate(63));
1916 // Combine both values into {kScratchRegister} and move into {dst}.
1918 Movq(dst, kScratchRegister);
1919}
1920
1922 DoubleRegister rhs) {
1923 liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs,
1925}
1926
1928 static constexpr uint64_t kSignBit = uint64_t{1} << 63;
1929 if (dst == src) {
1931 Andpd(dst, kScratchDoubleReg);
1932 } else {
1934 Andpd(dst, src);
1935 }
1936}
1937
1939 static constexpr uint64_t kSignBit = uint64_t{1} << 63;
1940 if (dst == src) {
1942 Xorpd(dst, kScratchDoubleReg);
1943 } else {
1945 Xorpd(dst, src);
1946 }
1947}
1948
1951 Roundsd(dst, src, kRoundUp);
1952 return true;
1953}
1954
1957 Roundsd(dst, src, kRoundDown);
1958 return true;
1959}
1960
1963 Roundsd(dst, src, kRoundToZero);
1964 return true;
1965}
1966
1968 DoubleRegister src) {
1970 Roundsd(dst, src, kRoundToNearest);
1971 return true;
1972}
1973
1975 Sqrtsd(dst, src);
1976}
1977
1978namespace liftoff {
1979#define __ assm->
1980// Used for float to int conversions. If the value in {converted_back} equals
1981// {src} afterwards, the conversion succeeded.
1982template <typename dst_type, typename src_type>
1984 DoubleRegister src,
1985 DoubleRegister converted_back) {
1986 if (std::is_same<double, src_type>::value) { // f64
1987 if (std::is_same<int32_t, dst_type>::value) { // f64 -> i32
1988 __ Cvttsd2si(dst, src);
1989 __ Cvtlsi2sd(converted_back, dst);
1990 } else if (std::is_same<uint32_t, dst_type>::value) { // f64 -> u32
1991 __ Cvttsd2siq(dst, src);
1992 __ movl(dst, dst);
1993 __ Cvtqsi2sd(converted_back, dst);
1994 } else if (std::is_same<int64_t, dst_type>::value) { // f64 -> i64
1995 __ Cvttsd2siq(dst, src);
1996 __ Cvtqsi2sd(converted_back, dst);
1997 } else {
1998 UNREACHABLE();
1999 }
2000 } else { // f32
2001 if (std::is_same<int32_t, dst_type>::value) { // f32 -> i32
2002 __ Cvttss2si(dst, src);
2003 __ Cvtlsi2ss(converted_back, dst);
2004 } else if (std::is_same<uint32_t, dst_type>::value) { // f32 -> u32
2005 __ Cvttss2siq(dst, src);
2006 __ movl(dst, dst);
2007 __ Cvtqsi2ss(converted_back, dst);
2008 } else if (std::is_same<int64_t, dst_type>::value) { // f32 -> i64
2009 __ Cvttss2siq(dst, src);
2010 __ Cvtqsi2ss(converted_back, dst);
2011 } else {
2012 UNREACHABLE();
2013 }
2014 }
2015}
2016
2017template <typename dst_type, typename src_type>
2018inline void EmitTruncateFloatToInt(LiftoffAssembler* assm, Register dst,
2019 DoubleRegister src, Label* trap) {
2020 if (!CpuFeatures::IsSupported(SSE4_1)) {
2021 __ bailout(kMissingCPUFeature, "no SSE4.1");
2022 return;
2023 }
2024 CpuFeatureScope feature(assm, SSE4_1);
2025
2027 DoubleRegister converted_back = kScratchDoubleReg2;
2028
2029 if (std::is_same<double, src_type>::value) { // f64
2030 __ Roundsd(rounded, src, kRoundToZero);
2031 } else { // f32
2032 __ Roundss(rounded, src, kRoundToZero);
2033 }
2034 ConvertFloatToIntAndBack<dst_type, src_type>(assm, dst, rounded,
2035 converted_back);
2036 if (std::is_same<double, src_type>::value) { // f64
2037 __ Ucomisd(converted_back, rounded);
2038 } else { // f32
2039 __ Ucomiss(converted_back, rounded);
2040 }
2041
2042 // Jump to trap if PF is 0 (one of the operands was NaN) or they are not
2043 // equal.
2044 __ j(parity_even, trap);
2045 __ j(not_equal, trap);
2046}
2047
2048template <typename dst_type, typename src_type>
2049inline void EmitSatTruncateFloatToInt(LiftoffAssembler* assm, Register dst,
2050 DoubleRegister src) {
2051 if (!CpuFeatures::IsSupported(SSE4_1)) {
2052 __ bailout(kMissingCPUFeature, "no SSE4.1");
2053 return;
2054 }
2055 CpuFeatureScope feature(assm, SSE4_1);
2056
2057 Label done;
2058 Label not_nan;
2059 Label src_positive;
2060
2062 DoubleRegister converted_back = kScratchDoubleReg2;
2064
2065 if (std::is_same<double, src_type>::value) { // f64
2066 __ Roundsd(rounded, src, kRoundToZero);
2067 } else { // f32
2068 __ Roundss(rounded, src, kRoundToZero);
2069 }
2070
2071 ConvertFloatToIntAndBack<dst_type, src_type>(assm, dst, rounded,
2072 converted_back);
2073 if (std::is_same<double, src_type>::value) { // f64
2074 __ Ucomisd(converted_back, rounded);
2075 } else { // f32
2076 __ Ucomiss(converted_back, rounded);
2077 }
2078
2079 // Return 0 if PF is 0 (one of the operands was NaN)
2080 __ j(parity_odd, &not_nan);
2081 __ xorl(dst, dst);
2082 __ jmp(&done);
2083
2084 __ bind(&not_nan);
2085 // If rounding is as expected, return result
2086 __ j(equal, &done);
2087
2088 __ xorpd(zero_reg, zero_reg);
2089
2090 // if out-of-bounds, check if src is positive
2091 if (std::is_same<double, src_type>::value) { // f64
2092 __ Ucomisd(src, zero_reg);
2093 } else { // f32
2094 __ Ucomiss(src, zero_reg);
2095 }
2096 __ j(above, &src_positive);
2097 if (std::is_same<int32_t, dst_type>::value ||
2098 std::is_same<uint32_t, dst_type>::value) { // i32
2099 __ movl(
2100 dst,
2101 Immediate(static_cast<int32_t>(std::numeric_limits<dst_type>::min())));
2102 } else if (std::is_same<int64_t, dst_type>::value) { // i64s
2103 __ movq(dst, Immediate64(std::numeric_limits<dst_type>::min()));
2104 } else {
2105 UNREACHABLE();
2106 }
2107 __ jmp(&done);
2108
2109 __ bind(&src_positive);
2110 if (std::is_same<int32_t, dst_type>::value ||
2111 std::is_same<uint32_t, dst_type>::value) { // i32
2112 __ movl(
2113 dst,
2114 Immediate(static_cast<int32_t>(std::numeric_limits<dst_type>::max())));
2115 } else if (std::is_same<int64_t, dst_type>::value) { // i64s
2116 __ movq(dst, Immediate64(std::numeric_limits<dst_type>::max()));
2117 } else {
2118 UNREACHABLE();
2119 }
2120
2121 __ bind(&done);
2122}
2123
2124template <typename src_type>
2126 DoubleRegister src) {
2127 if (!CpuFeatures::IsSupported(SSE4_1)) {
2128 __ bailout(kMissingCPUFeature, "no SSE4.1");
2129 return;
2130 }
2131 CpuFeatureScope feature(assm, SSE4_1);
2132
2133 Label done;
2134 Label neg_or_nan;
2136
2138
2139 __ xorpd(zero_reg, zero_reg);
2140 if (std::is_same<double, src_type>::value) { // f64
2141 __ Ucomisd(src, zero_reg);
2142 } else { // f32
2143 __ Ucomiss(src, zero_reg);
2144 }
2145 // Check if NaN
2146 __ j(parity_even, &neg_or_nan);
2147 __ j(below, &neg_or_nan);
2148 if (std::is_same<double, src_type>::value) { // f64
2149 __ Cvttsd2uiq(dst, src, &overflow);
2150 } else { // f32
2151 __ Cvttss2uiq(dst, src, &overflow);
2152 }
2153 __ jmp(&done);
2154
2155 __ bind(&neg_or_nan);
2156 __ movq(dst, zero_reg);
2157 __ jmp(&done);
2158
2159 __ bind(&overflow);
2160 __ movq(dst, Immediate64(std::numeric_limits<uint64_t>::max()));
2161 __ bind(&done);
2162}
2163#undef __
2164} // namespace liftoff
2165
2167 LiftoffRegister dst,
2168 LiftoffRegister src, Label* trap) {
2169 switch (opcode) {
2170 case kExprI32ConvertI64:
2171 movl(dst.gp(), src.gp());
2172 break;
2173 case kExprI32SConvertF32:
2174 liftoff::EmitTruncateFloatToInt<int32_t, float>(this, dst.gp(), src.fp(),
2175 trap);
2176 break;
2177 case kExprI32UConvertF32:
2178 liftoff::EmitTruncateFloatToInt<uint32_t, float>(this, dst.gp(), src.fp(),
2179 trap);
2180 break;
2181 case kExprI32SConvertF64:
2182 liftoff::EmitTruncateFloatToInt<int32_t, double>(this, dst.gp(), src.fp(),
2183 trap);
2184 break;
2185 case kExprI32UConvertF64:
2187 src.fp(), trap);
2188 break;
2189 case kExprI32SConvertSatF32:
2191 src.fp());
2192 break;
2193 case kExprI32UConvertSatF32:
2195 src.fp());
2196 break;
2197 case kExprI32SConvertSatF64:
2199 src.fp());
2200 break;
2201 case kExprI32UConvertSatF64:
2203 src.fp());
2204 break;
2205 case kExprI32ReinterpretF32:
2206 Movd(dst.gp(), src.fp());
2207 break;
2208 case kExprI64SConvertI32:
2209 movsxlq(dst.gp(), src.gp());
2210 break;
2211 case kExprI64SConvertF32:
2212 liftoff::EmitTruncateFloatToInt<int64_t, float>(this, dst.gp(), src.fp(),
2213 trap);
2214 break;
2215 case kExprI64UConvertF32: {
2217 Cvttss2uiq(dst.gp(), src.fp(), trap);
2218 break;
2219 }
2220 case kExprI64SConvertF64:
2221 liftoff::EmitTruncateFloatToInt<int64_t, double>(this, dst.gp(), src.fp(),
2222 trap);
2223 break;
2224 case kExprI64UConvertF64: {
2226 Cvttsd2uiq(dst.gp(), src.fp(), trap);
2227 break;
2228 }
2229 case kExprI64SConvertSatF32:
2231 src.fp());
2232 break;
2233 case kExprI64UConvertSatF32: {
2234 liftoff::EmitSatTruncateFloatToUInt64<float>(this, dst.gp(), src.fp());
2235 break;
2236 }
2237 case kExprI64SConvertSatF64:
2239 src.fp());
2240 break;
2241 case kExprI64UConvertSatF64: {
2242 liftoff::EmitSatTruncateFloatToUInt64<double>(this, dst.gp(), src.fp());
2243 break;
2244 }
2245 case kExprI64UConvertI32:
2246 emit_u32_to_uintptr(dst.gp(), src.gp());
2247 break;
2248 case kExprI64ReinterpretF64:
2249 Movq(dst.gp(), src.fp());
2250 break;
2251 case kExprF32SConvertI32:
2252 Cvtlsi2ss(dst.fp(), src.gp());
2253 break;
2254 case kExprF32UConvertI32:
2255 movl(kScratchRegister, src.gp());
2256 Cvtqsi2ss(dst.fp(), kScratchRegister);
2257 break;
2258 case kExprF32SConvertI64:
2259 Cvtqsi2ss(dst.fp(), src.gp());
2260 break;
2261 case kExprF32UConvertI64:
2262 Cvtqui2ss(dst.fp(), src.gp());
2263 break;
2264 case kExprF32ConvertF64:
2265 Cvtsd2ss(dst.fp(), src.fp());
2266 break;
2267 case kExprF32ReinterpretI32:
2268 Movd(dst.fp(), src.gp());
2269 break;
2270 case kExprF64SConvertI32:
2271 Cvtlsi2sd(dst.fp(), src.gp());
2272 break;
2273 case kExprF64UConvertI32:
2274 movl(kScratchRegister, src.gp());
2275 Cvtqsi2sd(dst.fp(), kScratchRegister);
2276 break;
2277 case kExprF64SConvertI64:
2278 Cvtqsi2sd(dst.fp(), src.gp());
2279 break;
2280 case kExprF64UConvertI64:
2281 Cvtqui2sd(dst.fp(), src.gp());
2282 break;
2283 case kExprF64ConvertF32:
2284 Cvtss2sd(dst.fp(), src.fp());
2285 break;
2286 case kExprF64ReinterpretI64:
2287 Movq(dst.fp(), src.gp());
2288 break;
2289 default:
2290 UNREACHABLE();
2291 }
2292 return true;
2293}
2294
2295void LiftoffAssembler::emit_i32_signextend_i8(Register dst, Register src) {
2296 movsxbl(dst, src);
2297}
2298
2299void LiftoffAssembler::emit_i32_signextend_i16(Register dst, Register src) {
2300 movsxwl(dst, src);
2301}
2302
2303void LiftoffAssembler::emit_i64_signextend_i8(LiftoffRegister dst,
2304 LiftoffRegister src) {
2305 movsxbq(dst.gp(), src.gp());
2306}
2307
2308void LiftoffAssembler::emit_i64_signextend_i16(LiftoffRegister dst,
2309 LiftoffRegister src) {
2310 movsxwq(dst.gp(), src.gp());
2311}
2312
2313void LiftoffAssembler::emit_i64_signextend_i32(LiftoffRegister dst,
2314 LiftoffRegister src) {
2315 movsxlq(dst.gp(), src.gp());
2316}
2317
2318void LiftoffAssembler::emit_jump(Label* label) { jmp(label); }
2319
2320void LiftoffAssembler::emit_jump(Register target) { jmp(target); }
2321
2323 ValueKind kind, Register lhs,
2324 Register rhs,
2325 const FreezeCacheState& frozen) {
2326 if (rhs != no_reg) {
2327 switch (kind) {
2328 case kI32:
2329 cmpl(lhs, rhs);
2330 break;
2331 case kRef:
2332 case kRefNull:
2333 DCHECK(cond == kEqual || cond == kNotEqual);
2334#if defined(V8_COMPRESS_POINTERS)
2335 // It's enough to do a 32-bit comparison. This is also necessary for
2336 // null checks which only compare against a 32 bit value, not a full
2337 // pointer.
2338 cmpl(lhs, rhs);
2339#else
2340 cmpq(lhs, rhs);
2341#endif
2342 break;
2343 case kI64:
2344 cmpq(lhs, rhs);
2345 break;
2346 default:
2347 UNREACHABLE();
2348 }
2349 } else {
2351 testl(lhs, lhs);
2352 }
2353
2354 j(cond, label);
2355}
2356
2358 Register lhs, int imm,
2359 const FreezeCacheState& frozen) {
2360 cmpl(lhs, Immediate(imm));
2361 j(cond, label);
2362}
2363
2365 Register lhs, int32_t imm,
2366 const FreezeCacheState& frozen) {
2367 cmpq(lhs, Immediate(imm));
2368 j(cond, label);
2369}
2370
2371void LiftoffAssembler::emit_i32_eqz(Register dst, Register src) {
2372 testl(src, src);
2373 setcc(equal, dst);
2374 movzxbl(dst, dst);
2375}
2376
2377void LiftoffAssembler::emit_i32_set_cond(Condition cond, Register dst,
2378 Register lhs, Register rhs) {
2379 cmpl(lhs, rhs);
2380 setcc(cond, dst);
2381 movzxbl(dst, dst);
2382}
2383
2384void LiftoffAssembler::emit_i64_eqz(Register dst, LiftoffRegister src) {
2385 testq(src.gp(), src.gp());
2386 setcc(equal, dst);
2387 movzxbl(dst, dst);
2388}
2389
2390void LiftoffAssembler::emit_i64_set_cond(Condition cond, Register dst,
2391 LiftoffRegister lhs,
2392 LiftoffRegister rhs) {
2393 cmpq(lhs.gp(), rhs.gp());
2394 setcc(cond, dst);
2395 movzxbl(dst, dst);
2396}
2397
2398namespace liftoff {
2399template <void (SharedMacroAssemblerBase::*cmp_op)(DoubleRegister,
2401void EmitFloatSetCond(LiftoffAssembler* assm, Condition cond, Register dst,
2402 DoubleRegister lhs, DoubleRegister rhs) {
2403 Label cont;
2404 Label not_nan;
2405
2406 (assm->*cmp_op)(lhs, rhs);
2407 // If PF is one, one of the operands was NaN. This needs special handling.
2408 assm->j(parity_odd, &not_nan, Label::kNear);
2409 // Return 1 for f32.ne, 0 for all other cases.
2410 if (cond == not_equal) {
2411 assm->movl(dst, Immediate(1));
2412 } else {
2413 assm->xorl(dst, dst);
2414 }
2415 assm->jmp(&cont, Label::kNear);
2416 assm->bind(&not_nan);
2417
2418 assm->setcc(cond, dst);
2419 assm->movzxbl(dst, dst);
2420 assm->bind(&cont);
2421}
2422} // namespace liftoff
2423
2424void LiftoffAssembler::emit_f32_set_cond(Condition cond, Register dst,
2425 DoubleRegister lhs,
2426 DoubleRegister rhs) {
2428 rhs);
2429}
2430
2431void LiftoffAssembler::emit_f64_set_cond(Condition cond, Register dst,
2432 DoubleRegister lhs,
2433 DoubleRegister rhs) {
2435 rhs);
2436}
2437
2438bool LiftoffAssembler::emit_select(LiftoffRegister dst, Register condition,
2439 LiftoffRegister true_value,
2440 LiftoffRegister false_value,
2441 ValueKind kind) {
2442 if (kind != kI32 && kind != kI64) return false;
2443
2444 testl(condition, condition);
2445
2446 if (kind == kI32) {
2447 if (dst == false_value) {
2448 cmovl(not_zero, dst.gp(), true_value.gp());
2449 } else {
2450 if (dst != true_value) movl(dst.gp(), true_value.gp());
2451 cmovl(zero, dst.gp(), false_value.gp());
2452 }
2453 } else {
2454 if (dst == false_value) {
2455 cmovq(not_zero, dst.gp(), true_value.gp());
2456 } else {
2457 if (dst != true_value) movq(dst.gp(), true_value.gp());
2458 cmovq(zero, dst.gp(), false_value.gp());
2459 }
2460 }
2461
2462 return true;
2463}
2464
2465void LiftoffAssembler::emit_smi_check(Register obj, Label* target,
2466 SmiCheckMode mode,
2467 const FreezeCacheState& frozen) {
2468 testb(obj, Immediate(kSmiTagMask));
2470 j(condition, target);
2471}
2472
2473// TODO(fanchenk): Distinguish mov* if data bypass delay matter.
2474namespace liftoff {
2475template <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister),
2476 void (Assembler::*sse_op)(XMMRegister, XMMRegister)>
2478 LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister lhs,
2479 LiftoffRegister rhs, std::optional<CpuFeature> feature = std::nullopt) {
2480 if (CpuFeatures::IsSupported(AVX)) {
2481 CpuFeatureScope scope(assm, AVX);
2482 (assm->*avx_op)(dst.fp(), lhs.fp(), rhs.fp());
2483 return;
2484 }
2485
2486 std::optional<CpuFeatureScope> sse_scope;
2487 if (feature.has_value()) sse_scope.emplace(assm, *feature);
2488
2489 if (dst.fp() == rhs.fp()) {
2490 (assm->*sse_op)(dst.fp(), lhs.fp());
2491 } else {
2492 if (dst.fp() != lhs.fp()) (assm->movaps)(dst.fp(), lhs.fp());
2493 (assm->*sse_op)(dst.fp(), rhs.fp());
2494 }
2495}
2496
2497template <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister),
2498 void (Assembler::*sse_op)(XMMRegister, XMMRegister)>
2500 LiftoffAssembler* assm, LiftoffRegister dst, LiftoffRegister lhs,
2501 LiftoffRegister rhs, std::optional<CpuFeature> feature = std::nullopt) {
2502 if (CpuFeatures::IsSupported(AVX)) {
2503 CpuFeatureScope scope(assm, AVX);
2504 (assm->*avx_op)(dst.fp(), lhs.fp(), rhs.fp());
2505 return;
2506 }
2507
2508 std::optional<CpuFeatureScope> sse_scope;
2509 if (feature.has_value()) sse_scope.emplace(assm, *feature);
2510
2511 if (dst.fp() == rhs.fp()) {
2512 assm->movaps(kScratchDoubleReg, rhs.fp());
2513 assm->movaps(dst.fp(), lhs.fp());
2514 (assm->*sse_op)(dst.fp(), kScratchDoubleReg);
2515 } else {
2516 if (dst.fp() != lhs.fp()) assm->movaps(dst.fp(), lhs.fp());
2517 (assm->*sse_op)(dst.fp(), rhs.fp());
2518 }
2519}
2520
2521template <void (Assembler::*avx_op)(XMMRegister, XMMRegister, XMMRegister),
2522 void (Assembler::*sse_op)(XMMRegister, XMMRegister), uint8_t width>
2523void EmitSimdShiftOp(LiftoffAssembler* assm, LiftoffRegister dst,
2524 LiftoffRegister operand, LiftoffRegister count) {
2525 constexpr int mask = (1 << width) - 1;
2526 assm->movq(kScratchRegister, count.gp());
2527 assm->andq(kScratchRegister, Immediate(mask));
2529 if (CpuFeatures::IsSupported(AVX)) {
2530 CpuFeatureScope scope(assm, AVX);
2531 (assm->*avx_op)(dst.fp(), operand.fp(), kScratchDoubleReg);
2532 } else {
2533 if (dst.fp() != operand.fp()) assm->movaps(dst.fp(), operand.fp());
2534 (assm->*sse_op)(dst.fp(), kScratchDoubleReg);
2535 }
2536}
2537
2538template <void (Assembler::*avx_op)(XMMRegister, XMMRegister, uint8_t),
2539 void (Assembler::*sse_op)(XMMRegister, uint8_t), uint8_t width>
2540void EmitSimdShiftOpImm(LiftoffAssembler* assm, LiftoffRegister dst,
2541 LiftoffRegister operand, int32_t count) {
2542 constexpr int mask = (1 << width) - 1;
2543 uint8_t shift = static_cast<uint8_t>(count & mask);
2544 if (CpuFeatures::IsSupported(AVX)) {
2545 CpuFeatureScope scope(assm, AVX);
2546 (assm->*avx_op)(dst.fp(), operand.fp(), shift);
2547 } else {
2548 if (dst.fp() != operand.fp()) assm->movaps(dst.fp(), operand.fp());
2549 (assm->*sse_op)(dst.fp(), shift);
2550 }
2551}
2552
2553inline void EmitAnyTrue(LiftoffAssembler* assm, LiftoffRegister dst,
2554 LiftoffRegister src) {
2555 assm->xorq(dst.gp(), dst.gp());
2556 assm->Ptest(src.fp(), src.fp());
2557 assm->setcc(not_equal, dst.gp());
2558}
2559
2560template <void (SharedMacroAssemblerBase::*pcmp)(XMMRegister, XMMRegister)>
2561inline void EmitAllTrue(LiftoffAssembler* assm, LiftoffRegister dst,
2562 LiftoffRegister src,
2563 std::optional<CpuFeature> feature = std::nullopt) {
2564 std::optional<CpuFeatureScope> sse_scope;
2565 if (feature.has_value()) sse_scope.emplace(assm, *feature);
2566
2567 XMMRegister tmp = kScratchDoubleReg;
2568 assm->xorq(dst.gp(), dst.gp());
2569 assm->Pxor(tmp, tmp);
2570 (assm->*pcmp)(tmp, src.fp());
2571 assm->Ptest(tmp, tmp);
2572 assm->setcc(equal, dst.gp());
2573}
2574
2575} // namespace liftoff
2576
2577void LiftoffAssembler::LoadTransform(LiftoffRegister dst, Register src_addr,
2578 Register offset_reg, uintptr_t offset_imm,
2579 LoadType type,
2580 LoadTransformationKind transform,
2581 uint32_t* protected_load_pc,
2582 bool i64_offset) {
2583 Operand src_op = liftoff::GetMemOp(this, src_addr, offset_reg, offset_imm);
2584 *protected_load_pc = pc_offset();
2585 MachineType memtype = type.mem_type();
2586 if (transform == LoadTransformationKind::kExtend) {
2587 if (memtype == MachineType::Int8()) {
2588 Pmovsxbw(dst.fp(), src_op);
2589 } else if (memtype == MachineType::Uint8()) {
2590 Pmovzxbw(dst.fp(), src_op);
2591 } else if (memtype == MachineType::Int16()) {
2592 Pmovsxwd(dst.fp(), src_op);
2593 } else if (memtype == MachineType::Uint16()) {
2594 Pmovzxwd(dst.fp(), src_op);
2595 } else if (memtype == MachineType::Int32()) {
2596 Pmovsxdq(dst.fp(), src_op);
2597 } else if (memtype == MachineType::Uint32()) {
2598 Pmovzxdq(dst.fp(), src_op);
2599 }
2600 } else if (transform == LoadTransformationKind::kZeroExtend) {
2601 if (memtype == MachineType::Int32()) {
2602 Movss(dst.fp(), src_op);
2603 } else {
2604 DCHECK_EQ(MachineType::Int64(), memtype);
2605 Movsd(dst.fp(), src_op);
2606 }
2607 } else {
2609 if (memtype == MachineType::Int8()) {
2610 S128Load8Splat(dst.fp(), src_op, kScratchDoubleReg);
2611 } else if (memtype == MachineType::Int16()) {
2612 S128Load16Splat(dst.fp(), src_op, kScratchDoubleReg);
2613 } else if (memtype == MachineType::Int32()) {
2614 S128Load32Splat(dst.fp(), src_op);
2615 } else if (memtype == MachineType::Int64()) {
2616 Movddup(dst.fp(), src_op);
2617 }
2618 }
2619}
2620
2621void LiftoffAssembler::LoadLane(LiftoffRegister dst, LiftoffRegister src,
2622 Register addr, Register offset_reg,
2623 uintptr_t offset_imm, LoadType type,
2624 uint8_t laneidx, uint32_t* protected_load_pc,
2625 bool i64_offset) {
2626 if (offset_reg != no_reg && !i64_offset) AssertZeroExtended(offset_reg);
2627 Operand src_op = liftoff::GetMemOp(this, addr, offset_reg, offset_imm);
2628
2629 MachineType mem_type = type.mem_type();
2630 if (mem_type == MachineType::Int8()) {
2631 Pinsrb(dst.fp(), src.fp(), src_op, laneidx, protected_load_pc);
2632 } else if (mem_type == MachineType::Int16()) {
2633 Pinsrw(dst.fp(), src.fp(), src_op, laneidx, protected_load_pc);
2634 } else if (mem_type == MachineType::Int32()) {
2635 Pinsrd(dst.fp(), src.fp(), src_op, laneidx, protected_load_pc);
2636 } else {
2637 DCHECK_EQ(MachineType::Int64(), mem_type);
2638 Pinsrq(dst.fp(), src.fp(), src_op, laneidx, protected_load_pc);
2639 }
2640}
2641
2642void LiftoffAssembler::StoreLane(Register dst, Register offset,
2643 uintptr_t offset_imm, LiftoffRegister src,
2644 StoreType type, uint8_t lane,
2645 uint32_t* protected_store_pc,
2646 bool i64_offset) {
2647 if (offset != no_reg && !i64_offset) AssertZeroExtended(offset);
2648 Operand dst_op = liftoff::GetMemOp(this, dst, offset, offset_imm);
2649 if (protected_store_pc) *protected_store_pc = pc_offset();
2650 MachineRepresentation rep = type.mem_rep();
2651 if (rep == MachineRepresentation::kWord8) {
2652 Pextrb(dst_op, src.fp(), lane);
2653 } else if (rep == MachineRepresentation::kWord16) {
2654 Pextrw(dst_op, src.fp(), lane);
2655 } else if (rep == MachineRepresentation::kWord32) {
2656 S128Store32Lane(dst_op, src.fp(), lane);
2657 } else {
2659 S128Store64Lane(dst_op, src.fp(), lane);
2660 }
2661}
2662
2663void LiftoffAssembler::emit_i8x16_shuffle(LiftoffRegister dst,
2664 LiftoffRegister lhs,
2665 LiftoffRegister rhs,
2666 const uint8_t shuffle[16],
2667 bool is_swizzle) {
2668 if (is_swizzle) {
2669 uint32_t imms[4];
2670 // Shuffles that use just 1 operand are called swizzles, rhs can be ignored.
2671 wasm::SimdShuffle::Pack16Lanes(imms, shuffle);
2673 make_uint64(imms[1], imms[0]));
2674 Pshufb(dst.fp(), lhs.fp(), kScratchDoubleReg);
2675 return;
2676 }
2677
2678 uint64_t mask1[2] = {};
2679 for (int i = 15; i >= 0; i--) {
2680 uint8_t lane = shuffle[i];
2681 int j = i >> 3;
2682 mask1[j] <<= 8;
2683 mask1[j] |= lane < kSimd128Size ? lane : 0x80;
2684 }
2687
2688 uint64_t mask2[2] = {};
2689 for (int i = 15; i >= 0; i--) {
2690 uint8_t lane = shuffle[i];
2691 int j = i >> 3;
2692 mask2[j] <<= 8;
2693 mask2[j] |= lane >= kSimd128Size ? (lane & 0x0F) : 0x80;
2694 }
2696
2697 Pshufb(dst.fp(), rhs.fp(), liftoff::kScratchDoubleReg2);
2698 Por(dst.fp(), kScratchDoubleReg);
2699}
2700
2701void LiftoffAssembler::emit_i8x16_swizzle(LiftoffRegister dst,
2702 LiftoffRegister lhs,
2703 LiftoffRegister rhs) {
2704 I8x16Swizzle(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg,
2706}
2707
2708void LiftoffAssembler::emit_i8x16_relaxed_swizzle(LiftoffRegister dst,
2709 LiftoffRegister lhs,
2710 LiftoffRegister rhs) {
2711 I8x16Swizzle(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg,
2712 kScratchRegister, true);
2713}
2714
2716 LiftoffRegister src) {
2717 Cvttps2dq(dst.fp(), src.fp());
2718}
2719
2721 LiftoffRegister src) {
2722 emit_i32x4_uconvert_f32x4(dst, src);
2723}
2724
2726 LiftoffRegister dst, LiftoffRegister src) {
2727 Cvttpd2dq(dst.fp(), src.fp());
2728}
2729
2731 LiftoffRegister dst, LiftoffRegister src) {
2733}
2734
2735void LiftoffAssembler::emit_s128_relaxed_laneselect(LiftoffRegister dst,
2736 LiftoffRegister src1,
2737 LiftoffRegister src2,
2738 LiftoffRegister mask,
2739 int lane_width) {
2740 // Passing {src2} first is not a typo: the x86 instructions copy from the
2741 // second operand when the mask is 1, contrary to the Wasm instruction.
2742 if (lane_width == 8) {
2743 Pblendvb(dst.fp(), src2.fp(), src1.fp(), mask.fp());
2744 } else if (lane_width == 32) {
2745 Blendvps(dst.fp(), src2.fp(), src1.fp(), mask.fp());
2746 } else if (lane_width == 64) {
2747 Blendvpd(dst.fp(), src2.fp(), src1.fp(), mask.fp());
2748 } else {
2749 UNREACHABLE();
2750 }
2751}
2752
2753void LiftoffAssembler::emit_i8x16_popcnt(LiftoffRegister dst,
2754 LiftoffRegister src) {
2755 I8x16Popcnt(dst.fp(), src.fp(), kScratchDoubleReg,
2757}
2758
2759void LiftoffAssembler::emit_i8x16_splat(LiftoffRegister dst,
2760 LiftoffRegister src) {
2761 I8x16Splat(dst.fp(), src.gp(), kScratchDoubleReg);
2762}
2763
2764void LiftoffAssembler::emit_i16x8_splat(LiftoffRegister dst,
2765 LiftoffRegister src) {
2766 I16x8Splat(dst.fp(), src.gp());
2767}
2768
2769void LiftoffAssembler::emit_i32x4_splat(LiftoffRegister dst,
2770 LiftoffRegister src) {
2771 Movd(dst.fp(), src.gp());
2772 Pshufd(dst.fp(), dst.fp(), static_cast<uint8_t>(0));
2773}
2774
2775void LiftoffAssembler::emit_i64x2_splat(LiftoffRegister dst,
2776 LiftoffRegister src) {
2777 Movq(dst.fp(), src.gp());
2778 Movddup(dst.fp(), dst.fp());
2779}
2780
2781void LiftoffAssembler::emit_f32x4_splat(LiftoffRegister dst,
2782 LiftoffRegister src) {
2783 F32x4Splat(dst.fp(), src.fp());
2784}
2785
2786void LiftoffAssembler::emit_f64x2_splat(LiftoffRegister dst,
2787 LiftoffRegister src) {
2788 Movddup(dst.fp(), src.fp());
2789}
2790
2791void LiftoffAssembler::emit_i8x16_eq(LiftoffRegister dst, LiftoffRegister lhs,
2792 LiftoffRegister rhs) {
2794 this, dst, lhs, rhs);
2795}
2796
2797void LiftoffAssembler::emit_i8x16_ne(LiftoffRegister dst, LiftoffRegister lhs,
2798 LiftoffRegister rhs) {
2800 this, dst, lhs, rhs);
2802 Pxor(dst.fp(), kScratchDoubleReg);
2803}
2804
2805void LiftoffAssembler::emit_i8x16_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
2806 LiftoffRegister rhs) {
2807 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpcmpgtb,
2808 &Assembler::pcmpgtb>(this, dst, lhs,
2809 rhs);
2810}
2811
2812void LiftoffAssembler::emit_i8x16_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
2813 LiftoffRegister rhs) {
2814 DoubleRegister ref = rhs.fp();
2815 if (dst == rhs) {
2816 Movaps(kScratchDoubleReg, rhs.fp());
2817 ref = kScratchDoubleReg;
2818 }
2820 this, dst, lhs, rhs, SSE4_1);
2821 Pcmpeqb(dst.fp(), ref);
2823 Pxor(dst.fp(), kScratchDoubleReg);
2824}
2825
2826void LiftoffAssembler::emit_i8x16_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
2827 LiftoffRegister rhs) {
2828 DoubleRegister ref = rhs.fp();
2829 if (dst == rhs) {
2830 Movaps(kScratchDoubleReg, rhs.fp());
2831 ref = kScratchDoubleReg;
2832 }
2834 this, dst, lhs, rhs, SSE4_1);
2835 Pcmpeqb(dst.fp(), ref);
2836}
2837
2838void LiftoffAssembler::emit_i8x16_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
2839 LiftoffRegister rhs) {
2840 DoubleRegister ref = rhs.fp();
2841 if (dst == rhs) {
2842 Movaps(kScratchDoubleReg, rhs.fp());
2843 ref = kScratchDoubleReg;
2844 }
2846 this, dst, lhs, rhs);
2847 Pcmpeqb(dst.fp(), ref);
2848}
2849
2850void LiftoffAssembler::emit_i16x8_eq(LiftoffRegister dst, LiftoffRegister lhs,
2851 LiftoffRegister rhs) {
2853 this, dst, lhs, rhs);
2854}
2855
2856void LiftoffAssembler::emit_i16x8_ne(LiftoffRegister dst, LiftoffRegister lhs,
2857 LiftoffRegister rhs) {
2859 this, dst, lhs, rhs);
2861 Pxor(dst.fp(), kScratchDoubleReg);
2862}
2863
2864void LiftoffAssembler::emit_i16x8_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
2865 LiftoffRegister rhs) {
2866 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpcmpgtw,
2867 &Assembler::pcmpgtw>(this, dst, lhs,
2868 rhs);
2869}
2870
2871void LiftoffAssembler::emit_i16x8_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
2872 LiftoffRegister rhs) {
2873 DoubleRegister ref = rhs.fp();
2874 if (dst == rhs) {
2875 Movaps(kScratchDoubleReg, rhs.fp());
2876 ref = kScratchDoubleReg;
2877 }
2879 this, dst, lhs, rhs, SSE4_1);
2880 Pcmpeqw(dst.fp(), ref);
2882 Pxor(dst.fp(), kScratchDoubleReg);
2883}
2884
2885void LiftoffAssembler::emit_i16x8_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
2886 LiftoffRegister rhs) {
2887 DoubleRegister ref = rhs.fp();
2888 if (dst == rhs) {
2889 Movaps(kScratchDoubleReg, rhs.fp());
2890 ref = kScratchDoubleReg;
2891 }
2893 this, dst, lhs, rhs);
2894 Pcmpeqw(dst.fp(), ref);
2895}
2896
2897void LiftoffAssembler::emit_i16x8_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
2898 LiftoffRegister rhs) {
2899 DoubleRegister ref = rhs.fp();
2900 if (dst == rhs) {
2901 Movaps(kScratchDoubleReg, rhs.fp());
2902 ref = kScratchDoubleReg;
2903 }
2905 this, dst, lhs, rhs, SSE4_1);
2906 Pcmpeqw(dst.fp(), ref);
2907}
2908
2909void LiftoffAssembler::emit_i32x4_eq(LiftoffRegister dst, LiftoffRegister lhs,
2910 LiftoffRegister rhs) {
2912 this, dst, lhs, rhs);
2913}
2914
2915void LiftoffAssembler::emit_i32x4_ne(LiftoffRegister dst, LiftoffRegister lhs,
2916 LiftoffRegister rhs) {
2918 this, dst, lhs, rhs);
2920 Pxor(dst.fp(), kScratchDoubleReg);
2921}
2922
2923void LiftoffAssembler::emit_i32x4_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
2924 LiftoffRegister rhs) {
2925 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpcmpgtd,
2926 &Assembler::pcmpgtd>(this, dst, lhs,
2927 rhs);
2928}
2929
2930void LiftoffAssembler::emit_i32x4_gt_u(LiftoffRegister dst, LiftoffRegister lhs,
2931 LiftoffRegister rhs) {
2932 DoubleRegister ref = rhs.fp();
2933 if (dst == rhs) {
2934 Movaps(kScratchDoubleReg, rhs.fp());
2935 ref = kScratchDoubleReg;
2936 }
2938 this, dst, lhs, rhs, SSE4_1);
2939 Pcmpeqd(dst.fp(), ref);
2941 Pxor(dst.fp(), kScratchDoubleReg);
2942}
2943
2944void LiftoffAssembler::emit_i32x4_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
2945 LiftoffRegister rhs) {
2946 DoubleRegister ref = rhs.fp();
2947 if (dst == rhs) {
2948 Movaps(kScratchDoubleReg, rhs.fp());
2949 ref = kScratchDoubleReg;
2950 }
2952 this, dst, lhs, rhs, SSE4_1);
2953 Pcmpeqd(dst.fp(), ref);
2954}
2955
2956void LiftoffAssembler::emit_i32x4_ge_u(LiftoffRegister dst, LiftoffRegister lhs,
2957 LiftoffRegister rhs) {
2958 DoubleRegister ref = rhs.fp();
2959 if (dst == rhs) {
2960 Movaps(kScratchDoubleReg, rhs.fp());
2961 ref = kScratchDoubleReg;
2962 }
2964 this, dst, lhs, rhs, SSE4_1);
2965 Pcmpeqd(dst.fp(), ref);
2966}
2967
2968void LiftoffAssembler::emit_i64x2_eq(LiftoffRegister dst, LiftoffRegister lhs,
2969 LiftoffRegister rhs) {
2971 this, dst, lhs, rhs, SSE4_1);
2972}
2973
2974void LiftoffAssembler::emit_i64x2_ne(LiftoffRegister dst, LiftoffRegister lhs,
2975 LiftoffRegister rhs) {
2977 this, dst, lhs, rhs, SSE4_1);
2979 Pxor(dst.fp(), kScratchDoubleReg);
2980}
2981
2982void LiftoffAssembler::emit_i64x2_gt_s(LiftoffRegister dst, LiftoffRegister lhs,
2983 LiftoffRegister rhs) {
2984 // Different register alias requirements depending on CpuFeatures supported:
2986 // 1. AVX, or SSE4_2 no requirements (I64x2GtS takes care of aliasing).
2987 I64x2GtS(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
2988 } else {
2989 // 2. Else, dst != lhs && dst != rhs (lhs == rhs is ok).
2990 if (dst == lhs || dst == rhs) {
2991 I64x2GtS(liftoff::kScratchDoubleReg2, lhs.fp(), rhs.fp(),
2994 } else {
2995 I64x2GtS(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
2996 }
2997 }
2998}
2999
3000void LiftoffAssembler::emit_i64x2_ge_s(LiftoffRegister dst, LiftoffRegister lhs,
3001 LiftoffRegister rhs) {
3002 // Different register alias requirements depending on CpuFeatures supported:
3003 if (CpuFeatures::IsSupported(AVX)) {
3004 // 1. AVX, no requirements.
3005 I64x2GeS(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
3006 } else if (CpuFeatures::IsSupported(SSE4_2)) {
3007 // 2. SSE4_2, dst != lhs.
3008 if (dst == lhs) {
3009 I64x2GeS(liftoff::kScratchDoubleReg2, lhs.fp(), rhs.fp(),
3012 } else {
3013 I64x2GeS(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
3014 }
3015 } else {
3016 // 3. Else, dst != lhs && dst != rhs (lhs == rhs is ok).
3017 if (dst == lhs || dst == rhs) {
3018 I64x2GeS(liftoff::kScratchDoubleReg2, lhs.fp(), rhs.fp(),
3021 } else {
3022 I64x2GeS(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
3023 }
3024 }
3025}
3026
3027void LiftoffAssembler::emit_f32x4_eq(LiftoffRegister dst, LiftoffRegister lhs,
3028 LiftoffRegister rhs) {
3030 this, dst, lhs, rhs);
3031}
3032
3033void LiftoffAssembler::emit_f32x4_ne(LiftoffRegister dst, LiftoffRegister lhs,
3034 LiftoffRegister rhs) {
3035 liftoff::EmitSimdCommutativeBinOp<&Assembler::vcmpneqps,
3036 &Assembler::cmpneqps>(this, dst, lhs, rhs);
3037}
3038
3039void LiftoffAssembler::emit_f32x4_lt(LiftoffRegister dst, LiftoffRegister lhs,
3040 LiftoffRegister rhs) {
3041 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vcmpltps,
3042 &Assembler::cmpltps>(this, dst, lhs,
3043 rhs);
3044}
3045
3046void LiftoffAssembler::emit_f32x4_le(LiftoffRegister dst, LiftoffRegister lhs,
3047 LiftoffRegister rhs) {
3048 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vcmpleps,
3049 &Assembler::cmpleps>(this, dst, lhs,
3050 rhs);
3051}
3052
3053void LiftoffAssembler::emit_f64x2_eq(LiftoffRegister dst, LiftoffRegister lhs,
3054 LiftoffRegister rhs) {
3056 this, dst, lhs, rhs);
3057}
3058
3059void LiftoffAssembler::emit_f64x2_ne(LiftoffRegister dst, LiftoffRegister lhs,
3060 LiftoffRegister rhs) {
3061 liftoff::EmitSimdCommutativeBinOp<&Assembler::vcmpneqpd,
3062 &Assembler::cmpneqpd>(this, dst, lhs, rhs);
3063}
3064
3065void LiftoffAssembler::emit_f64x2_lt(LiftoffRegister dst, LiftoffRegister lhs,
3066 LiftoffRegister rhs) {
3067 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vcmpltpd,
3068 &Assembler::cmpltpd>(this, dst, lhs,
3069 rhs);
3070}
3071
3072void LiftoffAssembler::emit_f64x2_le(LiftoffRegister dst, LiftoffRegister lhs,
3073 LiftoffRegister rhs) {
3074 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vcmplepd,
3075 &Assembler::cmplepd>(this, dst, lhs,
3076 rhs);
3077}
3078
3079void LiftoffAssembler::emit_s128_const(LiftoffRegister dst,
3080 const uint8_t imms[16]) {
3081 uint64_t vals[2];
3082 memcpy(vals, imms, sizeof(vals));
3083 MacroAssembler::Move(dst.fp(), vals[1], vals[0]);
3084}
3085
3086void LiftoffAssembler::emit_s128_not(LiftoffRegister dst, LiftoffRegister src) {
3087 S128Not(dst.fp(), src.fp(), kScratchDoubleReg);
3088}
3089
3090void LiftoffAssembler::emit_s128_and(LiftoffRegister dst, LiftoffRegister lhs,
3091 LiftoffRegister rhs) {
3093 this, dst, lhs, rhs);
3094}
3095
3096void LiftoffAssembler::emit_s128_or(LiftoffRegister dst, LiftoffRegister lhs,
3097 LiftoffRegister rhs) {
3099 this, dst, lhs, rhs);
3100}
3101
3102void LiftoffAssembler::emit_s128_xor(LiftoffRegister dst, LiftoffRegister lhs,
3103 LiftoffRegister rhs) {
3105 this, dst, lhs, rhs);
3106}
3107
3108void LiftoffAssembler::emit_s128_select(LiftoffRegister dst,
3109 LiftoffRegister src1,
3110 LiftoffRegister src2,
3111 LiftoffRegister mask) {
3112 // Ensure that we don't overwrite any inputs with the movaps below.
3113 DCHECK_NE(dst, src1);
3114 DCHECK_NE(dst, src2);
3115 if (!CpuFeatures::IsSupported(AVX) && dst != mask) {
3116 movaps(dst.fp(), mask.fp());
3117 S128Select(dst.fp(), dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg);
3118 } else {
3119 S128Select(dst.fp(), mask.fp(), src1.fp(), src2.fp(), kScratchDoubleReg);
3120 }
3121}
3122
3123void LiftoffAssembler::emit_i8x16_neg(LiftoffRegister dst,
3124 LiftoffRegister src) {
3125 if (dst.fp() == src.fp()) {
3127 Psignb(dst.fp(), kScratchDoubleReg);
3128 } else {
3129 Pxor(dst.fp(), dst.fp());
3130 Psubb(dst.fp(), src.fp());
3131 }
3132}
3133
3134void LiftoffAssembler::emit_v128_anytrue(LiftoffRegister dst,
3135 LiftoffRegister src) {
3136 liftoff::EmitAnyTrue(this, dst, src);
3137}
3138
3139void LiftoffAssembler::emit_i8x16_alltrue(LiftoffRegister dst,
3140 LiftoffRegister src) {
3142}
3143
3144void LiftoffAssembler::emit_i8x16_bitmask(LiftoffRegister dst,
3145 LiftoffRegister src) {
3146 Pmovmskb(dst.gp(), src.fp());
3147}
3148
3149void LiftoffAssembler::emit_i8x16_shl(LiftoffRegister dst, LiftoffRegister lhs,
3150 LiftoffRegister rhs) {
3151 I8x16Shl(dst.fp(), lhs.fp(), rhs.gp(), kScratchRegister, kScratchDoubleReg,
3153}
3154
3155void LiftoffAssembler::emit_i8x16_shli(LiftoffRegister dst, LiftoffRegister lhs,
3156 int32_t rhs) {
3157 I8x16Shl(dst.fp(), lhs.fp(), rhs, kScratchRegister, kScratchDoubleReg);
3158}
3159
3160void LiftoffAssembler::emit_i8x16_shr_s(LiftoffRegister dst,
3161 LiftoffRegister lhs,
3162 LiftoffRegister rhs) {
3163 I8x16ShrS(dst.fp(), lhs.fp(), rhs.gp(), kScratchRegister, kScratchDoubleReg,
3165}
3166
3167void LiftoffAssembler::emit_i8x16_shri_s(LiftoffRegister dst,
3168 LiftoffRegister lhs, int32_t rhs) {
3169 I8x16ShrS(dst.fp(), lhs.fp(), rhs, kScratchDoubleReg);
3170}
3171
3172void LiftoffAssembler::emit_i8x16_shr_u(LiftoffRegister dst,
3173 LiftoffRegister lhs,
3174 LiftoffRegister rhs) {
3175 I8x16ShrU(dst.fp(), lhs.fp(), rhs.gp(), kScratchRegister, kScratchDoubleReg,
3177}
3178
3179void LiftoffAssembler::emit_i8x16_shri_u(LiftoffRegister dst,
3180 LiftoffRegister lhs, int32_t rhs) {
3181 I8x16ShrU(dst.fp(), lhs.fp(), rhs, kScratchRegister, kScratchDoubleReg);
3182}
3183
3184void LiftoffAssembler::emit_i8x16_add(LiftoffRegister dst, LiftoffRegister lhs,
3185 LiftoffRegister rhs) {
3187 this, dst, lhs, rhs);
3188}
3189
3190void LiftoffAssembler::emit_i8x16_add_sat_s(LiftoffRegister dst,
3191 LiftoffRegister lhs,
3192 LiftoffRegister rhs) {
3194 this, dst, lhs, rhs);
3195}
3196
3197void LiftoffAssembler::emit_i8x16_add_sat_u(LiftoffRegister dst,
3198 LiftoffRegister lhs,
3199 LiftoffRegister rhs) {
3201 this, dst, lhs, rhs);
3202}
3203
3204void LiftoffAssembler::emit_i8x16_sub(LiftoffRegister dst, LiftoffRegister lhs,
3205 LiftoffRegister rhs) {
3207 this, dst, lhs, rhs);
3208}
3209
3210void LiftoffAssembler::emit_i8x16_sub_sat_s(LiftoffRegister dst,
3211 LiftoffRegister lhs,
3212 LiftoffRegister rhs) {
3214 this, dst, lhs, rhs);
3215}
3216
3217void LiftoffAssembler::emit_i8x16_sub_sat_u(LiftoffRegister dst,
3218 LiftoffRegister lhs,
3219 LiftoffRegister rhs) {
3220 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubusb,
3221 &Assembler::psubusb>(this, dst, lhs,
3222 rhs);
3223}
3224
3225void LiftoffAssembler::emit_i8x16_min_s(LiftoffRegister dst,
3226 LiftoffRegister lhs,
3227 LiftoffRegister rhs) {
3229 this, dst, lhs, rhs, SSE4_1);
3230}
3231
3232void LiftoffAssembler::emit_i8x16_min_u(LiftoffRegister dst,
3233 LiftoffRegister lhs,
3234 LiftoffRegister rhs) {
3236 this, dst, lhs, rhs);
3237}
3238
3239void LiftoffAssembler::emit_i8x16_max_s(LiftoffRegister dst,
3240 LiftoffRegister lhs,
3241 LiftoffRegister rhs) {
3243 this, dst, lhs, rhs, SSE4_1);
3244}
3245
3246void LiftoffAssembler::emit_i8x16_max_u(LiftoffRegister dst,
3247 LiftoffRegister lhs,
3248 LiftoffRegister rhs) {
3250 this, dst, lhs, rhs);
3251}
3252
3253void LiftoffAssembler::emit_i16x8_neg(LiftoffRegister dst,
3254 LiftoffRegister src) {
3255 if (dst.fp() == src.fp()) {
3257 Psignw(dst.fp(), kScratchDoubleReg);
3258 } else {
3259 Pxor(dst.fp(), dst.fp());
3260 Psubw(dst.fp(), src.fp());
3261 }
3262}
3263
3264void LiftoffAssembler::emit_i16x8_alltrue(LiftoffRegister dst,
3265 LiftoffRegister src) {
3267}
3268
3269void LiftoffAssembler::emit_i16x8_bitmask(LiftoffRegister dst,
3270 LiftoffRegister src) {
3272 Packsswb(tmp, src.fp());
3273 Pmovmskb(dst.gp(), tmp);
3274 shrq(dst.gp(), Immediate(8));
3275}
3276
3277void LiftoffAssembler::emit_i16x8_shl(LiftoffRegister dst, LiftoffRegister lhs,
3278 LiftoffRegister rhs) {
3280 lhs, rhs);
3281}
3282
3283void LiftoffAssembler::emit_i16x8_shli(LiftoffRegister dst, LiftoffRegister lhs,
3284 int32_t rhs) {
3286 this, dst, lhs, rhs);
3287}
3288
3289void LiftoffAssembler::emit_i16x8_shr_s(LiftoffRegister dst,
3290 LiftoffRegister lhs,
3291 LiftoffRegister rhs) {
3293 lhs, rhs);
3294}
3295
3296void LiftoffAssembler::emit_i16x8_shri_s(LiftoffRegister dst,
3297 LiftoffRegister lhs, int32_t rhs) {
3299 this, dst, lhs, rhs);
3300}
3301
3302void LiftoffAssembler::emit_i16x8_shr_u(LiftoffRegister dst,
3303 LiftoffRegister lhs,
3304 LiftoffRegister rhs) {
3306 lhs, rhs);
3307}
3308
3309void LiftoffAssembler::emit_i16x8_shri_u(LiftoffRegister dst,
3310 LiftoffRegister lhs, int32_t rhs) {
3312 this, dst, lhs, rhs);
3313}
3314
3315void LiftoffAssembler::emit_i16x8_add(LiftoffRegister dst, LiftoffRegister lhs,
3316 LiftoffRegister rhs) {
3318 this, dst, lhs, rhs);
3319}
3320
3321void LiftoffAssembler::emit_i16x8_add_sat_s(LiftoffRegister dst,
3322 LiftoffRegister lhs,
3323 LiftoffRegister rhs) {
3325 this, dst, lhs, rhs);
3326}
3327
3328void LiftoffAssembler::emit_i16x8_add_sat_u(LiftoffRegister dst,
3329 LiftoffRegister lhs,
3330 LiftoffRegister rhs) {
3332 this, dst, lhs, rhs);
3333}
3334
3335void LiftoffAssembler::emit_i16x8_sub(LiftoffRegister dst, LiftoffRegister lhs,
3336 LiftoffRegister rhs) {
3338 this, dst, lhs, rhs);
3339}
3340
3341void LiftoffAssembler::emit_i16x8_sub_sat_s(LiftoffRegister dst,
3342 LiftoffRegister lhs,
3343 LiftoffRegister rhs) {
3345 this, dst, lhs, rhs);
3346}
3347
3348void LiftoffAssembler::emit_i16x8_sub_sat_u(LiftoffRegister dst,
3349 LiftoffRegister lhs,
3350 LiftoffRegister rhs) {
3351 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpsubusw,
3352 &Assembler::psubusw>(this, dst, lhs,
3353 rhs);
3354}
3355
3356void LiftoffAssembler::emit_i16x8_mul(LiftoffRegister dst, LiftoffRegister lhs,
3357 LiftoffRegister rhs) {
3359 this, dst, lhs, rhs);
3360}
3361
3362void LiftoffAssembler::emit_i16x8_min_s(LiftoffRegister dst,
3363 LiftoffRegister lhs,
3364 LiftoffRegister rhs) {
3366 this, dst, lhs, rhs);
3367}
3368
3369void LiftoffAssembler::emit_i16x8_min_u(LiftoffRegister dst,
3370 LiftoffRegister lhs,
3371 LiftoffRegister rhs) {
3373 this, dst, lhs, rhs, SSE4_1);
3374}
3375
3376void LiftoffAssembler::emit_i16x8_max_s(LiftoffRegister dst,
3377 LiftoffRegister lhs,
3378 LiftoffRegister rhs) {
3380 this, dst, lhs, rhs);
3381}
3382
3383void LiftoffAssembler::emit_i16x8_max_u(LiftoffRegister dst,
3384 LiftoffRegister lhs,
3385 LiftoffRegister rhs) {
3387 this, dst, lhs, rhs, SSE4_1);
3388}
3389
3391 LiftoffRegister src) {
3392 I16x8ExtAddPairwiseI8x16S(dst.fp(), src.fp(), kScratchDoubleReg,
3394}
3395
3397 LiftoffRegister src) {
3398 I16x8ExtAddPairwiseI8x16U(dst.fp(), src.fp(), kScratchRegister);
3399}
3400
3402 LiftoffRegister src1,
3403 LiftoffRegister src2) {
3404 I16x8ExtMulLow(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg,
3405 /*is_signed=*/true);
3406}
3407
3409 LiftoffRegister src1,
3410 LiftoffRegister src2) {
3411 I16x8ExtMulLow(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg,
3412 /*is_signed=*/false);
3413}
3414
3416 LiftoffRegister src1,
3417 LiftoffRegister src2) {
3418 I16x8ExtMulHighS(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg);
3419}
3420
3422 LiftoffRegister src1,
3423 LiftoffRegister src2) {
3424 I16x8ExtMulHighU(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg);
3425}
3426
3427void LiftoffAssembler::emit_i16x8_q15mulr_sat_s(LiftoffRegister dst,
3428 LiftoffRegister src1,
3429 LiftoffRegister src2) {
3430 I16x8Q15MulRSatS(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg);
3431}
3432
3433void LiftoffAssembler::emit_i16x8_relaxed_q15mulr_s(LiftoffRegister dst,
3434 LiftoffRegister src1,
3435 LiftoffRegister src2) {
3436 if (CpuFeatures::IsSupported(AVX) || dst == src1) {
3437 Pmulhrsw(dst.fp(), src1.fp(), src2.fp());
3438 } else {
3439 movdqa(dst.fp(), src1.fp());
3440 pmulhrsw(dst.fp(), src2.fp());
3441 }
3442}
3443
3444void LiftoffAssembler::emit_i16x8_dot_i8x16_i7x16_s(LiftoffRegister dst,
3445 LiftoffRegister lhs,
3446 LiftoffRegister rhs) {
3447 I16x8DotI8x16I7x16S(dst.fp(), lhs.fp(), rhs.fp());
3448}
3449
3451 LiftoffRegister lhs,
3452 LiftoffRegister rhs,
3453 LiftoffRegister acc) {
3454 if (CpuFeatures::IsSupported(AVX_VNNI) ||
3455 CpuFeatures::IsSupported(AVX_VNNI_INT8)) {
3456 I32x4DotI8x16I7x16AddS(dst.fp(), lhs.fp(), rhs.fp(), acc.fp(),
3458 } else {
3459 static constexpr RegClass tmp_rc = reg_class_for(kS128);
3460 LiftoffRegister tmp1 =
3461 GetUnusedRegister(tmp_rc, LiftoffRegList{dst, lhs, rhs, acc});
3462 LiftoffRegister tmp2 =
3463 GetUnusedRegister(tmp_rc, LiftoffRegList{dst, lhs, rhs, acc, tmp1});
3464 I32x4DotI8x16I7x16AddS(dst.fp(), lhs.fp(), rhs.fp(), acc.fp(), tmp1.fp(),
3465 tmp2.fp());
3466 }
3467}
3468
3469void LiftoffAssembler::emit_i32x4_neg(LiftoffRegister dst,
3470 LiftoffRegister src) {
3471 if (dst.fp() == src.fp()) {
3473 Psignd(dst.fp(), kScratchDoubleReg);
3474 } else {
3475 Pxor(dst.fp(), dst.fp());
3476 Psubd(dst.fp(), src.fp());
3477 }
3478}
3479
3480void LiftoffAssembler::emit_i32x4_alltrue(LiftoffRegister dst,
3481 LiftoffRegister src) {
3483}
3484
3485void LiftoffAssembler::emit_i32x4_bitmask(LiftoffRegister dst,
3486 LiftoffRegister src) {
3487 Movmskps(dst.gp(), src.fp());
3488}
3489
3490void LiftoffAssembler::emit_i32x4_shl(LiftoffRegister dst, LiftoffRegister lhs,
3491 LiftoffRegister rhs) {
3493 lhs, rhs);
3494}
3495
3496void LiftoffAssembler::emit_i32x4_shli(LiftoffRegister dst, LiftoffRegister lhs,
3497 int32_t rhs) {
3499 this, dst, lhs, rhs);
3500}
3501
3502void LiftoffAssembler::emit_i32x4_shr_s(LiftoffRegister dst,
3503 LiftoffRegister lhs,
3504 LiftoffRegister rhs) {
3506 lhs, rhs);
3507}
3508
3509void LiftoffAssembler::emit_i32x4_shri_s(LiftoffRegister dst,
3510 LiftoffRegister lhs, int32_t rhs) {
3512 this, dst, lhs, rhs);
3513}
3514
3515void LiftoffAssembler::emit_i32x4_shr_u(LiftoffRegister dst,
3516 LiftoffRegister lhs,
3517 LiftoffRegister rhs) {
3519 lhs, rhs);
3520}
3521
3522void LiftoffAssembler::emit_i32x4_shri_u(LiftoffRegister dst,
3523 LiftoffRegister lhs, int32_t rhs) {
3525 this, dst, lhs, rhs);
3526}
3527
3528void LiftoffAssembler::emit_i32x4_add(LiftoffRegister dst, LiftoffRegister lhs,
3529 LiftoffRegister rhs) {
3531 this, dst, lhs, rhs);
3532}
3533
3534void LiftoffAssembler::emit_i32x4_sub(LiftoffRegister dst, LiftoffRegister lhs,
3535 LiftoffRegister rhs) {
3537 this, dst, lhs, rhs);
3538}
3539
3540void LiftoffAssembler::emit_i32x4_mul(LiftoffRegister dst, LiftoffRegister lhs,
3541 LiftoffRegister rhs) {
3543 this, dst, lhs, rhs, SSE4_1);
3544}
3545
3546void LiftoffAssembler::emit_i32x4_min_s(LiftoffRegister dst,
3547 LiftoffRegister lhs,
3548 LiftoffRegister rhs) {
3550 this, dst, lhs, rhs, SSE4_1);
3551}
3552
3553void LiftoffAssembler::emit_i32x4_min_u(LiftoffRegister dst,
3554 LiftoffRegister lhs,
3555 LiftoffRegister rhs) {
3557 this, dst, lhs, rhs, SSE4_1);
3558}
3559
3560void LiftoffAssembler::emit_i32x4_max_s(LiftoffRegister dst,
3561 LiftoffRegister lhs,
3562 LiftoffRegister rhs) {
3564 this, dst, lhs, rhs, SSE4_1);
3565}
3566
3567void LiftoffAssembler::emit_i32x4_max_u(LiftoffRegister dst,
3568 LiftoffRegister lhs,
3569 LiftoffRegister rhs) {
3571 this, dst, lhs, rhs, SSE4_1);
3572}
3573
3574void LiftoffAssembler::emit_i32x4_dot_i16x8_s(LiftoffRegister dst,
3575 LiftoffRegister lhs,
3576 LiftoffRegister rhs) {
3578 this, dst, lhs, rhs);
3579}
3580
3582 LiftoffRegister src) {
3583 I32x4ExtAddPairwiseI16x8S(dst.fp(), src.fp(), kScratchRegister);
3584}
3585
3587 LiftoffRegister src) {
3588 I32x4ExtAddPairwiseI16x8U(dst.fp(), src.fp(), kScratchDoubleReg);
3589}
3590
3591namespace liftoff {
3592// Helper function to check for register aliasing, AVX support, and moves
3593// registers around before calling the actual macro-assembler function.
3594inline void I32x4ExtMulHelper(LiftoffAssembler* assm, XMMRegister dst,
3595 XMMRegister src1, XMMRegister src2, bool low,
3596 bool is_signed) {
3597 // I32x4ExtMul requires dst == src1 if AVX is not supported.
3598 if (CpuFeatures::IsSupported(AVX) || dst == src1) {
3599 assm->I32x4ExtMul(dst, src1, src2, kScratchDoubleReg, low, is_signed);
3600 } else if (dst != src2) {
3601 // dst != src1 && dst != src2
3602 assm->movaps(dst, src1);
3603 assm->I32x4ExtMul(dst, dst, src2, kScratchDoubleReg, low, is_signed);
3604 } else {
3605 // dst == src2
3606 // Extended multiplication is commutative,
3607 assm->movaps(dst, src2);
3608 assm->I32x4ExtMul(dst, dst, src1, kScratchDoubleReg, low, is_signed);
3609 }
3610}
3611} // namespace liftoff
3612
3614 LiftoffRegister src1,
3615 LiftoffRegister src2) {
3616 liftoff::I32x4ExtMulHelper(this, dst.fp(), src1.fp(), src2.fp(), /*low=*/true,
3617 /*is_signed=*/true);
3618}
3619
3621 LiftoffRegister src1,
3622 LiftoffRegister src2) {
3623 liftoff::I32x4ExtMulHelper(this, dst.fp(), src1.fp(), src2.fp(), /*low=*/true,
3624 /*is_signed=*/false);
3625}
3626
3628 LiftoffRegister src1,
3629 LiftoffRegister src2) {
3630 liftoff::I32x4ExtMulHelper(this, dst.fp(), src1.fp(), src2.fp(),
3631 /*low=*/false,
3632 /*is_signed=*/true);
3633}
3634
3636 LiftoffRegister src1,
3637 LiftoffRegister src2) {
3638 liftoff::I32x4ExtMulHelper(this, dst.fp(), src1.fp(), src2.fp(),
3639 /*low=*/false,
3640 /*is_signed=*/false);
3641}
3642
3643void LiftoffAssembler::emit_i64x2_neg(LiftoffRegister dst,
3644 LiftoffRegister src) {
3645 I64x2Neg(dst.fp(), src.fp(), kScratchDoubleReg);
3646}
3647
3648void LiftoffAssembler::emit_i64x2_alltrue(LiftoffRegister dst,
3649 LiftoffRegister src) {
3650 liftoff::EmitAllTrue<&MacroAssembler::Pcmpeqq>(this, dst, src, SSE4_1);
3651}
3652
3653void LiftoffAssembler::emit_i64x2_shl(LiftoffRegister dst, LiftoffRegister lhs,
3654 LiftoffRegister rhs) {
3656 lhs, rhs);
3657}
3658
3659void LiftoffAssembler::emit_i64x2_shli(LiftoffRegister dst, LiftoffRegister lhs,
3660 int32_t rhs) {
3662 this, dst, lhs, rhs);
3663}
3664
3665void LiftoffAssembler::emit_i64x2_shr_s(LiftoffRegister dst,
3666 LiftoffRegister lhs,
3667 LiftoffRegister rhs) {
3668 I64x2ShrS(dst.fp(), lhs.fp(), rhs.gp(), kScratchDoubleReg,
3670}
3671
3672void LiftoffAssembler::emit_i64x2_shri_s(LiftoffRegister dst,
3673 LiftoffRegister lhs, int32_t rhs) {
3674 I64x2ShrS(dst.fp(), lhs.fp(), rhs & 0x3F, kScratchDoubleReg);
3675}
3676
3677void LiftoffAssembler::emit_i64x2_shr_u(LiftoffRegister dst,
3678 LiftoffRegister lhs,
3679 LiftoffRegister rhs) {
3681 lhs, rhs);
3682}
3683
3684void LiftoffAssembler::emit_i64x2_shri_u(LiftoffRegister dst,
3685 LiftoffRegister lhs, int32_t rhs) {
3687 this, dst, lhs, rhs);
3688}
3689
3690void LiftoffAssembler::emit_i64x2_add(LiftoffRegister dst, LiftoffRegister lhs,
3691 LiftoffRegister rhs) {
3693 this, dst, lhs, rhs);
3694}
3695
3696void LiftoffAssembler::emit_i64x2_sub(LiftoffRegister dst, LiftoffRegister lhs,
3697 LiftoffRegister rhs) {
3699 this, dst, lhs, rhs);
3700}
3701
3702void LiftoffAssembler::emit_i64x2_mul(LiftoffRegister dst, LiftoffRegister lhs,
3703 LiftoffRegister rhs) {
3704 static constexpr RegClass tmp_rc = reg_class_for(kS128);
3705 LiftoffRegister tmp1 =
3706 GetUnusedRegister(tmp_rc, LiftoffRegList{dst, lhs, rhs});
3707 LiftoffRegister tmp2 =
3708 GetUnusedRegister(tmp_rc, LiftoffRegList{dst, lhs, rhs, tmp1});
3709 I64x2Mul(dst.fp(), lhs.fp(), rhs.fp(), tmp1.fp(), tmp2.fp());
3710}
3711
3713 LiftoffRegister src1,
3714 LiftoffRegister src2) {
3715 I64x2ExtMul(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg, /*low=*/true,
3716 /*is_signed=*/true);
3717}
3718
3720 LiftoffRegister src1,
3721 LiftoffRegister src2) {
3722 I64x2ExtMul(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg, /*low=*/true,
3723 /*is_signed=*/false);
3724}
3725
3727 LiftoffRegister src1,
3728 LiftoffRegister src2) {
3729 I64x2ExtMul(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg, /*low=*/false,
3730 /*is_signed=*/true);
3731}
3732
3734 LiftoffRegister src1,
3735 LiftoffRegister src2) {
3736 I64x2ExtMul(dst.fp(), src1.fp(), src2.fp(), kScratchDoubleReg, /*low=*/false,
3737 /*is_signed=*/false);
3738}
3739
3740void LiftoffAssembler::emit_i64x2_bitmask(LiftoffRegister dst,
3741 LiftoffRegister src) {
3742 Movmskpd(dst.gp(), src.fp());
3743}
3744
3746 LiftoffRegister src) {
3747 Pmovsxdq(dst.fp(), src.fp());
3748}
3749
3751 LiftoffRegister src) {
3752 I64x2SConvertI32x4High(dst.fp(), src.fp());
3753}
3754
3756 LiftoffRegister src) {
3757 Pmovzxdq(dst.fp(), src.fp());
3758}
3759
3761 LiftoffRegister src) {
3762 I64x2UConvertI32x4High(dst.fp(), src.fp(), kScratchDoubleReg);
3763}
3764
3765void LiftoffAssembler::emit_f32x4_abs(LiftoffRegister dst,
3766 LiftoffRegister src) {
3767 Absps(dst.fp(), src.fp(), kScratchRegister);
3768}
3769
3770void LiftoffAssembler::emit_f32x4_neg(LiftoffRegister dst,
3771 LiftoffRegister src) {
3772 Negps(dst.fp(), src.fp(), kScratchRegister);
3773}
3774
3775void LiftoffAssembler::emit_f32x4_sqrt(LiftoffRegister dst,
3776 LiftoffRegister src) {
3777 Sqrtps(dst.fp(), src.fp());
3778}
3779
3780bool LiftoffAssembler::emit_f32x4_ceil(LiftoffRegister dst,
3781 LiftoffRegister src) {
3783 Roundps(dst.fp(), src.fp(), kRoundUp);
3784 return true;
3785}
3786
3787bool LiftoffAssembler::emit_f32x4_floor(LiftoffRegister dst,
3788 LiftoffRegister src) {
3790 Roundps(dst.fp(), src.fp(), kRoundDown);
3791 return true;
3792}
3793
3794bool LiftoffAssembler::emit_f32x4_trunc(LiftoffRegister dst,
3795 LiftoffRegister src) {
3797 Roundps(dst.fp(), src.fp(), kRoundToZero);
3798 return true;
3799}
3800
3801bool LiftoffAssembler::emit_f32x4_nearest_int(LiftoffRegister dst,
3802 LiftoffRegister src) {
3804 Roundps(dst.fp(), src.fp(), kRoundToNearest);
3805 return true;
3806}
3807
3808void LiftoffAssembler::emit_f32x4_add(LiftoffRegister dst, LiftoffRegister lhs,
3809 LiftoffRegister rhs) {
3810 // Addition is not commutative in the presence of NaNs.
3812 this, dst, lhs, rhs);
3813}
3814
3815void LiftoffAssembler::emit_f32x4_sub(LiftoffRegister dst, LiftoffRegister lhs,
3816 LiftoffRegister rhs) {
3818 this, dst, lhs, rhs);
3819}
3820
3821void LiftoffAssembler::emit_f32x4_mul(LiftoffRegister dst, LiftoffRegister lhs,
3822 LiftoffRegister rhs) {
3824 this, dst, lhs, rhs);
3825}
3826
3827void LiftoffAssembler::emit_f32x4_div(LiftoffRegister dst, LiftoffRegister lhs,
3828 LiftoffRegister rhs) {
3830 this, dst, lhs, rhs);
3831}
3832
3833void LiftoffAssembler::emit_f32x4_min(LiftoffRegister dst, LiftoffRegister lhs,
3834 LiftoffRegister rhs) {
3835 F32x4Min(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
3836}
3837
3838void LiftoffAssembler::emit_f32x4_max(LiftoffRegister dst, LiftoffRegister lhs,
3839 LiftoffRegister rhs) {
3840 F32x4Max(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
3841}
3842
3843void LiftoffAssembler::emit_f32x4_pmin(LiftoffRegister dst, LiftoffRegister lhs,
3844 LiftoffRegister rhs) {
3845 // Due to the way minps works, pmin(a, b) = minps(b, a).
3847 this, dst, rhs, lhs);
3848}
3849
3850void LiftoffAssembler::emit_f32x4_pmax(LiftoffRegister dst, LiftoffRegister lhs,
3851 LiftoffRegister rhs) {
3852 // Due to the way maxps works, pmax(a, b) = maxps(b, a).
3854 this, dst, rhs, lhs);
3855}
3856
3857void LiftoffAssembler::emit_f32x4_relaxed_min(LiftoffRegister dst,
3858 LiftoffRegister lhs,
3859 LiftoffRegister rhs) {
3861 this, dst, lhs, rhs);
3862}
3863
3864void LiftoffAssembler::emit_f32x4_relaxed_max(LiftoffRegister dst,
3865 LiftoffRegister lhs,
3866 LiftoffRegister rhs) {
3868 this, dst, lhs, rhs);
3869}
3870
3871void LiftoffAssembler::emit_f64x2_abs(LiftoffRegister dst,
3872 LiftoffRegister src) {
3873 Abspd(dst.fp(), src.fp(), kScratchRegister);
3874}
3875
3876void LiftoffAssembler::emit_f64x2_neg(LiftoffRegister dst,
3877 LiftoffRegister src) {
3878 Negpd(dst.fp(), src.fp(), kScratchRegister);
3879}
3880
3881void LiftoffAssembler::emit_f64x2_sqrt(LiftoffRegister dst,
3882 LiftoffRegister src) {
3883 Sqrtpd(dst.fp(), src.fp());
3884}
3885
3886bool LiftoffAssembler::emit_f64x2_ceil(LiftoffRegister dst,
3887 LiftoffRegister src) {
3889 Roundpd(dst.fp(), src.fp(), kRoundUp);
3890 return true;
3891}
3892
3893bool LiftoffAssembler::emit_f64x2_floor(LiftoffRegister dst,
3894 LiftoffRegister src) {
3896 Roundpd(dst.fp(), src.fp(), kRoundDown);
3897 return true;
3898}
3899
3900bool LiftoffAssembler::emit_f64x2_trunc(LiftoffRegister dst,
3901 LiftoffRegister src) {
3903 Roundpd(dst.fp(), src.fp(), kRoundToZero);
3904 return true;
3905}
3906
3907bool LiftoffAssembler::emit_f64x2_nearest_int(LiftoffRegister dst,
3908 LiftoffRegister src) {
3910 Roundpd(dst.fp(), src.fp(), kRoundToNearest);
3911 return true;
3912}
3913
3914void LiftoffAssembler::emit_f64x2_add(LiftoffRegister dst, LiftoffRegister lhs,
3915 LiftoffRegister rhs) {
3917 this, dst, lhs, rhs);
3918}
3919
3920void LiftoffAssembler::emit_f64x2_sub(LiftoffRegister dst, LiftoffRegister lhs,
3921 LiftoffRegister rhs) {
3923 this, dst, lhs, rhs);
3924}
3925
3926void LiftoffAssembler::emit_f64x2_mul(LiftoffRegister dst, LiftoffRegister lhs,
3927 LiftoffRegister rhs) {
3929 this, dst, lhs, rhs);
3930}
3931
3932void LiftoffAssembler::emit_f64x2_div(LiftoffRegister dst, LiftoffRegister lhs,
3933 LiftoffRegister rhs) {
3935 this, dst, lhs, rhs);
3936}
3937
3938void LiftoffAssembler::emit_f64x2_min(LiftoffRegister dst, LiftoffRegister lhs,
3939 LiftoffRegister rhs) {
3940 F64x2Min(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
3941}
3942
3943void LiftoffAssembler::emit_f64x2_max(LiftoffRegister dst, LiftoffRegister lhs,
3944 LiftoffRegister rhs) {
3945 F64x2Max(dst.fp(), lhs.fp(), rhs.fp(), kScratchDoubleReg);
3946}
3947
3948void LiftoffAssembler::emit_f64x2_relaxed_min(LiftoffRegister dst,
3949 LiftoffRegister lhs,
3950 LiftoffRegister rhs) {
3952 this, dst, lhs, rhs);
3953}
3954
3955void LiftoffAssembler::emit_f64x2_relaxed_max(LiftoffRegister dst,
3956 LiftoffRegister lhs,
3957 LiftoffRegister rhs) {
3959 this, dst, lhs, rhs);
3960}
3961
3962void LiftoffAssembler::emit_f64x2_pmin(LiftoffRegister dst, LiftoffRegister lhs,
3963 LiftoffRegister rhs) {
3964 // Due to the way minpd works, pmin(a, b) = minpd(b, a).
3966 this, dst, rhs, lhs);
3967}
3968
3969void LiftoffAssembler::emit_f64x2_pmax(LiftoffRegister dst, LiftoffRegister lhs,
3970 LiftoffRegister rhs) {
3971 // Due to the way maxpd works, pmax(a, b) = maxpd(b, a).
3973 this, dst, rhs, lhs);
3974}
3975
3977 LiftoffRegister src) {
3978 Cvtdq2pd(dst.fp(), src.fp());
3979}
3980
3982 LiftoffRegister src) {
3983 F64x2ConvertLowI32x4U(dst.fp(), src.fp(), kScratchRegister);
3984}
3985
3986void LiftoffAssembler::emit_f64x2_promote_low_f32x4(LiftoffRegister dst,
3987 LiftoffRegister src) {
3988 Cvtps2pd(dst.fp(), src.fp());
3989}
3990
3991void LiftoffAssembler::emit_i32x4_sconvert_f32x4(LiftoffRegister dst,
3992 LiftoffRegister src) {
3994}
3995
3996void LiftoffAssembler::emit_i32x4_uconvert_f32x4(LiftoffRegister dst,
3997 LiftoffRegister src) {
3998 I32x4TruncF32x4U(dst.fp(), src.fp(), kScratchDoubleReg,
4000}
4001
4002void LiftoffAssembler::emit_f32x4_sconvert_i32x4(LiftoffRegister dst,
4003 LiftoffRegister src) {
4004 Cvtdq2ps(dst.fp(), src.fp());
4005}
4006
4007void LiftoffAssembler::emit_f32x4_uconvert_i32x4(LiftoffRegister dst,
4008 LiftoffRegister src) {
4009 Pxor(kScratchDoubleReg, kScratchDoubleReg); // Zeros.
4010 Pblendw(kScratchDoubleReg, src.fp(), uint8_t{0x55}); // Get lo 16 bits.
4011 if (CpuFeatures::IsSupported(AVX)) {
4012 CpuFeatureScope scope(this, AVX);
4013 vpsubd(dst.fp(), src.fp(), kScratchDoubleReg); // Get hi 16 bits.
4014 } else {
4015 if (dst.fp() != src.fp()) movaps(dst.fp(), src.fp());
4016 psubd(dst.fp(), kScratchDoubleReg);
4017 }
4018 Cvtdq2ps(kScratchDoubleReg, kScratchDoubleReg); // Convert lo exactly.
4019 Psrld(dst.fp(), uint8_t{1}); // Divide by 2 to get in unsigned range.
4020 Cvtdq2ps(dst.fp(), dst.fp()); // Convert hi, exactly.
4021 Addps(dst.fp(), dst.fp()); // Double hi, exactly.
4022 Addps(dst.fp(), kScratchDoubleReg); // Add hi and lo, may round.
4023}
4024
4025void LiftoffAssembler::emit_f32x4_demote_f64x2_zero(LiftoffRegister dst,
4026 LiftoffRegister src) {
4027 Cvtpd2ps(dst.fp(), src.fp());
4028}
4029
4030void LiftoffAssembler::emit_i8x16_sconvert_i16x8(LiftoffRegister dst,
4031 LiftoffRegister lhs,
4032 LiftoffRegister rhs) {
4033 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpacksswb,
4034 &Assembler::packsswb>(this, dst, lhs,
4035 rhs);
4036}
4037
4038void LiftoffAssembler::emit_i8x16_uconvert_i16x8(LiftoffRegister dst,
4039 LiftoffRegister lhs,
4040 LiftoffRegister rhs) {
4041 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpackuswb,
4042 &Assembler::packuswb>(this, dst, lhs,
4043 rhs);
4044}
4045
4046void LiftoffAssembler::emit_i16x8_sconvert_i32x4(LiftoffRegister dst,
4047 LiftoffRegister lhs,
4048 LiftoffRegister rhs) {
4049 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpackssdw,
4050 &Assembler::packssdw>(this, dst, lhs,
4051 rhs);
4052}
4053
4054void LiftoffAssembler::emit_i16x8_uconvert_i32x4(LiftoffRegister dst,
4055 LiftoffRegister lhs,
4056 LiftoffRegister rhs) {
4057 liftoff::EmitSimdNonCommutativeBinOp<&Assembler::vpackusdw,
4058 &Assembler::packusdw>(this, dst, lhs,
4059 rhs, SSE4_1);
4060}
4061
4063 LiftoffRegister src) {
4064 Pmovsxbw(dst.fp(), src.fp());
4065}
4066
4068 LiftoffRegister src) {
4069 I16x8SConvertI8x16High(dst.fp(), src.fp());
4070}
4071
4073 LiftoffRegister src) {
4074 Pmovzxbw(dst.fp(), src.fp());
4075}
4076
4078 LiftoffRegister src) {
4079 I16x8UConvertI8x16High(dst.fp(), src.fp(), kScratchDoubleReg);
4080}
4081
4083 LiftoffRegister src) {
4084 Pmovsxwd(dst.fp(), src.fp());
4085}
4086
4088 LiftoffRegister src) {
4089 I32x4SConvertI16x8High(dst.fp(), src.fp());
4090}
4091
4093 LiftoffRegister src) {
4094 Pmovzxwd(dst.fp(), src.fp());
4095}
4096
4098 LiftoffRegister src) {
4099 I32x4UConvertI16x8High(dst.fp(), src.fp(), kScratchDoubleReg);
4100}
4101
4103 LiftoffRegister src) {
4104 I32x4TruncSatF64x2SZero(dst.fp(), src.fp(), kScratchDoubleReg,
4106}
4107
4109 LiftoffRegister src) {
4110 I32x4TruncSatF64x2UZero(dst.fp(), src.fp(), kScratchDoubleReg,
4112}
4113
4114void LiftoffAssembler::emit_s128_and_not(LiftoffRegister dst,
4115 LiftoffRegister lhs,
4116 LiftoffRegister rhs) {
4118 this, dst, rhs, lhs);
4119}
4120
4122 LiftoffRegister lhs,
4123 LiftoffRegister rhs) {
4125 this, dst, lhs, rhs);
4126}
4127
4129 LiftoffRegister lhs,
4130 LiftoffRegister rhs) {
4132 this, dst, lhs, rhs);
4133}
4134
4135void LiftoffAssembler::emit_i8x16_abs(LiftoffRegister dst,
4136 LiftoffRegister src) {
4137 Pabsb(dst.fp(), src.fp());
4138}
4139
4140void LiftoffAssembler::emit_i16x8_abs(LiftoffRegister dst,
4141 LiftoffRegister src) {
4142 Pabsw(dst.fp(), src.fp());
4143}
4144
4145void LiftoffAssembler::emit_i32x4_abs(LiftoffRegister dst,
4146 LiftoffRegister src) {
4147 Pabsd(dst.fp(), src.fp());
4148}
4149
4150void LiftoffAssembler::emit_i64x2_abs(LiftoffRegister dst,
4151 LiftoffRegister src) {
4152 I64x2Abs(dst.fp(), src.fp(), kScratchDoubleReg);
4153}
4154
4155void LiftoffAssembler::emit_i8x16_extract_lane_s(LiftoffRegister dst,
4156 LiftoffRegister lhs,
4157 uint8_t imm_lane_idx) {
4158 Pextrb(dst.gp(), lhs.fp(), imm_lane_idx);
4159 movsxbl(dst.gp(), dst.gp());
4160}
4161
4162void LiftoffAssembler::emit_i8x16_extract_lane_u(LiftoffRegister dst,
4163 LiftoffRegister lhs,
4164 uint8_t imm_lane_idx) {
4165 Pextrb(dst.gp(), lhs.fp(), imm_lane_idx);
4166}
4167
4168void LiftoffAssembler::emit_i16x8_extract_lane_s(LiftoffRegister dst,
4169 LiftoffRegister lhs,
4170 uint8_t imm_lane_idx) {
4171 Pextrw(dst.gp(), lhs.fp(), imm_lane_idx);
4172 movsxwl(dst.gp(), dst.gp());
4173}
4174
4175void LiftoffAssembler::emit_i16x8_extract_lane_u(LiftoffRegister dst,
4176 LiftoffRegister lhs,
4177 uint8_t imm_lane_idx) {
4178 Pextrw(dst.gp(), lhs.fp(), imm_lane_idx);
4179}
4180
4181void LiftoffAssembler::emit_i32x4_extract_lane(LiftoffRegister dst,
4182 LiftoffRegister lhs,
4183 uint8_t imm_lane_idx) {
4184 Pextrd(dst.gp(), lhs.fp(), imm_lane_idx);
4185}
4186
4187void LiftoffAssembler::emit_i64x2_extract_lane(LiftoffRegister dst,
4188 LiftoffRegister lhs,
4189 uint8_t imm_lane_idx) {
4190 Pextrq(dst.gp(), lhs.fp(), static_cast<int8_t>(imm_lane_idx));
4191}
4192
4193void LiftoffAssembler::emit_f32x4_extract_lane(LiftoffRegister dst,
4194 LiftoffRegister lhs,
4195 uint8_t imm_lane_idx) {
4196 F32x4ExtractLane(dst.fp(), lhs.fp(), imm_lane_idx);
4197}
4198
4199void LiftoffAssembler::emit_f64x2_extract_lane(LiftoffRegister dst,
4200 LiftoffRegister lhs,
4201 uint8_t imm_lane_idx) {
4202 F64x2ExtractLane(dst.fp(), lhs.fp(), imm_lane_idx);
4203}
4204
4205void LiftoffAssembler::emit_i8x16_replace_lane(LiftoffRegister dst,
4206 LiftoffRegister src1,
4207 LiftoffRegister src2,
4208 uint8_t imm_lane_idx) {
4209 if (CpuFeatures::IsSupported(AVX)) {
4210 CpuFeatureScope scope(this, AVX);
4211 vpinsrb(dst.fp(), src1.fp(), src2.gp(), imm_lane_idx);
4212 } else {
4213 CpuFeatureScope scope(this, SSE4_1);
4214 if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp());
4215 pinsrb(dst.fp(), src2.gp(), imm_lane_idx);
4216 }
4217}
4218
4219void LiftoffAssembler::emit_i16x8_replace_lane(LiftoffRegister dst,
4220 LiftoffRegister src1,
4221 LiftoffRegister src2,
4222 uint8_t imm_lane_idx) {
4223 if (CpuFeatures::IsSupported(AVX)) {
4224 CpuFeatureScope scope(this, AVX);
4225 vpinsrw(dst.fp(), src1.fp(), src2.gp(), imm_lane_idx);
4226 } else {
4227 if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp());
4228 pinsrw(dst.fp(), src2.gp(), imm_lane_idx);
4229 }
4230}
4231
4232void LiftoffAssembler::emit_i32x4_replace_lane(LiftoffRegister dst,
4233 LiftoffRegister src1,
4234 LiftoffRegister src2,
4235 uint8_t imm_lane_idx) {
4236 if (CpuFeatures::IsSupported(AVX)) {
4237 CpuFeatureScope scope(this, AVX);
4238 vpinsrd(dst.fp(), src1.fp(), src2.gp(), imm_lane_idx);
4239 } else {
4240 CpuFeatureScope scope(this, SSE4_1);
4241 if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp());
4242 pinsrd(dst.fp(), src2.gp(), imm_lane_idx);
4243 }
4244}
4245
4246void LiftoffAssembler::emit_i64x2_replace_lane(LiftoffRegister dst,
4247 LiftoffRegister src1,
4248 LiftoffRegister src2,
4249 uint8_t imm_lane_idx) {
4250 if (CpuFeatures::IsSupported(AVX)) {
4251 CpuFeatureScope scope(this, AVX);
4252 vpinsrq(dst.fp(), src1.fp(), src2.gp(), imm_lane_idx);
4253 } else {
4254 CpuFeatureScope scope(this, SSE4_1);
4255 if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp());
4256 pinsrq(dst.fp(), src2.gp(), imm_lane_idx);
4257 }
4258}
4259
4260void LiftoffAssembler::emit_f32x4_replace_lane(LiftoffRegister dst,
4261 LiftoffRegister src1,
4262 LiftoffRegister src2,
4263 uint8_t imm_lane_idx) {
4264 if (CpuFeatures::IsSupported(AVX)) {
4265 CpuFeatureScope scope(this, AVX);
4266 vinsertps(dst.fp(), src1.fp(), src2.fp(), (imm_lane_idx << 4) & 0x30);
4267 } else {
4268 CpuFeatureScope scope(this, SSE4_1);
4269 if (dst.fp() != src1.fp()) movaps(dst.fp(), src1.fp());
4270 insertps(dst.fp(), src2.fp(), (imm_lane_idx << 4) & 0x30);
4271 }
4272}
4273
4274void LiftoffAssembler::emit_f64x2_replace_lane(LiftoffRegister dst,
4275 LiftoffRegister src1,
4276 LiftoffRegister src2,
4277 uint8_t imm_lane_idx) {
4278 F64x2ReplaceLane(dst.fp(), src1.fp(), src2.fp(), imm_lane_idx);
4279}
4280
4281void LiftoffAssembler::emit_f32x4_qfma(LiftoffRegister dst,
4282 LiftoffRegister src1,
4283 LiftoffRegister src2,
4284 LiftoffRegister src3) {
4285 F32x4Qfma(dst.fp(), src1.fp(), src2.fp(), src3.fp(), kScratchDoubleReg);
4286}
4287
4288void LiftoffAssembler::emit_f32x4_qfms(LiftoffRegister dst,
4289 LiftoffRegister src1,
4290 LiftoffRegister src2,
4291 LiftoffRegister src3) {
4292 F32x4Qfms(dst.fp(), src1.fp(), src2.fp(), src3.fp(), kScratchDoubleReg);
4293}
4294
4295void LiftoffAssembler::emit_f64x2_qfma(LiftoffRegister dst,
4296 LiftoffRegister src1,
4297 LiftoffRegister src2,
4298 LiftoffRegister src3) {
4299 F64x2Qfma(dst.fp(), src1.fp(), src2.fp(), src3.fp(), kScratchDoubleReg);
4300}
4301
4302void LiftoffAssembler::emit_f64x2_qfms(LiftoffRegister dst,
4303 LiftoffRegister src1,
4304 LiftoffRegister src2,
4305 LiftoffRegister src3) {
4306 F64x2Qfms(dst.fp(), src1.fp(), src2.fp(), src3.fp(), kScratchDoubleReg);
4307}
4308
4309bool LiftoffAssembler::emit_f16x8_splat(LiftoffRegister dst,
4310 LiftoffRegister src) {
4312 return false;
4313 }
4314 CpuFeatureScope f16c_scope(this, F16C);
4315 CpuFeatureScope avx2_scope(this, AVX2);
4316 vcvtps2ph(dst.fp(), src.fp(), 0);
4317 vpbroadcastw(dst.fp(), dst.fp());
4318 return true;
4319}
4320
4321bool LiftoffAssembler::emit_f16x8_extract_lane(LiftoffRegister dst,
4322 LiftoffRegister lhs,
4323 uint8_t imm_lane_idx) {
4325 return false;
4326 }
4327 CpuFeatureScope f16c_scope(this, F16C);
4328 CpuFeatureScope avx_scope(this, AVX);
4329 Pextrw(kScratchRegister, lhs.fp(), imm_lane_idx);
4330 vmovd(dst.fp(), kScratchRegister);
4331 vcvtph2ps(dst.fp(), dst.fp());
4332 return true;
4333}
4334
4335bool LiftoffAssembler::emit_f16x8_replace_lane(LiftoffRegister dst,
4336 LiftoffRegister src1,
4337 LiftoffRegister src2,
4338 uint8_t imm_lane_idx) {
4340 return false;
4341 }
4342 CpuFeatureScope f16c_scope(this, F16C);
4343 CpuFeatureScope avx_scope(this, AVX);
4344 vcvtps2ph(kScratchDoubleReg, src2.fp(), 0);
4346 vpinsrw(dst.fp(), src1.fp(), kScratchRegister, imm_lane_idx);
4347 return true;
4348}
4349
4350bool LiftoffAssembler::emit_f16x8_abs(LiftoffRegister dst,
4351 LiftoffRegister src) {
4352 if (!CpuFeatures::IsSupported(AVX)) {
4353 return false;
4354 }
4355 CpuFeatureScope avx_scope(this, AVX);
4356 Absph(dst.fp(), src.fp(), kScratchRegister);
4357 return true;
4358}
4359
4360bool LiftoffAssembler::emit_f16x8_neg(LiftoffRegister dst,
4361 LiftoffRegister src) {
4362 if (!CpuFeatures::IsSupported(AVX)) {
4363 return false;
4364 }
4365 CpuFeatureScope avx_scope(this, AVX);
4366 Negph(dst.fp(), src.fp(), kScratchRegister);
4367 return true;
4368}
4369
4370bool LiftoffAssembler::emit_f16x8_sqrt(LiftoffRegister dst,
4371 LiftoffRegister src) {
4373 return false;
4374 }
4375 CpuFeatureScope f16c_scope(this, F16C);
4376 CpuFeatureScope avx_scope(this, AVX);
4377 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4378 vcvtph2ps(ydst, src.fp());
4379 vsqrtps(ydst, ydst);
4380 vcvtps2ph(dst.fp(), ydst, 0);
4381 return true;
4382}
4383
4384bool LiftoffAssembler::emit_f16x8_ceil(LiftoffRegister dst,
4385 LiftoffRegister src) {
4387 return false;
4388 }
4389 CpuFeatureScope f16c_scope(this, F16C);
4390 CpuFeatureScope avx_scope(this, AVX);
4391 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4392 vcvtph2ps(ydst, src.fp());
4393 vroundps(ydst, ydst, kRoundUp);
4394 vcvtps2ph(dst.fp(), ydst, 0);
4395 return true;
4396}
4397
4398bool LiftoffAssembler::emit_f16x8_floor(LiftoffRegister dst,
4399 LiftoffRegister src) {
4401 return false;
4402 }
4403 CpuFeatureScope f16c_scope(this, F16C);
4404 CpuFeatureScope avx_scope(this, AVX);
4405 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4406 vcvtph2ps(ydst, src.fp());
4407 vroundps(ydst, ydst, kRoundDown);
4408 vcvtps2ph(dst.fp(), ydst, 0);
4409 return true;
4410}
4411
4412bool LiftoffAssembler::emit_f16x8_trunc(LiftoffRegister dst,
4413 LiftoffRegister src) {
4415 return false;
4416 }
4417 CpuFeatureScope f16c_scope(this, F16C);
4418 CpuFeatureScope avx_scope(this, AVX);
4419 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4420 vcvtph2ps(ydst, src.fp());
4421 vroundps(ydst, ydst, kRoundToZero);
4422 vcvtps2ph(dst.fp(), ydst, 0);
4423 return true;
4424}
4425
4426bool LiftoffAssembler::emit_f16x8_nearest_int(LiftoffRegister dst,
4427 LiftoffRegister src) {
4429 return false;
4430 }
4431 CpuFeatureScope f16c_scope(this, F16C);
4432 CpuFeatureScope avx_scope(this, AVX);
4433 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4434 vcvtph2ps(ydst, src.fp());
4435 vroundps(ydst, ydst, kRoundToNearest);
4436 vcvtps2ph(dst.fp(), ydst, 0);
4437 return true;
4438}
4439
4440template <void (Assembler::*avx_op)(YMMRegister, YMMRegister, YMMRegister)>
4444 !CpuFeatures::IsSupported(AVX2)) {
4445 return false;
4446 }
4447 CpuFeatureScope f16c_scope(assm, F16C);
4448 CpuFeatureScope avx_scope(assm, AVX);
4449 CpuFeatureScope avx2_scope(assm, AVX2);
4450 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4451 assm->vcvtph2ps(ydst, lhs.fp());
4452 assm->vcvtph2ps(kScratchSimd256Reg, rhs.fp());
4453 (assm->*avx_op)(ydst, ydst, kScratchSimd256Reg);
4454 assm->vpackssdw(ydst, ydst, ydst);
4455 return true;
4456}
4457
4458bool LiftoffAssembler::emit_f16x8_eq(LiftoffRegister dst, LiftoffRegister lhs,
4459 LiftoffRegister rhs) {
4460 return F16x8CmpOpViaF32<&Assembler::vcmpeqps>(this, dst, lhs, rhs);
4461}
4462
4463bool LiftoffAssembler::emit_f16x8_ne(LiftoffRegister dst, LiftoffRegister lhs,
4464 LiftoffRegister rhs) {
4465 return F16x8CmpOpViaF32<&Assembler::vcmpneqps>(this, dst, lhs, rhs);
4466}
4467
4468bool LiftoffAssembler::emit_f16x8_lt(LiftoffRegister dst, LiftoffRegister lhs,
4469 LiftoffRegister rhs) {
4470 return F16x8CmpOpViaF32<&Assembler::vcmpltps>(this, dst, lhs, rhs);
4471}
4472
4473bool LiftoffAssembler::emit_f16x8_le(LiftoffRegister dst, LiftoffRegister lhs,
4474 LiftoffRegister rhs) {
4475 return F16x8CmpOpViaF32<&Assembler::vcmpleps>(this, dst, lhs, rhs);
4476}
4477
4478template <void (Assembler::*avx_op)(YMMRegister, YMMRegister, YMMRegister)>
4482 return false;
4483 }
4484 CpuFeatureScope f16c_scope(assm, F16C);
4485 CpuFeatureScope avx_scope(assm, AVX);
4486 static constexpr RegClass res_rc = reg_class_for(kS128);
4487 LiftoffRegister tmp =
4488 assm->GetUnusedRegister(res_rc, LiftoffRegList{dst, lhs, rhs});
4489 YMMRegister ytmp = YMMRegister::from_code(tmp.fp().code());
4490 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4491 // dst can overlap with rhs or lhs, so cannot be used as temporary reg.
4492 assm->vcvtph2ps(ytmp, lhs.fp());
4493 assm->vcvtph2ps(kScratchSimd256Reg, rhs.fp());
4494 (assm->*avx_op)(ydst, ytmp, kScratchSimd256Reg);
4495 assm->vcvtps2ph(dst.fp(), ydst, 0);
4496 return true;
4497}
4498
4499bool LiftoffAssembler::emit_f16x8_add(LiftoffRegister dst, LiftoffRegister lhs,
4500 LiftoffRegister rhs) {
4501 return F16x8BinOpViaF32<&Assembler::vaddps>(this, dst, lhs, rhs);
4502}
4503
4504bool LiftoffAssembler::emit_f16x8_sub(LiftoffRegister dst, LiftoffRegister lhs,
4505 LiftoffRegister rhs) {
4506 return F16x8BinOpViaF32<&Assembler::vsubps>(this, dst, lhs, rhs);
4507}
4508
4509bool LiftoffAssembler::emit_f16x8_mul(LiftoffRegister dst, LiftoffRegister lhs,
4510 LiftoffRegister rhs) {
4511 return F16x8BinOpViaF32<&Assembler::vmulps>(this, dst, lhs, rhs);
4512}
4513
4514bool LiftoffAssembler::emit_f16x8_div(LiftoffRegister dst, LiftoffRegister lhs,
4515 LiftoffRegister rhs) {
4516 return F16x8BinOpViaF32<&Assembler::vdivps>(this, dst, lhs, rhs);
4517}
4518
4519bool LiftoffAssembler::emit_f16x8_min(LiftoffRegister dst, LiftoffRegister lhs,
4520 LiftoffRegister rhs) {
4522 return false;
4523 }
4524 static constexpr RegClass res_rc = reg_class_for(kS128);
4525 LiftoffRegister tmp =
4526 GetUnusedRegister(res_rc, LiftoffRegList{dst, lhs, rhs});
4527 YMMRegister ytmp = YMMRegister::from_code(tmp.fp().code());
4528 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4529 F16x8Min(ydst, lhs.fp(), rhs.fp(), kScratchSimd256Reg, ytmp);
4530 return true;
4531}
4532
4533bool LiftoffAssembler::emit_f16x8_max(LiftoffRegister dst, LiftoffRegister lhs,
4534 LiftoffRegister rhs) {
4536 return false;
4537 }
4538 static constexpr RegClass res_rc = reg_class_for(kS128);
4539 LiftoffRegister tmp =
4540 GetUnusedRegister(res_rc, LiftoffRegList{dst, lhs, rhs});
4541 YMMRegister ytmp = YMMRegister::from_code(tmp.fp().code());
4542 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4543 F16x8Max(ydst, lhs.fp(), rhs.fp(), kScratchSimd256Reg, ytmp);
4544 return true;
4545}
4546
4547bool LiftoffAssembler::emit_f16x8_pmin(LiftoffRegister dst, LiftoffRegister lhs,
4548 LiftoffRegister rhs) {
4549 // Due to the way minps works, pmin(a, b) = minps(b, a).
4550 return F16x8BinOpViaF32<&Assembler::vminps>(this, dst, rhs, lhs);
4551}
4552
4553bool LiftoffAssembler::emit_f16x8_pmax(LiftoffRegister dst, LiftoffRegister lhs,
4554 LiftoffRegister rhs) {
4555 // Due to the way maxps works, pmax(a, b) = maxps(b, a).
4556 return F16x8BinOpViaF32<&Assembler::vmaxps>(this, dst, rhs, lhs);
4557}
4558
4559bool LiftoffAssembler::emit_i16x8_sconvert_f16x8(LiftoffRegister dst,
4560 LiftoffRegister src) {
4562 !CpuFeatures::IsSupported(AVX2)) {
4563 return false;
4564 }
4565
4566 CpuFeatureScope f16c_scope(this, F16C);
4567 CpuFeatureScope avx_scope(this, AVX);
4568 CpuFeatureScope avx2_scope(this, AVX2);
4569
4570 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4572 return true;
4573}
4574
4575bool LiftoffAssembler::emit_i16x8_uconvert_f16x8(LiftoffRegister dst,
4576 LiftoffRegister src) {
4578 !CpuFeatures::IsSupported(AVX2)) {
4579 return false;
4580 }
4581
4582 CpuFeatureScope f16c_scope(this, F16C);
4583 CpuFeatureScope avx_scope(this, AVX);
4584 CpuFeatureScope avx2_scope(this, AVX2);
4585
4586 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4587 I16x8TruncF16x8U(ydst, src.fp(), kScratchSimd256Reg);
4588 return true;
4589}
4590
4591bool LiftoffAssembler::emit_f16x8_sconvert_i16x8(LiftoffRegister dst,
4592 LiftoffRegister src) {
4594 !CpuFeatures::IsSupported(AVX2)) {
4595 return false;
4596 }
4597
4598 CpuFeatureScope f16c_scope(this, F16C);
4599 CpuFeatureScope avx_scope(this, AVX);
4600 CpuFeatureScope avx2_scope(this, AVX2);
4601 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4602 vpmovsxwd(ydst, src.fp());
4603 vcvtdq2ps(ydst, ydst);
4604 vcvtps2ph(dst.fp(), ydst, 0);
4605 return true;
4606}
4607
4608bool LiftoffAssembler::emit_f16x8_uconvert_i16x8(LiftoffRegister dst,
4609 LiftoffRegister src) {
4611 !CpuFeatures::IsSupported(AVX2)) {
4612 return false;
4613 }
4614
4615 CpuFeatureScope f16c_scope(this, F16C);
4616 CpuFeatureScope avx_scope(this, AVX);
4617 CpuFeatureScope avx2_scope(this, AVX2);
4618 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4619 vpmovzxwd(ydst, src.fp());
4620 vcvtdq2ps(ydst, ydst);
4621 vcvtps2ph(dst.fp(), ydst, 0);
4622 return true;
4623}
4624
4625bool LiftoffAssembler::emit_f16x8_demote_f32x4_zero(LiftoffRegister dst,
4626 LiftoffRegister src) {
4627 if (!CpuFeatures::IsSupported(F16C)) {
4628 return false;
4629 }
4630 CpuFeatureScope f16c_scope(this, F16C);
4631 YMMRegister ysrc = YMMRegister::from_code(src.fp().code());
4632 vcvtps2ph(dst.fp(), ysrc, 0);
4633 return true;
4634}
4635
4636bool LiftoffAssembler::emit_f16x8_demote_f64x2_zero(LiftoffRegister dst,
4637 LiftoffRegister src) {
4639 return false;
4640 }
4641
4642 CpuFeatureScope avx_scope(this, AVX);
4643 CpuFeatureScope f16c_scope(this, F16C);
4644 LiftoffRegister tmp = GetUnusedRegister(RegClass::kGpReg, {});
4645 LiftoffRegister ftmp =
4646 GetUnusedRegister(RegClass::kFpReg, LiftoffRegList{dst, src});
4647 LiftoffRegister ftmp2 =
4648 GetUnusedRegister(RegClass::kFpReg, LiftoffRegList{dst, src, ftmp});
4649 F64x2ExtractLane(ftmp.fp(), src.fp(), 1);
4650 Cvtpd2ph(ftmp2.fp(), ftmp.fp(), tmp.gp());
4651 // Cvtpd2ph requires dst and src to not overlap.
4652 if (dst == src) {
4653 Move(ftmp.fp(), src.fp(), kF64);
4654 Cvtpd2ph(dst.fp(), ftmp.fp(), tmp.gp());
4655 } else {
4656 Cvtpd2ph(dst.fp(), src.fp(), tmp.gp());
4657 }
4658 vmovd(tmp.gp(), ftmp2.fp());
4659 vpinsrw(dst.fp(), dst.fp(), tmp.gp(), 1);
4660 // Set ftmp to 0.
4661 pxor(ftmp.fp(), ftmp.fp());
4662 // Reset all unaffected lanes.
4663 F64x2ReplaceLane(dst.fp(), dst.fp(), ftmp.fp(), 1);
4664 vinsertps(dst.fp(), dst.fp(), ftmp.fp(), (1 << 4) & 0x30);
4665 return true;
4666}
4667
4668bool LiftoffAssembler::emit_f32x4_promote_low_f16x8(LiftoffRegister dst,
4669 LiftoffRegister src) {
4670 if (!CpuFeatures::IsSupported(F16C)) {
4671 return false;
4672 }
4673 CpuFeatureScope f16c_scope(this, F16C);
4674 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4675 vcvtph2ps(ydst, src.fp());
4676 return true;
4677}
4678
4679bool LiftoffAssembler::emit_f16x8_qfma(LiftoffRegister dst,
4680 LiftoffRegister src1,
4681 LiftoffRegister src2,
4682 LiftoffRegister src3) {
4684 return false;
4685 }
4686
4687 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4690 F16x8Qfma(ydst, src1.fp(), src2.fp(), src3.fp(), tmp, tmp2);
4691 return true;
4692}
4693
4694bool LiftoffAssembler::emit_f16x8_qfms(LiftoffRegister dst,
4695 LiftoffRegister src1,
4696 LiftoffRegister src2,
4697 LiftoffRegister src3) {
4699 return false;
4700 }
4701
4702 YMMRegister ydst = YMMRegister::from_code(dst.fp().code());
4705 F16x8Qfms(ydst, src1.fp(), src2.fp(), src3.fp(), tmp, tmp2);
4706 return true;
4707}
4708
4711}
4712
4713void LiftoffAssembler::set_trap_on_oob_mem64(Register index, uint64_t max_index,
4714 Label* trap_label) {
4715 if (is_uint31(max_index)) {
4716 cmpq(index, Immediate(static_cast<int32_t>(max_index)));
4717 } else {
4718 movq(kScratchRegister, Immediate64(max_index));
4719 cmpq(index, kScratchRegister);
4720 }
4721 j(above_equal, trap_label);
4722}
4723
4724void LiftoffAssembler::StackCheck(Label* ool_code) {
4726 j(below_equal, ool_code);
4727}
4728
4731}
4732
4733void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {
4734 LiftoffRegList gp_regs = regs & kGpCacheRegList;
4735 while (!gp_regs.is_empty()) {
4736 LiftoffRegister reg = gp_regs.GetFirstRegSet();
4737 pushq(reg.gp());
4738 gp_regs.clear(reg);
4739 }
4740 LiftoffRegList fp_regs = regs & kFpCacheRegList;
4741 unsigned num_fp_regs = fp_regs.GetNumRegsSet();
4742 if (num_fp_regs) {
4743 AllocateStackSpace(num_fp_regs * kSimd128Size);
4744 unsigned offset = 0;
4745 while (!fp_regs.is_empty()) {
4746 LiftoffRegister reg = fp_regs.GetFirstRegSet();
4747 Movdqu(Operand(rsp, offset), reg.fp());
4748 fp_regs.clear(reg);
4750 }
4751 DCHECK_EQ(offset, num_fp_regs * kSimd128Size);
4752 }
4753}
4754
4755void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {
4756 LiftoffRegList fp_regs = regs & kFpCacheRegList;
4757 unsigned fp_offset = 0;
4758 while (!fp_regs.is_empty()) {
4759 LiftoffRegister reg = fp_regs.GetFirstRegSet();
4760 Movdqu(reg.fp(), Operand(rsp, fp_offset));
4761 fp_regs.clear(reg);
4762 fp_offset += kSimd128Size;
4763 }
4764 if (fp_offset) addq(rsp, Immediate(fp_offset));
4765 LiftoffRegList gp_regs = regs & kGpCacheRegList;
4766 while (!gp_regs.is_empty()) {
4767 LiftoffRegister reg = gp_regs.GetLastRegSet();
4768 popq(reg.gp());
4769 gp_regs.clear(reg);
4770 }
4771}
4772
4774 SafepointTableBuilder::Safepoint& safepoint, LiftoffRegList all_spills,
4775 LiftoffRegList ref_spills, int spill_offset) {
4776 LiftoffRegList fp_spills = all_spills & kFpCacheRegList;
4777 int spill_space_size = fp_spills.GetNumRegsSet() * kSimd128Size;
4778 LiftoffRegList gp_spills = all_spills & kGpCacheRegList;
4779 while (!gp_spills.is_empty()) {
4780 LiftoffRegister reg = gp_spills.GetFirstRegSet();
4781 if (ref_spills.has(reg)) {
4782 safepoint.DefineTaggedStackSlot(spill_offset);
4783 }
4784 gp_spills.clear(reg);
4785 ++spill_offset;
4786 spill_space_size += kSystemPointerSize;
4787 }
4788 // Record the number of additional spill slots.
4789 RecordOolSpillSpaceSize(spill_space_size);
4790}
4791
4792void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {
4793 DCHECK_LT(num_stack_slots,
4794 (1 << 16) / kSystemPointerSize); // 16 bit immediate
4795 ret(static_cast<int>(num_stack_slots * kSystemPointerSize));
4796}
4797
4799 const std::initializer_list<VarState> args, const LiftoffRegister* rets,
4800 ValueKind return_kind, ValueKind out_argument_kind, int stack_bytes,
4801 ExternalReference ext_ref) {
4802 AllocateStackSpace(stack_bytes);
4803
4804 int arg_offset = 0;
4805 for (const VarState& arg : args) {
4806 Operand dst{rsp, arg_offset};
4807 liftoff::StoreToMemory(this, dst, arg);
4808 arg_offset += value_kind_size(arg.kind());
4809 }
4810 DCHECK_LE(arg_offset, stack_bytes);
4811
4812 // Pass a pointer to the buffer with the arguments to the C function.
4813 movq(kCArgRegs[0], rsp);
4814
4815 constexpr int kNumCCallArgs = 1;
4816
4817 // Now call the C function.
4818 PrepareCallCFunction(kNumCCallArgs);
4819 CallCFunction(ext_ref, kNumCCallArgs);
4820
4821 // Move return value to the right register.
4822 const LiftoffRegister* next_result_reg = rets;
4823 if (return_kind != kVoid) {
4824 constexpr Register kReturnReg = rax;
4825 if (kReturnReg != next_result_reg->gp()) {
4826 Move(*next_result_reg, LiftoffRegister(kReturnReg), return_kind);
4827 }
4828 ++next_result_reg;
4829 }
4830
4831 // Load potential output value from the buffer on the stack.
4832 if (out_argument_kind != kVoid) {
4833 liftoff::LoadFromStack(this, *next_result_reg, Operand(rsp, 0),
4834 out_argument_kind);
4835 }
4836
4837 addq(rsp, Immediate(stack_bytes));
4838}
4839
4840void LiftoffAssembler::CallC(const std::initializer_list<VarState> args,
4841 ExternalReference ext_ref) {
4842 // First, prepare the stack for the C call.
4843 int num_args = static_cast<int>(args.size());
4844 PrepareCallCFunction(num_args);
4845
4846 // Then execute the parallel register move and also move values to parameter
4847 // stack slots.
4848 int reg_args = 0;
4849#ifdef V8_TARGET_OS_WIN
4850 // See comment on {kWindowsHomeStackSlots}.
4851 int stack_args = kWindowsHomeStackSlots;
4852#else
4853 int stack_args = 0;
4854#endif
4855 ParallelMove parallel_move{this};
4856 for (const VarState& arg : args) {
4857 if (reg_args < int{arraysize(kCArgRegs)}) {
4858 parallel_move.LoadIntoRegister(LiftoffRegister{kCArgRegs[reg_args]}, arg);
4859 ++reg_args;
4860 } else {
4861 Operand dst{rsp, stack_args * kSystemPointerSize};
4862 liftoff::StoreToMemory(this, dst, arg);
4863 ++stack_args;
4864 }
4865 }
4866 parallel_move.Execute();
4867
4868 // Now call the C function.
4869 CallCFunction(ext_ref, num_args);
4870}
4871
4874}
4875
4878}
4879
4881 compiler::CallDescriptor* call_descriptor,
4882 Register target) {
4883 if (target == no_reg) {
4885 target = kScratchRegister;
4886 }
4887 CallWasmCodePointer(target, call_descriptor->signature_hash());
4888}
4889
4891 compiler::CallDescriptor* call_descriptor, Register target) {
4892 if (target == no_reg) {
4894 target = kScratchRegister;
4895 }
4896 CallWasmCodePointer(target, call_descriptor->signature_hash(),
4898}
4899
4901 // A direct call to a builtin. Just encode the builtin index. This will be
4902 // patched at relocation.
4903 near_call(static_cast<Address>(builtin), RelocInfo::WASM_STUB_CALL);
4904}
4905
4906void LiftoffAssembler::AllocateStackSlot(Register addr, uint32_t size) {
4907 AllocateStackSpace(size);
4908 movq(addr, rsp);
4909}
4910
4911void LiftoffAssembler::DeallocateStackSlot(uint32_t size) {
4912 addq(rsp, Immediate(size));
4913}
4914
4916 cmpq(liftoff::kOSRTargetSlot, Immediate(0));
4917 j(not_equal, static_cast<Address>(Builtin::kWasmOnStackReplace),
4919}
4920
4922 DoubleRegister src,
4923 ValueKind kind) {
4924 if (kind == kF32) {
4925 Ucomiss(src, src);
4926 } else {
4928 Ucomisd(src, src);
4929 }
4930 Label ret;
4931 j(parity_odd, &ret);
4932 movl(Operand(dst, 0), Immediate(1));
4933 bind(&ret);
4934}
4935
4937 LiftoffRegister src,
4938 Register tmp_gp,
4939 LiftoffRegister tmp_s128,
4940 ValueKind lane_kind) {
4941 if (lane_kind == kF32) {
4942 movaps(tmp_s128.fp(), src.fp());
4943 cmpunordps(tmp_s128.fp(), tmp_s128.fp());
4944 } else {
4945 DCHECK_EQ(lane_kind, kF64);
4946 movapd(tmp_s128.fp(), src.fp());
4947 cmpunordpd(tmp_s128.fp(), tmp_s128.fp());
4948 }
4949 pmovmskb(tmp_gp, tmp_s128.fp());
4950 orl(Operand(dst, 0), tmp_gp);
4951}
4952
4953void LiftoffAssembler::emit_store_nonzero(Register dst) {
4954 movl(Operand(dst, 0), Immediate(1));
4955}
4956
4957void LiftoffStackSlots::Construct(int param_slots) {
4958 DCHECK_LT(0, slots_.size());
4960 int last_stack_slot = param_slots;
4961 for (auto& slot : slots_) {
4962 const int stack_slot = slot.dst_slot_;
4963 int stack_decrement = (last_stack_slot - stack_slot) * kSystemPointerSize;
4964 last_stack_slot = stack_slot;
4965 const LiftoffAssembler::VarState& src = slot.src_;
4966 DCHECK_LT(0, stack_decrement);
4967 switch (src.loc()) {
4969 if (src.kind() == kI32) {
4970 asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize);
4971 // Load i32 values to a register first to ensure they are zero
4972 // extended.
4973 asm_->movl(kScratchRegister, liftoff::GetStackSlot(slot.src_offset_));
4975 } else if (src.kind() == kS128) {
4976 asm_->AllocateStackSpace(stack_decrement - kSimd128Size);
4977 // Since offsets are subtracted from sp, we need a smaller offset to
4978 // push the top of a s128 value.
4979 asm_->pushq(liftoff::GetStackSlot(slot.src_offset_ - 8));
4980 asm_->pushq(liftoff::GetStackSlot(slot.src_offset_));
4981 } else {
4982 asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize);
4983 // For all other types, just push the whole (8-byte) stack slot.
4984 // This is also ok for f32 values (even though we copy 4 uninitialized
4985 // bytes), because f32 and f64 values are clearly distinguished in
4986 // Turbofan, so the uninitialized bytes are never accessed.
4987 asm_->pushq(liftoff::GetStackSlot(slot.src_offset_));
4988 }
4989 break;
4991 int pushed = src.kind() == kS128 ? kSimd128Size : kSystemPointerSize;
4992 liftoff::push(asm_, src.reg(), src.kind(), stack_decrement - pushed);
4993 break;
4994 }
4996 asm_->AllocateStackSpace(stack_decrement - kSystemPointerSize);
4997 asm_->pushq(Immediate(src.i32_const()));
4998 break;
4999 }
5000 }
5001}
5002
5003#undef RETURN_FALSE_IF_MISSING_CPU_FEATURE
5004
5005} // namespace v8::internal::wasm
5006
5007#endif // V8_WASM_BASELINE_X64_LIFTOFF_ASSEMBLER_X64_INL_H_
Builtins::Kind kind
Definition builtins.cc:40
V8_INLINE void RecordComment(const char *comment, const SourceLocation &loc=SourceLocation::Current())
Definition assembler.h:417
void emit_trace_instruction(Immediate markid)
void divss(XMMRegister dst, XMMRegister src)
void movsxwq(Register dst, Register src)
void movapd(XMMRegister dst, XMMRegister src)
void cmpxchgb(Operand dst, Register src)
void shll(const VRegister &vd, const VRegister &vn, int shift)
void movss(XMMRegister dst, Operand src)
void subss(XMMRegister dst, XMMRegister src)
void vmovd(XMMRegister dst, Register src)
void vroundps(XMMRegister dst, XMMRegister src, RoundingMode mode)
void jmp_rel(int offset)
void vpinsrq(XMMRegister dst, XMMRegister src1, Register src2, uint8_t imm8)
void vaddss(XMMRegister dst, XMMRegister src1, XMMRegister src2)
void popcntl(Register dst, Register src)
void mulss(XMMRegister dst, XMMRegister src)
void negw(Register reg)
void j(Condition cc, Label *L, Label::Distance distance=Label::kFar)
void xchgb(Register reg, Operand op)
void vmulss(XMMRegister dst, XMMRegister src1, XMMRegister src2)
void pinsrq(XMMRegister dst, Register src, uint8_t imm8)
void cmovq(Condition cc, Register dst, Register src)
void vpinsrb(XMMRegister dst, XMMRegister src1, Register src2, uint8_t offset)
void negb(Register reg)
void vpinsrw(XMMRegister dst, XMMRegister src1, Register src2, uint8_t offset)
void movdqa(XMMRegister dst, Operand src)
void pinsrw(XMMRegister dst, Register src, uint8_t offset)
void vsubss(XMMRegister dst, XMMRegister src1, XMMRegister src2)
void negl(Register reg)
void vdivss(XMMRegister dst, XMMRegister src1, XMMRegister src2)
void setcc(Condition cc, Register reg)
void pushq(Immediate value)
void movb(Register dst, Operand src)
void pinsrb(XMMRegister dst, Register src, uint8_t offset)
void pinsrd(XMMRegister dst, Register src, uint8_t offset)
void movsxwl(Register dst, Register src)
void xaddl(Operand dst, Register src)
void btrq(Register dst, Immediate imm8)
void movw(Register reg, uint32_t immediate, Condition cond=al)
void movsd(XMMRegister dst, XMMRegister src)
void movaps(XMMRegister dst, XMMRegister src)
void movsxbl(Register dst, Register src)
void xaddb(Operand dst, Register src)
void movsxbq(Register dst, Register src)
void cmovl(Condition cc, Register dst, Register src)
void xaddw(Operand dst, Register src)
void vcvtph2ps(XMMRegister dst, XMMRegister src)
void negq(Register reg)
void cmpxchgw(Operand dst, Register src)
void popq(Register dst)
void near_jmp(intptr_t disp, RelocInfo::Mode rmode)
void popcntq(Register dst, Register src)
void xchgw(Register reg, Operand op)
void movsxlq(Register dst, Register src)
void vinsertps(XMMRegister dst, XMMRegister src1, XMMRegister src2, uint8_t offset)
void pmovmskb(Register dst, XMMRegister src)
void movl(Operand dst, Label *src)
void testb(Register reg, Operand op)
void sub_sp_32(uint32_t imm)
Assembler(const AssemblerOptions &, std::unique_ptr< AssemblerBuffer >={})
void vpinsrd(XMMRegister dst, XMMRegister src1, Register src2, uint8_t offset)
void vcvtps2ph(XMMRegister dst, XMMRegister src, uint8_t imm8)
void xaddq(Operand dst, Register src)
void insertps(XMMRegister dst, XMMRegister src, uint8_t offset)
void addss(XMMRegister dst, XMMRegister src)
void movq(XMMRegister dst, Operand src)
static constexpr int kFixedFrameSizeAboveFp
static bool IsSupported(CpuFeature f)
static V8_EXPORT_PRIVATE ExternalReference isolate_address()
static constexpr MachineType Uint8()
static constexpr MachineType Int32()
static constexpr MachineType Uint32()
static constexpr MachineType Uint16()
static constexpr MachineType Int16()
static constexpr MachineType Int64()
static constexpr MachineType Int8()
void F32x4ExtractLane(DoubleRegister dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch1, Register scratch2, Register scratch3)
void I32x4TruncSatF64x2SZero(Simd128Register dst, Simd128Register src, Simd128Register scratch)
void Cvtqui2sd(XMMRegister dst, Register src)
void S128Select(Simd128Register dst, Simd128Register src1, Simd128Register src2, Simd128Register mask)
void I64x2UConvertI32x4High(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2)
void Cvttsd2uiq(Register dst, Operand src, Label *fail=nullptr)
void Cvttss2uiq(Register dst, Operand src, Label *fail=nullptr)
void LoadAddress(Register destination, ExternalReference source)
void I16x8Q15MulRSatS(Simd128Register dst, Simd128Register src1, Simd128Register src2, Simd128Register scratch1, Simd128Register scratch2, Simd128Register scratch3)
void Pextrq(Register dst, XMMRegister src, int8_t imm8)
void I64x2GtS(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2)
void near_call(int offset, RelocInfo::Mode rmode)
void Move(Register dst, Tagged< Smi > smi)
void Cvtqsi2sd(XMMRegister dst, Register src)
void F16x8Max(YMMRegister dst, XMMRegister lhs, XMMRegister rhs, YMMRegister scratch, YMMRegister scratch2)
void LoadTrustedPointerField(Register destination, MemOperand field_operand, IndirectPointerTag tag)
void I16x8Splat(Simd128Register dst, Register src)
void JumpIfSmi(Register value, Label *smi_label)
void AssertUnreachable(AbortReason reason) NOOP_UNLESS_DEBUG_CODE
void Cvtlsi2ss(XMMRegister dst, Register src)
void Cvtqui2ss(XMMRegister dst, Register src)
void Cvtqsi2ss(XMMRegister dst, Register src)
void F16x8Qfma(YMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, YMMRegister tmp, YMMRegister tmp2)
void I64x2Mul(Simd128Register dst, Simd128Register src1, Simd128Register src2, Register scratch1, Register scrahc2, Register scratch3, Simd128Register scratch4)
void I32x4SConvertF32x4(Simd128Register dst, Simd128Register src, Simd128Register scratch1, Register scratch2)
void F64x2Max(Simd128Register dst, Simd128Register src1, Simd128Register src2, Simd128Register scratch1, Simd128Register scratch2)
void Movq(XMMRegister dst, Register src)
void Tzcntq(Register dst, Register src)
void Cvtsd2ss(XMMRegister dst, XMMRegister src)
void I16x8SConvertF16x8(YMMRegister dst, XMMRegister src, YMMRegister tmp, Register scratch)
void I64x2GeS(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2)
void StoreTaggedField(const Register &value, const MemOperand &dst_field_operand)
void F64x2ConvertLowI32x4U(QwNeonRegister dst, QwNeonRegister src)
void LoadTaggedField(const Register &destination, const MemOperand &field_operand)
void Pinsrq(XMMRegister dst, XMMRegister src1, Register src2, uint8_t imm8, uint32_t *load_pc_offset=nullptr)
void Cvtlsi2sd(XMMRegister dst, Register src)
void I32x4UConvertI16x8High(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2)
void LoadProtectedPointerField(Register destination, MemOperand field_operand)
void F64x2Min(Simd128Register dst, Simd128Register src1, Simd128Register src2, Simd128Register scratch1, Simd128Register scratch2)
void CheckPageFlag(Register object, int mask, Condition cc, Label *condition_met)
void Lzcntl(Register dst, Register src)
int CallCFunction(ExternalReference function, int num_arguments, SetIsolateDataSlots set_isolate_data_slots=SetIsolateDataSlots::kYes, Label *return_label=nullptr)
void I16x8TruncF16x8U(YMMRegister dst, XMMRegister src, YMMRegister tmp)
void I64x2Abs(QwNeonRegister dst, QwNeonRegister src)
Operand StackLimitAsOperand(StackLimitKind kind)
void Cvtpd2ph(XMMRegister dst, XMMRegister src, Register tmp)
void SmiAddConstant(Operand dst, Tagged< Smi > constant)
void F64x2ExtractLane(DoubleRegister dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch1, Register scratch2)
void AllocateStackSpace(Register bytes)
void AssertZeroExtended(Register int32_register)
void I16x8UConvertI8x16High(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2)
void CallRecordWriteStubSaveRegisters(Register object, Operand offset, SaveFPRegsMode fp_mode, StubCallMode mode=StubCallMode::kCallBuiltinPointer)
void F16x8Qfms(YMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, YMMRegister tmp, YMMRegister tmp2)
void Cvtss2sd(XMMRegister dst, XMMRegister src)
void PrepareCallCFunction(int num_reg_arguments, int num_double_registers=0, Register scratch=no_reg)
void I8x16Splat(Simd128Register dst, Register src)
void F32x4Splat(Simd128Register dst, DoubleRegister src, DoubleRegister scratch1, Register scratch2)
void Lzcntq(Register dst, Register src)
void F16x8Min(YMMRegister dst, XMMRegister lhs, XMMRegister rhs, YMMRegister scratch, YMMRegister scratch2)
void F64x2ReplaceLane(Simd128Register dst, Simd128Register src1, DoubleRegister src2, uint8_t imm_lane_idx, Register scratch1, Simd128Register scratch2)
void Tzcntl(Register dst, Register src)
void I32x4TruncSatF64x2UZero(Simd128Register dst, Simd128Register src, Simd128Register scratch)
void I8x16Swizzle(Simd128Register dst, Simd128Register src1, Simd128Register src2, Register scratch1, Register scratch2, Simd128Register scratch3)
static constexpr MainThreadFlags kPointersToHereAreInterestingMask
static constexpr MainThreadFlags kPointersFromHereAreInterestingMask
constexpr int8_t code() const
void S128Load16Splat(XMMRegister dst, Operand src, XMMRegister scratch)
void F32x4Qfms(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, XMMRegister tmp)
void F32x4Max(XMMRegister dst, XMMRegister lhs, XMMRegister rhs, XMMRegister scratch)
void I16x8ExtMulLow(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister scrat, bool is_signed)
void F64x2Qfms(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, XMMRegister tmp)
void Pblendvb(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister mask)
void S128Not(XMMRegister dst, XMMRegister src, XMMRegister scratch)
void I16x8SConvertI8x16High(XMMRegister dst, XMMRegister src)
void I16x8ExtMulHighS(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister scratch)
void S128Store64Lane(Operand dst, XMMRegister src, uint8_t laneidx)
void Pinsrb(XMMRegister dst, XMMRegister src1, Op src2, uint8_t imm8, uint32_t *load_pc_offset=nullptr)
void I32x4DotI8x16I7x16AddS(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, XMMRegister scratch, XMMRegister splat_reg)
void Blendvpd(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister mask)
void Blendvps(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister mask)
void S128Load8Splat(XMMRegister dst, Operand src, XMMRegister scratch)
void I8x16ShrU(XMMRegister dst, XMMRegister src1, uint8_t src2, Register tmp1, XMMRegister tmp2)
void F32x4Min(XMMRegister dst, XMMRegister lhs, XMMRegister rhs, XMMRegister scratch)
void I32x4SConvertI16x8High(XMMRegister dst, XMMRegister src)
void I64x2ShrS(XMMRegister dst, XMMRegister src, uint8_t shift, XMMRegister xmm_tmp)
void I64x2ExtMul(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister scratch, bool low, bool is_signed)
void Pshufb(XMMRegister dst, XMMRegister src, Op mask)
void I64x2SConvertI32x4High(XMMRegister dst, XMMRegister src)
void F64x2Qfma(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, XMMRegister tmp)
void I8x16Shl(XMMRegister dst, XMMRegister src1, uint8_t src2, Register tmp1, XMMRegister tmp2)
void I16x8DotI8x16I7x16S(XMMRegister dst, XMMRegister src1, XMMRegister src2)
void I8x16ShrS(XMMRegister dst, XMMRegister src1, uint8_t src2, XMMRegister tmp)
void I64x2Neg(XMMRegister dst, XMMRegister src, XMMRegister scratch)
void F32x4Qfma(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister src3, XMMRegister tmp)
void Pinsrw(XMMRegister dst, XMMRegister src1, Op src2, uint8_t imm8, uint32_t *load_pc_offset=nullptr)
void I16x8ExtMulHighU(XMMRegister dst, XMMRegister src1, XMMRegister src2, XMMRegister scratch)
void I32x4ExtAddPairwiseI16x8U(XMMRegister dst, XMMRegister src, XMMRegister tmp)
void S128Store32Lane(Operand dst, XMMRegister src, uint8_t laneidx)
void Negpd(XMMRegister dst, XMMRegister src, Register tmp)
void I32x4TruncF32x4U(XMMRegister dst, XMMRegister src, XMMRegister scratch1, XMMRegister scratch2)
void Absps(XMMRegister dst, XMMRegister src, Register tmp)
void Negph(XMMRegister dst, XMMRegister src, Register tmp)
void Negps(XMMRegister dst, XMMRegister src, Register tmp)
void Pinsrd(XMMRegister dst, XMMRegister src1, Op src2, uint8_t imm8, uint32_t *load_pc_offset=nullptr)
void I16x8ExtAddPairwiseI8x16S(XMMRegister dst, XMMRegister src, XMMRegister scratch, Register tmp)
void Abspd(XMMRegister dst, XMMRegister src, Register tmp)
void Pextrd(Register dst, XMMRegister src, uint8_t imm8)
void Absph(XMMRegister dst, XMMRegister src, Register tmp)
void I16x8ExtAddPairwiseI8x16U(XMMRegister dst, XMMRegister src, Register scratch)
void I32x4ExtAddPairwiseI16x8S(XMMRegister dst, XMMRegister src, Register scratch)
void I8x16Popcnt(XMMRegister dst, XMMRegister src, XMMRegister tmp1, XMMRegister tmp2, Register scratch)
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr int32_t TypeToMarker(Type type)
Definition frames.h:196
static constexpr int kFrameTypeOffset
static constexpr YMMRegister from_code(int code)
void emit_i8x16_swizzle(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_uconvert_i32x4_low(LiftoffRegister dst, LiftoffRegister src)
void ClearRegister(Register reg, std::initializer_list< Register * > possible_uses, LiftoffRegList pinned)
bool emit_f16x8_nearest_int(LiftoffRegister dst, LiftoffRegister src)
void emit_store_nonzero_if_nan(Register dst, DoubleRegister src, ValueKind kind)
bool emit_f32x4_floor(LiftoffRegister dst, LiftoffRegister src)
void emit_f64_div(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_f32x4_pmax(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_sconvert_i32x4_low(LiftoffRegister dst, LiftoffRegister src)
void emit_i64x2_shl(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_lt(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_gt_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void set_trap_on_oob_mem64(Register index, uint64_t max_index, Label *trap_label)
void emit_i16x8_add_sat_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f32x4_le(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_div(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void AtomicXor(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister value, LiftoffRegister result, StoreType type, bool i64_offset)
void emit_i64_shl(LiftoffRegister dst, LiftoffRegister src, Register amount)
void emit_i64_ori(LiftoffRegister dst, LiftoffRegister lhs, int32_t imm)
void emit_i64_shli(LiftoffRegister dst, LiftoffRegister src, int32_t amount)
void emit_i8x16_add_sat_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_relaxed_trunc_f64x2_u_zero(LiftoffRegister dst, LiftoffRegister src)
void emit_i32x4_min_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_relaxed_q15mulr_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_i8x16_extract_lane_s(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
void emit_f32_min(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_i32x4_ge_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_qfms(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3)
void emit_f32x4_div(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f64_ceil(DoubleRegister dst, DoubleRegister src)
void emit_i16x8_extmul_high_i8x16_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_f64x2_pmax(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_trunc(LiftoffRegister dst, LiftoffRegister src)
bool emit_f16x8_extract_lane(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
void emit_i32_rems(Register dst, Register lhs, Register rhs, Label *trap_rem_by_zero)
void emit_i64x2_extmul_high_i32x4_u(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_i32_clz(Register dst, Register src)
void emit_i8x16_min_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32_shri(Register dst, Register src, int32_t amount)
void emit_f64x2_max(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64_mul(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_i16x8_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_shli(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void emit_i32_eqz(Register dst, Register src)
void emit_i32x4_extadd_pairwise_i16x8_s(LiftoffRegister dst, LiftoffRegister src)
void emit_i32x4_uconvert_f32x4(LiftoffRegister dst, LiftoffRegister src)
void emit_i16x8_uconvert_i8x16_low(LiftoffRegister dst, LiftoffRegister src)
bool emit_f32_floor(DoubleRegister dst, DoubleRegister src)
void emit_f32x4_neg(LiftoffRegister dst, LiftoffRegister src)
void emit_i16x8_splat(LiftoffRegister dst, LiftoffRegister src)
void emit_f32_max(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_i8x16_uconvert_i16x8(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_shri_s(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void FillI64Half(Register, int offset, RegPairHalf)
bool emit_f16x8_splat(LiftoffRegister dst, LiftoffRegister src)
void emit_f32x4_demote_f64x2_zero(LiftoffRegister dst, LiftoffRegister src)
void emit_i64_sari(LiftoffRegister dst, LiftoffRegister src, int32_t amount)
void emit_f64x2_splat(LiftoffRegister dst, LiftoffRegister src)
bool emit_i64_remu(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs, Label *trap_rem_by_zero)
void CallCWithStackBuffer(const std::initializer_list< VarState > args, const LiftoffRegister *rets, ValueKind return_kind, ValueKind out_argument_kind, int stack_bytes, ExternalReference ext_ref)
void emit_f32_mul(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_s128_and(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_neg(LiftoffRegister dst, LiftoffRegister src)
void emit_i64x2_abs(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_sub_sat_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f32x4_max(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_ge_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f32_nearest_int(DoubleRegister dst, DoubleRegister src)
void emit_f64x2_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx)
void emit_i32x4_dot_i16x8_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64_muli(LiftoffRegister dst, LiftoffRegister lhs, int32_t imm)
void emit_i64_xori(LiftoffRegister dst, LiftoffRegister lhs, int32_t imm)
void emit_i16x8_extmul_low_i8x16_u(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_f64x2_le(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_shr_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_shr_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_uconvert_i8x16_high(LiftoffRegister dst, LiftoffRegister src)
void emit_i16x8_eq(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f32x4_pmin(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_alltrue(LiftoffRegister dst, LiftoffRegister src)
void emit_i16x8_dot_i8x16_i7x16_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_i16x8_sconvert_i8x16_high(LiftoffRegister dst, LiftoffRegister src)
void emit_f64x2_qfma(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3)
void emit_i32_subi(Register dst, Register lhs, int32_t imm)
void emit_i32_shli(Register dst, Register src, int32_t amount)
void emit_i32x4_extmul_low_i16x8_u(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void AtomicAdd(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister value, LiftoffRegister result, StoreType type, bool i64_offset)
void AtomicSub(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister value, LiftoffRegister result, StoreType type, bool i64_offset)
void LoadTransform(LiftoffRegister dst, Register src_addr, Register offset_reg, uintptr_t offset_imm, LoadType type, LoadTransformationKind transform, uint32_t *protected_load_pc, bool i64_offset)
void emit_i32x4_uconvert_i16x8_low(LiftoffRegister dst, LiftoffRegister src)
void emit_s128_store_nonzero_if_nan(Register dst, LiftoffRegister src, Register tmp_gp, LiftoffRegister tmp_s128, ValueKind lane_kind)
void emit_i32x4_splat(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_sar(Register dst, Register src, Register amount)
void emit_i16x8_shri_u(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
bool emit_i16x8_sconvert_f16x8(LiftoffRegister dst, LiftoffRegister src)
void AtomicAnd(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister value, LiftoffRegister result, StoreType type, bool i64_offset)
void emit_i16x8_sconvert_i32x4(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_add_sat_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_shl(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_add_sat_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void AtomicCompareExchange(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister expected, LiftoffRegister new_value, LiftoffRegister value, StoreType type, bool i64_offset)
void emit_i8x16_shl(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_s128_not(LiftoffRegister dst, LiftoffRegister src)
void emit_i64_signextend_i16(LiftoffRegister dst, LiftoffRegister src)
void emit_i32x4_gt_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_dot_i8x16_i7x16_add_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister acc)
bool emit_f16x8_neg(LiftoffRegister dst, LiftoffRegister src)
void emit_f64x2_convert_low_i32x4_u(LiftoffRegister dst, LiftoffRegister src)
void emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_f32x4_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_pmax(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_eq(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_shli(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void emit_f64_min(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_i64x2_shr_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_sconvert_i16x8(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f64_trunc(DoubleRegister dst, DoubleRegister src)
void emit_f64_set_cond(Condition condition, Register dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_f32x4_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_abs(LiftoffRegister dst, LiftoffRegister src)
void Fill(LiftoffRegister, int offset, ValueKind)
void emit_i32_shr(Register dst, Register src, Register amount)
void emit_i64_signextend_i32(LiftoffRegister dst, LiftoffRegister src)
void emit_i64x2_extract_lane(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
void emit_f32x4_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx)
void LoadFullPointer(Register dst, Register src_addr, int32_t offset_imm)
void emit_i8x16_max_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_extmul_low_i32x4_u(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_i16x8_max_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_abs(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_andi(Register dst, Register lhs, int32_t imm)
bool emit_f16x8_abs(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_ge_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_convert_low_i32x4_s(LiftoffRegister dst, LiftoffRegister src)
bool emit_f16x8_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx)
bool emit_f32x4_promote_low_f16x8(LiftoffRegister dst, LiftoffRegister src)
void Store(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister src, StoreType type, LiftoffRegList pinned, uint32_t *protected_store_pc=nullptr, bool is_store_mem=false, bool i64_offset=false)
bool emit_f16x8_mul(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void Load(LiftoffRegister dst, Register src_addr, Register offset_reg, uintptr_t offset_imm, LoadType type, uint32_t *protected_load_pc=nullptr, bool is_load_mem=false, bool i64_offset=false, bool needs_shift=false)
void emit_i64x2_shri_u(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
bool emit_f16x8_max(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_shr_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f32x4_uconvert_i32x4(LiftoffRegister dst, LiftoffRegister src)
void emit_i64x2_extmul_high_i32x4_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_f32x4_relaxed_min(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_shri_s(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void emit_f64_sub(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_i32_signextend_i16(Register dst, Register src)
void emit_i8x16_gt_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32_divs(Register dst, Register lhs, Register rhs, Label *trap_div_by_zero, Label *trap_div_unrepresentable)
void emit_f32_neg(DoubleRegister dst, DoubleRegister src)
void emit_f64x2_promote_low_f32x4(LiftoffRegister dst, LiftoffRegister src)
void emit_i64_addi(LiftoffRegister dst, LiftoffRegister lhs, int64_t imm)
void LoadLane(LiftoffRegister dst, LiftoffRegister src, Register addr, Register offset_reg, uintptr_t offset_imm, LoadType type, uint8_t lane, uint32_t *protected_load_pc, bool i64_offset)
void emit_i16x8_sub_sat_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_bitmask(LiftoffRegister dst, LiftoffRegister src)
void emit_i32x4_alltrue(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_and(Register dst, Register lhs, Register rhs)
void emit_i16x8_extract_lane_s(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
void emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
bool emit_f64x2_trunc(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_rounding_average_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_ne(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_relaxed_swizzle(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_abs(LiftoffRegister dst, LiftoffRegister src)
bool emit_f16x8_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void CallFrameSetupStub(int declared_function_index)
void emit_i64x2_uconvert_i32x4_high(LiftoffRegister dst, LiftoffRegister src)
void emit_f32_abs(DoubleRegister dst, DoubleRegister src)
void emit_i32_remu(Register dst, Register lhs, Register rhs, Label *trap_rem_by_zero)
bool emit_f64x2_ceil(LiftoffRegister dst, LiftoffRegister src)
bool emit_f16x8_eq(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void LoadSpillAddress(Register dst, int offset, ValueKind kind)
void emit_i16x8_extmul_high_i8x16_u(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_f32x4_qfms(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3)
void emit_f64_neg(DoubleRegister dst, DoubleRegister src)
void emit_i64x2_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx)
void emit_i32_ctz(Register dst, Register src)
void StoreCallerFrameSlot(LiftoffRegister, uint32_t caller_slot_idx, ValueKind, Register frame_pointer)
void emit_i32x4_shli(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void AtomicExchange(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister value, LiftoffRegister result, StoreType type, bool i64_offset)
void emit_i32x4_min_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_mul(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32_xor(Register dst, Register lhs, Register rhs)
void emit_s128_select(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister mask)
bool emit_i64_rems(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs, Label *trap_rem_by_zero)
void emit_i8x16_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx)
bool emit_f16x8_ne(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_sconvert_i32x4_high(LiftoffRegister dst, LiftoffRegister src)
void CallC(const std::initializer_list< VarState > args, ExternalReference ext_ref)
void emit_i32x4_trunc_sat_f64x2_s_zero(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_or(Register dst, Register lhs, Register rhs)
bool emit_f16x8_floor(LiftoffRegister dst, LiftoffRegister src)
void emit_i64_signextend_i8(LiftoffRegister dst, LiftoffRegister src)
void emit_i16x8_extadd_pairwise_i8x16_s(LiftoffRegister dst, LiftoffRegister src)
void emit_i64x2_bitmask(LiftoffRegister dst, LiftoffRegister src)
void emit_i64x2_extmul_low_i32x4_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
bool emit_i64_divu(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs, Label *trap_div_by_zero)
bool emit_f16x8_demote_f32x4_zero(LiftoffRegister dst, LiftoffRegister src)
void emit_f32x4_qfma(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3)
void emit_f32x4_ne(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_gt_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_min(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_shri_s(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
bool emit_f64x2_nearest_int(LiftoffRegister dst, LiftoffRegister src)
void DropStackSlotsAndRet(uint32_t num_stack_slots)
void emit_f32x4_abs(LiftoffRegister dst, LiftoffRegister src)
void emit_s128_and_not(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_s128_relaxed_laneselect(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister mask, int lane_width)
void emit_i32x4_shri_u(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void emit_f64x2_extract_lane(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
void emit_i16x8_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx)
void emit_i32x4_sconvert_f32x4(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_shri_u(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void emit_i32_sari(Register dst, Register src, int32_t amount)
void LoadConstant(LiftoffRegister, WasmValue)
void emit_i32x4_uconvert_i16x8_high(LiftoffRegister dst, LiftoffRegister src)
void emit_i16x8_sub_sat_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_max_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f32x4_trunc(LiftoffRegister dst, LiftoffRegister src)
void emit_i32x4_max_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_ne(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64_xor(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void PrepareTailCall(int num_callee_stack_params, int stack_param_delta)
void emit_f32x4_relaxed_max(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f64_nearest_int(DoubleRegister dst, DoubleRegister src)
bool emit_f16x8_ceil(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_divu(Register dst, Register lhs, Register rhs, Label *trap_div_by_zero)
void emit_cond_jump(Condition, Label *, ValueKind value, Register lhs, Register rhs, const FreezeCacheState &frozen)
void LoadFromInstance(Register dst, Register instance, int offset, int size)
void emit_i8x16_min_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_ne(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_smi_check(Register obj, Label *target, SmiCheckMode mode, const FreezeCacheState &frozen)
void emit_f64_max(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_f32x4_extract_lane(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
void LoadProtectedPointer(Register dst, Register src_addr, int32_t offset)
void emit_i32x4_extmul_low_i16x8_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_f64_add(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_i64_sar(LiftoffRegister dst, LiftoffRegister src, Register amount)
void emit_i16x8_shr_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32_ori(Register dst, Register lhs, int32_t imm)
void emit_f64x2_qfms(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3)
bool emit_f32x4_ceil(LiftoffRegister dst, LiftoffRegister src)
bool emit_i64_popcnt(LiftoffRegister dst, LiftoffRegister src)
void emit_u32_to_uintptr(Register dst, Register src)
void emit_i32x4_trunc_sat_f64x2_u_zero(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_mul(Register dst, Register lhs, Register rhs)
void emit_i8x16_extract_lane_u(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
bool emit_f64_floor(DoubleRegister dst, DoubleRegister src)
void emit_f32_set_cond(Condition condition, Register dst, DoubleRegister lhs, DoubleRegister rhs)
bool emit_f16x8_uconvert_i16x8(LiftoffRegister dst, LiftoffRegister src)
void emit_i16x8_min_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_mul(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_demote_f64x2_zero(LiftoffRegister dst, LiftoffRegister src)
bool emit_f16x8_div(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_gt_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f32x4_nearest_int(LiftoffRegister dst, LiftoffRegister src)
void emit_i64_shri(LiftoffRegister dst, LiftoffRegister src, int32_t amount)
void emit_i32x4_sconvert_i16x8_high(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_shri_s(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void emit_i64_set_cond(Condition condition, Register dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f64x2_floor(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_sub_sat_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_neg(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_sconvert_i16x8_low(LiftoffRegister dst, LiftoffRegister src)
void emit_f64x2_ne(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_le(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_i32_popcnt(Register dst, Register src)
void emit_i16x8_rounding_average_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_replace_lane(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, uint8_t imm_lane_idx)
void MoveStackValue(uint32_t dst_offset, uint32_t src_offset, ValueKind)
void emit_i64x2_gt_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_min_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_ge_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void Move(LiftoffRegister dst, LiftoffRegister src, ValueKind)
void emit_i8x16_ge_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64x2_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_uconvert_i32x4(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_lt(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_popcnt(LiftoffRegister dst, LiftoffRegister src)
void AtomicStore(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister src, StoreType type, LiftoffRegList pinned, bool i64_offset)
void emit_f64_abs(DoubleRegister dst, DoubleRegister src)
void emit_i64_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_pmin(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void PatchPrepareStackFrame(int offset, SafepointTableBuilder *, bool feedback_vector_slot, size_t stack_param_slots)
void emit_f32x4_sconvert_i32x4(LiftoffRegister dst, LiftoffRegister src)
void emit_ptrsize_cond_jumpi(Condition, Label *, Register lhs, int32_t imm, const FreezeCacheState &frozen)
void LoadCallerFrameSlot(LiftoffRegister, uint32_t caller_slot_idx, ValueKind)
void emit_i64x2_ne(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64_or(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f32_sqrt(DoubleRegister dst, DoubleRegister src)
void emit_i64x2_alltrue(LiftoffRegister dst, LiftoffRegister src)
void emit_f32_sub(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_i16x8_ge_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32_xori(Register dst, Register lhs, int32_t imm)
void emit_i64_ctz(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_set_cond(Condition, Register dst, Register lhs, Register rhs)
void emit_f32x4_min(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_i64_divs(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs, Label *trap_div_by_zero, Label *trap_div_unrepresentable)
void emit_i16x8_sconvert_i8x16_low(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_sub(Register dst, Register lhs, Register rhs)
void TailCallIndirect(compiler::CallDescriptor *call_descriptor, Register target)
void emit_i16x8_q15mulr_sat_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_i64x2_neg(LiftoffRegister dst, LiftoffRegister src)
void emit_i64x2_shli(LiftoffRegister dst, LiftoffRegister lhs, int32_t rhs)
void emit_i64_shr(LiftoffRegister dst, LiftoffRegister src, Register amount)
void emit_i16x8_bitmask(LiftoffRegister dst, LiftoffRegister src)
void emit_i32x4_sub(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_max_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f32_div(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
void emit_i64_andi(LiftoffRegister dst, LiftoffRegister lhs, int32_t imm)
bool emit_f16x8_min(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_relaxed_trunc_f32x4_s(LiftoffRegister dst, LiftoffRegister src)
void emit_i64x2_splat(LiftoffRegister dst, LiftoffRegister src)
void emit_f32x4_sqrt(LiftoffRegister dst, LiftoffRegister src)
void emit_i16x8_mul(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_shr_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_extmul_low_i8x16_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_f64x2_mul(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void AllocateStackSlot(Register addr, uint32_t size)
void emit_i32x4_extract_lane(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
void emit_s128_or(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void LoadTaggedPointer(Register dst, Register src_addr, Register offset_reg, int32_t offset_imm, uint32_t *protected_load_pc=nullptr, bool offset_reg_needs_shift=false)
void emit_f64x2_eq(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_alltrue(LiftoffRegister dst, LiftoffRegister src)
void emit_i32x4_shr_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_abs(LiftoffRegister dst, LiftoffRegister src)
void emit_f32x4_splat(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_shr_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32_cond_jumpi(Condition, Label *, Register lhs, int imm, const FreezeCacheState &frozen)
void emit_i64_eqz(Register dst, LiftoffRegister src)
void StoreTaggedPointer(Register dst_addr, Register offset_reg, int32_t offset_imm, Register src, LiftoffRegList pinned, uint32_t *protected_store_pc=nullptr, SkipWriteBarrier=kNoSkipWriteBarrier)
void emit_i64_clz(LiftoffRegister dst, LiftoffRegister src)
void emit_f32x4_mul(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void IncrementSmi(LiftoffRegister dst, int offset)
LiftoffRegister GetUnusedRegister(RegClass rc, std::initializer_list< LiftoffRegister > try_first, LiftoffRegList pinned)
void emit_i16x8_gt_s(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_shl(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_splat(LiftoffRegister dst, LiftoffRegister src)
bool emit_f16x8_sconvert_i16x8(LiftoffRegister dst, LiftoffRegister src)
void emit_f64x2_sqrt(LiftoffRegister dst, LiftoffRegister src)
void emit_i8x16_shuffle(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs, const uint8_t shuffle[16], bool is_swizzle)
void emit_i32x4_extadd_pairwise_i16x8_u(LiftoffRegister dst, LiftoffRegister src)
bool emit_f32_ceil(DoubleRegister dst, DoubleRegister src)
void emit_i32_addi(Register dst, Register lhs, int32_t imm)
void emit_i16x8_extadd_pairwise_i8x16_u(LiftoffRegister dst, LiftoffRegister src)
void emit_i32x4_extmul_high_i16x8_s(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_i64x2_add(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i64_mul(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i8x16_max_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void AtomicOr(Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister value, LiftoffRegister result, StoreType type, bool i64_offset)
bool emit_select(LiftoffRegister dst, Register condition, LiftoffRegister true_value, LiftoffRegister false_value, ValueKind kind)
bool emit_i16x8_uconvert_f16x8(LiftoffRegister dst, LiftoffRegister src)
bool emit_type_conversion(WasmOpcode opcode, LiftoffRegister dst, LiftoffRegister src, Label *trap=nullptr)
void emit_i8x16_neg(LiftoffRegister dst, LiftoffRegister src)
void AtomicLoad(LiftoffRegister dst, Register src_addr, Register offset_reg, uintptr_t offset_imm, LoadType type, LiftoffRegList pinned, bool i64_offset)
void emit_i64x2_eq(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void LoadReturnStackSlot(LiftoffRegister, int offset, ValueKind)
void emit_i32x4_neg(LiftoffRegister dst, LiftoffRegister src)
void emit_s128_xor(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i16x8_ge_u(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32x4_relaxed_trunc_f32x4_u(LiftoffRegister dst, LiftoffRegister src)
bool emit_f32_trunc(DoubleRegister dst, DoubleRegister src)
void LoadTaggedPointerFromInstance(Register dst, Register instance, int offset)
void emit_v128_anytrue(LiftoffRegister dst, LiftoffRegister src)
void emit_i32_shl(Register dst, Register src, Register amount)
void emit_i32x4_extmul_high_i16x8_u(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2)
void emit_f32x4_lt(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_s128_const(LiftoffRegister dst, const uint8_t imms[16])
void emit_f64_sqrt(DoubleRegister dst, DoubleRegister src)
void emit_i64_and(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void StoreLane(Register dst, Register offset, uintptr_t offset_imm, LiftoffRegister src, StoreType type, uint8_t lane, uint32_t *protected_store_pc, bool i64_offset)
void CheckTierUp(int declared_func_index, int budget_used, Label *ool_label, const FreezeCacheState &frozen)
void emit_i16x8_extract_lane_u(LiftoffRegister dst, LiftoffRegister lhs, uint8_t imm_lane_idx)
void emit_f64x2_relaxed_min(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void CallIndirect(const ValueKindSig *sig, compiler::CallDescriptor *call_descriptor, Register target)
void RecordSpillsInSafepoint(SafepointTableBuilder::Safepoint &safepoint, LiftoffRegList all_spills, LiftoffRegList ref_spills, int spill_offset)
void emit_f64x2_relaxed_max(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool emit_f16x8_qfma(LiftoffRegister dst, LiftoffRegister src1, LiftoffRegister src2, LiftoffRegister src3)
void emit_i8x16_eq(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f64x2_pmin(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_f32_add(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs)
bool emit_f16x8_sqrt(LiftoffRegister dst, LiftoffRegister src)
void LoadTrustedPointer(Register dst, Register src_addr, int offset, IndirectPointerTag tag)
void emit_i32_add(Register dst, Register lhs, Register rhs)
void emit_i32x4_relaxed_trunc_f64x2_s_zero(LiftoffRegister dst, LiftoffRegister src)
void emit_f32x4_eq(LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
void emit_i32_signextend_i8(Register dst, Register src)
void emit_i8x16_bitmask(LiftoffRegister dst, LiftoffRegister src)
constexpr Register set(Register reg)
constexpr unsigned GetNumRegsSet() const
constexpr DoubleRegister fp() const
base::SmallVector< Slot, 8 > slots_
static constexpr int ToTagged(int offset)
static void Pack16Lanes(uint32_t *dst, const uint8_t *shuffle)
Handle< Code > code
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
int start
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
Label label
static constexpr unsigned kSignBit
int32_t offset
double remainder
ZoneVector< RpoNumber > & result
#define dop(name,...)
#define RETURN_FALSE_IF_MISSING_CPU_FEATURE(name)
#define iop(name,...)
LiftoffRegister reg
MovableLabel continuation
LiftoffRegList regs_to_save
std::optional< OolTrapLabel > trap
uint32_t const mask
int int32_t
Definition unicode.cc:40
constexpr bool IsPowerOfTwo(T value)
Definition bits.h:187
constexpr int WhichPowerOfTwo(T value)
Definition bits.h:195
void EmitAllTrue(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister src, VectorFormat format)
void EmitIntDivOrRem(LiftoffAssembler *assm, Register dst, Register lhs, Register rhs, Label *trap_div_by_zero, Label *trap_div_unrepresentable)
void AtomicBinop(LiftoffAssembler *lasm, Register dst_addr, Register offset_reg, uintptr_t offset_imm, LiftoffRegister value, LiftoffRegister result, StoreType type, Binop op)
void EmitCommutativeBinOpImm(LiftoffAssembler *assm, Register dst, Register lhs, int32_t imm)
void EmitSatTruncateFloatToInt(LiftoffAssembler *assm, Register dst, DoubleRegister src)
void EmitFloatMinOrMax(LiftoffAssembler *assm, RegisterType dst, RegisterType lhs, RegisterType rhs, MinOrMax min_or_max)
void StoreToMemory(LiftoffAssembler *assm, MemOperand dst, const LiftoffAssembler::VarState &src)
constexpr DoubleRegister kScratchDoubleReg
void EmitAnyTrue(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister src)
void EmitFloatSetCond(LiftoffAssembler *assm, Condition cond, Register dst, DoubleRegister lhs, DoubleRegister rhs)
void EmitSimdNonCommutativeBinOp(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs, std::optional< CpuFeature > feature=std::nullopt)
void EmitSimdShiftOp(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister operand, LiftoffRegister count)
void EmitTruncateFloatToInt(LiftoffAssembler *assm, Register dst, DoubleRegister src, Label *trap)
void EmitSimdShiftOpImm(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister operand, int32_t count)
void push(LiftoffAssembler *assm, LiftoffRegister reg, ValueKind kind, int padding=0)
constexpr DoubleRegister kScratchDoubleReg2
void EmitShiftOperation(LiftoffAssembler *assm, Register dst, Register src, Register amount, void(Assembler::*emit_shift)(Register))
void EmitCommutativeBinOp(LiftoffAssembler *assm, Register dst, Register lhs, Register rhs)
MemOperand GetMemOp(LiftoffAssembler *assm, UseScratchRegisterScope *temps, Register addr, Register offset, int32_t offset_imm, unsigned shift_amount=0)
void EmitSatTruncateFloatToUInt64(LiftoffAssembler *assm, Register dst, DoubleRegister src)
void ConvertFloatToIntAndBack(LiftoffAssembler *assm, Register dst, DoubleRegister src, DoubleRegister converted_back, LiftoffRegList pinned)
void EmitSimdCommutativeBinOp(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs, std::optional< CpuFeature > feature=std::nullopt)
void LoadFromStack(LiftoffAssembler *assm, LiftoffRegister dst, Operand src, ValueKind kind)
void I32x4ExtMulHelper(LiftoffAssembler *assm, XMMRegister dst, XMMRegister src1, XMMRegister src2, bool low, bool is_signed)
static constexpr RegClass reg_class_for(ValueKind kind)
constexpr DoubleRegister kFpReturnRegisters[]
constexpr Register kGpParamRegisters[]
constexpr DoubleRegister kFpParamRegisters[]
constexpr DoubleRegList kLiftoffAssemblerFpCacheRegs
constexpr int value_kind_full_size(ValueKind kind)
constexpr RegList kLiftoffAssemblerGpCacheRegs
constexpr Register kGpReturnRegisters[]
bool F16x8CmpOpViaF32(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
bool F16x8BinOpViaF32(LiftoffAssembler *assm, LiftoffRegister dst, LiftoffRegister lhs, LiftoffRegister rhs)
int declared_function_index(const WasmModule *module, int func_index)
typedef void(VECTORCALL PWasmOp)(const uint8_t *code
constexpr int value_kind_size(ValueKind kind)
static constexpr LiftoffRegList kGpCacheRegList
static constexpr LiftoffRegList kFpCacheRegList
constexpr bool is_reference(ValueKind kind)
LiftoffAssembler::ValueKindSig ValueKindSig
constexpr Register no_reg
constexpr int kMinInt
Definition globals.h:375
constexpr VFPRoundingMode kRoundToNearest
constexpr int kSimd128Size
Definition globals.h:706
DwVfpRegister DoubleRegister
constexpr DoubleRegister kScratchDoubleReg
kWasmInternalFunctionIndirectPointerTag instance_data
constexpr DoubleRegister kScratchDoubleReg2
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
constexpr int kSystemPointerSize
Definition globals.h:410
constexpr Register kReturnRegister0
constexpr Register kScratchRegister
constexpr int kInt32Size
Definition globals.h:401
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr Register r11
const intptr_t kSmiTagMask
Definition v8-internal.h:88
constexpr VFPRoundingMode kRoundToZero
constexpr Register kCArgRegs[]
std::unique_ptr< AssemblerBuffer > ExternalAssemblerBuffer(void *start, int size)
Definition assembler.cc:161
bool is_signed(Condition cond)
constexpr YMMRegister kScratchSimd256Reg
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
#define arraysize(array)
Definition macros.h:67
uint64_t make_uint64(uint32_t high, uint32_t low)
Definition macros.h:365
#define V8_LIKELY(condition)
Definition v8config.h:661